From 9561a5f4725f0aed4d161b24ad7c8b6a8d6bf1ac Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Mon, 30 Mar 2026 18:18:13 +1100 Subject: [PATCH 01/17] Aspect pipe resprite, more modular crafter func --- assets/bundles/bundle.properties | 4 + assets/bundles/bundle.shitpost | 3 + .../fluid/director/aspect-pipe-bottom-1.png | Bin 244 -> 1062 bytes .../fluid/director/aspect-pipe-bottom-2.png | Bin 233 -> 952 bytes .../fluid/director/aspect-pipe-bottom-3.png | Bin 213 -> 1204 bytes .../fluid/director/aspect-pipe-bottom-4.png | Bin 217 -> 1180 bytes .../fluid/director/aspect-pipe-preview.png | Bin 507 -> 0 bytes .../fluid/director/aspect-pipe-top-.png | Bin 0 -> 446 bytes .../fluid/director/aspect-pipe-top-0.png | Bin 314 -> 364 bytes .../fluid/director/aspect-pipe-top-1.png | Bin 472 -> 471 bytes .../fluid/director/aspect-pipe-top-2.png | Bin 444 -> 401 bytes .../fluid/director/aspect-pipe-top-3.png | Bin 446 -> 376 bytes .../fluid/director/aspect-pipe-top-4.png | Bin 460 -> 413 bytes assets/sprites/items/clay-mallow.png | Bin 0 -> 359 bytes src/meld/content/MeldBlocks.java | 245 ++++++++++++++++-- src/meld/content/MeldItems.java | 16 +- src/meld/world/blocks/LiquidUtil.java | 33 +++ .../world/blocks/crafting/ItemRecipe.java | 77 ++++++ .../world/blocks/crafting/ModularCrafter.java | 89 ++++++- src/meld/world/blocks/crafting/Recipe.java | 9 + .../crafting/modules/AdditionModule.java | 13 + .../blocks/crafting/modules/ConsumeGate.java | 20 +- .../blocks/crafting/modules/GateModule.java | 115 ++++++++ .../blocks/crafting/modules/LambdaModule.java | 14 + .../modules/RecipeCraftingModule.java | 19 ++ 25 files changed, 620 insertions(+), 37 deletions(-) create mode 100644 assets/bundles/bundle.shitpost delete mode 100644 assets/sprites/blocks/fluid/director/aspect-pipe-preview.png create mode 100644 assets/sprites/blocks/fluid/director/aspect-pipe-top-.png create mode 100644 assets/sprites/items/clay-mallow.png create mode 100644 src/meld/world/blocks/LiquidUtil.java create mode 100644 src/meld/world/blocks/crafting/ItemRecipe.java create mode 100644 src/meld/world/blocks/crafting/Recipe.java create mode 100644 src/meld/world/blocks/crafting/modules/AdditionModule.java create mode 100644 src/meld/world/blocks/crafting/modules/GateModule.java create mode 100644 src/meld/world/blocks/crafting/modules/LambdaModule.java create mode 100644 src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index d9add3f..e0a45f5 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -589,6 +589,10 @@ item.meld-clay-mallow.name = Clay-Mallow item.meld-clay-mallow.description = Clay from the Badlands. Easly moulded to form containers, but difficult to aquire by blasting soil. item.meld-clay-mallow.details = A delicate substance valued for its malleability and ability to keep its shape, along with its velvety texture. +item.meld-glass-mallow.name = Glass-Mallow +item.meld-glass-mallow.description = Refined clay from the Badlands, more glass than ceramic. +item.meld-glass-mallow.details = A glossy, crystalline substance. + item.meld-riplom.name = Riplom item.meld-riplom.description = Shale from the Storm Planes. A great flux for glasswork, though not much practical use found. Slightly volatile. item.meld-riplom.details = Looks almost fungal. Seems to absorb [#cbdbfc]Aspect[] from its suroundings. diff --git a/assets/bundles/bundle.shitpost b/assets/bundles/bundle.shitpost new file mode 100644 index 0000000..ffd634e --- /dev/null +++ b/assets/bundles/bundle.shitpost @@ -0,0 +1,3 @@ +item.meld.glass-mallow.name = Pan-fried Plates + +item.meld.crucible-plating.name = Boiled Plates \ No newline at end of file diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-bottom-1.png b/assets/sprites/blocks/fluid/director/aspect-pipe-bottom-1.png index ffa41c18c4726f35a4b3d91622253cc5b23d3fb8..f876a7232e2b2056262bb6ed5b8fc0b04d2ffec5 100644 GIT binary patch delta 1028 zcmV+f1pE8+0j3C$Fn{j43iva-~Dg_4l+xA#fMWm-67ltUNLua`S030gbMR&X!JqMebk1u61OWPp$Bq)vR9z`OjUjmS$8)WO|* z;4m7hDvo8*Eq{78ak|1?tkfdC(&5}qZA3i`!)DX~&gEc6zIFb%1vAwv#>K_-~nFef7+bC|0ocBp)0{5|mP)_;6Be8FH1 z#F{s_8|Z?26iXNpNTjAyamIh)^&Xy5;wwDHWz z{WZpa3~rLy!hS6|;(j&%whc0=90!4wFt_VO1_TC)6!Fe~PU@=O;WZ}Y@o2;?<$)%*c=R-SvbP6z1#0000wYX4#Tc^&7k8*Rs*?<2}9K&Yiu|E@yks*_M8_U{|PFl{9eKm-C%Ydvnj z6;Q1G5uMK8`@E(5R@4R@_X+i=#{v%ojD)8mf`6e0Z3i^Y5PuoC6Cfhg<9I-0w7Liw z@KWa*GzMvp9tI$x&U5|L-gTOACKn^u-sO{!hC1WWj4pY ztpFm91b%|-0@3UN9U!U;&i8dwfr8ujf>v3G29~;t*)X^K`(f}O*S7NyVO%qxtM3Q}0fg+hOxFDzFVz`7Jh=nQ`ji{Dm z8E)%_GygXw_w9H}r5W1rRG^eHWsb&Mq>xSMAfE{A_kT_jaUKi>n9Gbw?||bxSTVhU z$J=|8L8l5p-KDY!2t;b@e;UXBcj=Z@L_Uw#F~{?Xzigvd#8b0wTwN#7rDaLe@W{v5 z`ukgOB@lMNJk-Y3+IwF=w~tJxHd121f64z=IhR3)_?!XM*3M}NgcfN7gEJYj?-JdU znB#i`m4DgdWi>iCyb-tz2>}rUtRS|g!QhaByEJ6*2`Vz@%s%W?6}6o&@68NiTZI|S z1quZNeomYOZA6yz>K#=aL{uQsA!4h|nsp7TsIT({W|!Q7S=puX9>K74Q1`-j3W#(_ z@95GK5mQ7VBB zh!m7k^8}1jOub3z8oSZ)7P)-}cx%l`G*hE5Me6JPMRD*V1zPH?QQ97%)KjCXHy+5( zlp-tQ-Wys!(OV|brK6tb3&H{1BPW_X0U_nHW@by1`@Iqm_BG|eGw7qsAoHq;Ru-E!W|;T>Q)rsS!>t$ zHC*%i<;IKyyg8xTTT4U3s=>kM)3SsY*3aAMaPhm7#Pma(eyFXt89Ec8O9x9w5t(^R s?~Ujw5K23rKOq(9VXq04a%)>JA_^Cs5S^!%+u}I$+cRL&^aFaG*2B0UwrF00000NkvXXu0mjf(?wA9 diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-bottom-3.png b/assets/sprites/blocks/fluid/director/aspect-pipe-bottom-3.png index bfd93ec587d3106bb3b1e334762b3540224a2b1a..e506fa0ce5f0be0b64078edcebae528176f3bcd5 100644 GIT binary patch delta 1172 zcmV;F1Z(@%0kjE_FnQllAb-M%2;BYtJsb($o~wgA z*9v(OK|~QzRFu$0t7p2lhH67p^Vk3|7xp~d@o?N75y7#_fEU07H~$9+AR?#;s!D5( zC}1K&@2w{?)!$@cMdt398)}M)=F0W)0jxmg29b}{dZLO(BO>U4k@tG*2ZA6f1z=?% zD!n5@cf(x4WPhd}AUyD}31pQ(Dtb-6L;$^lR3e<-+kpu4<~%b%WC@aJm7U1VRr5KY zJh6=rnSYTiZ3_iDh@m35=DPhjUNe;I9;jHRa7(-@m zxWrZx-2mL>JL?ZnAcTNuRn);@$qaZzN^F$co&jjcOaNLVV#ad= z+>hf6cbhD~X?k#gyRH$LTu~9cWGqw4dIK{yn;?^&61a05tvigMZ1g_E|b#_M5qulGn2BG?-nDML69{ zk>wDP=@b9kr<>oK$TNx|U8xLDNtI)k=gzjfXAf9q@xaADe4?A>G~;H~OokEd!^9vQ zzail|&vb7HQbmr0BVpj9RK)?iPRtGS3p2Z$(1Yzw^>Ke`d`WC~M7AcisY*1JCPF{2 zvwvExO(z_k3K1l-qcQvWs)>$4Lk55~S+Nmzbja)}itk2r6@X7GUa3Zu_JbA6(~4Pj z&UGBK8skI|+pPFJzkh5-b2Ay&tlIyj84WIN2_1{BW^|tKAKG#C^O0`R> z4(EzLUTl1f_3r7q!*??`YP{Z=;njc4ExRE?TJAQ<@Mt(ga`XH43b&h( m+&p0)YP@F4r3|x+{{XszB8kWblnu}T00008M00000NkvXXu0mjf%RNTz diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-bottom-4.png b/assets/sprites/blocks/fluid/director/aspect-pipe-bottom-4.png index 05179056c007360e36e744267239bbfc0bd49ae6..1465f60983df46c30306a6c03f2198a1ec6580d8 100644 GIT binary patch delta 1147 zcmV->1cdw90h|etFnzXX6l zAR>SWNJ2=Egi_&kR09bL3@mWuO*;{f*uWm1M52h)PqBv}nTR9_3L%nLQbARyD?G-< zctitVKpV{Sz5f|~l10k^Dso{S@&*qbD{ue+MKS|5EO@#U@Q`2DJ=<- zAPsa&5hC(N9-fiaF*7I)MuV!se1fhJ%Lv_>ac?C`Wg&qh0;FK{zB4eE{&0fhY4 zz>3~HnVQY4CugRQgjf-vG!YgE0tju{DNPi(m&URULw{23k|%-l%j5(}%mrR;CAR7< zAPA62qICfdK18I-#?(ZWd! A%I6ft}+(W|IflIZOz4l?5jr{nGYB(Gh-mjEXRQ*qv{aJ#p*zN0UmNRX2PdF0n zgybf4NF;a&5RP3s{3XH-EpnELHOocMLP6G&akd;5F)6~*(y;dh;L_25wBbr`-F!uR z9e-`WhsXln<%sRA8{Fe`(&?U-fz`5Wg%WB;U$b1PP|dS8oK8+yrRdQESNq=kak zyH`|7<{GsDN0M1YSifhLNO%-nwLJ@t-A-Br_Atu-lRYrlYuqBwHTdZ8t?9HA?dEQ*XXVMBC@nl zB&dfVONf`+*GgC5bIu|$GaGg?GSYdtH(6=oQq@Zf%F%$25RdSdxY|l*MZ)rFsFN_a zG@^d?F5gc@ztt}*a_$+j2H95owN=f06q}!uiACVFp&UcmM#Og2M($)P(|`KHr13yjaXQuYNU+%LkwjONu!%a)KHSk%4xTa8ls61rOEZC&vcE2^G zVsBNMiRFHK#ka19EQ!sDS{ZQxpVR#Q&n(=dHJT5g`uysMEzDDne*uZ&qp#6Abol@P N002ovPDHLkV1jMcA3Oj6 delta 177 zcmV;i08am$3E2UVFn<7(NklPx$wMj%lR9J=0SG`WdKn!+J)^2PpU8rC|Ak+mRwn{tzAS$u(959rfH()~o!N7`? zt)MQbP<5foh6GQL2Po5>T*vnL(zNhRNzOmt`FydR9G!HhKycM<(@!23cW>fa72Orp z+7giBmxJ96007AH0y?dRs_0}L`ooDTpXG(u!LmLA)L@nuX6Mp3$rhGXkANegIpWr| zjQ{{7pHJ7*kRUz|N$%$M*+1X+j)TsfO;5n8aC-SD%5XS8I}~jJJpwK9vb>0P4kR+1 zk5UduB&eY(Bskk_5>ml=oQG_Px4@CmoR7u>7>x&J65J80*U-B27!nl8%lmh!7Fe;r zvo`bo`tcKOqt;qL2`!yK6%q@nhA|}myc{otKuj{$P9XLs)JmYrHB48(9>m2^@xec! z?X5kNLszOD)Ch2;l!Mhdhnao=1NR1X6eD1E4^jkZV`7bj2FXT=fYcSuL&E8Dwxe4z zPDVSTP)p|L0&7!hL8vLkb4TJvGpXIC&O==>O*Bc~4JYa~Px$cu7P-R9J<@m!VPvF%X9T+|*&v?E_p*MLT_uV$atx!vj>+;}Bp_m{`gyV3{H? ztp_xwwqV$qG}+v4E_c^|Cg!rqewW>36Z3O8{^DP&^#fep-(DLCa>tWC_TSPlOv)hu zpb#xP*1)B$ss*gw^x~NO4*ZT(h$s6Je4EbZ>hWv{s%oL0fYbZ-Ee{|?H_IzFQMC|J zfN?o$1%g^K007)QJ_lPY6+)62g03N00DsBafQW@50Eii;K*Yq&T};X$sP%COS-XMj zGgyJ${)-)$65p6DH#eIDzG0K(^2fw}%+yuGaXD(dz3SxpJXrz%@ae+2uOI{|Cty=u zUKEBJn*)77kXoq)odBSv!zT-%4+!(R{XB6X)p704AaKb(SOMuerCAZzMzUu^kORT> z)!8?`lBGI|^#wUVl5)X6+cn#ks|QhlIvA~UE|h-BSB1cxD91UNE5AAirn7mra}Gik o0untaB_%yh>1uQ?o&9zE2O^-nLN*sF761SM07*qoM6N<$g6i(UAOHXW literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-top-0.png b/assets/sprites/blocks/fluid/director/aspect-pipe-top-0.png index 5a79cbff4ecd0c38987758fb0d442b7e5514d898..e7e4c94776bbad41e22c2b960ea21cd2fa2f1811 100644 GIT binary patch delta 325 zcmV-L0lNOW0_*~iFn<9iNkld4q)cX zwFQ7AnK+ZT+kN4A(C@K%qjBu57104HPRGNC;U&F_xjyEgOMf6i*a0Xh_p5 z8N2ei8UQe51*^@Dg?qrNHX_xnSoJVc zJ&wQ9kZ8AL9X>k1wdb_K^fjmL`Dh$}G^K^DSh^eJg+k3Gk4SpK3Dz~|yv+Y{stxc0 X`fbkPZFs`c00000NkvXXu0mjf`b3kC delta 275 zcmV+u0qp+l0=fc_Fn<8_Nkli;0j(`786pBO%DSD0|O&I4U^_`@vToTv}q||b3b}^22P6yfn Z02TPQx%1g^weiqC7xZI<)G0z}lS!kl0uG`7l%5>$_OR|*Mq zdGny@__ny%J!dHlVstV*Zj7^ay@C17W~cvRKChO40QO6LL4VjQpI1xdMahRCHH2*r z0PpoDaEKhB=3W4fI<+|fsF&4;=3abTy#fHP&(D&SqD#RL+&?W?z+M5&>Ln0*t7HJS zxetOGcZE0_4F|hHUXf)Z$vKH=Y^zqa0i_e zzy~8W=R#Rk&yBGt1azW(%)wmw#W^sZO!qeDAVeWBqA9m0pVsw8JXbav4#X4pp@V!G aQT+l65!$ATHG~)d0000?R-Q90I5WH=!>92^(+ear30>ELn zP5cEse|{(bR+_UV(BO}os|x@C=!X%yc0DOkKaA1;*ZwE|kAD#egV&i<+P&BkY(}HA$_uf0_vVv(8P9ktF zITlfBBbMT&M1Rb38|>KpPWlBs54q5&=?IR3jqTa=wdOvRso%Ten76qh0kVq3U~l&5bg9i02@<;5C#u%Ua zC;)0Ig`dp?h_dh?04^RbLHH;NKnst7sC@=PA)*25f~W*g2SoR$VU@w1E(^vFt~rNQgX_tMu2OjCFC4L0lqD3BHRh7WL&ga0dyuv zjf4it$4G!Qkd%n#L-9xl-z>YP>S~s=T|dn+@|EQ(oCH({c@s~ zq4mvkd;|e_U8+Sc`NCWccc5*!B_jUic6v;qRF`{|`aXNf>k)2Hl8)ZpA^9QP6Z8 z>_Ad?X|RRYNlEZWvc`*vEgXs#D=#Ll;kpt`1(%(WZG-Q2D$(){rxLW~8`5dZ*;(+uZ_2cbgaG-v+z&+q&`M}HtK(hZT~6jaMRf(R2e z4opd7eMpa^mV`hOv4s<9*0yYDF+lP1^iWg<{h^h%z%fp?S(TvXpnz(l~(@dn{ z#4N*z>8Qq$4bX8ZN?hZjT7$G;O~*YZ{^fN11AaWUAP{;s(2xKC002ovPDHLkV1oN) ByT$+j diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-top-4.png b/assets/sprites/blocks/fluid/director/aspect-pipe-top-4.png index e031d19dcb9a0ab12851ffb96c343b8c34698ff1..4046d12767a36b0f80c9429a84c4f3d602ea0eb7 100644 GIT binary patch delta 373 zcmV-*0gC?21DykqF@IM{L_t(og~gYlj>13?hNn#(=JfFZ#qcU{wg!a(5*!9qg~5^B zVNPLcfmgs15E$wKjlo{eurS>&6v{u#pET*VoBZGI&hE@Q$J1XzXZ6D|as3QC4gu8e zeJ8v<2wRtT7h&*>DtW5?V5}+Y;b0VT` zyeGOB0~Nnaqu*(A>;EfK=63;<&=B05h{##2c1DBsYME+xn_rMEsq5iwD773$fU5r~ z;q@4RGH(PmD*z5ZicR8&hD03X0+{qsa$z8aazPPjC;$@TrEG|Ru%3>g0El2L41n4R zg#eJ-(97!}eQpqWoA{9W!1Dk%mr`a46p#&bBLIhZ8-Pht1xaoYBFuR)qnBj4Gk_j> z=3;WI<2K%lO*@A$0z}aaYN$^;hseYL+MGl1k*ku=;|Gs^JC=gr^``Z7tS`quteAcC TWm}0V00000NkvXXu0mjfrctXq delta 421 zcmV;W0b2f@1Iz=EF@J_hL_t(oh0RwnPQ)+}9G~3s4Fol!rQ-oe2P2{#vJ%-jluQ9>ld4A>z$%+s{aLyGC^HrFvz@g&Q zMC}|g6|ZGtk$>B;#>Agr$BP)S1Y=@=-qCA`gRj6`6Sd+1;I;a132|OCsxgqeO6Q2@ zAR36Zfo8((VHL|&%vl4xFtM(L28kmvAXPi^O9NcI2Bo5u z_8l&^X3}NE#cNwL$wbUK>M?B59hEr5RNS&P<6KnB=N<-HWk+t}Uv|g8zk$1{l~&cU P00000NkvXXu0mjfZcfK{ diff --git a/assets/sprites/items/clay-mallow.png b/assets/sprites/items/clay-mallow.png new file mode 100644 index 0000000000000000000000000000000000000000..34015836e3b4c64eecd112ce64f766b270be77d1 GIT binary patch literal 359 zcmV-t0hs=YP)Px$AxT6*R9J=WmMs#3Kp2M6@djk7S(C*kh2|AJ04K0eJOKyr3N{NiiU~87>=`tz z0{iXv$Bv9Mya{Gu-{<>V2!cr?Yo>j%xnEwcwP>?v@2dj9%%vb=0IoR~LIfZ+=RmLl zwB{593t*@@2C>j?_Ppkw>o7^xP;=@5DEhWJbng{_G9L;d0vHmh3IJ=qFiAVL*Y*L} zgy%S7cRknGHHH>|#2iz*T&wKHJBT3j_>@~48o8o}o^?Tx0PF1%Mt4A9jS4}KQ&5#P zx?UW=0MwK`vYizmnE@jx6MZ-;TSo0nu+M?2tUHEOX1Ef63w#+Hbuw@$8uc%l7l2mc$8!Y!q!-W-rI8hO%x>kaO?cwvYL>i7Tv002ovPDHLk FV1l0Qk1qfK literal 0 HcmV?d00001 diff --git a/src/meld/content/MeldBlocks.java b/src/meld/content/MeldBlocks.java index b948d51..3d4f736 100644 --- a/src/meld/content/MeldBlocks.java +++ b/src/meld/content/MeldBlocks.java @@ -2,16 +2,18 @@ import arc.graphics.Color; import arc.math.Interp; +import arc.util.Log; import meld.*; import meld.entities.bullet.OutflowBulletType; import meld.entities.bullet.TransitionBulletType; import meld.graphics.*; import meld.world.blocks.*; import meld.world.blocks.crafting.ModularCrafter; -import meld.world.blocks.crafting.modules.ConsumeGate; -import meld.world.blocks.crafting.modules.ConsumeLiquidModule; -import meld.world.blocks.crafting.modules.MultiplierModule; -import meld.world.blocks.crafting.modules.ProduceLiquidModule; +import meld.world.blocks.crafting.ItemRecipe; +import meld.world.blocks.crafting.Recipe; +import meld.world.blocks.crafting.modules.*; +import meld.world.blocks.crafting.modules.GateModule.ConsumeCondition; +import meld.world.blocks.crafting.modules.GateModule.OutputCondition; import meld.world.meta.*; import mindustry.Vars; import mindustry.content.Fx; @@ -37,6 +39,7 @@ import mindustry.world.blocks.liquid.LiquidJunction; import mindustry.world.blocks.liquid.LiquidRouter; import mindustry.world.blocks.production.*; +import mindustry.world.blocks.storage.Unloader; import mindustry.world.blocks.units.UnitFactory; import mindustry.world.consumers.ConsumeLiquid; import mindustry.world.draw.*; @@ -47,12 +50,14 @@ public class MeldBlocks { //Strata blocks first - public static Block chute, chuteRouter, chuteBridge, chuteJunction, chuteOverflow; + public static Block chute, chuteRouter, chuteBridge, chuteJunction, unloadingHub; public static Block sonarSpire, movementAnchor, nullifier; public static Block coreRaft, aetherAccumulator, elementalBlaster, earthboundInfuser, sharkFactory; + public static ModularCrafter gasKiln, rotaryKiln; + public static Block channelNode, channelFace, aspectOutlet, aspectPipe; public static Block sunder, molotov, vivisection; @@ -102,6 +107,8 @@ public static void load(){ health = 200; + solid = false; + placeableLiquid = true; liquidOutputDirections = new int[]{0}; @@ -124,7 +131,7 @@ public static void load(){ aspectPipe = new AspectPipe("aspect-pipe"){{ requirements(Category.liquid, with( - MeldItems.silver, 3 + MeldItems.annealedSilver, 5, MeldItems.glassMallows, 2 )); leaks = false; health = 120; @@ -528,18 +535,11 @@ public static void load(){ modules.addAll( new ProduceLiquidModule(new LiquidStack(MeldLiquids.fumes, 2f), 0), new ConsumeLiquidModule(LiquidStack.with(MeldLiquids.fumes, 1, MeldLiquids.aspect, outletRate * 2), 1, 2), - new ConsumeGate(with(MeldItems.debris, 1), 3), - new MultiplierModule(){{ - inputPins = new int[]{2,3}; - outputPin = 4; - }}, - new ItemCraftingModule(){{ - efficiencyPin = 4; + new RecipeCraftingModule(){{ + efficiencyPin = 2; progressPin = 5; craftTime = 12; - - inputItems = with(MeldItems.debris, 1); - outputItem = new ItemStack(MeldItems.carbolith, 1); + recipe = new ItemRecipe(with(MeldItems.debris, 1), with(MeldItems.carbolith, 1)); }} ); @@ -551,6 +551,209 @@ public static void load(){ */ }}; + gasKiln = new ModularCrafter("gas-kiln"){{ + requirements(Category.crafting, with(MeldItems.debris, 80)); + size = 2; + + hasItems = true; + hasLiquids = true; + liquidCapacity = outletRate * 60; + + itemCapacity = 10; + + acceptedLiquids.addAll(MeldLiquids.aspect); + acceptedItems.addAll(MeldItems.tenbris, MeldItems.clayMallows, MeldItems.carbolith, MeldItems.debris, MeldItems.shadesteel, MeldItems.glassMallows, MeldItems.silver); + dumpedItems.addAll(MeldItems.cruciblePlating, MeldItems.shadesteel, MeldItems.glassMallows, MeldItems.annealedSilver); + + + ItemRecipe + shadesteel = new ItemRecipe(with(MeldItems.tenbris, 2), with(MeldItems.shadesteel, 2)), + glass = new ItemRecipe(with(MeldItems.clayMallows, 2), with(MeldItems.glassMallows, 2)), + silver = new ItemRecipe(with(MeldItems.silver, 1), with(MeldItems.annealedSilver, 1)), + platings1 = new ItemRecipe(with(MeldItems.shadesteel, 4, MeldItems.carbolith, 2), with(MeldItems.cruciblePlating, 4)), + platings2 = new ItemRecipe(with(MeldItems.glassMallows, 4, MeldItems.debris, 2), with(MeldItems.cruciblePlating, 4)); + + float produceTime = 60; + + modules.addAll( + new GateModule( + ModOUT.ZERO, new GateModule.RecipeCondition(shadesteel) + ), + new GateModule( + ModOUT.ONE, new GateModule.RecipeCondition(glass) + ), + new GateModule( + ModOUT.TWO, new GateModule.RecipeCondition(silver) + ), + new GateModule( + ModOUT.THREE, new GateModule.RecipeCondition(platings1) + ), + new GateModule( + ModOUT.FOUR, new GateModule.RecipeCondition(platings2) + ), + new LambdaModule(){{ + //Set every ping after the first one found as 1 to zero + updater = b -> { + int a = 0; + for(int i = 0; i < 5; i++){ + b.setPin(i, Math.max(b.getPin(i) - a, 0)); + a = (int)Math.max(a, b.getPin(i)); + } + b.setPin(ModOUT.FIVE, a); + + /* + int firstValid = -1; + for(int i = 0; i < 5; i++){ + if(firstValid != -1){ + b.setPin(i, 0); + continue; + } + + float pinValue = b.getPin(i); + if(pinValue > 0){ + firstValid = i; + } + } + */ + }; + }}, + new ConsumeLiquidModule(LiquidStack.with(MeldLiquids.aspect, outletRate * 2), ModIN.FIVE, ModOUT.SIX), + new RecipeCraftingModule(){{ + recipe = shadesteel; + efficiencyPins = new int[]{ModIN.SIX, ModIN.ZERO}; + progressPin = ModOUT.SEVEN; + craftTime = produceTime; + }}, + new RecipeCraftingModule(){{ + recipe = glass; + efficiencyPins = new int[]{ModIN.SIX, ModIN.ONE}; + progressPin = ModOUT.EIGHT; + craftTime = produceTime; + }}, + new RecipeCraftingModule(){{ + recipe = silver; + efficiencyPins = new int[]{ModIN.SIX, ModIN.TWO}; + progressPin = ModOUT.NINE; + craftTime = produceTime; + }}, + new RecipeCraftingModule(){{ + recipe = platings1; + efficiencyPins = new int[]{ModIN.SIX, ModIN.THREE}; + progressPin = ModOUT.TEN; + craftTime = produceTime; + }}, + new RecipeCraftingModule(){{ + recipe = platings2; + efficiencyPins = new int[]{ModIN.SIX, ModIN.FOUR}; + progressPin = ModOUT.ELEVEN; + craftTime = produceTime; + }} + ); + }}; + + rotaryKiln = new ModularCrafter("rotary-kiln"){{ + requirements(Category.crafting, with(MeldItems.debris, 350)); + size = 5; + + hasItems = true; + hasLiquids = true; + liquidCapacity = outletRate * 60 * 2; + + itemCapacity = 48; + + acceptedLiquids.addAll(MeldLiquids.aspect); + acceptedItems.addAll(MeldItems.tenbris, MeldItems.clayMallows, MeldItems.carbolith, MeldItems.debris, MeldItems.shadesteel, MeldItems.glassMallows, MeldItems.silver); + dumpedItems.addAll(MeldItems.cruciblePlating, MeldItems.shadesteel, MeldItems.glassMallows, MeldItems.annealedSilver); + + defaultData.put(0, 1); + + ItemRecipe shadesteel = new ItemRecipe(with(MeldItems.tenbris, 12), with(MeldItems.shadesteel, 12)); + ItemRecipe glass = new ItemRecipe(with(MeldItems.clayMallows, 12), with(MeldItems.glassMallows, 12)); + ItemRecipe silver = new ItemRecipe(with(MeldItems.silver, 1), with(MeldItems.annealedSilver, 1)); + ItemRecipe platings1 = new ItemRecipe(with(MeldItems.shadesteel, 4, MeldItems.carbolith, 2), with(MeldItems.cruciblePlating, 4)); + ItemRecipe platings2 = new ItemRecipe(with(MeldItems.glassMallows, 4, MeldItems.debris, 2), with(MeldItems.cruciblePlating, 4)); + + //The max crafting speed when boosted + float craftingTime = 120; + + modules.addAll( + //Set the base rate based on aspect intake + new ConsumeLiquidModule(LiquidStack.with(MeldLiquids.aspect, outletRate * 8), 0, 1), + //Setup the flags for possible recipies + new GateModule( + ModOUT.TWO, + new ConsumeCondition(shadesteel.inputItems), + new OutputCondition(shadesteel.outputItems) + ), + new GateModule( + ModOUT.THREE, + new ConsumeCondition(glass.inputItems), + new OutputCondition(glass.outputItems) + ), + new GateModule( + ModOUT.FOUR, + new ConsumeCondition(platings1.inputItems), + new OutputCondition(platings1.outputItems) + ), + new GateModule( + ModOUT.FIVE, + new ConsumeCondition(platings2.inputItems), + new OutputCondition(platings2.outputItems) + ), + new GateModule( + ModOUT.SIX, + new ConsumeCondition(silver.inputItems), + new OutputCondition(silver.outputItems) + ), + //Take the average efficiency + new LambdaModule(){{ + int[] gatePins = new int[]{2, 3, 4, 5, 6}; + float drums = 3; + int outPin = 7; + + updater = build -> { + float total = 0; + for(int i: gatePins){ + total += build.data.get(i); + } + float out = drums/Math.max(total, 1); + build.setPin(outPin, out); + }; + }}, + //Recipies + new RecipeCraftingModule(){{ + recipe = shadesteel; + efficiencyPins = new int[]{1, 2, 7}; + progressPin = 8; + craftTime = craftingTime; + }}, + new RecipeCraftingModule(){{ + recipe = glass; + efficiencyPins = new int[]{1, 3, 7}; + progressPin = 9; + craftTime = craftingTime; + }}, + new RecipeCraftingModule(){{ + recipe = platings1; + efficiencyPins = new int[]{1, 4, 7}; + progressPin = 10; + craftTime = craftingTime; + }}, + new RecipeCraftingModule(){{ + recipe = platings2; + efficiencyPins = new int[]{1, 5, 7}; + progressPin = 11; + craftTime = craftingTime; + }}, + new RecipeCraftingModule(){{ + recipe = silver; + efficiencyPins = new int[]{1, 6, 7}; + progressPin = 12; + craftTime = craftingTime/8f; + }} + ); + }}; + sharkFactory = new UnitFactory("shark-factory"){{ requirements(Category.units, with(MeldItems.debris, 500, MeldItems.carbolith, 350, MeldItems.silver, 450)); size = 5; @@ -634,10 +837,12 @@ public static void load(){ ((Duct) chute).bridgeReplacement = this; }}; - chuteOverflow = new OverflowDuct("chute-overflow"){{ - requirements(Category.distribution, with(MeldItems.debris, 6)); - health = 90; - speed = 4f; + unloadingHub = new Unloader("unloading-hub"){{ + requirements(Category.distribution, with(MeldItems.debris, 450)); + size = 3; + health = 900; + speed = 1f; + solid = false; }}; diff --git a/src/meld/content/MeldItems.java b/src/meld/content/MeldItems.java index e047fd5..b0d36ba 100644 --- a/src/meld/content/MeldItems.java +++ b/src/meld/content/MeldItems.java @@ -4,7 +4,7 @@ public class MeldItems { public static Item - debris, carbolith, silver, resonarum, + debris, carbolith, silver, resonarum, clayMallows, meldShard; @@ -13,19 +13,23 @@ public class MeldItems { //Heavy industry content public static Item - tenbris, shadesteel, elnarDust, annealedSilver, cruciblePlating, aspectPipe; + tenbris, shadesteel, elnarDust, annealedSilver, glassMallows, cruciblePlating, aspectPipe; public static void load(){ debris = new Item("debris"){{ - cost = 0.1f; + cost = 0.5f; }}; carbolith = new Item("carbolith"){{ - cost = 0.5f; + cost = 0.8f; }}; silver = new Item("silver"){{ - cost = 0.4f; + cost = 0.3f; + }}; + clayMallows = new Item("clay-mallow"){{ + cost = 0.2f; }}; + resonarum = new Item("resonarum"); stonyParticulate = new Item("stony-particulate"){{ @@ -53,6 +57,8 @@ public static void load(){ }}; + glassMallows = new Item("glass-mallow"); + aspectPipe = new Item("aspect-pipe"){{ }}; diff --git a/src/meld/world/blocks/LiquidUtil.java b/src/meld/world/blocks/LiquidUtil.java new file mode 100644 index 0000000..abb42f1 --- /dev/null +++ b/src/meld/world/blocks/LiquidUtil.java @@ -0,0 +1,33 @@ +package meld.world.blocks; + +import mindustry.gen.Building; +import mindustry.type.LiquidStack; +import mindustry.world.modules.LiquidModule; + +public class LiquidUtil { + + public static boolean hasAll(LiquidStack[] liquids, Building build){ + for(LiquidStack stack: liquids){ + if(!(build.liquids.get(stack.liquid) < stack.amount)) return false; + } + return true; + } + + public static boolean has(LiquidStack[] liquids, Building build){ + for(LiquidStack stack: liquids){ + if(!(build.liquids.get(stack.liquid) < 0)) return false; + } + return true; + } + + public static void add(LiquidStack[] liquids, LiquidModule module){ + for(var liquid: liquids){ + module.add(liquid.liquid, liquid.amount); + } + } + public static void remove(LiquidStack[] liquids, LiquidModule module){ + for(var liquid: liquids){ + module.remove(liquid.liquid, liquid.amount); + } + } +} diff --git a/src/meld/world/blocks/crafting/ItemRecipe.java b/src/meld/world/blocks/crafting/ItemRecipe.java new file mode 100644 index 0000000..5faaeb1 --- /dev/null +++ b/src/meld/world/blocks/crafting/ItemRecipe.java @@ -0,0 +1,77 @@ +package meld.world.blocks.crafting; + +import meld.world.blocks.LiquidUtil; +import mindustry.gen.Building; +import mindustry.type.ItemStack; +import mindustry.type.LiquidStack; + +public class ItemRecipe extends Recipe{ + public ItemStack[] inputItems; + public ItemStack[] outputItems; + + public LiquidStack[] inputLiquids; + public LiquidStack[] outputLiquids; + + public ItemRecipe(){ + + } + + public ItemRecipe(ItemStack[] inputItems, ItemStack[] outputItems){ + this.inputItems = inputItems; + this.outputItems = outputItems; + }; + + @Override + public boolean valid(Building build){ + if(outputItems != null){ + for(var output : outputItems){ + if(build.items.get(output.item) + output.amount > build.block.itemCapacity){ + return false; + } + } + } + if(outputLiquids != null){ + for(var output: outputLiquids){ + if(build.liquids.get(output.liquid) + output.amount >= build.block.liquidCapacity){ + return false; + } + } + } + if(inputLiquids != null && !LiquidUtil.has(inputLiquids, build)) return false; + + //Set the output to zero if the build doesn't have the items, otherwise set it to whatever the out is + return build.items.has(inputItems); + } + + @Override + public void apply(Building building) { + if(inputItems != null) building.items.remove(inputItems); + + if(outputItems != null) { + for (ItemStack item : outputItems) { + building.items.add(item.item, item.amount); + } + } + + if(inputLiquids != null) LiquidUtil.remove(inputLiquids, building.liquids); + if(outputLiquids != null) LiquidUtil.add(outputLiquids, building.liquids); + } + + //Builder methods + public ItemRecipe input(ItemStack[] items){ + inputItems = items; + return this; + } + public ItemRecipe output(ItemStack[] items){ + outputItems = items; + return this; + } + public ItemRecipe input(LiquidStack[] liquids){ + inputLiquids = liquids; + return this; + } + public ItemRecipe output(LiquidStack[] liquids){ + outputLiquids = liquids; + return this; + } +} diff --git a/src/meld/world/blocks/crafting/ModularCrafter.java b/src/meld/world/blocks/crafting/ModularCrafter.java index 9c91a89..58eef7a 100644 --- a/src/meld/world/blocks/crafting/ModularCrafter.java +++ b/src/meld/world/blocks/crafting/ModularCrafter.java @@ -11,6 +11,7 @@ import mindustry.type.ItemStack; import mindustry.type.Liquid; import mindustry.world.Block; +import mindustry.world.blocks.production.GenericCrafter; import mindustry.world.meta.Attribute; import java.util.HashMap; @@ -21,12 +22,21 @@ public class ModularCrafter extends Block { public Seq modules = new Seq(); public ObjectMap> listeners = new ObjectMap>(); + //list of items/liquids which this block accepts public Seq acceptedLiquids = new Seq<>(); public Seq acceptedItems = new Seq<>(); + //List of items/liquids which get dumped public Seq dumpedLiquids = new Seq<>(); public Seq dumpedItems = new Seq<>(); + //Default float data array + public IntFloatMap defaultData = new IntFloatMap(); + + public ModularCrafter(String name) { + super(name); + update = true; + } @Override public void setBars() { @@ -34,6 +44,7 @@ public void setBars() { if(acceptedLiquids.size + dumpedLiquids.size > 0){ removeBar("liquid"); + for(Liquid liquid: acceptedLiquids){ addLiquidBar(liquid); } @@ -43,14 +54,6 @@ public void setBars() { } } - public ModularCrafter(String name) { - super(name); - update = true; - } - - //Default float data array - public IntFloatMap defaultData = new IntFloatMap(); - public static void trigger(ModularCrafter block, ModularCrafterBuild build, Object event){ Seq events = block.listeners.get(event); if(events != null) events.each(c -> c.update(build)); @@ -88,12 +91,26 @@ public void update(ModularCrafterBuild build){ } public static abstract class CraftingModule extends CrafterModule{ - public int efficiencyPin; + public int efficiencyPin = -1; + public int[] efficiencyPins; public int progressPin; - public float craftTime; + public float craftTime = 60; + + public boolean canCraft(ModularCrafterBuild build){ + return true; + }; public void update(ModularCrafterBuild build){ - float efficiency = build.getPin(efficiencyPin); + if(!canCraft(build)) return; + + float efficiency = 1; + if(efficiencyPin != -1) efficiency = build.getPin(efficiencyPin); + if(efficiencyPins != null){ + for(int i: efficiencyPins){ + efficiency *= build.getPin(i); + } + } + float progress = build.getPin(progressPin); progress += efficiency * Time.delta; @@ -140,7 +157,19 @@ public static class ItemCraftingModule extends CraftingModule{ @Override public void update(ModularCrafterBuild build) { super.update(build); + } + @Override + public boolean canCraft(ModularCrafterBuild build) { + if(outputItems != null){ + for(var output : outputItems){ + if(build.items.get(output.item) + output.amount >= build.block.itemCapacity){ + return false; + } + } + } + if(outputItem != null && build.items.get(outputItem.item) + outputItem.amount >= build.block.itemCapacity) return false; + return true; } @Override @@ -157,6 +186,44 @@ public void craft(ModularCrafterBuild build) { } } + //Just some static finals to help readability + public static class ModOUT{ + public static final float ON = 1, OFF = 0; + public static final int + ZERO = 0, + ONE = 1, + TWO = 2, + THREE = 3, + FOUR = 4, + FIVE = 5, + SIX = 6, + SEVEN = 7, + EIGHT = 8, + NINE = 9, + TEN = 10, + ELEVEN = 11, + TWELVE = 12; + }; + public static class ModIN{ + public static final float ON = 1, OFF = 0; + public static final int + ZERO = 0, + ONE = 1, + TWO = 2, + THREE = 3, + FOUR = 4, + FIVE = 5, + SIX = 6, + SEVEN = 7, + EIGHT = 8, + NINE = 9, + TEN = 10, + ELEVEN = 11, + TWELVE = 12; + }; + + public static final float ON = 1, OFF = 0; + public class ModularCrafterBuild extends Building { public ModularCrafter modular; diff --git a/src/meld/world/blocks/crafting/Recipe.java b/src/meld/world/blocks/crafting/Recipe.java new file mode 100644 index 0000000..12a227a --- /dev/null +++ b/src/meld/world/blocks/crafting/Recipe.java @@ -0,0 +1,9 @@ +package meld.world.blocks.crafting; + +import mindustry.gen.Building; + +public abstract class Recipe { + + public abstract boolean valid(Building building); + public abstract void apply(Building building); +} diff --git a/src/meld/world/blocks/crafting/modules/AdditionModule.java b/src/meld/world/blocks/crafting/modules/AdditionModule.java new file mode 100644 index 0000000..9e4a2f7 --- /dev/null +++ b/src/meld/world/blocks/crafting/modules/AdditionModule.java @@ -0,0 +1,13 @@ +package meld.world.blocks.crafting.modules; + +import meld.world.blocks.crafting.ModularCrafter; + +public class AdditionModule extends ModularCrafter.CrafterModule { + int[] inputPins; + int outputPin; + + public AdditionModule(int outputPin, int... inputPins){ + this.outputPin = outputPin; + this.inputPins = inputPins; + } +} diff --git a/src/meld/world/blocks/crafting/modules/ConsumeGate.java b/src/meld/world/blocks/crafting/modules/ConsumeGate.java index e323ce3..bb79adf 100644 --- a/src/meld/world/blocks/crafting/modules/ConsumeGate.java +++ b/src/meld/world/blocks/crafting/modules/ConsumeGate.java @@ -1,7 +1,10 @@ package meld.world.blocks.crafting.modules; +import meld.world.blocks.LiquidUtil; import meld.world.blocks.crafting.ModularCrafter; import mindustry.type.ItemStack; +import mindustry.type.Liquid; +import mindustry.type.LiquidStack; //If item requirement is not met, set the output to 0. Otherwise, set the output to one. public class ConsumeGate extends ModularCrafter.CrafterModule { @@ -10,13 +13,28 @@ public ConsumeGate(ItemStack[] items, int outputPin){ this.items = items; this.outputPin = outputPin; } + public ConsumeGate(LiquidStack[] liquids, int outputPin){ + this.liquids = liquids; + this.outputPin = outputPin; + } + public ConsumeGate(ItemStack[] items, LiquidStack[] liquids, int outputPin){ + this.items = items; + this.liquids = liquids; + this.outputPin = outputPin; + } public ItemStack[] items; + public LiquidStack[] liquids; public int outputPin; @Override public void update(ModularCrafter.ModularCrafterBuild build) { - build.setPin(outputPin,build.items.has(items) ? 1 : 0); + float out = 1; + + if(liquids != null && !LiquidUtil.has(liquids, build)) out = 0; + + //Set the output to zero if the build doesn't have the items, otherwise set it to whatever the out is + build.setPin(outputPin,build.items.has(items) ? out : 0); } } diff --git a/src/meld/world/blocks/crafting/modules/GateModule.java b/src/meld/world/blocks/crafting/modules/GateModule.java new file mode 100644 index 0000000..6b38676 --- /dev/null +++ b/src/meld/world/blocks/crafting/modules/GateModule.java @@ -0,0 +1,115 @@ +package meld.world.blocks.crafting.modules; + +import arc.struct.Seq; +import meld.world.blocks.LiquidUtil; +import meld.world.blocks.crafting.ModularCrafter; +import meld.world.blocks.crafting.ItemRecipe; +import mindustry.type.ItemStack; +import mindustry.type.LiquidStack; + +public class GateModule extends ModularCrafter.CrafterModule { + + + int outputPin; + + public Seq conditions = new Seq<>(); + + public GateModule(){ + + } + + public GateModule(int outputPin, CrafterCondition... conditions){ + this.outputPin = outputPin; + this.conditions.set(conditions); + } + + @Override + public void update(ModularCrafter.ModularCrafterBuild build) { + build.setPin(outputPin, validate(build) ? 1 : 0); + } + + public boolean validate(ModularCrafter.ModularCrafterBuild build){ + for (var condition: conditions){ + if(!condition.valid(build)) return false; + } + return true; + } + + public abstract static class CrafterCondition{ + public abstract boolean valid(ModularCrafter.ModularCrafterBuild build); + } + + public static class ConsumeCondition extends CrafterCondition{ + public ConsumeCondition(ItemStack[] items){ + this.items = items; + } + + public ConsumeCondition(LiquidStack[] liquids){ + this.liquids = liquids; + } + + public ConsumeCondition(ItemStack[] items, LiquidStack[] liquids){ + this.items = items; + this.liquids = liquids; + } + + public ItemStack[] items; + public LiquidStack[] liquids; + + public boolean valid(ModularCrafter.ModularCrafterBuild build){ + if(liquids != null && !LiquidUtil.has(liquids, build)) return false; + + //Set the output to zero if the build doesn't have the items, otherwise set it to whatever the out is + return build.items.has(items); + } + } + public static class OutputCondition extends CrafterCondition{ + public OutputCondition(ItemStack[] items){ + this.items = items; + } + + public OutputCondition(LiquidStack[] liquids){ + this.liquids = liquids; + } + + public OutputCondition(ItemStack[] items, LiquidStack[] liquids){ + this.items = items; + this.liquids = liquids; + } + + public ItemStack[] items; + public LiquidStack[] liquids; + + public boolean valid(ModularCrafter.ModularCrafterBuild build){ + if(items != null){ + for(var output : items){ + if(build.items.get(output.item) + output.amount > build.block.itemCapacity){ + return false; + } + } + } + if(liquids != null){ + for(var output: liquids){ + if(build.liquids.get(output.liquid) + output.amount >= build.block.liquidCapacity){ + return false; + } + } + } + return true; + } + } + + public static class RecipeCondition extends CrafterCondition{ + public ItemRecipe recipe; + + public RecipeCondition(ItemRecipe recipe){ + this.recipe = recipe; + } + + @Override + public boolean valid(ModularCrafter.ModularCrafterBuild build) { + return recipe.valid(build); + } + } + +} diff --git a/src/meld/world/blocks/crafting/modules/LambdaModule.java b/src/meld/world/blocks/crafting/modules/LambdaModule.java new file mode 100644 index 0000000..661f70e --- /dev/null +++ b/src/meld/world/blocks/crafting/modules/LambdaModule.java @@ -0,0 +1,14 @@ +package meld.world.blocks.crafting.modules; + +import arc.func.Cons; +import meld.world.blocks.crafting.ModularCrafter; + +public class LambdaModule extends ModularCrafter.CrafterModule { + public Cons updater; + + @Override + public void update(ModularCrafter.ModularCrafterBuild build) { + updater.get(build); + } + +} diff --git a/src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java b/src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java new file mode 100644 index 0000000..6564059 --- /dev/null +++ b/src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java @@ -0,0 +1,19 @@ +package meld.world.blocks.crafting.modules; + +import meld.world.blocks.crafting.ModularCrafter; +import meld.world.blocks.crafting.Recipe; + +public class RecipeCraftingModule extends ModularCrafter.CraftingModule { + public Recipe recipe; + + + @Override + public boolean canCraft(ModularCrafter.ModularCrafterBuild build) { + return recipe.valid(build); + } + + @Override + public void craft(ModularCrafter.ModularCrafterBuild build) { + recipe.apply(build); + } +} From e6411940bb3696a9e3b17acdcf8bbdeb64851fc3 Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Tue, 31 Mar 2026 01:49:50 +1100 Subject: [PATCH 02/17] Healing Blocks, Walls, SingleBeamDrill --- assets/bundles/bundle.properties | 4 +- ...ttom-0.png => aspect-channel-bottom-0.png} | Bin ...ttom-1.png => aspect-channel-bottom-1.png} | Bin ...ttom-2.png => aspect-channel-bottom-2.png} | Bin ...ttom-3.png => aspect-channel-bottom-3.png} | Bin ...ttom-4.png => aspect-channel-bottom-4.png} | Bin ...ipe-top-0.png => aspect-channel-top-0.png} | Bin ...ipe-top-1.png => aspect-channel-top-1.png} | Bin ...ipe-top-2.png => aspect-channel-top-2.png} | Bin ...ipe-top-3.png => aspect-channel-top-3.png} | Bin ...ipe-top-4.png => aspect-channel-top-4.png} | Bin .../fluid/director/aspect-pipe-top-.png | Bin 446 -> 0 bytes .../blocks/walls/shadesteel-shingles.png | Bin 0 -> 264 bytes .../blocks/walls/silver-husk-bottom.png | Bin 0 -> 325 bytes .../blocks/walls/silver-husk-preview.png | Bin 0 -> 542 bytes assets/sprites/blocks/walls/silver-husk.png | Bin 0 -> 452 bytes src/meld/content/MeldBlocks.java | 393 ++++++++++++------ src/meld/graphics/MeldPal.java | 1 + src/meld/world/blocks/AspectPipe.java | 2 +- src/meld/world/blocks/Bruiskit.java | 62 +++ src/meld/world/blocks/Gauze.java | 82 ++++ .../blocks/production/SingleBeamDrill.java | 104 +++++ 22 files changed, 511 insertions(+), 137 deletions(-) rename assets/sprites/blocks/fluid/director/{aspect-pipe-bottom-0.png => aspect-channel-bottom-0.png} (100%) rename assets/sprites/blocks/fluid/director/{aspect-pipe-bottom-1.png => aspect-channel-bottom-1.png} (100%) rename assets/sprites/blocks/fluid/director/{aspect-pipe-bottom-2.png => aspect-channel-bottom-2.png} (100%) rename assets/sprites/blocks/fluid/director/{aspect-pipe-bottom-3.png => aspect-channel-bottom-3.png} (100%) rename assets/sprites/blocks/fluid/director/{aspect-pipe-bottom-4.png => aspect-channel-bottom-4.png} (100%) rename assets/sprites/blocks/fluid/director/{aspect-pipe-top-0.png => aspect-channel-top-0.png} (100%) rename assets/sprites/blocks/fluid/director/{aspect-pipe-top-1.png => aspect-channel-top-1.png} (100%) rename assets/sprites/blocks/fluid/director/{aspect-pipe-top-2.png => aspect-channel-top-2.png} (100%) rename assets/sprites/blocks/fluid/director/{aspect-pipe-top-3.png => aspect-channel-top-3.png} (100%) rename assets/sprites/blocks/fluid/director/{aspect-pipe-top-4.png => aspect-channel-top-4.png} (100%) delete mode 100644 assets/sprites/blocks/fluid/director/aspect-pipe-top-.png create mode 100644 assets/sprites/blocks/walls/shadesteel-shingles.png create mode 100644 assets/sprites/blocks/walls/silver-husk-bottom.png create mode 100644 assets/sprites/blocks/walls/silver-husk-preview.png create mode 100644 assets/sprites/blocks/walls/silver-husk.png create mode 100644 src/meld/world/blocks/Bruiskit.java create mode 100644 src/meld/world/blocks/Gauze.java create mode 100644 src/meld/world/blocks/production/SingleBeamDrill.java diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index e0a45f5..55d1a48 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -135,8 +135,8 @@ block.meld-channel-node.description = Acts as a fluid router. Liquid can be inpu block.meld-aspect-outlet.name = Aspect Outlet block.meld-aspect-outlet.description = Decompresses [#cb8650]Aether[] into highly volatile [#cbdbfc]Aspect[].\n\nWorks as an output terminal for a fluid network. -block.meld-aspect-pipe.name = Aspect Pipe -block.meld-aspect-pipe.description = Acts as a pipe.\n\nWhen transporting [#cb8650]Aether[], fills nearby buildings with highly volatile [#cbdbfc]Aspect[].\n\nWorks as an input/output terminal for a fluid network. +block.meld-aspect-channel.name = Aspect Channel +block.meld-aspect-channel.description = Acts as a pipe.\n\nWhen transporting [#cb8650]Aether[], fills nearby buildings with highly volatile [#cbdbfc]Aspect[].\n\nWorks as an input/output terminal for a fluid network. block.meld-channel-director.name = Channel Director block.meld-channel-director.description = [red]Restricts[] the flow of fluids from its input to output by half.\n\nCan [red]detonate[] Channel Nodes full of [#cbdbfc]Aspect[].\n[accent]Transports at 50% pressure.[]\n\n[red]Will chain destruct![] diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-bottom-0.png b/assets/sprites/blocks/fluid/director/aspect-channel-bottom-0.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-pipe-bottom-0.png rename to assets/sprites/blocks/fluid/director/aspect-channel-bottom-0.png diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-bottom-1.png b/assets/sprites/blocks/fluid/director/aspect-channel-bottom-1.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-pipe-bottom-1.png rename to assets/sprites/blocks/fluid/director/aspect-channel-bottom-1.png diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-bottom-2.png b/assets/sprites/blocks/fluid/director/aspect-channel-bottom-2.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-pipe-bottom-2.png rename to assets/sprites/blocks/fluid/director/aspect-channel-bottom-2.png diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-bottom-3.png b/assets/sprites/blocks/fluid/director/aspect-channel-bottom-3.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-pipe-bottom-3.png rename to assets/sprites/blocks/fluid/director/aspect-channel-bottom-3.png diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-bottom-4.png b/assets/sprites/blocks/fluid/director/aspect-channel-bottom-4.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-pipe-bottom-4.png rename to assets/sprites/blocks/fluid/director/aspect-channel-bottom-4.png diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-top-0.png b/assets/sprites/blocks/fluid/director/aspect-channel-top-0.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-pipe-top-0.png rename to assets/sprites/blocks/fluid/director/aspect-channel-top-0.png diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-top-1.png b/assets/sprites/blocks/fluid/director/aspect-channel-top-1.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-pipe-top-1.png rename to assets/sprites/blocks/fluid/director/aspect-channel-top-1.png diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-top-2.png b/assets/sprites/blocks/fluid/director/aspect-channel-top-2.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-pipe-top-2.png rename to assets/sprites/blocks/fluid/director/aspect-channel-top-2.png diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-top-3.png b/assets/sprites/blocks/fluid/director/aspect-channel-top-3.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-pipe-top-3.png rename to assets/sprites/blocks/fluid/director/aspect-channel-top-3.png diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-top-4.png b/assets/sprites/blocks/fluid/director/aspect-channel-top-4.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-pipe-top-4.png rename to assets/sprites/blocks/fluid/director/aspect-channel-top-4.png diff --git a/assets/sprites/blocks/fluid/director/aspect-pipe-top-.png b/assets/sprites/blocks/fluid/director/aspect-pipe-top-.png deleted file mode 100644 index 2ed0dc478d3c17e87e02db5c8e229a86557c5f01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 446 zcmV;v0YUzWP)Px$cu7P-R9J<@m!VPvF%X9T+|*&v?E_p*MLT_uV$atx!vj>+;}Bp_m{`gyV3{H? ztp_xwwqV$qG}+v4E_c^|Cg!rqewW>36Z3O8{^DP&^#fep-(DLCa>tWC_TSPlOv)hu zpb#xP*1)B$ss*gw^x~NO4*ZT(h$s6Je4EbZ>hWv{s%oL0fYbZ-Ee{|?H_IzFQMC|J zfN?o$1%g^K007)QJ_lPY6+)62g03N00DsBafQW@50Eii;K*Yq&T};X$sP%COS-XMj zGgyJ${)-)$65p6DH#eIDzG0K(^2fw}%+yuGaXD(dz3SxpJXrz%@ae+2uOI{|Cty=u zUKEBJn*)77kXoq)odBSv!zT-%4+!(R{XB6X)p704AaKb(SOMuerCAZzMzUu^kORT> z)!8?`lBGI|^#wUVl5)X6+cn#ks|QhlIvA~UE|h-BSB1cxD91UNE5AAirn7mra}Gik o0untaB_%yh>1uQ?o&9zE2O^-nLN*sF761SM07*qoM6N<$g6i(UAOHXW diff --git a/assets/sprites/blocks/walls/shadesteel-shingles.png b/assets/sprites/blocks/walls/shadesteel-shingles.png new file mode 100644 index 0000000000000000000000000000000000000000..694abd832bb624f75038dc875e7f5ff9f970ace3 GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}hdf;zLn2y} z&lns2IPajuv2nXvD7W7M7t_fnSb7|#v{c#~c=-8`iXC>E`1I%O>l#9nlop9d`*BHp z(2yu#-!NhE%ahafd06kgQ+XX-{6VAbMnn6770hgR73A3H8^C176xXQ-^f14V;Z44Ymtu?bybTK7seOrNKMqsOY@iHU*1T>X_!T7b>Y35|lDL~&ac)I$z JtaD0e0szKhVMYJ| literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/walls/silver-husk-bottom.png b/assets/sprites/blocks/walls/silver-husk-bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..5e8a6358734b88643dfbfd5bbced7318b990c2e0 GIT binary patch literal 325 zcmV-L0lNN)P)Px#|4BqaR9J=WmOT!_FbsuFPtt{rl_RkB7Gz{WoC2{hhFf&y2&`-@Jqcy9MBV)O zr9`1p-`3Xl`{X1}i53;s3QaJ^^r7$8TBs%z95YXWPzP$wQHTmDnnUwh0tvC*tOxHO z&lhZ-1VBV|yPln$*dI=CJ!eAKUV0*;x;c6aN{Em-cg@wE(F-Px$*hxe|R9J=0mp^L)K@i2Cho8YhA_yU95evn1wzjsx!rnGbN{f^M38b=!RSFTC zkTzxPB3hV22|^%Zkq;3ql9jo=+1Xu7%0`ljOr5YP)-CT!-eF-8Ch!so$0u@L|X;t*m1bcpGE zg+{aG{Ln_T<@^GP+q;Lg6i_UcL)Z76D*(XR=}Bn(<@IfAPGxIq5kNOrnhksGc)n6+ z$0Z211hv!xwba7+BhJWVj-RG9HD&~W8fTV$CkV-0l?;a25h{V{tv`;=*>ROxQ^Qen zD!N!1X8{#gb6Quf#-={eWd(S8|B5`2Go)iGR-Y+50Z`3`J+Y$;xwP|}?*woNc>&}r zb#aB8&R61$*a@JT4Yuagh%=|4AgkkE0J=G6$N{-#A_VaGc^nBatpNZq=(aKFwvG3> z4NO0Px$en~_@R9J<@mo0L`Fc5{GJYglpned>1cuaGL9-_F1DefV92UCv>g2Fw)A)!%` zrW<*+Khrc8vi0{quXms2(8nq5wrecanlTPIp3chw0Kk$Et9&uW0YC@sb-cbbK^nhY zZ^;AD&>Jlhnz(gN6+nXUZ0wmk1CSv8qp<)b#PM`SA1Cv>?c8?~`SJc1B(XkD>CkRM*;f { + int a = 0; + for(int i = 0; i < 2; i++){ + b.setPin(i, Math.max(b.getPin(i) - a, 0)); + a = (int)Math.max(a, b.getPin(i)); + } + b.setPin(ModOUT.TWO, a); + }; + }}, + new ConsumeLiquidModule(LiquidStack.with(MeldLiquids.aspect, outletRate * 2), ModIN.TWO, ModOUT.THREE), + new RecipeCraftingModule(){{ + recipe = aspectPipe1; + efficiencyPins = new int[]{ModIN.THREE, ModIN.ZERO}; + progressPin = ModOUT.FOUR; + craftTime = produceTime; + }}, + new RecipeCraftingModule(){{ + recipe = aspectPipe2; + efficiencyPins = new int[]{ModIN.THREE, ModIN.ONE}; + progressPin = ModOUT.FIVE; + craftTime = produceTime; + }} + ); + }}; + sharkFactory = new UnitFactory("shark-factory"){{ requirements(Category.units, with(MeldItems.debris, 500, MeldItems.carbolith, 350, MeldItems.silver, 450)); size = 5; @@ -815,6 +920,26 @@ public static void load(){ health = 300; }}; + bruisekit = new Bruiskit("bruisekit"){{ + requirements(Category.effect, with( + MeldItems.debris, 60, + MeldItems.aspectPipe, 45, + MeldItems.resonarum, 80 + )); + size = 2; + }}; + + gauze = new Gauze("gauze"){{ + requirements(Category.effect, with( + MeldItems.debris, 60, + MeldItems.aspectPipe, 45, + MeldItems.resonarum, 80 + )); + size = 3; + + health = 640; + }}; + chute = new Duct("chute"){{ requirements(Category.distribution, with(MeldItems.debris, 1)); health = 90; diff --git a/src/meld/graphics/MeldPal.java b/src/meld/graphics/MeldPal.java index 5a49b6d..52d238a 100644 --- a/src/meld/graphics/MeldPal.java +++ b/src/meld/graphics/MeldPal.java @@ -5,6 +5,7 @@ public class MeldPal { public static Color + aspect = Color.valueOf("f0f5fe"), shark = Color.valueOf("a393feff"), darkShark = Color.valueOf("665c9f"), accentClear = Pal.accent.cpy().a(0), diff --git a/src/meld/world/blocks/AspectPipe.java b/src/meld/world/blocks/AspectPipe.java index e644719..eee07ac 100644 --- a/src/meld/world/blocks/AspectPipe.java +++ b/src/meld/world/blocks/AspectPipe.java @@ -73,7 +73,7 @@ public float moveLiquid(Building other, Liquid liquid) { } //At the same time try dumping aspect - if(liquid == MeldLiquids.aether && this.canDumpLiquid(other, MeldLiquids.aspect)) { + if(!(other instanceof ConduitBuild || other instanceof LiquidRouter.LiquidRouterBuild) && liquid == MeldLiquids.aether && this.canDumpLiquid(other, MeldLiquids.aspect)) { Liquid original = liquid; liquid = MeldLiquids.aspect; float ofract = other.liquids.get(liquid) / other.block.liquidCapacity; diff --git a/src/meld/world/blocks/Bruiskit.java b/src/meld/world/blocks/Bruiskit.java new file mode 100644 index 0000000..3d3f211 --- /dev/null +++ b/src/meld/world/blocks/Bruiskit.java @@ -0,0 +1,62 @@ +package meld.world.blocks; + +import arc.graphics.g2d.Draw; +import arc.graphics.g2d.Lines; +import arc.math.Mathf; +import arc.struct.Seq; +import mindustry.Vars; +import mindustry.entities.Units; +import mindustry.gen.Building; +import mindustry.gen.Teamc; + +public class Bruiskit extends FieldPulsar{ + Seq tmpDamaged = new Seq<>(); + + int targetTimer = timers++; + + public float healSpeed = 2; + public float retargetInterval = 5; + + public float recentDamageMultiplier = 0.1f; + + public Bruiskit(String name) { + super(name); + } + + public class BruiskitBuild extends PulsarBuild{ + public Building target; + + + @Override + public void updateTile() { + super.updateTile(); + if(timer.get(targetTimer, retargetInterval)) findTarget(); + if(target != null){ + if(target.isAdded() && target.damaged()) { + float healAmount = healSpeed; + if(target.wasRecentlyDamaged()) healAmount *= recentDamageMultiplier; + + target.heal(healAmount); + } + } + } + + public void findTarget(){ + tmpDamaged.clear(); + + Units.nearbyBuildings(x, y, smoothRadius, b -> { + if(b.team == team() && b.damaged() && b.block.size > 1) tmpDamaged.add(b); + }); + + tmpDamaged.sort(b -> b.block.size + (1 - b.healthf()) + Mathf.log(10, b.block.health)/10); + if(!tmpDamaged.isEmpty()) target = tmpDamaged.pop(); + } + + @Override + public void draw() { + super.draw(); + Draw.alpha(1); + if(target != null) Lines.line(x, y, target.x, target.y); + } + } +} diff --git a/src/meld/world/blocks/Gauze.java b/src/meld/world/blocks/Gauze.java new file mode 100644 index 0000000..f60a9e1 --- /dev/null +++ b/src/meld/world/blocks/Gauze.java @@ -0,0 +1,82 @@ +package meld.world.blocks; + +import arc.math.Mathf; +import arc.struct.Seq; +import mindustry.content.Fx; +import mindustry.gen.Building; +import mindustry.graphics.Pal; +import mindustry.world.Block; +import mindustry.world.Tile; + +public class Gauze extends Block { + public float reload = 60; + public int propagateMaxRange = 10; + + public float healAmount = 200; + public float maxFract = 0.1f; + + Seq searching = new Seq<>(), qued = new Seq<>(), explored = new Seq<>(); + + public Gauze(String name) { + super(name); + update = true; + } + + + public class GauzeBuild extends Building { + + public float time; + + @Override + public void updateTile() { + super.updateTile(); + time += efficiency; + if(time >= reload){ + propagate(); + time %= reload; + } + } + + //Only propagates through 1x1 blocks and their adjacent blocks + public void propagate(){ + explored.clear(); + searching.clear(); + qued.clear(); + + explored.add(this); + searching.addAll(this.proximity); + + float charge = healAmount; + + for(int i = 0; i < propagateMaxRange; i++){ + for(Building build: searching){ + Fx.healBlock.at(build.x, build.y, 1); + if(build.damaged()){ + /** + * Max of a few numbers + * -Missing health + * -maxFract * build.maxHealth + * -Remaining charge + * -0 + */ + float healAmount = Mathf.maxZero(Math.min(Math.min(build.maxHealth * maxFract, build.block.health - build.health), charge)); + if(healAmount > 0){ + Fx.healBlockFull.at(build.x, build.y, 0, Pal.heal, build.block); + build.heal(healAmount); + charge -= healAmount; + } + } + + if(build.block.size == 1) build.proximity.each( b -> !explored.contains(b), qued::addUnique); + } + + explored.add(searching); + searching.set(qued); + qued.clear(); + + //No more healing to expand, goodbye world + if(charge == 0) break; + } + } + } +} diff --git a/src/meld/world/blocks/production/SingleBeamDrill.java b/src/meld/world/blocks/production/SingleBeamDrill.java new file mode 100644 index 0000000..d434c3b --- /dev/null +++ b/src/meld/world/blocks/production/SingleBeamDrill.java @@ -0,0 +1,104 @@ +package meld.world.blocks.production; + +import arc.graphics.Color; +import arc.math.Mathf; +import arc.math.geom.Geometry; +import arc.math.geom.Point2; +import arc.struct.EnumSet; +import arc.struct.IntMap; +import arc.struct.ObjectFloatMap; +import arc.struct.ObjectMap; +import arc.util.Log; +import arc.util.Time; +import mindustry.Vars; +import mindustry.content.Fx; +import mindustry.entities.Damage; +import mindustry.gen.Building; +import mindustry.gen.Sounds; +import mindustry.type.Item; +import mindustry.world.Block; +import mindustry.world.Tile; +import mindustry.world.blocks.production.BeamDrill; +import mindustry.world.meta.BlockFlag; + +//HAS TO be an odd number in size. +public class SingleBeamDrill extends Block { + + public int range = 5, tier = 4; + + //I know that sounds like a lot of items at once but well... yeah it's a lot of items at once + public int baseProductivity = 25; + public ObjectFloatMap itemMultipliers = new ObjectFloatMap<>(); + public float drillTime = 120; + + public SingleBeamDrill(String name) { + super(name); + hasItems = true; + rotate = true; + update = true; + solid = true; + drawArrow = false; + regionRotated1 = 1; + ignoreLineRotation = true; + ambientSoundVolume = 0.05F; + ambientSound = Sounds.loopMineBeam; + envEnabled |= 2; + flags = EnumSet.of(new BlockFlag[]{BlockFlag.drill}); + } + + public class SingleBeamBuild extends Building{ + public float time; + + @Override + public void updateTile() { + super.updateTile(); + time += efficiency; + if(time >= drillTime){ + drill(); + time %= drillTime; + } + + dump(); + } + + public void drill(){ + Item found = null; + + int offset = (size + 1)/2; + Point2 dir = Geometry.d4(rotation); + + int tx = tileX(), ty = tileY(); + for(int i = 0; i < range; i++){ + int j = i + offset; + Tile other = Vars.world.tile(tx + dir.x * j, ty + dir.y * j); + + if(other.solid()){ + Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 5, 30000, Vars.tilesize * 3, true); + Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 15, 0, Vars.tilesize * 2, true); + Item drop = other.wallDrop(); + if(drop == null) break; + + if(drop.hardness <= tier) found = drop; + + break; + } + else { + Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 2, 0, Vars.tilesize * 3, true); + } + + } + + if(found == null) return; + + int mined = (int)(baseProductivity * itemMultipliers.get(found, 1)); + + mined = Mathf.ceilPositive(Math.min(itemCapacity - items.get(found), mined)); + items.add(found, mined); + } + + @Override + public float progress() { + return time/drillTime; + } + } +} From 9936b478f901a96060a80bb09e2da266e71bc768 Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Tue, 31 Mar 2026 18:56:09 +1100 Subject: [PATCH 03/17] Badlands tileset, some clifflikes -Gauze now attempts to craft spool and sync with other gauzes -SingleBeamDrill now does self damage and damages whatever it hits -Recipe now takes both a Block and a Building -aspect pipe visuals updated -many more env tiles for the barrens have been added -ChannelVent block, drops fluids into the world past a certain % fullness --- .../environment/badlands/aspect-soil1.png | Bin 0 -> 283 bytes .../environment/badlands/aspect-soil2.png | Bin 0 -> 251 bytes .../environment/badlands/aspect-soil3.png | Bin 0 -> 264 bytes .../badlands/cracked-sand-edge.png | Bin 0 -> 1046 bytes .../environment/badlands/cracked-sand1.png | Bin 0 -> 451 bytes .../environment/badlands/cracked-sand2.png | Bin 0 -> 448 bytes .../environment/badlands/cracked-sand3.png | Bin 0 -> 445 bytes .../environment/badlands/cracked-sand4.png | Bin 0 -> 412 bytes .../environment/badlands/crackstone-wall1.png | Bin 0 -> 371 bytes .../environment/badlands/crackstone-wall2.png | Bin 0 -> 386 bytes .../environment/badlands/mallow-wall1.png | Bin 0 -> 322 bytes .../environment/badlands/mallow-wall2.png | Bin 0 -> 319 bytes .../environment/badlands/red-sand-meld1.png | Bin 0 -> 316 bytes .../environment/badlands/red-sand-meld2.png | Bin 0 -> 309 bytes .../environment/badlands/red-sand-meld3.png | Bin 0 -> 382 bytes .../environment/badlands/red-sand-weave1.png | Bin 0 -> 338 bytes .../environment/badlands/red-sand-weave2.png | Bin 0 -> 328 bytes .../environment/badlands/red-sand-weave3.png | Bin 0 -> 290 bytes .../blocks/environment/badlands/red-sand1.png | Bin 0 -> 285 bytes .../blocks/environment/badlands/red-sand2.png | Bin 0 -> 247 bytes .../blocks/environment/badlands/red-sand3.png | Bin 0 -> 282 bytes .../badlands/silver-deposit-depleted2.png | Bin 0 -> 361 bytes .../badlands/silver-deposit-depleted3.png | Bin 0 -> 366 bytes .../environment/badlands/vitric-weave1.png | Bin 0 -> 1042 bytes .../environment/badlands/vitric-weave2.png | Bin 0 -> 993 bytes .../environment/barrens/bedrock-edge.png | Bin 0 -> 472 bytes .../blocks/environment/barrens/bedrock1.png | Bin 226 -> 226 bytes .../blocks/environment/barrens/bedrock2.png | Bin 240 -> 236 bytes .../blocks/environment/barrens/bedrock3.png | Bin 239 -> 231 bytes .../environment/barrens/elnar-silt1.png | Bin 0 -> 196 bytes .../environment/barrens/elnar-silt2.png | Bin 0 -> 191 bytes .../environment/barrens/elnar-silt3.png | Bin 0 -> 190 bytes .../environment/barrens/elnar-silt4.png | Bin 0 -> 158 bytes .../barrens/embedded-elnar-overflowing1.png | Bin 0 -> 652 bytes .../barrens/embedded-elnar-overflowing2.png | Bin 0 -> 616 bytes .../environment/barrens/embedded-elnar1.png | Bin 0 -> 621 bytes .../environment/barrens/embedded-elnar2.png | Bin 0 -> 596 bytes .../environment/barrens/tenbris-mix1.png | Bin 0 -> 599 bytes .../environment/barrens/tenbris-mix2.png | Bin 0 -> 565 bytes .../environment/barrens/tenbris-ridges1.png | Bin 0 -> 360 bytes .../environment/barrens/tenbris-ridges2.png | Bin 0 -> 373 bytes assets/sprites/blocks/production/fumehood.png | Bin 0 -> 848 bytes assets/sprites/chute-crossing-bottom.png | Bin 0 -> 503 bytes assets/sprites/chute-crossing-top.png | Bin 0 -> 448 bytes assets/sprites/pressure-vent-bottom.png | Bin 0 -> 328 bytes assets/sprites/pressure-vent.png | Bin 0 -> 505 bytes src/meld/content/MeldBlocks.java | 100 +++++++++-- src/meld/content/MeldEnvironment.java | 63 ++++++- src/meld/world/blocks/AspectPipe.java | 11 ++ src/meld/world/blocks/ChannelVent.java | 39 +++++ src/meld/world/blocks/Gauze.java | 109 +++++++++++- src/meld/world/blocks/VisualAspectPipe.java | 159 ++++++++++++++++++ .../world/blocks/crafting/ItemRecipe.java | 7 +- src/meld/world/blocks/crafting/Recipe.java | 7 +- .../world/blocks/crafting/SpoolRecipe.java | 29 ++++ .../blocks/crafting/modules/GateModule.java | 2 +- .../crafting/modules/ProduceLiquidModule.java | 4 +- .../modules/RecipeCraftingModule.java | 4 +- .../blocks/production/SingleBeamDrill.java | 11 +- 59 files changed, 513 insertions(+), 32 deletions(-) create mode 100644 assets/sprites/blocks/environment/badlands/aspect-soil1.png create mode 100644 assets/sprites/blocks/environment/badlands/aspect-soil2.png create mode 100644 assets/sprites/blocks/environment/badlands/aspect-soil3.png create mode 100644 assets/sprites/blocks/environment/badlands/cracked-sand-edge.png create mode 100644 assets/sprites/blocks/environment/badlands/cracked-sand1.png create mode 100644 assets/sprites/blocks/environment/badlands/cracked-sand2.png create mode 100644 assets/sprites/blocks/environment/badlands/cracked-sand3.png create mode 100644 assets/sprites/blocks/environment/badlands/cracked-sand4.png create mode 100644 assets/sprites/blocks/environment/badlands/crackstone-wall1.png create mode 100644 assets/sprites/blocks/environment/badlands/crackstone-wall2.png create mode 100644 assets/sprites/blocks/environment/badlands/mallow-wall1.png create mode 100644 assets/sprites/blocks/environment/badlands/mallow-wall2.png create mode 100644 assets/sprites/blocks/environment/badlands/red-sand-meld1.png create mode 100644 assets/sprites/blocks/environment/badlands/red-sand-meld2.png create mode 100644 assets/sprites/blocks/environment/badlands/red-sand-meld3.png create mode 100644 assets/sprites/blocks/environment/badlands/red-sand-weave1.png create mode 100644 assets/sprites/blocks/environment/badlands/red-sand-weave2.png create mode 100644 assets/sprites/blocks/environment/badlands/red-sand-weave3.png create mode 100644 assets/sprites/blocks/environment/badlands/red-sand1.png create mode 100644 assets/sprites/blocks/environment/badlands/red-sand2.png create mode 100644 assets/sprites/blocks/environment/badlands/red-sand3.png create mode 100644 assets/sprites/blocks/environment/badlands/silver-deposit-depleted2.png create mode 100644 assets/sprites/blocks/environment/badlands/silver-deposit-depleted3.png create mode 100644 assets/sprites/blocks/environment/badlands/vitric-weave1.png create mode 100644 assets/sprites/blocks/environment/badlands/vitric-weave2.png create mode 100644 assets/sprites/blocks/environment/barrens/bedrock-edge.png create mode 100644 assets/sprites/blocks/environment/barrens/elnar-silt1.png create mode 100644 assets/sprites/blocks/environment/barrens/elnar-silt2.png create mode 100644 assets/sprites/blocks/environment/barrens/elnar-silt3.png create mode 100644 assets/sprites/blocks/environment/barrens/elnar-silt4.png create mode 100644 assets/sprites/blocks/environment/barrens/embedded-elnar-overflowing1.png create mode 100644 assets/sprites/blocks/environment/barrens/embedded-elnar-overflowing2.png create mode 100644 assets/sprites/blocks/environment/barrens/embedded-elnar1.png create mode 100644 assets/sprites/blocks/environment/barrens/embedded-elnar2.png create mode 100644 assets/sprites/blocks/environment/barrens/tenbris-mix1.png create mode 100644 assets/sprites/blocks/environment/barrens/tenbris-mix2.png create mode 100644 assets/sprites/blocks/environment/barrens/tenbris-ridges1.png create mode 100644 assets/sprites/blocks/environment/barrens/tenbris-ridges2.png create mode 100644 assets/sprites/blocks/production/fumehood.png create mode 100644 assets/sprites/chute-crossing-bottom.png create mode 100644 assets/sprites/chute-crossing-top.png create mode 100644 assets/sprites/pressure-vent-bottom.png create mode 100644 assets/sprites/pressure-vent.png create mode 100644 src/meld/world/blocks/ChannelVent.java create mode 100644 src/meld/world/blocks/VisualAspectPipe.java create mode 100644 src/meld/world/blocks/crafting/SpoolRecipe.java diff --git a/assets/sprites/blocks/environment/badlands/aspect-soil1.png b/assets/sprites/blocks/environment/badlands/aspect-soil1.png new file mode 100644 index 0000000000000000000000000000000000000000..ade29f25507bafabddaaaeca1370fa0f7594e9fc GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}S3O-ELn2!5 zPCLunY{1j%dsL63wDH}ch}bSx3jBUI6rRT1&e;9V(t**z?>$$*;%bH`r`Du+cOTgG)>YuT z(UyiCOf3pKziLhoiz$+NB^UbPI>SjBkFDX}ZOUD43fFIE|FUCguv@LiFs(OIAk)z4*}Q$iB}EZS~r literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/aspect-soil2.png b/assets/sprites/blocks/environment/badlands/aspect-soil2.png new file mode 100644 index 0000000000000000000000000000000000000000..981f51829d34c0d3c792d09f017ba87a3fc08258 GIT binary patch literal 251 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}TRmMILn2z= zUOCI#puod+!T+(|kqr#HEv9+zY+zr0QMgUuRQ*ATDxu~NI!iC_TWfB0>`w7#MhOOn zh#g{KL3_?0ublWf!YCnc-SKbMVGN>rE}x|~2*!3@a4Ff(s>2X})tvE&!WY8{wFg2s zYSyQnTfR=gA*JEhf$af2DpC)+qd08OWgYeEdh)nHv7t%n%vl$K37ZOdkJw8G3Mwq$ zv5LuLk?4_X7DW%&6M0$x-Z7r*Hpg!=>B!z zAE*3JcF~=;YdPBlA@N08O+p-6Vmp{)IvKsV`?{9Iv(GuaBjK3?*CCT82^Z6bCBGdR zvr@SPin*Brgq&Z^{qHiNSn)fLRnLOwjTPx&&`Cr=RCt{2n>~&qF%X44tA%7lK!5;=Xe2UDfJDd@<~SR0oV^0!NP7Y@q>WYr zGywtHgbCQlD^s%Fc4Jo+@V=C8PtU7AcU9XM000000000000000000000000y53Bj) zvYJmWwbrh&Zd+cYAAmvy`tj>ek!N(*EwyF|zDYko6D2%Wo7cO1mwo`t``c?!Br9O9 z=V}(-qAmh9`=iNg6!-X6?)dnoodUBRX5f@lQ1zr9|3 zqT6WLozB5~m(yX@XETo;0kLi8Y}Aj6Zwg04O8TpXND+3$-|UZ9sV7%dSG?Fd<6gIM zozgWX1@;JtdH!a9Y!r&(MoR1*A_a*^U^T#E(D8~-h08U9Z#{Pnj(X7+)*@^TkScIf z9dHS)Nz+P`m(%NO7h<*=5c2*~>`v$ZMv%zmZDBD$Tk*%eZdMfBlkgUn8u0P?brr@X zQj5!SI!w;<+Kj|jgsBm7xV0#!@)X<9w)l*Y<6jY1*JfH{EsjdV;@P{c|flB#|AaE4N=nwtTmvm_)U}^)^oy= zf?`v!6jH^t*J&QWP^zaODt?L7V+H0&OSNl2^%V5;_us33ASYEcT^no0-Ah_xNkP^K zx2B>Hv54@crO=lY6prtLSht~e5VPJMuHJ;H2yH!gIUOe5tECZVw7dyx5kms8p*)=j zgg%VQEvCLG@U5XG3RDf{xdqYC3K1E~TSCKmH!@1>WY*h5wsE=62i(O_zSNd7)d-xY zXH*nn7n>G*^8!vIaKUN-8U<8jD}F3DmxzYgN4(r;$JiqvH5H|t4+xREbD~C&IJhTv zLS`}OTtX2*33)3uQrj`-Y}6M!H7QmDZYjzkaz1% ztXI?DsgShw;agLK_(n?vP|uB#BIGUS5x7y|1*XL*niLNXt*OQPjg|cU8d+D{B z#5bBEz<4~?70dpnO~8j@G3Z=spQZ!=000000000000000000000Kk**54iXGrQiS; QDF6Tf07*qoM6N<$f?qPszyJUM literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/cracked-sand1.png b/assets/sprites/blocks/environment/badlands/cracked-sand1.png new file mode 100644 index 0000000000000000000000000000000000000000..e56e214ab1022f0b0db72b21893430810b3b7fb4 GIT binary patch literal 451 zcmV;!0X+VRP)Px$eMv+?R9J<*S38cvFc6(Y5e=fCN|3ffqT>YgT!91awe}ix93X5(k&cFK*4ALp zjNb&qlhQbj-_6ZL_|NAU$SuA_1W6_dK35VhqZYYN2?KRR*R{G1*90K zyLzaHz$GB{f+PYZNB5~7@L)fz#keCPG65woAjBRK9p9iGHct1Lh@K2b5Iw*TmP!t> zR)dy1=j*Lb4$MIi)SR}pyqjDKclQZmjhu+6MaiuSD3M$FBqm`ATr`@jK_oZC-H6hT=B<>?YLSIo z6~L8BA9}${ksFeQAe{*svB!F?4~PORK|xH7CIt(S#Eet9(F9o5QJ)x1Zh|ha?&m&uZls*sYWBxM4)KNY5lAHAidhTJm4j_42$C!wH_t+=2GSXX=uEI tIG_oC$7GDvIhRosu?(%5j$Eoyasnog*^ZO002ovPDHLkV1h#&!KwfN literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/cracked-sand2.png b/assets/sprites/blocks/environment/badlands/cracked-sand2.png new file mode 100644 index 0000000000000000000000000000000000000000..3d3421a4f8e00ee0a980f2fa256706949fd77e32 GIT binary patch literal 448 zcmV;x0YCnUP)Px$dPzha}tWZ#_WV$wRg*=~B5g z&7UN`DgKD>iJ|!D=IiqMgg;!re?Y^>`)PM?niuxnap=`p2^}TCBF@KyD@YAm?cweI z*j!7y4HZDs%!!B;qGmvYCB!Ro6@UX;S%^dnPPJHsx58ZlBy#S^jYGeZQk| zkB3kjP8(@H-(H^dq18|%aJ#mqs@*Z$AB~u#Uq&~ zxChnqfESWbR}pfEI+E%@5>1}6fa|9lhdwJ{F1h9(s~vlHA7NS)Yz?GIC?`Px$cS%G+R9Jqh@K(6(M_U1wMO@^zA5DbZ9r}Vz*EyPxndC8$9h^*uYO}r_HO35j%_h;mVAc#_^2^)(clLA_2J{N&U zALRfgZe6{ECLZt#rJjidtjm)3gu6ZCQ2ntPW z?f``~J?C)Px$R!KxbR9J<@Ryz)ZFbs7O>QXTueWvmUR=Gu?V8Fw5AzCHYVgo+`*9)fdGzTC=*PvVW>r9&y@Z_t zZC#>67QTEK4ErF&Ggbw#VSEv)+67kuW-oyoC|=v(XzP;1%kiPEL^Oi)XHtf?0DLW_Nnz~zKtC=!cc(H3OHUyt#H?@Zo81$f@&vGZywv zxE1rKEnz>0`|@8Zu5qSZkB`|4DXkDUc_YZ{(e%sE#HsJYc_ID=mpk0?s%{#wM~*6& zP2J5SsNfbSDjc9Z>!9VqGL|h(lE!h|n=W7UZ;Jjr{fTUA?OrAWj|X`Id6!l&%`}~6 zc<^!6H@AHS2YRK96C}jy7j1REw`1M)ys0dDA^kfS3j3^P6Px#4^T{0MF0Q*pF|yODh|?#QQ@YJt(N6^00005bW%=J0RR90{~XXJQUCw}5J^Nq zR7i=v)Z4bhAP5A|jQsyUpQYku0Ev0%@ujhu9Wl~A&%Y0mk8uNXFMS;6hrICYNa()U zk>lx>R-H6)Sk)h6;|ZVc9O87GJt-pK0Ex0rB(<{W(>AlK=n!07*qoM6N<$f=7L+z5oCK literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/mallow-wall1.png b/assets/sprites/blocks/environment/badlands/mallow-wall1.png new file mode 100644 index 0000000000000000000000000000000000000000..a606a30967147ab1bc3423e87f15dfa9bf0343aa GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sjKx9jP7LeL$-D$|cmjMvT!Hj_ z7ugF9&W}%SxII6y2FPbA3GxeO`2YX^W?hF4ApeS|i(`mK=g~`%e1{cySOSjS`F}2y zOXVK#sztw6_deSwvHe^1*VX4P?OxPvb=F?(fSFzM!Lq!6Tx`#|KYg5Q)}XYWdx7vp zI|hdmB{7L6jVu0jOp8Rnw=!oiCrt5CV<_*O`q(-nz>L#t58tUh`&hU&?rJTtm>nYj zg1htKHy5@&b~pQW9^eb*T(jxGlba!i6PY*c7D>?QOV8mp@MqT6TEH)A>dCN6-eu3` z-+Zff8YV>d++T6P=u`gb*4PI;2O6ASlsN6Xe|L|5lZH6cv&y~K^M1Ym%D6v`r(?pd SLkocZWAJqKb6Mw<&;$U(DuGV` literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/mallow-wall2.png b/assets/sprites/blocks/environment/badlands/mallow-wall2.png new file mode 100644 index 0000000000000000000000000000000000000000..4b228b088f9be9f215329076010558f36fea8ed0 GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sjKx9jP7LeL$-D$|cmjMvT!Hj_ z7ugF9&W}%SxII6y2FPbA3GxeO`2YX^W?hF4ApfGLi(`mK=hMr9e9Vd*ECCYl>Yp!* zU8}*f+INH$wXttB8@PEi7%4xbl)&M`#qwFPx#_DMuRR9J=WmQ4zn&$3P`jCIrH58 z5R3#++Gnlr;d`barc|#>+aRuh6oL)lkD^2@0E&683S@wod2a4g5N`mfx6>-SuV@l- zjHcd^0_Z8#9N_E%^&s*gI&08bgJUzVCTDgVQuH#J0RXq4BH<avH||Px#?@2^KR9J=WmO%=`AP_}=N;k~`nm{~J@6zM-5QQ9~3j>k^B%4CJsnW!$jObt& z{#7*KfBwv9n%m|2LO~r$npc1dPys3c030P3KdauGo3+`D#S);*srllcKm_2|?kSNq za2k|*UMHPS6p)v|w>dQy2cQ%Sv9I*dJ9Z7^fS~3?&w)@9R#9CbQ4d}M>!h7gN3_$@ zJOS`_#}S!8r+U&H0NM{+Os|LJCBRwOK_ESeO#;?@VIDs1ppujL-@AaDf*1f7B5MuA zLOkwck~y&Jf>|3@QROfu0W5?kZQS9M`+8>I1ycV7#oO==(Mm;zAy5e300000NkvXX Hu0mjf;5mK! literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/red-sand-meld3.png b/assets/sprites/blocks/environment/badlands/red-sand-meld3.png new file mode 100644 index 0000000000000000000000000000000000000000..f4bf27636abd13b27853095f292d54f3cc864df2 GIT binary patch literal 382 zcmV-^0fGLBP)Px$I7vi7R9J=Wmr)LaFbsyP@dXbcCfkGO@h%?ELzs979!3Hj0A5V=L6$6|Tid~c z8vD2{^rQRRA2!$XN_n!M)Bj`2b>x0RZ+&!%1mqM~I;|NdV{- zaFW|7$FqgfP&n(!0FvZbNFlO_Py&&y3%C$j+mHhx2IxJtw?r#a5EB4SZ}+u^$&ke*tL+yOe%mSER+tG5PL8NVbA)VHA{q)b8>>M0k<-#ik}65!%Rgd zjmZ^A-j4b>@dKNzs0O$YloL|Pg8&i;j%mftL^a?-VC`x5Z34e5IA+EcA*UiK{|Ue2 chF=Tt0)yUrx6oJvw*UYD07*qoM6N<$f+p6Q!vFvP literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/red-sand-weave1.png b/assets/sprites/blocks/environment/badlands/red-sand-weave1.png new file mode 100644 index 0000000000000000000000000000000000000000..3b666b0e6a6609d2fc8f8e97b04e3a3ccf67cfd2 GIT binary patch literal 338 zcmV-Y0j>UtP)Px$3`s;mR9J=0m(2~sAPj{~lqs@F*2o&n(+zs=29+{L2k08f){e(TP zUlEQ1sRb7ina_hg;@mud=e|qbaxg2*j|kEIU7D9Z3c$lOAP~SvaSq7<4Pe!Q8$ijl zWvKa||NmzRM9O7Av!KbAIs+ajAPmqFBU)n$0D;H@T1o_!ptmiVvcQK?g0NgVTJzK* zM4J?nH4{Ku+^btsjYtDg^QAi>b6Z-r=+lZBh{?ONX(2-XG-HJ2awlXmVTBL1$LUqs kr~0U=<5w`HVdt^fc407*qoM6N<$f;Do7c>n+a literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/red-sand-weave2.png b/assets/sprites/blocks/environment/badlands/red-sand-weave2.png new file mode 100644 index 0000000000000000000000000000000000000000..8706a0ff56f09aac4c3d505de9e333772706de9a GIT binary patch literal 328 zcmV-O0k{5%P)Px$0!c(cR9J=0m(3A_AP|KEV->>y`5$V}=;0k)Bx$Y6x!vHKu-H%C}L z_E+8WetTUM+P4*2H!nea?=^=bhNEhrY5*3534j4H?b`|)u__1Q;|nyY*gAwj17Zcw z<^XDx;k9BCO2(NXGgrY+07_LeFQK`jXq_;9ZUGSiYO$^zfAfs(Km7K^uB?$4-ZFy7EIDMbJT0ucgH3<0AHB9{hxXTdi__i@|; a!_pha6?tUW2U{Ef0000Px#+(|@1R9J=Gm)#A3APj`XIE9Px#*GWV{R9J=Wmq8MMAP7aP=?v}Lb%oBl0HlsXF{^oyH_l*J$bxD9!#OGd~1IbBr3pnX6ZNVe}%CH(h zA_&;`H=@!kc&9*X?5rp41@JA92J!wHfC7}6*Z7T+3?Lk-@O#gj3)i{u#^x zs*4#fxCu9{IL+iMs?Z=ak!QhLr&=xxR?&6O6Ir*c5r|yCsJM<%v!zlnC?S|(ev}r2 skn|N14#$GmAGXUhesG;T_d_s)y1TBSE*DE*7SQnwp00i_>zopr0K=_SrvLx| literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/red-sand3.png b/assets/sprites/blocks/environment/badlands/red-sand3.png new file mode 100644 index 0000000000000000000000000000000000000000..a06eb414f49758fff28cab9cb978c586c3391bc1 GIT binary patch literal 282 zcmV+#0pPx#)Ja4^R9J=WmP-zVAPk19nKQ6w#}z!&Tyl=#&b^n=6~xi1D;u)i)ddQUS0$L82^a{#O`i0&CUL#TxC2vHouGkGjj)JhsK z)`cwxL@ob33J_~bfhaX}0ie!|3-JfQ)k=Zz=R*iN&5d=**`}_ke+$F_Y7IWe090BK zH$a6508&dUweFPx2@BLQL=DtT-~!M)3t|Rp!BK#o7NQ2$WiAHc0B2u8Zg8%xqJP4c gujF0}(F>qaJM<+&X=Ags>;M1&07*qoM6N<$g1JC%{r~^~ literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/silver-deposit-depleted2.png b/assets/sprites/blocks/environment/badlands/silver-deposit-depleted2.png new file mode 100644 index 0000000000000000000000000000000000000000..f695e383b96b808092d059ef526cef0e1260eea1 GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU3?z3ec*FxK#^NA%Cx&(BWL^R}q5(c3u0VQY zjo+!I<+qP+o-}8};d4(ueErA0dU^>^g1scjFPPy!7%Z({_8Tbl-qXb~#G<$NYNXg< z1rFAL$~X1rZ9BR84~FcEDmrSI)+71r$bt)#KCZduGv&gZFx{2M6_^g1scjFPPy!7%Z({_8Tbl#nZ(x#G<$Na-`T{ z1rFALw!iOpx~EhK_#O^#UG28TMQ+uq5W}{;3`-5?=ym=0{VXi>w}6w&7u^H3i2H_b#SrG9nV?b87nulXviGDxnX`^O`Y|QrEcAX_NwU<+e>4W zhEL*Vk^$^T_J)VbXql88)?2&u(cI^Jk?OqSMhbUk9-ez9XvgxF)#qow^mnr=nHeC* zIN@<1&(5%|EIO4QymeXF05e=Vi`!uc8BxspBa zKb6gL-03{w=hXBFeU<4;)_-ENyxZjRRmN69G(5;qa+%R*=3-Iq6t^cFe}VpI@O1Ta JS?83{1OQy@n|lBN literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/vitric-weave1.png b/assets/sprites/blocks/environment/badlands/vitric-weave1.png new file mode 100644 index 0000000000000000000000000000000000000000..d49cebcc82420079600ff55a51a37c451509082c GIT binary patch literal 1042 zcmV+t1nv8YP)Px&%t=H+RCt{2TfJ`EFc3a9eTBl_f{YoQE%8>sOE+uG6Sy!8s87(r@Q^2{fWWAp zz@xo&G0;u+<_sPKZw~qlfjZHpPDhGAXUQn|0Ujbt6u*z(9gm~~5D*X$5D*X$z=-$P zym)`ji?;h=f{438O#JGm&;AZhd}zA^ZNpoD<9t*c=Od-vFFh2z?1_nY$5{km9tJw$ zL|YU@`yAobN(ih+4_em%sGTK?%i%6o0aT>qj;==!1pvT)yEAH2+>hJg0&55ebjMkQ zJNx_T8`;L~{T+E73-tN>kIFq9A>iErCBlBYt8`cvV38k6-#x#)mHHu%x(vBZuIbe~ z1n@|yti8w&r;ot%%UguW0{{%N4M|Rj$XQ#k|Aw8?YHk zApllAo3$W?xO&jKdoecy3TG+GKzlOfE~)v1vA^Xq4AGNtkj z*XRRSIzY85qdEyt9{v4x2m9^rL|zB+9B$WiQ^Y1=vK2yD2uz-Wu6R;~PTlC+&KA}J z)a}GfdL8Yl&mupRN@d{;j(5Aj$pN~KP}v>;DqG^W_jjcal}zQfOvt;`3eF)w?e0?K zXX&bP7ND9rC?}`{#gNI{BuVdCK!`xu9v4fl7M>tLzrIUE;*f^jr2qf` M07*qoM6N<$f-EKD+5i9m literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/badlands/vitric-weave2.png b/assets/sprites/blocks/environment/badlands/vitric-weave2.png new file mode 100644 index 0000000000000000000000000000000000000000..c9d212c704b177613446d5a0b85e036f1a22fe4f GIT binary patch literal 993 zcmV<710MW|P)Px&n@L1LRCt{2TD@)>K@k2fK;KiM(^@1azgjGv9-@ISl1aYU2R>Z<^VE5E6o){h_%WrVwoqCj>*l1QGM)2F(jlPWJ~QJb>f%VYuB)#|M|36yzc(y@@6X zz#$0@zNpZg+w;@L-ou|0dS+t*2vQ*=B1~rMiy|4d}R33)(40Dhm>LR;j4 zL;-At3;juLxE9(bd7xoKgm(YikM9R#W?|&34r%P)pI^IiZZl-dv=@U$AwZsBONO!D z5NfuNJx%g}LJk?U=3dD%uI{GHFwe=1VDz{UStyah*$~?C@9Qplx9i@={D@YjMv|3N-;-yAB-poDV@w0O|kv5G1!h0>4&kdqLJyz(+o2 zeonM{4*>SbOO8HU!$k8`$SQzIFt(uab&Ir+ttUvZk*0(xDW!9x^$_5&9h<&9puPLR zkp$p7Z@cH)vV0Emz!5zll*q38XFDNskq3?(0=9RHrbpx?Ur6P)Px#3{Xr|MF0Q*84?^bGDAv7S4{qYgxAq+%g{Qv)4brY`3it&KeR`opXLv&6shIR6KMIw<%@1l#qh_)c)MZ3t4j8D{HY z1tOI%((sERKhgrJ{L3&ds610}S$#$u8-ZU7>H@6>K?PZ1+y^lTE`_z1Y=Ych#1d=* z10UVww8>9PK|OyI9}!S@MQIKvLE!@e>b5IrhK7%H5wQ)d z0OdDb3JL6ORQaCg02FXj1zsX{ZoxO19*j_dh;oAwc+hew=_0ua&=*eLD{^RAzcN4H zgSxH_Qw96V#0M{8^aTY8Z0ASCQh?nk&k9ID;^W}qo0YoB^NF);ZU-<(4@d{0Mu86(> O0000@~ delta 20 ccmaFF_=s_WB^NsfpP8v!@WQCw6P@P+07JG0%MhSEA;5K+fOseYhvx&p!+>&RT2NIH z1KDljCy*+O4im_Q6o}M8SYQqr@d&8>2Hd@PfTecvi!eYHv@{1qI@$>AJuxuW@p{#6 p;rUH)ft18f~I0{4*QE8y`r;OQj;YIVwAL^uGZp?korlNUkUCk1Mq t=h*7>;Qe33g=jx(u`m^42XF&STRx6_28!|`5&ZxF002ovPDHLkV1f;`Ppkj{ diff --git a/assets/sprites/blocks/environment/barrens/bedrock3.png b/assets/sprites/blocks/environment/barrens/bedrock3.png index 216f5d90be31ea662cbf1d526d6fb98a54bf74a2..a660cdb6a932b7f1bd55e559925f3dd355bcb95e 100644 GIT binary patch delta 182 zcmV;n07?Jv0p|gbIe!@v95XUQgWZY500003bW%=J0RR6)P}U&;004bSL_t(IjkVKJ z5`Z8G1W@4qhi+&}VcDQQ@{4ibkeZ6ZFc^XWMFCR>%r`KeFW@za7hus_;H{hd1nu|- zq(##XabJ(%CVUN{#dm=JRdxX2G684-J|(epEGSS**Cqmf?=QS;flmu$aC<1or!u?? k1mw&IVC54dm|r)70|T4}n^j#AIRF3v07*qoM6N<$g5Qfq{{R30 delta 190 zcmV;v073uf0q+5jIe!NT4mLGLQ=wYB00003bW%=J0RR6)P}U&;004zaL_t(IjkVKJ z4uBvG1JJSiAKFX>N>^C?kROSC8HmFg4X0rYSR_zY;Cuqt`2aB&@c=6FyXX;wu=}ye zBeHGQ_wWl?HZ3dQcWpr@dJjmwy+4CP&n%FdY<4GmMY(XU@?|8(R|6RbphxS22WQ%mvv4FO#oPyM+X1^ literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/barrens/elnar-silt2.png b/assets/sprites/blocks/environment/barrens/elnar-silt2.png new file mode 100644 index 0000000000000000000000000000000000000000..9c11030bbdf5a4b9152f605af27cc87d3f5e1a4b GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}m7Xq+ArY;~ z2@J$ z$2U>kqC*-ItR~F6-{1S?zhc9pNG-SR65)LdJDCf9O3hY&5hajVe4}A{i%B7armD)> m?n@UJRg3gA1sc3yWZ2@N_Wj!#Q+A*m7(8A5T-G@yGywp=tU@pV literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/barrens/elnar-silt4.png b/assets/sprites/blocks/environment/barrens/elnar-silt4.png new file mode 100644 index 0000000000000000000000000000000000000000..6349d8349b14cea1896bb882ec67e0908d69170e GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}5uPrNArY;~ z2@Px%MoC0LR9J<@mpyA6K@f&t3I72H6R?|OAq0b)!yg1v1cH-VMIbI^+_*6|!eG=H zb;4jm(xnMb>2$6wb8v+l!J!`zIMhguz_lC6jc3`LoBcRh;I}&M-rYPq@6OJtcGUYf z1AvF?JG_SKbg{g*`?>&CwJ6{kSwIT0!VGS^f4_aIudlk7c7XMb?b(-~XTbo{%FSoY zz@}^vOU`J4vIXV$ND!qxu)MeH^jFHzO+J_#vyZb+fxmJahF zA{B*MP$jsO1*sHCwe^kdnRV6^eDl+1eLd*@Da^&~196-bsR($<7m+C`2#v+<0}aE2 z<0To8PDpdpuB@(T0Fu-@yZ{`+b~H;BLlD!CsxWT0@1Xw$u72PuRb4?S0?=oi8c)MA mK%y1-0!y-4SqWef;vi4%CJsv%qc?T{0000Px%B1uF+R9J<@moaMsK@f#U$sdSaDm_Rc*oYbe7J?+TDN+Qi#9mSe;kvXEut-v+ zvkF+GFl{1&g%E;b9THBfbovi8Mcid}Zgy|aljMQL9p1ce-^}fDv6rupb*I&a|5AJx zMdscd=H7fefJUVXHMjZa#u5MkAS?uDyec}|0|?nbL|w5Fz!ri^tlm2aKT`6EMx`1E zVY~V;vl00%$hvjq8mC|bVGU4on{fSb7nUy&LJNS~plgX(eXdlN_j0AOFBKDn0)Xd0 z7-REJs|`sfshDG75L<0E14$|dO)wPNW^VJ$B5#XNw;tH_-l zoWW!`P{1&-kW4_B>kP0sKw5k<92jc|#nPF=8k^f1>Oe&j0zf3dt=<|S3RN-_!6xuI zev>~eT|0D}OwXGJwkNO!6e3qDvn!^D69usXNX&R13IUtgbs%Bna|{Dv0>PrQfQNC9 zdmu53%YmfV^oRujc)h$)3yj8adV9s1Q~5R`tVL?2BtrKI0pbH-bpQP5yVq&8`2?gP zX~*K}T>+U42l8H!@F3z;j0x;oqAgfE`8u{0*Qy^~g#>C>xPkfr0000Px%CrLy>R9J<@moZDjKorOSErsqS2$|AA5y7Pxr63{*4(@^o9SU9CDqWU90-+4x4Lz;Qq(Mjl_+YZYZ1o52&TOpW)KJ>rP=*iy z_&NZwYRk6ZY&rmd(*6eCU!H~e6{jW*BvWo>b$!AQ7^WeeOf{>aDSwM$uP^wd>|@r^ zEbyXUh3$`F`@h?;+h_~_8K#lAAQC_af`L#FX_DqI@B>)3MW#)*BW}+wgy%tVH2W<( zYoq|I*qCt^kZz-m5BDw6mMK<*6hJg6CEYtk=1wRJq}!-S0K+sAoh7YSrGX^^@Y`k{ z2-R!|HITIlr9rCL&wU!I7M~1M31CnhCAM5uQ4oSxzHv}vLo-i0$+88b_OWFRiX&7z zO;kHgAvkL+loKd49GPN`C@haracWrG-T?qST%G{{?ym1=bGk<@A#hY_g~{8*GEn*y zhuCGK-a4F(o!(pv!Ll|WetvYDOk^xklsRUm*fUYQrg?t^WiptgxzMTU1wv^Tz00000NkvXX Hu0mjf4yFrJ literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/barrens/embedded-elnar2.png b/assets/sprites/blocks/environment/barrens/embedded-elnar2.png new file mode 100644 index 0000000000000000000000000000000000000000..4bf05f7b360be3198258a1408ea9825a08f29932 GIT binary patch literal 596 zcmV-a0;~OrP)Px%4oO5oR9J<@mp@3uKorJ5gWxO_p)MgHBDfU)AczQ}f}5KP9SSbp3f;PuZf=5` zi{Pl6vxwkOC=zj&Ldar40?sb2)1B9M?~<4J?}N}gn!ESQ_ugGD6B|2wBLMINAO9gw zHR34#7l6s415IE*@U6a7p4pMQK<~@yrvfB{M0~S!^1=@MlyW(ccd+#7q!1neaA`=J zAP+mX!>yb+Yrcj7!BYm#@p9NaiAg)&LXU|jx!vtUjk9|U19;y;8F;x_W4;pfZ=*z1y^aHx_y0Q^Qm0mf>Vdocn>81 zom$fgp(dh}xT!dbtxc=iIKoZzY`H*z#)`00Z+x|DP4vUw*udwL3l`EPmA zz9hlT8kt*O6G5^kqE5YG6%0M~n4+sk8XN#778X}VV0J>TVmScUzF}%Jk{-BFl6r+9m%A@L5eslI3y0_ z3C=0&B~|#lz?ADSQ!1Bq;krNypNf+~qAv+p?h_F=i5a+vxI?OV6?{joI`RYmcRoz0 iT#m(2{5JqdN!=$%#sLT9ynO5c0000Px%5lKWrR9J<@m%nPmFc8KsAzcc=9qgulY2L}cLz8s9jEZu>f@VymqWhG z|IYw6@>d#g5At2^of6Jym#OSmWz`wrdp6&z_VTHBc5!(C02n1BwiAv>0zZyovVA#> z*mv3~sLDz-LBTno*7Irw005Kw2fqQy#81H?YNr4zWICw%rNC13Kw`N6D7ZA-+~NuWYmtcv03cH}WU7Xj?bc}jdV3W=NWs_d>-Mr`tN}d&nW~+R zo1*Z7DA~~2^~|_;cEQzYPXvd;sc3DuV?Y99sNR-b%BA4Iq<6zW)ReGk%$K?>D4Z{z zrW5D+qG}uyP9BJwQUu#cDIKRqn=eT%s>U$jOo0?JRR_AlZLw=01Re_J;K2qscxX*H zIiIq990Sw}$MeiVxsNXl54~5Z|m;{ zFG4sLA73q?q6Xrup+}-`cfx1HOw};>{0KJ4!6lK^P**}N95t0ERGfI>+)2wZfQ!+l zDB7C9nFxtmI$?Qh0WkZxZ4-|5KDcARr{DNvGNynUP8BE4;?$CUYH%N^A9*U4q=z&F lF1@eCo(VbmA_{pQ>l;+T5|r&e%((yn002ovPDHLkV1naw4MzX~ literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/barrens/tenbris-mix2.png b/assets/sprites/blocks/environment/barrens/tenbris-mix2.png new file mode 100644 index 0000000000000000000000000000000000000000..664a6f6f2c5299ea81b7853150fda6aec72bde1b GIT binary patch literal 565 zcmV-50?Pe~P)Px$?@2^KR9J<@m$7OBK@f&V(IybIu(4VWn@F%S5D2kLkt#*rBu$#UL7KctioAjl zurLHHl0uPdw7Gysz$V3|ahAEgncdM`^ao-0?)JWacV=hL%H`E{1{;~kz`j+bop>G} z*1#cDqa95M=qi;FvRblCpw(_|1uj!n0Dxqfcp=<%&FpW#)8I2U1h^9MJpS|2QZQ{l zA2$lm+9af5&@8v~jAqtUHR*M2>}`pIOfPEcz=8ek#=wf8sno(rZLzm8QV3Q0%@ zQSj$tQ5fuQRTOu$!zRJqFo>1#{HRhY9LNr%Cd5L-LCb)H^R>kq2%Q6E2$OrOvjEF5 zSE_uo_lYe;wBD!9w*5)4UE$zM!vB(6>i7QV)LpG#SL5noe3{~j00000NkvXXu0mjf Dd3OX{ literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/environment/barrens/tenbris-ridges1.png b/assets/sprites/blocks/environment/barrens/tenbris-ridges1.png new file mode 100644 index 0000000000000000000000000000000000000000..490c112f092e857197666cb848ee35015437f8a1 GIT binary patch literal 360 zcmV-u0hj)XP)Px$B1uF+R9J=0SIZHEAPkMpRv||(HsILBwy^zdIksREUbxbRd&0>=2oOYkM+Wj< z{@Q)!`FM{bv_cO6uxi~_KuZyQ!W|Z?)Np3b-51C!r?*cR(!sm{=;}xhcr; zJ{R~cDL_J=+bz~cb_z;2q5GZ`K#{Ck!*|KP)Px$FG)l}R9J<@SIZ5Jee*^IeYz#Sqk0(wIo)?Oa=bm4XfMgV}rT9~!=54ocu zbgndpci^zr|D@#DeO7?OXI;hQH4xVTMPA(nz{p-o4gfH^;%hYx*T!LY0hT={36_8w z@?3$c(hns_#jbXsW%d^Vn=#2o5|^m9r~^46t=a&!8e&1e`=0zR{?DF@F*x#AEF~Tj zOV!DkBQGV5-@9wL%3>fLC|MbE!Cjox1f_tHB}I<4o3&2XgYN?FKA;qvF{l&Gwq)D{ z*aAYr6nRdV$bs4|999e2Vb~h+#&vj3)0u412-J}6b}pd0s_Vf76Vd%-6pQ!)=`yed TF1mhF00000NkvXXu0mjf*m9r! literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/production/fumehood.png b/assets/sprites/blocks/production/fumehood.png new file mode 100644 index 0000000000000000000000000000000000000000..1f2defbd9a4cd5c1d8decabbf186ddb370c17be1 GIT binary patch literal 848 zcmV-W1F!svP)Px#Bv4FLMF0Q*W@cual8fN7jj}*A<9S*9o{}#uIRF3vHyayYH8rhRSRT9>R{#J2 z40KXXQvm<}|NsC0|NsC0{|UrUCIA2e!bwCyRA_Ab*rG|<9L8c(DGAS6SVx4@(8Sg3SkhrzLKBv zi2C|9La6@|)cll3AYv*(Mo9H{fh1G~*l)luQ$egBg6q~Nf@9aC_dZ4@$n`_u`LAHY z32Yng*Iz)S1FS&K=K=xtFEO4#Bm<1VkO4$xljY~oj`1XNPu(?sDv@V9y9|` z9{Onjw+&PPCjegqh+Yxc#GnD5+=2`Mctrp(0zOA%0PKJ)Ko+b(WB_Df7odp(fE|c^ zz_;Zu!3rWA)?`~BEUd}4o4l|l+kk~N*$UiV zlg+>tcNTrM4^{x<-$eo-PZhuQ;M2h4|HeN3k9cP*!O#a~E8+EoO>TzheNZ+-zy_qb zJ}BEcUys0DW9F4lLc zE7V8s*Tg{Lc$>jV!uisGl%ED8((%5869iWPAwP`+Z7*(U`O*l>t0#K?cz~t8C4a5H aoc{+n6}`%6aWC8e0000<1NmzidDj02i(o2f)x%w$)^ z&R6sxgnk4NkeOx7Nm3HN^>t5uRCh6+<=^*b^{P3G0RfSCmKml^yg@v@X&apPi6g8i ztHkHTVt?1$8VeqE(<&}Vy08`#1Ue#(8fv|v!baHPZ38|O{aVzl354hX`2A>SslwB!EOUUPe_cQvYEHH2jbgy}HYo6ou0Z7xVk~hG?Auw8?>~)`a zceT&$-=60DegMYna$*P0SvLRx05nNNK~z|U?ana~05A;1uuu8)I)^{721XW{fK~7I t&thkD4gdfE00000000000001xBm;v50o1XVUnc+n002ovPDHLkV1n2K(Ifx> literal 0 HcmV?d00001 diff --git a/assets/sprites/chute-crossing-top.png b/assets/sprites/chute-crossing-top.png new file mode 100644 index 0000000000000000000000000000000000000000..4f7105ed98f57b41a47d8b4c75906d18620e0bec GIT binary patch literal 448 zcmV;x0YCnUP)Px$dPzh^W~ zUaj^gOkNcYlHM0d`_@g@buU2LZ8vxbAL|w(y4|1Ico?T_9NPVMe=ZEH$^htpUo+?a zu8DfIr5`{ze$KE2!R>*)n#=dsYca!U9$9C41Dd0@oCFInj1vswwAjdU&lZU63TTP+ zeV>i5=c5W>|9Qy9kDpT!a79gP8`mJHIVXG)<{Xd=H0D&UAmWTX<^TWkH(1Dh;kKa84VGA- zA_)l-i49NtZeN#wU>Xn_+^E8y(891u`GRxPgr`SVDV}0{(Wh`UA?V7ZQid~vOMZ2U zxC@jxxZKT}q^o{ZutL_M^XU;Qrsd2l5-kn;6eL);ur213C_S)(xxgyHHCW@S&cSf! zN4$(#7EJ+PeGIrX3Rw(unHODRuPx$vq?ljR9J=0S21qGFbt#&ul|OS%thC3en0@jfIrb8OQ)hJI(5m=PZ%%^k<=f2bZ3g5LqvdL? z@Uza^%hLh?0QQFy000bqr-r^WcE|1JD!UX4mq0rN0I14>CD-`*{La`Qjvx!E&`$n4BWVo5p8IQI&`-}1V$n{9P*I1Q&0h-K}bufc})hmp+r$P?YKXjym}$Y z1mw@PA~?c1 zKPCf1-v!&pXQR7A(uUZN(rptX#jci>{0R-so3sfzq8M_F$LWGpEl&aF%3KR`kOOxj z!oy~&(~)n0Ss92ql)}HH-YVPHIF4~fXUEXXgTS25E~v_4l09+UZbsj 0){ + + float leakAmount = ventEfficiency * ventRate; + Puddles.deposit(tile, tile, liquid, leakAmount, true, true); + liquids.remove(liquid, leakAmount); + } + } + } + } +} diff --git a/src/meld/world/blocks/Gauze.java b/src/meld/world/blocks/Gauze.java index f60a9e1..4726a03 100644 --- a/src/meld/world/blocks/Gauze.java +++ b/src/meld/world/blocks/Gauze.java @@ -1,40 +1,100 @@ package meld.world.blocks; +import arc.graphics.Color; +import arc.graphics.g2d.Lines; import arc.math.Mathf; import arc.struct.Seq; +import arc.util.Time; +import meld.world.blocks.crafting.Recipe; +import meld.world.blocks.crafting.SpoolRecipe; +import mindustry.Vars; import mindustry.content.Fx; import mindustry.gen.Building; import mindustry.graphics.Pal; +import mindustry.ui.Bar; import mindustry.world.Block; import mindustry.world.Tile; public class Gauze extends Block { - public float reload = 60; + + public float craftTime = 60; + public float spoolStorage = 800; + + public Seq recipies = new Seq<>(); + + public float reload = 120; + public float detectHeadstart = 0.75f; + + public float syncMargin = 5f; + public int propagateMaxRange = 10; public float healAmount = 200; public float maxFract = 0.1f; Seq searching = new Seq<>(), qued = new Seq<>(), explored = new Seq<>(); + Seq connectedGauzes = new Seq<>(); public Gauze(String name) { super(name); update = true; } + @Override + public void setBars() { + super.setBars(); + addBar( + "spool", + entity -> new Bar("stats.spool", Pal.heal, () -> ((GauzeBuild)entity).spoolf()).blink(Color.red) + ); + } public class GauzeBuild extends Building { + Gauze gauze; + public float time; + public float craftTimer; + public float energy = 0; + + public float spoolf(){ + return energy/spoolStorage; + } @Override public void updateTile() { super.updateTile(); - time += efficiency; if(time >= reload){ - propagate(); time %= reload; + propagate(); } + time += Time.delta; + + craftTimer += efficiency; + if(craftTimer >= craftTime){ + craft(); + craftTimer %= craftTime; + } + } + + @Override + public void created() { + super.created(); + gauze = (Gauze) block; + } + + public boolean shouldCraft(){ + return recipies.copy().find(r -> r.valid(gauze, this)) != null; + } + + @Override + public boolean shouldConsume() { + return super.shouldConsume() && shouldCraft(); + } + + public void craft(){ + SpoolRecipe recipe = recipies.find(r -> r.valid(gauze, this)); + recipe.apply(gauze, this); } //Only propagates through 1x1 blocks and their adjacent blocks @@ -46,6 +106,7 @@ public void propagate(){ explored.add(this); searching.addAll(this.proximity); + boolean healed = false; float charge = healAmount; for(int i = 0; i < propagateMaxRange; i++){ @@ -64,10 +125,14 @@ public void propagate(){ Fx.healBlockFull.at(build.x, build.y, 0, Pal.heal, build.block); build.heal(healAmount); charge -= healAmount; + healed = true; } } if(build.block.size == 1) build.proximity.each( b -> !explored.contains(b), qued::addUnique); + if(build instanceof GauzeBuild gauze){ + connectedGauzes.add(gauze); + } } explored.add(searching); @@ -77,6 +142,44 @@ public void propagate(){ //No more healing to expand, goodbye world if(charge == 0) break; } + + if(healed) time = reload * detectHeadstart; + energy = energy - Mathf.clamp(healAmount - charge, 0, healAmount); + + float totalTime = 0; + float averageEnergy = 0; + connectedGauzes.addAll(this); + + for(GauzeBuild gauze: connectedGauzes){ + averageEnergy += gauze.energy; + } + averageEnergy /= connectedGauzes.size; + + for(GauzeBuild gauze: connectedGauzes){ + gauze.energy = averageEnergy; + } + + //Remove gauzes close to firing, then sync + + connectedGauzes.removeAll(b -> reload - b.time < syncMargin); + for(GauzeBuild gauze: connectedGauzes){ + totalTime += gauze.time; + } + + float averageTime = totalTime / (connectedGauzes.size); + + for(GauzeBuild gauze: connectedGauzes){ + gauze.time = averageTime; + } + + connectedGauzes.clear(); + } + + @Override + public void draw() { + super.draw(); + + Lines.arc(x, y, Vars.tilesize * 3, time/reload); } } } diff --git a/src/meld/world/blocks/VisualAspectPipe.java b/src/meld/world/blocks/VisualAspectPipe.java new file mode 100644 index 0000000..d8ef37b --- /dev/null +++ b/src/meld/world/blocks/VisualAspectPipe.java @@ -0,0 +1,159 @@ +package meld.world.blocks; + +import arc.graphics.Blending; +import arc.graphics.Color; +import arc.graphics.g2d.Draw; +import arc.graphics.g2d.Fill; +import arc.graphics.g2d.TextureRegion; +import arc.math.Angles; +import arc.math.Interp; +import arc.math.Mathf; +import arc.math.Rand; +import arc.math.geom.Geometry; +import arc.util.Time; +import arc.util.Tmp; +import mindustry.gen.Building; +import mindustry.graphics.Drawf; +import mindustry.graphics.Layer; +import mindustry.type.Liquid; + +import static mindustry.Vars.renderer; +import static mindustry.Vars.tilesize; + +//PLEASEWORKPLEAEWORKAPSLEAOSKOPK +public class VisualAspectPipe extends AspectPipe{ + protected static final Rand rand = new Rand(); + + public int sides = 12; + public float px = 0, py = 0; + public float alpha = 0.1f; + public int particles = 12; + public float particleRotation = 0, particleLife = 70f, particleRad = 4.2f, particleSize = 3f, fadeMargin = 0.4f, rotateScl = 3f; + public boolean reverse = false, poly = false; + public Interp particleInterp = new Interp.PowIn(1.5f); + public Interp particleSizeInterp = Interp.slope; + public Blending blendMode = Blending.additive; + + public VisualAspectPipe(String name) { + super(name); + } + + public class VisualPipeBuild extends AspectPipeBuild{ + + float warmup = 0; + + @Override + public void updateTile() { + super.updateTile(); + warmup = Mathf.lerpDelta(warmup, liquids.currentAmount()/liquidCapacity, 0.1f); + } + + @Override + public float warmup() { + return Interp.pow5Out.apply(warmup); + } + + @Override + public void draw(){ + int r = this.rotation; + + //draw extra conduits facing this one for tiling purposes + //WHY WHY WHY WHY WHYYYYYYYYYYYYYYYYYYYYYYYYYYYY + Draw.z(Layer.blockUnder); + for(int i = 0; i < 4; i++){ + if((blending & (1 << i)) != 0){ + int dir = r - i; + drawAt(x + Geometry.d4x(dir) * tilesize*0.75f, y + Geometry.d4y(dir) * tilesize*0.75f, 0, i == 0 ? r : dir, i != 0 ? SliceMode.bottom : SliceMode.top); + } + } + + Draw.z(Layer.block -0.001f); + + drawInbetween(); + Draw.z(Layer.block); + + Draw.scl(xscl, yscl); + drawAt(x, y, blendbits, r, SliceMode.none); + Draw.reset(); + + if(capped && capRegion.found()) Draw.rect(capRegion, x, y, rotdeg()); + if(backCapped && capRegion.found()) Draw.rect(capRegion, x, y, rotdeg() + 180); + } + + @Override + protected void drawAt(float x, float y, int bits, int rotation, SliceMode slice){ + float angle = rotation * 90f; + Draw.color(botColor); + + Draw.z(Layer.blockUnder - 0.1f); + Draw.rect(sliced(botRegions[bits], slice), x, y, angle); + + int offset = yscl == -1 ? 3 : 0; + + int frame = liquids.current().getAnimationFrame(); + int gas = liquids.current().gas ? 1 : 0; + float ox = 0f, oy = 0f; + int wrapRot = (rotation + offset) % 4; + TextureRegion liquidr = bits == 1 && padCorners ? rotateRegions[wrapRot][gas][frame] : renderer.fluidFrames[gas][frame]; + + if(bits == 1 && padCorners){ + ox = rotateOffsets[wrapRot][0]; + oy = rotateOffsets[wrapRot][1]; + } + + Draw.z(Layer.blockUnder); + + //the drawing state machine sure was a great design choice with no downsides or hidden behavior!!! + float xscl = Draw.xscl, yscl = Draw.yscl; + Draw.scl(1f, 1f); + Drawf.liquid(sliced(liquidr, slice), x + ox, y + oy, smoothLiquid, liquids.current().color.write(Tmp.c1).a(1f)); + Draw.scl(xscl, yscl); + + Draw.z(Layer.block - 0.01f); + Draw.rect(sliced(topRegions[bits], slice), x, y, angle); + } + + public void drawInbetween(){ + Draw.z(Layer.blockUnder + 0.01f); + + Liquid current = liquids.current(); + if(warmup() > 0f && current != null){ + float a = alpha * warmup(); + + Draw.blend(blendMode); + Draw.color(current.color); + + float base = Time.time / particleLife; + rand.setSeed(id); + + for(int i = 0; i < particles; i++){ + float fin = (rand.random(2f) + base) % 1f; + if(reverse) fin = 1f - fin; + float fout = 1f - fin; + float angle = rand.random(360f) + (Time.time / rotateScl) % 360f; + float len = particleRad * particleInterp.apply(fout); + + Draw.alpha(a * (1f - Mathf.curve(fin, 1f - fadeMargin))); + if(poly){ + Fill.poly( + px + x + Angles.trnsx(angle, len), + py + y + Angles.trnsy(angle, len), + sides, + particleSize * particleSizeInterp.apply(fin) * warmup(), + particleRotation + ); + }else{ + Fill.circle( + px + x + Angles.trnsx(angle, len), + py + y + Angles.trnsy(angle, len), + particleSize * particleSizeInterp.apply(fin) * warmup() + ); + } + } + + Draw.blend(); + Draw.reset(); + } + } + } +} diff --git a/src/meld/world/blocks/crafting/ItemRecipe.java b/src/meld/world/blocks/crafting/ItemRecipe.java index 5faaeb1..784e187 100644 --- a/src/meld/world/blocks/crafting/ItemRecipe.java +++ b/src/meld/world/blocks/crafting/ItemRecipe.java @@ -4,8 +4,9 @@ import mindustry.gen.Building; import mindustry.type.ItemStack; import mindustry.type.LiquidStack; +import mindustry.world.Block; -public class ItemRecipe extends Recipe{ +public class ItemRecipe extends Recipe{ public ItemStack[] inputItems; public ItemStack[] outputItems; @@ -22,7 +23,7 @@ public ItemRecipe(ItemStack[] inputItems, ItemStack[] outputItems){ }; @Override - public boolean valid(Building build){ + public boolean valid(Block block, Building build){ if(outputItems != null){ for(var output : outputItems){ if(build.items.get(output.item) + output.amount > build.block.itemCapacity){ @@ -44,7 +45,7 @@ public boolean valid(Building build){ } @Override - public void apply(Building building) { + public void apply(Block block, Building building) { if(inputItems != null) building.items.remove(inputItems); if(outputItems != null) { diff --git a/src/meld/world/blocks/crafting/Recipe.java b/src/meld/world/blocks/crafting/Recipe.java index 12a227a..ffae399 100644 --- a/src/meld/world/blocks/crafting/Recipe.java +++ b/src/meld/world/blocks/crafting/Recipe.java @@ -1,9 +1,10 @@ package meld.world.blocks.crafting; import mindustry.gen.Building; +import mindustry.world.Block; -public abstract class Recipe { +public abstract class Recipe { - public abstract boolean valid(Building building); - public abstract void apply(Building building); + public abstract boolean valid(T block, A building); + public abstract void apply(T block, A building); } diff --git a/src/meld/world/blocks/crafting/SpoolRecipe.java b/src/meld/world/blocks/crafting/SpoolRecipe.java new file mode 100644 index 0000000..74f483a --- /dev/null +++ b/src/meld/world/blocks/crafting/SpoolRecipe.java @@ -0,0 +1,29 @@ +package meld.world.blocks.crafting; + +import meld.world.blocks.Gauze; +import mindustry.gen.Building; +import mindustry.type.ItemStack; +import mindustry.type.LiquidStack; +import mindustry.world.Block; + +public class SpoolRecipe extends Recipe { + + public SpoolRecipe(ItemStack ammo, float energy){ + this.ammo = ammo; + this.energy = energy; + } + + public ItemStack ammo; + public float energy; + + @Override + public boolean valid(Gauze block, Gauze.GauzeBuild build) { + return build.items.has(ammo.item, ammo.amount) && build.energy + energy <= block.spoolStorage; + } + + @Override + public void apply(Gauze block, Gauze.GauzeBuild build) { + build.removeStack(ammo.item, ammo.amount); + build.energy += energy; + } +} diff --git a/src/meld/world/blocks/crafting/modules/GateModule.java b/src/meld/world/blocks/crafting/modules/GateModule.java index 6b38676..504c291 100644 --- a/src/meld/world/blocks/crafting/modules/GateModule.java +++ b/src/meld/world/blocks/crafting/modules/GateModule.java @@ -108,7 +108,7 @@ public RecipeCondition(ItemRecipe recipe){ @Override public boolean valid(ModularCrafter.ModularCrafterBuild build) { - return recipe.valid(build); + return recipe.valid(build.block, build); } } diff --git a/src/meld/world/blocks/crafting/modules/ProduceLiquidModule.java b/src/meld/world/blocks/crafting/modules/ProduceLiquidModule.java index 560af62..590998e 100644 --- a/src/meld/world/blocks/crafting/modules/ProduceLiquidModule.java +++ b/src/meld/world/blocks/crafting/modules/ProduceLiquidModule.java @@ -1,5 +1,6 @@ package meld.world.blocks.crafting.modules; +import arc.math.Mathf; import meld.world.blocks.crafting.ModularCrafter; import mindustry.type.LiquidStack; @@ -15,6 +16,7 @@ public ProduceLiquidModule(LiquidStack liquid, int efficiencyPin){ @Override public void update(ModularCrafter.ModularCrafterBuild build) { float efficiency = build.getPin(efficiencyPin); - build.liquids.add(liquid.liquid, liquid.amount * efficiency); + float addedAmount = Math.min(liquid.amount * efficiency, Mathf.maxZero(build.block.liquidCapacity - build.liquids.get(liquid.liquid))); + build.liquids.add(liquid.liquid, addedAmount); } } diff --git a/src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java b/src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java index 6564059..3d0da58 100644 --- a/src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java +++ b/src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java @@ -9,11 +9,11 @@ public class RecipeCraftingModule extends ModularCrafter.CraftingModule { @Override public boolean canCraft(ModularCrafter.ModularCrafterBuild build) { - return recipe.valid(build); + return recipe.valid(build.block, build); } @Override public void craft(ModularCrafter.ModularCrafterBuild build) { - recipe.apply(build); + recipe.apply(build.block, build); } } diff --git a/src/meld/world/blocks/production/SingleBeamDrill.java b/src/meld/world/blocks/production/SingleBeamDrill.java index d434c3b..cd173d6 100644 --- a/src/meld/world/blocks/production/SingleBeamDrill.java +++ b/src/meld/world/blocks/production/SingleBeamDrill.java @@ -27,9 +27,11 @@ public class SingleBeamDrill extends Block { public int range = 5, tier = 4; //I know that sounds like a lot of items at once but well... yeah it's a lot of items at once - public int baseProductivity = 25; + public int baseProductivity = 30; + public float selfDamage = 400; + public float targetDamage = 2400; public ObjectFloatMap itemMultipliers = new ObjectFloatMap<>(); - public float drillTime = 120; + public float drillTime = 300; public SingleBeamDrill(String name) { super(name); @@ -62,6 +64,8 @@ public void updateTile() { } public void drill(){ + damage(selfDamage); + Item found = null; int offset = (size + 1)/2; @@ -75,7 +79,10 @@ public void drill(){ if(other.solid()){ Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 5, 30000, Vars.tilesize * 3, true); Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 15, 0, Vars.tilesize * 2, true); + if(other.build != null) other.build.damage(targetDamage); + Item drop = other.wallDrop(); + if(drop == null) break; if(drop.hardness <= tier) found = drop; From 2974936454127e19cd75001962efc2df44894f3c Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Tue, 31 Mar 2026 21:02:17 +1100 Subject: [PATCH 04/17] Gauze heal cap, SingleBeamDrill minHealthf, descs --- assets/bundles/bundle.properties | 32 ++++++++++++++++--- src/meld/content/MeldBlocks.java | 20 +++++++++--- src/meld/content/MeldEnvironment.java | 3 +- src/meld/world/blocks/Bruiskit.java | 2 ++ src/meld/world/blocks/Gauze.java | 17 ++++++---- .../world/blocks/crafting/ModularCrafter.java | 5 ++- .../blocks/production/SingleBeamDrill.java | 11 ++++++- 7 files changed, 71 insertions(+), 19 deletions(-) diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index 55d1a48..fd93b4c 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -27,7 +27,17 @@ block.meld-tantrum.name = Tantrum block.meld-tantrum.description = Compacts and puffs out clouds of [#8872da]Rift[] using a Silver piston, dealing heavy knockback.\n[accent]Reduces target's drag[] block.meld-earthbound-infuser.name = Earthbound Infuser -block.meld-earthbound-infuser.description = Infuses Debris with vent fumes to synthesize Carbolith.\n\nRequires [#cbdbfc]Aspect[] to run. +block.meld-earthbound-infuser.description = Infuses Debris with vent fumes to synthesize Carbolith.\n\nRequires [#cbdbfc]Aspect[] to run, can siphon [#5b4739]Fumes[] from vents. + +block.meld-gas-kiln.name = Gas-fired Kiln +block.meld-gas-kiln.description = Heats materials using [#cbdbfc]Aspect[][accent]\n\nCarbolith + Tenbris -> Shadesteel + [#5b4739]Fumes[]\nClay-Mallows -> Glass-Mallows\nSilver -> Annealed Silver\nDebris + Glass-Mallows -> Crucible Platings\nDebris + Shadesteel -> Crucible Platings + +block.meld-rotary-kiln.name = Gas-fired Kiln +block.meld-rotary-kiln.description = Constantly burns [#cbdbfc]Aspect[] as fuel, heats materials to process them in bulk. [accent]\n\nTenbris -> Shadesteel + [#5b4739]Fumes[]\nClay-Mallows -> Glass-Mallows\nSilver -> Annealed Silver\nDebris + Glass-Mallows -> Crucible Platings\nDebris + Shadesteel -> Crucible Platings + +block.meld-pneumatic-extruder.name = Pneumatic Extruder +block.meld-pneumatic-extruder.description = Extrudes insulated pipes, uses[#cbdbfc]Aspect[] to run. [accent]\n\nShadesteel + Elnar -> Aspect Pipe\n\nAnnealed Silver + Debris -> Aspect Pipe + block.meld-heating-basin.name = Heating Basin block.meld-heating-basin.description = Runs [#b89f47]Nectar[] through pipes laced with Carbolith dust over geothermal sources to extract [#89828c]Mercury[], producing loads of Debris as a byproduct. @@ -83,6 +93,12 @@ block.meld-sonar-spire.details = Initially an aether flarestack build to help tr block.meld-movement-anchor.name = Movement Anchor block.meld-movement-anchor.description = Targets and [accent]Anchor[]s enemy units. +block.meld-gauze.name = Gauze +block.meld-gauze.description = Weaves a [accent]Resonarum[] thread using [#5b4739]Fumes[], automatically applying it to connected blocks. + +block.meld-bruisekit.name = Bruisekit +block.meld-bruisekit.description = Regenerates target block's health.\n\nPrioritises large, functional blocks and can't target 1x1s. + block.meld-mercurial-diffuser.name = Mercurial Diffuser block.meld-mercurial-diffuser.description = Puffs clouds which intoxicate [#ea9ad6]Meld[] units. Applies a coating of [#89828c]Mercury[] to allied units. @@ -195,6 +211,9 @@ block.meld-thermo-matting.details = ...appears to be little to no waste left beh block.meld-aether-accumulator.name = Aether Accumulator block.meld-aether-accumulator.description = Collects [#cb8650]Aether[] from suitable sources. +block.meld-fumehood.name = Fumehood +block.meld-fumehood.description = Placed over sources of aspects or gasses. + block.meld-crystal-cracker.name = Crystal Cracker block.meld-crystal-cracker.description = Breaks open Dissonitre crystals over [accent]aspect soil[] as a source of [#cb8650]Aether[]. @@ -209,10 +228,6 @@ block.meld-vitric-stimulator-ruined.name = Vitric Stimu1ator [lightgray](Ruined) block.meld-vitric-stimulator.description = Harvests [#8872da]Rift[] from suitable sources using Vitric Meshes to filter the air, producing a small amount of glass waste.\n\nRequires Power to run.\n\n[orange]Inefficient, deconstruction is advised[] block.meld-vitric-stimulator.details = If only those vents could be harvested from... -block.meld-vitric-stimulator.name = Vitric Stimu1ator -block.meld-vitric-stimulator.description = Harvests [#8872da]Rift[] from suitable sources using Vitric Meshes to filter the air, producing a substantial amount of glass waste.\n\nRequires Power to run. -block.meld-vitric-stimulator.details = If only those vents could be harvested from... - block.meld-flarestack-filter.name = Flarestack Filter block.meld-flarestack-filter.description = Harvests [#8872da]Rift[] from suitable sources by neutralizing the impurities from the air.\n\nRequires Resonarum and Riplom to run. block.meld-flarestack-filter.details = Neutralizes the Aether content of an impure [accent]rift vent[] by focusing it into Aspect and combusting it with Riplom, but requires a constant supply of lenses to function. @@ -233,6 +248,9 @@ block.meld-displacement-pump.description = Dumps Debris into fluids to retrive a block.meld-elemental-blaster.name = Elemental Blaster block.meld-elemental-blaster.description = Blasts deposits for items indefinitely. Requires [#cbdbfc]Aspect[] to run.\n\nCan be boosted with [#ea9ad6]Meld[] to double harvesting speed. +block.meld-pneumatic-pulsar.name = Pneumatic Pulsar +block.meld-pneumatic-pulsar.description = Blasts a single deposit for items indefinitely. Requires [#cb8650]Aether[] to run.\n\n[red]Explosions damage everything around them, high maintenance![] + block.meld-elemental-sampler.name = Elemental Sampler block.meld-elemental-sampler.description = Samples deposits for items indefinitely. Requires [#cbdbfc]Aspect[] and [#8872da]Rift[] to run.\n\nCan be boosted with [#b460e2]Warp[] to double harvesting speed.\n\n[accent]More efficient against soft tissue[] block.meld-elemental-sampler.details = It wants to return home. @@ -696,6 +714,10 @@ liquid.meld-aspect.name = [#cbdbfc]Aspect liquid.meld-aspect.description = Unstable alternative power source. Refinable. liquid.meld-aspect.details = Mixed primordial aspects. +liquid.meld-fumes.name = [#5b4739]Fumes +liquid.meld-fumes.description = Passively seeps into conductive materials. Used for a variety of metallurgic and restorative appliances. +liquid.meld-fumes.details = Smoggy primordial aspects. + liquid.meld-nectar.name = [#b89f47]Nectar liquid.meld-nectar.description = Used as a potent coolant. Can be refined into [#89828c]Mercury[] over high heat with the right reagents. Encourages a slight mending effect on units. liquid.meld-nectar.details = Blood of the swamp. diff --git a/src/meld/content/MeldBlocks.java b/src/meld/content/MeldBlocks.java index 8822856..80d9234 100644 --- a/src/meld/content/MeldBlocks.java +++ b/src/meld/content/MeldBlocks.java @@ -543,6 +543,7 @@ public static void load(){ health = 500; armor = 2; hasLiquids = true; + replaceBars = false; squareSprite = false; @@ -605,7 +606,14 @@ public static void load(){ requirements(Category.production, with(MeldItems.debris, 200, MeldItems.carbolith, 150, MeldItems.aspectPipe, 300)); health = 1800; size = 5; - itemCapacity = 50; + itemCapacity = 100; + baseProductivity = 50; + drillTime = 360; + + transformItems.putAll( + MeldItems.clayMallows, MeldItems.glassMallows, + MeldItems.tenbris, MeldItems.shadesteel + ); range = 8; @@ -644,7 +652,7 @@ public static void load(){ modules.addAll( new ProduceLiquidModule(new LiquidStack(MeldLiquids.fumes, 2f), 0), - new GateModule(2, new GateModule.RecipeCondition(carbolith)), + new GateModule(1, new GateModule.RecipeCondition(carbolith)), new ConsumeLiquidModule(LiquidStack.with(MeldLiquids.fumes, 1, MeldLiquids.aspect, outletRate * 2), 1, 2), new RecipeCraftingModule(){{ efficiencyPin = 2; @@ -781,7 +789,7 @@ public static void load(){ ItemRecipe shadesteel = new ItemRecipe(with(MeldItems.tenbris, 12), with(MeldItems.shadesteel, 12)); ItemRecipe glass = new ItemRecipe(with(MeldItems.clayMallows, 12), with(MeldItems.glassMallows, 12)); ItemRecipe silver = new ItemRecipe(with(MeldItems.silver, 1), with(MeldItems.annealedSilver, 2)); - ItemRecipe platings1 = new ItemRecipe(with(MeldItems.shadesteel, 4, MeldItems.carbolith, 2), with(MeldItems.cruciblePlating, 4)); + ItemRecipe platings1 = new ItemRecipe(with(MeldItems.shadesteel, 4, MeldItems.debris, 2), with(MeldItems.cruciblePlating, 4)); ItemRecipe platings2 = new ItemRecipe(with(MeldItems.glassMallows, 4, MeldItems.debris, 2), with(MeldItems.cruciblePlating, 4)); //The max crafting speed when boosted @@ -987,6 +995,10 @@ public static void load(){ MeldItems.resonarum, 80 )); size = 2; + + consume( + new ConsumeLiquid(MeldLiquids.fumes, 0.5f) + ); }}; gauze = new Gauze("gauze"){{ @@ -1004,7 +1016,7 @@ public static void load(){ new SpoolRecipe(new ItemStack(MeldItems.resonarum, 2), 200) ); - consumeLiquid(MeldLiquids.fumes, 0.5f); + consumeLiquid(MeldLiquids.fumes, 1f); consumeItem(MeldItems.resonarum, 2); }}; diff --git a/src/meld/content/MeldEnvironment.java b/src/meld/content/MeldEnvironment.java index 02a4966..2b878d1 100644 --- a/src/meld/content/MeldEnvironment.java +++ b/src/meld/content/MeldEnvironment.java @@ -41,7 +41,7 @@ public class MeldEnvironment { metalWeave, metalWeaveHole, metalWeaveGlow, //Badlands sandMeld, softSand, sandstone, - redsandMeld, redSand, redSandWeave, crackstone, + redsandMeld, redSand, aspectSoil, redSandWeave, crackstone, //Barrens bedrock, bedrockMeld, slate, slateMeld, @@ -281,6 +281,7 @@ public static void load(){ sandstone = new Floor("hard-sand", 3); redSandWeave = new Floor("red-sand-weave", 3); redSand = new Floor("red-sand", 3); + aspectSoil = new Floor("aspect-soil", 3); crackstone = new Floor("cracked-sand", 4); meldWall = new StaticWall("meld-wall"){{ diff --git a/src/meld/world/blocks/Bruiskit.java b/src/meld/world/blocks/Bruiskit.java index 3d3f211..c61090f 100644 --- a/src/meld/world/blocks/Bruiskit.java +++ b/src/meld/world/blocks/Bruiskit.java @@ -8,8 +8,10 @@ import mindustry.entities.Units; import mindustry.gen.Building; import mindustry.gen.Teamc; +import mindustry.world.blocks.units.RepairTower; public class Bruiskit extends FieldPulsar{ + Seq tmpDamaged = new Seq<>(); int targetTimer = timers++; diff --git a/src/meld/world/blocks/Gauze.java b/src/meld/world/blocks/Gauze.java index 4726a03..1b6cba9 100644 --- a/src/meld/world/blocks/Gauze.java +++ b/src/meld/world/blocks/Gauze.java @@ -25,11 +25,11 @@ public class Gauze extends Block { public float reload = 120; public float detectHeadstart = 0.75f; - public float syncMargin = 5f; + public float syncMargin = 20; public int propagateMaxRange = 10; - public float healAmount = 200; + public float pulseStrength = 200; public float maxFract = 0.1f; Seq searching = new Seq<>(), qued = new Seq<>(), explored = new Seq<>(); @@ -73,7 +73,6 @@ public void updateTile() { craftTimer += efficiency; if(craftTimer >= craftTime){ craft(); - craftTimer %= craftTime; } } @@ -94,7 +93,11 @@ public boolean shouldConsume() { public void craft(){ SpoolRecipe recipe = recipies.find(r -> r.valid(gauze, this)); - recipe.apply(gauze, this); + if(recipe != null){ + //I've somehow had recipe be null so im not taking any chances here + recipe.apply(gauze, this); + craftTimer %= craftTime; + } } //Only propagates through 1x1 blocks and their adjacent blocks @@ -107,7 +110,7 @@ public void propagate(){ searching.addAll(this.proximity); boolean healed = false; - float charge = healAmount; + float charge = pulseStrength; for(int i = 0; i < propagateMaxRange; i++){ for(Building build: searching){ @@ -120,7 +123,7 @@ public void propagate(){ * -Remaining charge * -0 */ - float healAmount = Mathf.maxZero(Math.min(Math.min(build.maxHealth * maxFract, build.block.health - build.health), charge)); + float healAmount = Mathf.maxZero(Math.min(Math.min(Math.min(build.maxHealth, pulseStrength) * maxFract, build.block.health - build.health), charge)); if(healAmount > 0){ Fx.healBlockFull.at(build.x, build.y, 0, Pal.heal, build.block); build.heal(healAmount); @@ -144,7 +147,7 @@ public void propagate(){ } if(healed) time = reload * detectHeadstart; - energy = energy - Mathf.clamp(healAmount - charge, 0, healAmount); + energy = energy - Mathf.clamp(pulseStrength - charge, 0, pulseStrength); float totalTime = 0; float averageEnergy = 0; diff --git a/src/meld/world/blocks/crafting/ModularCrafter.java b/src/meld/world/blocks/crafting/ModularCrafter.java index 58eef7a..ab2bc5c 100644 --- a/src/meld/world/blocks/crafting/ModularCrafter.java +++ b/src/meld/world/blocks/crafting/ModularCrafter.java @@ -30,19 +30,22 @@ public class ModularCrafter extends Block { public Seq dumpedLiquids = new Seq<>(); public Seq dumpedItems = new Seq<>(); + public boolean replaceBars = true; + //Default float data array public IntFloatMap defaultData = new IntFloatMap(); public ModularCrafter(String name) { super(name); update = true; + solid = true; } @Override public void setBars() { super.setBars(); - if(acceptedLiquids.size + dumpedLiquids.size > 0){ + if(replaceBars && acceptedLiquids.size + dumpedLiquids.size > 0){ removeBar("liquid"); for(Liquid liquid: acceptedLiquids){ diff --git a/src/meld/world/blocks/production/SingleBeamDrill.java b/src/meld/world/blocks/production/SingleBeamDrill.java index cd173d6..508cec0 100644 --- a/src/meld/world/blocks/production/SingleBeamDrill.java +++ b/src/meld/world/blocks/production/SingleBeamDrill.java @@ -26,11 +26,13 @@ public class SingleBeamDrill extends Block { public int range = 5, tier = 4; + public float minHealthf = 0.25f; //I know that sounds like a lot of items at once but well... yeah it's a lot of items at once public int baseProductivity = 30; public float selfDamage = 400; public float targetDamage = 2400; public ObjectFloatMap itemMultipliers = new ObjectFloatMap<>(); + public ObjectMap transformItems = new ObjectMap<>(); public float drillTime = 300; public SingleBeamDrill(String name) { @@ -51,10 +53,15 @@ public SingleBeamDrill(String name) { public class SingleBeamBuild extends Building{ public float time; + @Override + public boolean shouldConsume() { + return super.shouldConsume() && healthf() >= minHealthf; + } + @Override public void updateTile() { super.updateTile(); - time += efficiency; + if(healthf() >= minHealthf) time += efficiency; if(time >= drillTime){ drill(); time %= drillTime; @@ -97,6 +104,8 @@ public void drill(){ if(found == null) return; + found = transformItems.get(found, found); + int mined = (int)(baseProductivity * itemMultipliers.get(found, 1)); mined = Mathf.ceilPositive(Math.min(itemCapacity - items.get(found), mined)); From 380f0c3b738dba4ff5e8a3ffa32b2b448152ade9 Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Tue, 31 Mar 2026 21:05:42 +1100 Subject: [PATCH 05/17] Update mod.hjson --- mod.hjson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod.hjson b/mod.hjson index 14e1686..f78e66c 100644 --- a/mod.hjson +++ b/mod.hjson @@ -14,7 +14,7 @@ main: "meld.Meld" description: "Meld Java.\n\n[[]accent]Only has custom game content! (play the info map to understand)[[]]\n\nIncompatable with hjson meld" #the mod version -version: gameplay test 1.01 +version: gameplay expirimental v1 #the minimum game build required to run this mod minGameVersion: 154 From 36d5539975aa939e2402efd8c884e3bd91e739bf Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Tue, 31 Mar 2026 21:20:19 +1100 Subject: [PATCH 06/17] add the testing map --- assets/bundles/bundle.properties | 2 +- assets/maps/heavy-industry-test-1.msav | Bin 0 -> 19922 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 assets/maps/heavy-industry-test-1.msav diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index fd93b4c..cc57d09 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -32,7 +32,7 @@ block.meld-earthbound-infuser.description = Infuses Debris with vent fumes to sy block.meld-gas-kiln.name = Gas-fired Kiln block.meld-gas-kiln.description = Heats materials using [#cbdbfc]Aspect[][accent]\n\nCarbolith + Tenbris -> Shadesteel + [#5b4739]Fumes[]\nClay-Mallows -> Glass-Mallows\nSilver -> Annealed Silver\nDebris + Glass-Mallows -> Crucible Platings\nDebris + Shadesteel -> Crucible Platings -block.meld-rotary-kiln.name = Gas-fired Kiln +block.meld-rotary-kiln.name = Rotary Kiln block.meld-rotary-kiln.description = Constantly burns [#cbdbfc]Aspect[] as fuel, heats materials to process them in bulk. [accent]\n\nTenbris -> Shadesteel + [#5b4739]Fumes[]\nClay-Mallows -> Glass-Mallows\nSilver -> Annealed Silver\nDebris + Glass-Mallows -> Crucible Platings\nDebris + Shadesteel -> Crucible Platings block.meld-pneumatic-extruder.name = Pneumatic Extruder diff --git a/assets/maps/heavy-industry-test-1.msav b/assets/maps/heavy-industry-test-1.msav new file mode 100644 index 0000000000000000000000000000000000000000..7ab6586649c1413ef73b9b624f8720b15b4bca3c GIT binary patch literal 19922 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 I234 Date: Wed, 1 Apr 2026 16:38:03 +1100 Subject: [PATCH 07/17] Move Recipe, add save breaking saving --- src/meld/Meld.java | 24 +++++ src/meld/content/MeldBlocks.java | 23 +++-- src/meld/content/MeldLiquids.java | 18 +++- src/meld/world/blocks/Gauze.java | 44 +++++---- src/meld/world/blocks/MovementAnchor.java | 14 +++ .../blocks/consumers/ConsumeAspects.java | 96 +++++++++++++++++++ .../blocks/crafting/MeldGenericCrafter.java | 28 ++++++ .../world/blocks/crafting/ModularCrafter.java | 28 +++++- src/meld/world/blocks/crafting/Recipe.java | 10 -- .../blocks/crafting/modules/GateModule.java | 2 +- .../modules/RecipeCraftingModule.java | 2 +- .../crafting/{ => recipe}/ItemRecipe.java | 2 +- .../world/blocks/crafting/recipe/Recipe.java | 12 +++ .../crafting/{ => recipe}/SpoolRecipe.java | 5 +- .../blocks/production/SingleBeamDrill.java | 14 +++ 15 files changed, 274 insertions(+), 48 deletions(-) create mode 100644 src/meld/world/blocks/consumers/ConsumeAspects.java create mode 100644 src/meld/world/blocks/crafting/MeldGenericCrafter.java delete mode 100644 src/meld/world/blocks/crafting/Recipe.java rename src/meld/world/blocks/crafting/{ => recipe}/ItemRecipe.java (98%) create mode 100644 src/meld/world/blocks/crafting/recipe/Recipe.java rename src/meld/world/blocks/crafting/{ => recipe}/SpoolRecipe.java (83%) diff --git a/src/meld/Meld.java b/src/meld/Meld.java index d547908..74f62a2 100644 --- a/src/meld/Meld.java +++ b/src/meld/Meld.java @@ -1,11 +1,13 @@ package meld; import arc.*; +import arc.graphics.Color; import arc.math.geom.Geometry; import arc.math.geom.Point2; import arc.struct.IntSeq; import arc.struct.Seq; import arc.util.Time; +import arc.util.Tmp; import meld.content.*; import mindustry.Vars; import mindustry.content.Blocks; @@ -30,6 +32,28 @@ public Meld(){ public static String prefix(String in){ return name + "-" + in; } + private static final StringBuilder b = new StringBuilder(); + + public static String gradient(String in, Color... colors){ + if(colors.length == 1) return "[#" + colors[0].toString().substring(0, 6) + "]" + in + "[]"; + + b.setLength(0); + b.trimToSize(); + int length = in.length(); + int spaces = 0; + + for(int i = 0; i < length; i++){ + char ind = in.charAt(i); + if(Character.isWhitespace(ind)){ + spaces++; + b.append(' '); + continue; + } + b.append("[#").append(Tmp.c1.set(colors[0]).lerp(colors, (float) i / (length - spaces)).toString(), 0, 6).append("]").append(ind).append("[]"); + } + + return b.toString(); + } @Override public void init() { diff --git a/src/meld/content/MeldBlocks.java b/src/meld/content/MeldBlocks.java index 80d9234..bfd79ad 100644 --- a/src/meld/content/MeldBlocks.java +++ b/src/meld/content/MeldBlocks.java @@ -6,11 +6,12 @@ import meld.entities.bullet.OutflowBulletType; import meld.entities.bullet.TransitionBulletType; import meld.graphics.*; +import meld.world.blocks.consumers.ConsumeAspects; import meld.world.blocks.*; +import meld.world.blocks.crafting.MeldGenericCrafter; import meld.world.blocks.crafting.ModularCrafter; -import meld.world.blocks.crafting.ItemRecipe; -import meld.world.blocks.crafting.Recipe; -import meld.world.blocks.crafting.SpoolRecipe; +import meld.world.blocks.crafting.recipe.ItemRecipe; +import meld.world.blocks.crafting.recipe.SpoolRecipe; import meld.world.blocks.crafting.modules.*; import meld.world.blocks.crafting.modules.GateModule.ConsumeCondition; import meld.world.blocks.crafting.modules.GateModule.OutputCondition; @@ -128,7 +129,7 @@ public static void load(){ placeableLiquid = true; }}; - aspectOutlet = new GenericCrafter("aspect-outlet"){{ + aspectOutlet = new MeldGenericCrafter("aspect-outlet"){{ requirements(Category.liquid, with( MeldItems.debris, 7 )); @@ -145,13 +146,17 @@ public static void load(){ drawer = new DrawMulti( new DrawRegion("-bottom"), - new DrawLiquidTile(), + new DrawLiquidTile(){{ + drawLiquid = MeldLiquids.aspect; + }}, new DrawRegion(), new DrawSideRegion() ); - consume(new ConsumeLiquid( - MeldLiquids.aether, outletRate/10f + //consumeLiquid(MeldLiquids.aether, outletRate/10); + + consume(new ConsumeAspects( + outletRate/10f, MeldLiquids.aetherEfficiencies )); outputLiquid = new LiquidStack(MeldLiquids.aspect, outletRate); @@ -547,7 +552,7 @@ public static void load(){ squareSprite = false; - dumpedLiquids.addAll(MeldLiquids.aether, MeldLiquids.fumes); + dumpedLiquids.addAll(MeldLiquids.pollutantMixture, MeldLiquids.fumes); //Should make all the modules trigger in order hookAll(BlockEvent.Defaults.proximityUpdate, @@ -570,7 +575,7 @@ public static void load(){ ); modules.addAll( - new ProduceLiquidModule(new LiquidStack(MeldLiquids.aether, 1), 0), + new ProduceLiquidModule(new LiquidStack(MeldLiquids.pollutantMixture, 1), 0), new ProduceLiquidModule(new LiquidStack(MeldLiquids.fumes, 1), 1) ); }}; diff --git a/src/meld/content/MeldLiquids.java b/src/meld/content/MeldLiquids.java index 8f41fb6..b6cdfba 100644 --- a/src/meld/content/MeldLiquids.java +++ b/src/meld/content/MeldLiquids.java @@ -1,16 +1,21 @@ package meld.content; import arc.graphics.Color; +import arc.struct.ObjectFloatMap; import mindustry.type.Liquid; public class MeldLiquids { - public static Liquid aether, aspect, meld, fumes; + public static Liquid aether, aspect, meld, fumes, + pollutantMixture; + + public static ObjectFloatMap aetherEfficiencies = new ObjectFloatMap<>(); public static void load(){ aether = new Liquid("aether"){{ gas = true; color = Color.valueOf("cb8650"); + temperature = 0.6f; }}; aspect = new Liquid("aspect"){{ @@ -18,6 +23,7 @@ public static void load(){ flammability = 1; explosiveness = 2; color = Color.valueOf("cbdbfc"); + temperature = 0.6f; }}; meld = new Liquid("meld"){{ @@ -31,5 +37,15 @@ public static void load(){ color = Color.valueOf("5b4739"); temperature = 0.6f; }}; + + pollutantMixture = new Liquid("pollutant-mixture"){{ + gas = true; + color = Color.valueOf("6a634d"); + temperature = 0.6f; + }}; + + aetherEfficiencies.put(aether, 1); + aetherEfficiencies.put(pollutantMixture, 0.5f); + } } diff --git a/src/meld/world/blocks/Gauze.java b/src/meld/world/blocks/Gauze.java index 1b6cba9..37bc601 100644 --- a/src/meld/world/blocks/Gauze.java +++ b/src/meld/world/blocks/Gauze.java @@ -5,15 +5,15 @@ import arc.math.Mathf; import arc.struct.Seq; import arc.util.Time; -import meld.world.blocks.crafting.Recipe; -import meld.world.blocks.crafting.SpoolRecipe; +import arc.util.io.Reads; +import arc.util.io.Writes; +import meld.world.blocks.crafting.recipe.SpoolRecipe; import mindustry.Vars; import mindustry.content.Fx; import mindustry.gen.Building; import mindustry.graphics.Pal; import mindustry.ui.Bar; import mindustry.world.Block; -import mindustry.world.Tile; public class Gauze extends Block { @@ -30,7 +30,7 @@ public class Gauze extends Block { public int propagateMaxRange = 10; public float pulseStrength = 200; - public float maxFract = 0.1f; + public float maxFract = 0.25f; Seq searching = new Seq<>(), qued = new Seq<>(), explored = new Seq<>(); Seq connectedGauzes = new Seq<>(); @@ -64,11 +64,13 @@ public float spoolf(){ @Override public void updateTile() { super.updateTile(); - if(time >= reload){ - time %= reload; - propagate(); + if(energy >= pulseStrength){ + if(time >= reload) { + time %= reload; + propagate(); + } + time += Time.delta; } - time += Time.delta; craftTimer += efficiency; if(craftTimer >= craftTime){ @@ -150,18 +152,8 @@ public void propagate(){ energy = energy - Mathf.clamp(pulseStrength - charge, 0, pulseStrength); float totalTime = 0; - float averageEnergy = 0; connectedGauzes.addAll(this); - for(GauzeBuild gauze: connectedGauzes){ - averageEnergy += gauze.energy; - } - averageEnergy /= connectedGauzes.size; - - for(GauzeBuild gauze: connectedGauzes){ - gauze.energy = averageEnergy; - } - //Remove gauzes close to firing, then sync connectedGauzes.removeAll(b -> reload - b.time < syncMargin); @@ -178,6 +170,22 @@ public void propagate(){ connectedGauzes.clear(); } + @Override + public void write(Writes write) { + super.write(write); + write.f(time); + write.f(craftTimer); + write.f(energy); + } + + @Override + public void read(Reads read, byte revision) { + super.read(read, revision); + time = read.f(); + craftTimer = read.f(); + energy = read.f(); + } + @Override public void draw() { super.draw(); diff --git a/src/meld/world/blocks/MovementAnchor.java b/src/meld/world/blocks/MovementAnchor.java index 3b0b7c6..f4daac4 100644 --- a/src/meld/world/blocks/MovementAnchor.java +++ b/src/meld/world/blocks/MovementAnchor.java @@ -4,6 +4,8 @@ import arc.graphics.g2d.Lines; import arc.struct.Seq; import arc.util.Time; +import arc.util.io.Reads; +import arc.util.io.Writes; import meld.content.MeldFx; import meld.content.MeldStatusEffects; import mindustry.entities.Units; @@ -99,5 +101,17 @@ public void draw() { Draw.z(Layer.effect); Lines.arc(x, y, range, reloadTime/reload); } + + @Override + public void write(Writes write) { + super.write(write); + write.f(reloadTime); + } + + @Override + public void read(Reads read, byte revision) { + super.read(read, revision); + reloadTime = read.f(); + } } } diff --git a/src/meld/world/blocks/consumers/ConsumeAspects.java b/src/meld/world/blocks/consumers/ConsumeAspects.java new file mode 100644 index 0000000..c6a18bc --- /dev/null +++ b/src/meld/world/blocks/consumers/ConsumeAspects.java @@ -0,0 +1,96 @@ +package meld.world.blocks.consumers; + +import arc.Core; +import arc.graphics.Color; +import arc.math.Mathf; +import arc.struct.ObjectFloatMap; +import arc.util.Log; +import meld.world.blocks.crafting.MeldGenericCrafter; +import mindustry.Vars; +import mindustry.gen.Building; +import mindustry.type.Liquid; +import mindustry.ui.Bar; +import mindustry.world.Block; +import mindustry.world.consumers.*; + +public class ConsumeAspects extends ConsumeLiquidBase implements MeldGenericCrafter.BarConsumer { + + public ObjectFloatMap efficiencyMap; + + + public ConsumeAspects(float amount, ObjectFloatMap efficiencyMap){ + super(); + this.efficiencyMap = efficiencyMap; + this.amount = amount; + } + + private static Liquid currentBest; + + + + public void apply(Block block) { + block.hasLiquids = true; + Vars.content.liquids().each(l -> efficiencyMap.containsKey(l), (item) -> { + block.liquidFilter[item.id] = true; + }); + } + + @Override + public boolean consumes(Liquid liquid) { + return efficiencyMap.containsKey(liquid); + } + + public void update(Building build) { + build.liquids.remove(getConsumed(build), this.amount * build.edelta() * this.multiplier.get(build)); + } + + + public Liquid getConsumed(Building build){ + float highest = 0; + currentBest = null; + for(Liquid liquid: efficiencyMap.keys()){ + if(!Mathf.zero(build.liquids.get(liquid))) { + float value = efficiencyMap.get(liquid, 0); + + if(value > highest){ + highest = value; + currentBest = liquid; + } + } + } + return currentBest; + } + + @Override + public float efficiency(Building build) { + Liquid liq = this.getConsumed(build); + float ed = build.edelta(); + if(Mathf.zero(ed)) return 0; + else { + float multi = efficiencyMap.get(liq, 0); + return liq != null ? Math.min(build.liquids.get(liq) / (this.amount * ed * multi), multi) : 0; + } + } + + @Override + public float efficiencyMultiplier(Building build) { + Liquid liq = this.getConsumed(build); + return liq == null ? 0.0F : efficiencyMap.get(liq, 0); + } + + @Override + public void setBars(MeldGenericCrafter crafter) { + + crafter.addBar("liquid", entity -> { + Liquid current = getConsumed(entity); + + return new Bar( + () -> current == null || entity.liquids.get(current) <= 0.001f ? Core.bundle.get("bar.liquid") : current.localizedName, + () -> current == null ? Color.clear : current.barColor(), + () -> current == null ? 0f : entity.liquids.get(current) / crafter.liquidCapacity + ); + } + ); + + } +} diff --git a/src/meld/world/blocks/crafting/MeldGenericCrafter.java b/src/meld/world/blocks/crafting/MeldGenericCrafter.java new file mode 100644 index 0000000..54d1e29 --- /dev/null +++ b/src/meld/world/blocks/crafting/MeldGenericCrafter.java @@ -0,0 +1,28 @@ +package meld.world.blocks.crafting; + +import mindustry.world.blocks.production.GenericCrafter; +import mindustry.world.consumers.ConsumeLiquid; +import mindustry.world.consumers.ConsumeLiquids; + +public class MeldGenericCrafter extends GenericCrafter { + public MeldGenericCrafter(String name) { + super(name); + } + + public interface BarConsumer{ + void setBars(MeldGenericCrafter crafter); + } + + @Override + public void setBars() { + super.setBars(); + + for(var consl : consumers){ + if(consl instanceof BarConsumer barCons) barCons.setBars(this); + } + } + + public class MeldGenericCrafterBuild extends GenericCrafterBuild{ + + } +} diff --git a/src/meld/world/blocks/crafting/ModularCrafter.java b/src/meld/world/blocks/crafting/ModularCrafter.java index ab2bc5c..fc836ce 100644 --- a/src/meld/world/blocks/crafting/ModularCrafter.java +++ b/src/meld/world/blocks/crafting/ModularCrafter.java @@ -1,10 +1,10 @@ package meld.world.blocks.crafting; -import arc.struct.IntFloatMap; -import arc.struct.ObjectMap; -import arc.struct.Seq; +import arc.struct.*; import arc.util.Log; import arc.util.Time; +import arc.util.io.Reads; +import arc.util.io.Writes; import mindustry.game.Team; import mindustry.gen.Building; import mindustry.type.Item; @@ -284,5 +284,27 @@ public void update() { super.update(); modules.each(c -> c.update(this)); } + + @Override + public void write(Writes write) { + super.write(write); + write.i(data.size); + int[] keys = data.keys().toArray().toArray(); + + for(int i: keys){ + write.i(i); + write.f(data.get(i)); + } + } + + @Override + public void read(Reads read, byte revision) { + super.read(read, revision); + data = new IntFloatMap(); + int len = read.i(); + for (int i = 0; i < len; i++){ + data.put(read.i(), read.f()); + } + } } } diff --git a/src/meld/world/blocks/crafting/Recipe.java b/src/meld/world/blocks/crafting/Recipe.java deleted file mode 100644 index ffae399..0000000 --- a/src/meld/world/blocks/crafting/Recipe.java +++ /dev/null @@ -1,10 +0,0 @@ -package meld.world.blocks.crafting; - -import mindustry.gen.Building; -import mindustry.world.Block; - -public abstract class Recipe { - - public abstract boolean valid(T block, A building); - public abstract void apply(T block, A building); -} diff --git a/src/meld/world/blocks/crafting/modules/GateModule.java b/src/meld/world/blocks/crafting/modules/GateModule.java index 504c291..f740b85 100644 --- a/src/meld/world/blocks/crafting/modules/GateModule.java +++ b/src/meld/world/blocks/crafting/modules/GateModule.java @@ -3,7 +3,7 @@ import arc.struct.Seq; import meld.world.blocks.LiquidUtil; import meld.world.blocks.crafting.ModularCrafter; -import meld.world.blocks.crafting.ItemRecipe; +import meld.world.blocks.crafting.recipe.ItemRecipe; import mindustry.type.ItemStack; import mindustry.type.LiquidStack; diff --git a/src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java b/src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java index 3d0da58..2320925 100644 --- a/src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java +++ b/src/meld/world/blocks/crafting/modules/RecipeCraftingModule.java @@ -1,7 +1,7 @@ package meld.world.blocks.crafting.modules; import meld.world.blocks.crafting.ModularCrafter; -import meld.world.blocks.crafting.Recipe; +import meld.world.blocks.crafting.recipe.Recipe; public class RecipeCraftingModule extends ModularCrafter.CraftingModule { public Recipe recipe; diff --git a/src/meld/world/blocks/crafting/ItemRecipe.java b/src/meld/world/blocks/crafting/recipe/ItemRecipe.java similarity index 98% rename from src/meld/world/blocks/crafting/ItemRecipe.java rename to src/meld/world/blocks/crafting/recipe/ItemRecipe.java index 784e187..3b887d3 100644 --- a/src/meld/world/blocks/crafting/ItemRecipe.java +++ b/src/meld/world/blocks/crafting/recipe/ItemRecipe.java @@ -1,4 +1,4 @@ -package meld.world.blocks.crafting; +package meld.world.blocks.crafting.recipe; import meld.world.blocks.LiquidUtil; import mindustry.gen.Building; diff --git a/src/meld/world/blocks/crafting/recipe/Recipe.java b/src/meld/world/blocks/crafting/recipe/Recipe.java new file mode 100644 index 0000000..f52eef3 --- /dev/null +++ b/src/meld/world/blocks/crafting/recipe/Recipe.java @@ -0,0 +1,12 @@ +package meld.world.blocks.crafting.recipe; + +import mindustry.gen.Building; +import mindustry.world.Block; + +public abstract class Recipe { + + public abstract boolean valid(T block, A building); + public abstract void apply(T block, A building); + public void update(T block, A building) { + } +} diff --git a/src/meld/world/blocks/crafting/SpoolRecipe.java b/src/meld/world/blocks/crafting/recipe/SpoolRecipe.java similarity index 83% rename from src/meld/world/blocks/crafting/SpoolRecipe.java rename to src/meld/world/blocks/crafting/recipe/SpoolRecipe.java index 74f483a..99c8fc0 100644 --- a/src/meld/world/blocks/crafting/SpoolRecipe.java +++ b/src/meld/world/blocks/crafting/recipe/SpoolRecipe.java @@ -1,10 +1,7 @@ -package meld.world.blocks.crafting; +package meld.world.blocks.crafting.recipe; import meld.world.blocks.Gauze; -import mindustry.gen.Building; import mindustry.type.ItemStack; -import mindustry.type.LiquidStack; -import mindustry.world.Block; public class SpoolRecipe extends Recipe { diff --git a/src/meld/world/blocks/production/SingleBeamDrill.java b/src/meld/world/blocks/production/SingleBeamDrill.java index 508cec0..f4471f1 100644 --- a/src/meld/world/blocks/production/SingleBeamDrill.java +++ b/src/meld/world/blocks/production/SingleBeamDrill.java @@ -10,6 +10,8 @@ import arc.struct.ObjectMap; import arc.util.Log; import arc.util.Time; +import arc.util.io.Reads; +import arc.util.io.Writes; import mindustry.Vars; import mindustry.content.Fx; import mindustry.entities.Damage; @@ -116,5 +118,17 @@ public void drill(){ public float progress() { return time/drillTime; } + + @Override + public void write(Writes write) { + super.write(write); + write.f(time); + } + + @Override + public void read(Reads read, byte revision) { + super.read(read, revision); + time = read.f(); + } } } From 89097a8f20fc7a7038a1353a8a518c22ce65432a Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Wed, 1 Apr 2026 19:23:12 +1100 Subject: [PATCH 08/17] Fix LiquidUtil#hasAll the humble !: --- src/meld/world/blocks/LiquidUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/meld/world/blocks/LiquidUtil.java b/src/meld/world/blocks/LiquidUtil.java index abb42f1..ed0d46f 100644 --- a/src/meld/world/blocks/LiquidUtil.java +++ b/src/meld/world/blocks/LiquidUtil.java @@ -8,7 +8,7 @@ public class LiquidUtil { public static boolean hasAll(LiquidStack[] liquids, Building build){ for(LiquidStack stack: liquids){ - if(!(build.liquids.get(stack.liquid) < stack.amount)) return false; + if(build.liquids.get(stack.liquid) <= 0) return false; } return true; } From 2006e13542e8eadc126d2f3e18df49eb4648b629 Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Thu, 2 Apr 2026 00:44:06 +1100 Subject: [PATCH 09/17] RecipeCrafter multicrafter, alt fuel This WILL break previous saves -Adjust hasAll in LiquidUtil to use the stack values of the input liquid stack array -Added an alt fuel source to Aether/Aspect -Aspect Outlets changed to use Recipe Crafter -RecipeCrafter, the class I hope can acompany ModularCrafter in the quest to help with crafter logic --- assets/bundles/bundle.properties | 10 +- assets/bundles/bundle.shitpost | 6 +- assets/maps/gameplay-testmap-2.msav | Bin 26386 -> 28734 bytes assets/sprites/liquids/bound-aspect.png | Bin 0 -> 351 bytes assets/sprites/liquids/pollutant-mixture.png | Bin 0 -> 513 bytes src/meld/content/MeldBlocks.java | 80 ++--- src/meld/content/MeldLiquids.java | 28 +- src/meld/world/blocks/AspectPipe.java | 40 +-- src/meld/world/blocks/LiquidUtil.java | 13 +- .../blocks/consumers/ConsumeAspects.java | 19 +- .../world/blocks/crafting/ModularCrafter.java | 61 ---- .../world/blocks/crafting/RecipeCrafter.java | 285 ++++++++++++++++++ .../crafting/modules/AttributeModule.java | 27 ++ .../crafting/modules/ConsumeAspectModule.java | 58 ++++ .../blocks/crafting/recipe/ItemRecipe.java | 15 +- .../world/blocks/crafting/recipe/Recipe.java | 6 +- .../blocks/crafting/recipe/TimedRecipe.java | 10 + src/meld/world/meta/ContentTags.java | 9 + 18 files changed, 514 insertions(+), 153 deletions(-) create mode 100644 assets/sprites/liquids/bound-aspect.png create mode 100644 assets/sprites/liquids/pollutant-mixture.png create mode 100644 src/meld/world/blocks/crafting/RecipeCrafter.java create mode 100644 src/meld/world/blocks/crafting/modules/AttributeModule.java create mode 100644 src/meld/world/blocks/crafting/modules/ConsumeAspectModule.java create mode 100644 src/meld/world/blocks/crafting/recipe/TimedRecipe.java create mode 100644 src/meld/world/meta/ContentTags.java diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index cc57d09..725db31 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -152,7 +152,7 @@ block.meld-aspect-outlet.name = Aspect Outlet block.meld-aspect-outlet.description = Decompresses [#cb8650]Aether[] into highly volatile [#cbdbfc]Aspect[].\n\nWorks as an output terminal for a fluid network. block.meld-aspect-channel.name = Aspect Channel -block.meld-aspect-channel.description = Acts as a pipe.\n\nWhen transporting [#cb8650]Aether[], fills nearby buildings with highly volatile [#cbdbfc]Aspect[].\n\nWorks as an input/output terminal for a fluid network. +block.meld-aspect-channel.description = Acts as a directional router.\n\nWhen transporting [#cb8650]Aether[], fills nearby buildings with highly volatile [#cbdbfc]Aspect[].\n\nWorks as an input/output terminal for a fluid network. block.meld-channel-director.name = Channel Director block.meld-channel-director.description = [red]Restricts[] the flow of fluids from its input to output by half.\n\nCan [red]detonate[] Channel Nodes full of [#cbdbfc]Aspect[].\n[accent]Transports at 50% pressure.[]\n\n[red]Will chain destruct![] @@ -718,6 +718,14 @@ liquid.meld-fumes.name = [#5b4739]Fumes liquid.meld-fumes.description = Passively seeps into conductive materials. Used for a variety of metallurgic and restorative appliances. liquid.meld-fumes.details = Smoggy primordial aspects. +liquid.meld-pollutant-mixture.name = [#cb8650][#6b4e4e]Pollutant Mix[] +liquid.meld-pollutant-mixture.description = A mix of common aspects in the atmosphere of Ikaru. Emitted by [accent]aether vents[].\n\nCan be used in place of [#cb8650]Aether[] +liquid.meld-pollutant-mixture.details = A mixture of secondary aspects. + +liquid.meld-bound-aspect.name = [#a451c8]Bound Aspect[] +liquid.meld-bound-aspect.description = A highly energy dense, stable fuel.\n\nCan be used in place of [#cbdbfc]Aspect[] +liquid.meld-bound-aspect.details = Confusing mixture of primordial aspects + liquid.meld-nectar.name = [#b89f47]Nectar liquid.meld-nectar.description = Used as a potent coolant. Can be refined into [#89828c]Mercury[] over high heat with the right reagents. Encourages a slight mending effect on units. liquid.meld-nectar.details = Blood of the swamp. diff --git a/assets/bundles/bundle.shitpost b/assets/bundles/bundle.shitpost index ffd634e..4e3cb48 100644 --- a/assets/bundles/bundle.shitpost +++ b/assets/bundles/bundle.shitpost @@ -1,3 +1,5 @@ -item.meld.glass-mallow.name = Pan-fried Plates +item.meld-glass-mallow.name = Pan-fried Plates -item.meld.crucible-plating.name = Boiled Plates \ No newline at end of file +item.meld-crucible-plating.name = Boiled Plates + +block.meld-sonar-spire.name = Slay the Sonar Spire \ No newline at end of file diff --git a/assets/maps/gameplay-testmap-2.msav b/assets/maps/gameplay-testmap-2.msav index 35af6f9b2a55186ad4c98ff18d692e7d7c7f82dc..541753e78fee7ac3199e80b527589d3859428802 100644 GIT binary patch literal 28734 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�MUaQeFq5&!9XamGYPSN!Tb-SX;- zI!jHS?(lUae+YWsgDB7hM+=Z}8my$B>v12+ZdjMEZ%)_Ry2@B+eX*9aC(53E2Aco`ZCq1gR-A~b z5V=)bUo>rQ0CeTS-TK`(*?jkbuMD1p!qxQsJc#?C8wN+%G93vKyX2$!IUu^W@6RH^ zJGnOblo%Uh)>$HE0QEKAbVlmjYbftMqg?oRF=?j zWQYjc$OyhRL7pltbGhRaqI#O%Pp!g8M+yS;QNA9G#?{k)XEk+qqdiDknAdHwi+R6E z5cybVe}A1DZ38{Ilt-W2bw4D^gH#NA82=vsNiayBCP^S(_<}5+lR-Cx&a&`>8ft^! z;JTpb8~cx|wA>Xwa=0g6T##DMw)y0+r$N$UBo^zf9lJ~OPUx>Qxr~1KCZcKKGm@99 z_U>|hRQ>|HL3HZ?-YBQ=PP*+xX?o#Yo>t@gX;R-|d=%{)-8BSeP+C@#j0uO_uK)*4 zKeckWRhz6W71{-nzx9KfSd@aLT>3d=5?tn4A0m231$rj|CXK}k++LJ=xpnD+fnzP) z9#rxQRSlyxU;hmG_`!4TseX&^EXnO)!g4Z%*(gRkf9}g7xoQx&S!IvaWl{B6^5RR^ zmb{XL(L+*FMgq}+KiF7xxzqhTS}_S)o}63x zHQmJN$tQT128%KM;Tls=RywR1V_VIDTAb(EJsYAee6rIs6)-6dbxv+YO`QyNZwr&D zC)wMT12UZNc2rk9Z-jX7XZ?@z`Gy$i6*JqS_m?Ey#uG;?4-AuM-@j(22E1sn;vn-p3TOs?VWz zJ44Uk;OJv*bU|P#74qBLFPjH5n0F21ba8XwvtAhQGy`<)-pk|5lvsankl9~(5`qe8 zp7xD|0riFQneUDX>1ETBEUPq9Ebr7wAAu<*QZ0YiBCZLrTz-A&8na~X1-woLh{D2? z{N8xWVFToxZDz4vBEM!M@7Rv?=a&a3Wx4OVx}|K6Kz`-w_qbQ->qPJSjkT?>z3I2j zI<+Y7p~j3-%?`FLE%0vL=p|gC9-J5!HSqz^G8qQ6G*<%) zk;m$PgVyNwb>kIIT^Tug&Yg7RNn@~;qVbGC_1x~ksS#q>XD!ICbU%rxXI`FMvaR;? zN%4IDRl>SX;Lk}Cf5X<6JQ$4Yl{Q!Q`cBGw@w|720~4FUzo_#jWy|NGpVS zN5u`0NEz2=5>SUY5aY)Qylpeey}k~%f4m?oER zy2r&;34IgkpSj&f@|K!?t1yJ+16i;NxK!Sv);P#yFIaz4DfkH>^r#M&tdn9`L zsESJpEKQM|LfFukmw?LY#+yC~ot_a&20l%dggxkw7Ae#^DdQw>H44JXLZy?V_nPl8cQ`WwP% ziE@G%yE)DpJTiIM81`F2mP|M!Jr9Q$o$$@D;uhS+wD6aJMcBb>#9DoHPCB)WFG_!H zI2spNF54Dj53t1;#lVP`5&loYwXxxC$E7WfR+s1jS0ygWa}&a&UzDEha|`m^G=+^J zmuANO=jKK3r=`F5ghIc21eKBnhz56w>yQ#Zp zq%FR0^_%|PIl=e5*gvH6ZyfoY&E5Pu(NsayH^mv2caMDTlf)VCx$v;(rsTQB!=AG+ z-zJ?lGIVIq7OGp);unN7HsSJXhqagzd7c+@V_RGnSf=0;k6)K-_Ad4^4R_xa>+>U# zcDy?Sci$01`y=58-kpQHZ;R3YkwA))I1hKfM&8uiU6i|L;qF(&RsKjM=eFE^6ONYU z?t<_a@8YuBt8y0|&}Z;Dxcg`?}oy4Y4YpleVu5%zsAi z;%g&k;O=X3_s{xwu`RCpL+||O{JS{rt3s>a^v691cVCgaza=&i+n$HJpOTfbBzLb7B^&BNxTu4-hStXgO^Js3+xonze{bva*Z6!@ z|K8H)U*z-aeEzEb{qOYo4L<(@pWo#6ujt?ZR-fPE{y(pO{~LXNTmODSpMQ?e;r^%e z`OEtEzvlDL@cDnm{XN6y|0Umlmizmg+~4zj{-5#rOML#H@cGLO&ws?{ukiW5&*xv{ z=l_8Ff1U6Db-w>)KL2<5{7rxdb-1Dan!Z*HFK8WK)aUeDtNdHj_utabKCd9EX{dikU#p~^E$iO|uiIyf`uJbPu`cNQi#p7@pvQn`Y3vsj z1b+?nSM;?8-^+1-A;alD3w>7@-e1@ECit01|3-|X+ZLYx3e%&ikD-Q==-*$(K8O~1 z{Tu7w0*@Uz?Owttq`~n^L;Z_P*8PB0m~xRRORKZQgBv5nADf`eO=04B}Jdz~i>RhOjntJ8J(pw`(x|&@OSt2RszQ zOLTSn0oWHZ`Wa*1D@P_G?k7t1bCuzlXP#cs$3IYDgovL>@K2DBiL}?Ifq4_MJS;hV zJc0CC(1s11O+)<3;q?2q%#D0M`DW%LC6+nGzjJxZ=ijGBP^&I(;;DA{0ZnK_?wz;{HMtF zs)pLJ~Oo@rV}x)DvM7#o(_U(-+oX{k-j!68^<+u*sst<(>XXlto5^7Bfew^3{XLZ)EC zTuB%g1(f2yVblzUJ;U7bsr|h)wU2Q(i&Htazhij3pmK=m0_P^_yaDGd#o+VSk@O99 z(czlmNW{J(N>Ms3ixp$j@wtB@dYiDOfn6_*NX3yTZvGf{%s&jJPQ+dgsFP=^0Ckje zKFQRnDzf5jMH;2MRI|ZSG9v2# zgXvpa`0wkdi>bcVG5h=P@#&f1(EjRR)IDaBDn!hIA;QwX+IPeNa5^rE2 z)X)=V+|&9O7+XVT>TnmSK@1$7ad~z`aqu4=_2kk047q!B&qLWYHeltBvZ$n&z*77W zqlr6!wF+2IY#mj{A~`3P!NqgI^S_p1qu_sl13vk`I}H6n`bn@2M?Vq#gORP_KwG8I zBc9RXfq1d?dxFKL0RBtg2T>}r*nqeo**SUwu{y7R=Z1<8#4iEDH0;T6bVeH{#vJeh z^H9AxTp4HM>M|-mj^3qokc{^*9V~J%kOcqp;Uh7@p~oN<7M6p*tB+HE3PPa;{<;k@ zX3Sws#3nvJGD8YO$n4$z!Ozrf*G~-G9%6!yZu=2N`s3R_XSa`*#7B>ujw{tl;glm_ z0}j)e+z4^b&}UK()BPLKc`8aV;P1#*IUoG5_~ev&@i#w`ldR{Y#((G%=1vB zkC~}BwYkv8caOfC?Q+LCCc>Gb79g14L(KH1qEH*|!9-wQSy4PQg6kbNlNlZ*O$~h_ zJp+w7Lp39Tj59+F{$3z|?!6I%rBS0@=MN}2veHse2l@s2Nq>*7#JVFp3p+gaA_M#K zfBJf6=chZr*J2>e$e#zlH6y8S4p;D*TfABqguC50E<%9GUC&D@Y^yCED zwx7wnN8+pe_zWt$N6(#x#%!YocR13}-iFIj<&dx+Vz|1K`g}`KLih~)4h_6#hKBd& zQ=$1HPaWKlJa9wuAxU62kRLAAN8dkkBsEHjt;i)dC0HFL6vN;dIp8;c{|i6(!ch-e ziXA2c^>7|Vy5`8i*Ax{5VHy~4O=fHac^I0|e(t1fQ==tZMzeS$&ixc5(}xK|iOHw9 zo;rH@>llnb=>x+NJ+Gw!%EMKj(ZLMvOW`DPufh^BJm)^5BzRl^(jAv`@NWd9{IbZX zoD6wYMDz%p^#APWi<-QUW2x{MK;G9hd0`wVS;7jD;U&ru$ot|cD#`C{E~ZKYYb;Ia_1Seo=F_{9$l5tpp<*8|WnXKlO9`hmA+!81xfxLd`7Y zI5J6m3d(YUZIMgTFKCj&F?gxQX_54$p}_t_ynik*_p>v9|1g!uKHV7gINplbOE5qG z|7Hg`>bW&Vf^f3hdWlQ25w9jR;*p$=^8Qa5e?#icL)m$B`*T|ERLV%dqUFx`Ls&XF zBs%^%ynEz~S&gh`iuK9-J&IoaFhe&+a%Rfv2K@~)eHE^K#4OtdQwup2)0ZXMr{|W> zvIrZoO^fhM@E)^Sk0;rI-$2SFDk%t*K$f=09O-fO`nFqynL** z%m4$1#v&(93t=Be8Xz@_m|SMVQaOb6$4vE%XpMNCT^1)n_02To)Hr#ZWZdAq{q(3@ zJE1o|EkzvFgs1ofJjokAv3)6>Ca;EO-P8zgEgU1pI*!vH*6Y#1z(=#1@Kd_0=nXk| zqV9wh$Fw#42mg45M-1~J1sUN5l*@*qfY`_@JY3=zWy~vaCMQ0AwETK^fAEvLtB#$c zJidK9e&B0c7lvBL+b41R!sw$G56#PaLpeyqCZQGx@QNpRx>x68RJ2YUlCwATVJ7e3e};%!9#%!K(&f zvYJS^NqmFbq&RD*O)w+Hmwy)0jqtytgK>OfL}ofnB+P~ieL^D>X` zq9l$GRav7zh{pN7vlV59$Y>qp4~NHaBM8xFNA^L-&#j$g;(Z!3GL;gM(e>Q037&c? zc;VY>#N><5*dqKYcw?Cu3w{hNK%JMiUd8iCv>Y+t0}C?Yy)x-Cd0^4d&-vXfp>B*O z)T26s;|5blP9D8AC!^c2;od!MJ3irv7=%(aUTFcOD6oiuI4vs@u>#+VdHy#(u)6H~ zN3SkRt+>ezWz%@@pX;aj4+uG6NIo=Md-Bz7$9YS97<2POnfn=LW=a17>FO9g*kTd% z31OI-C_RPelW0SrFY_|vc*eW)BQsbXhpCQT48$%5OK2DWmhE5cB8k9-RKRlX6sQ|y zym>LKP1d|>IF~+aD)B%E;1pYRQ>!fV`I8D#Vv{mmg?KN=E_>XwUEdq9UB|hd@yh8* zb@al>A^5or5{|O+)P4TMsUekKc9X@nXAG+xwt=M#IX?}oE5Vix`u7QC*Qc2`{u`&r zvY)Nn?kdcI+e7j%N4Nb5BmMF1pYH7+X2o+OJd*Y;=T9M}GwS@}c-iK`pmDS!M}O;fM~;5`6u%?EBE? z9_0=0QJ)?qpgwHf*K@T?Bk{}J!>bToSoOtsuLPnuO3=^17eE?w5gPwU@VW)wUS z@tRk|s8};dcf*INu{)8`?V9lsM$Z*J)WV z9%nC2CioNrs4wt-Rj?s?$))26G#{Q!eFf?4zG^x^!y|7F>IXdhDC?w$^6^MGMtue4 z5Q}&;*N1iBhy=tTODqy5=6D>$0mK5icZxxq5e?YQ8tw&-iVb1?M{|YS32V_{+e^db z^%1Pa$fhQ}o|n&AKES0evl|`b^>a@`EDCPZ3GS5|7To6tt4b#gPG1RW%Td@Kca%NF zYbTK}1z$b^UX5blhb^u@k`pHrhM^A}y*U?rou|M|hqpF9!7ex)$r$91XAC~C8HXPR z*T3VAA;9g=)hLTCAl59OII4NXO$SFX!oxQ;99b+z=nQE_JWQB}5ZyMyN%ZpU1f965>3BiGLWxP7KM)rhd_brfV<#Np9C4l^>5@7PmH^wOa}aW`w&=adMsGlxjKwTBk_><2kEaf z`nP^cID~9{-sX42LI(%X|0+-AT85q}x&lmPr0XPoeoUW(jt{Q{4Tmk@OwrrU{`|KD zHn5bF`1uzYZ#lIN@)Cc}$^E<+xOgZaC(M`Jho{pY-*xXQ%gcAz69O-9b6|p*LGXqw z*N=Pp@cm4E2nQBo|KN!1PLf)PeUZOwfjv1AQsu>ydA1_vb6vm0uWS z;$P?o7F=F&v?NSP=41Rp6!YOj<%~@^(?tx^z*58SFYsbdSQ_ypkBuMPg23My^YSpN zjX>4M88-Ns5Pr}Qxk6(UnI6#UJ%$Om_&5j9MO-gu=>Xy9r3|Za#rbfU`7jKutpkf$ zL`j)Ms}%5pa#MnWlB74YbWMjTF;#l9!Kso!?)A_n01Y`T~m$ zHvLup7Ln--a88`Q@O{3J-pGKyfFEOAEi$qJmUEKff;KhAF~?p5WCk@M_@}(hBhe0s zbcW#sI>YnuF}t&lmT|K3a}LZ=NS~;gcPf)b z?)L@8F?M)_Up<2B$oENF-pa6_j^9NAaOe$)@-DdZ?D zW?Zf^%#&$7UQrj?0eD!%BLf z^+jhHQo$MLxsX2I7_q+O80R7{@r_bE2zZ=}EYIeaVarI<3=HUwWh#{fY8X38DG(h>jfS&HoVrq*Y%hnH;=PEn=y;dm=lJkc#mjl zzLW# z7ie{r;W?-5-YTYFu#KMzDKQe;5N%af%|Xi{ulJI`G{`7c))L!ZEOj3k3W{leMe5;1@8Nkp(z3ot)OqP z56?2s&GL6>TSgm9cK(@=J_v01L%M7G2K+w9eFEKKZ`aQ{JgKqV7SR6i2SrnTR8oC_ zE`HjfGuit^PKD9OZw(wpe#xSQdP6u)a9=CBFVL}1GL9wg%jnxnA$`Eu?F(NKfEPN@ z_E2&uVL6##J-Vj*1-tYK?zhbS<`~9{oVdMc_`>}|zvCel1W7N+|K%8-3AUwIb^lLr z|B2Io#Qi_UNkuaT>Ob=w^A?au3mfu*$4ku1kjEQmKEpUqI^)z>uENwf0gn^2Z4DU* z7$e}c+G8w>ih12&J%BNua(GZ-T+A33%owJ^0rX({o#ioIzhTBc$741aX65L3i^u#F zKVLQQF#d}sDa+|Lg?dZX6~J{~WZr)E4QP6v$DH6Xb3E1)EU%#Z5GhYGZs%czoU`b` zB=pa4Y#DOjir;YnT7q4=z++S#od7<)&VAP(=BG%4jHZ}q_^u#pOa3Xz&r4bYp6pF^y4?3^$*Z*EV6GGwB#7? zF{j@tMX6f&XKddp+n+V2UyL@Cbl@h_xaRb4=sV5y1X|5;e;}7PxxZEBHGL4d!5^tM zA5tbBUNn_L#>4y;c|4;_0gpKYeu!}aKL+vKB_6BHW8_$ea-mrzN3!@>YAnUSWkqpf zo##*?C#YeJc^+dP`=rluc{^f88dN_|{mdNniJgA76@)_i>ZI>!~zkI6&@D3=spPvsIQ4qwDihSMr3`@K%Zb|PZ?xX5EZ#$z^kOpJ?7yvXC$c`gy9 zUXY(TR@No``a4K?-htM98a86>ZaGk1bg*bRTrg2>j;RIEPB@UlKqIX8b#O7zML6dm z{+ale_{I>jj5Zx8VO~4w$ezjRgpARfA-#Z`rel<t*}PkWGMswEU?x38b_BtWJhoQ za1`7Ira6odD2mES&X=M&a}IEwWlL({nrFD)d`Pjofnb$wFw6t5FgM3p&Vd@gc#@S7 z?CbN7AYsF?n#F7k&0=zFKNQn9a@Ksd8Dp9PtZy6ZJn9-|1sh}?m;SRj-(JLc zIAME`bL=zP6Z3Iw2kJY_6M~xf_f|-8esI#g>s5MBiOjmoN3-fTw8k*Y-Y~}$kCc@W zW5E^6$aU61m)hgZrLVD^oNPJ62=5x4loLwf_h90XGG+zFIWk!^2iLQVD?~IUWute{ zh2n9R8=oTFQAk;3f!opNf}_jl7%9Xu@`OA%u{J2$_!_eetnm@s@xWMA zCkkvbFFwJ%0I$7^cv$+LHcTasW&)DrGulaegunQO+8cD;vfj%~p z2EDW#4S+gIz|kAP`vJtjLq{9-+Wbd>^FLY72lOvs4ab*>!0~vlb%lRx9B+J*`4EP7 zF8^(ijg#_0|2@HQxp{OG@0iaf-{4pj;DA}AsegZGXq>67(<#9Cq=v&R3avOb12g}F z+{rA%M{iY7l+ZiT>fuq|Pdb@ri$;nShts$?5*3F(@f6E|*(xdG2n6y$Gfdwprf+Zx z^gZ6fRO@|5`6$?^eHrf>o&x<^4&5TA+q9!M2d4%1iNAI;D$R$DGn)JwTBHB@XnF?3 zW*C209sa_T&ujidEeUGJkXQTWv1R^f`nq3HJGE`?PQmUO{D;T5AJI5K!HkRQHLvjc z0N^3iR~A@zUlV%!dBIX9AALC={+WW|vUZ!{`@AD#0N*_O-d9dE^G#=BGxx20?oX-@ zd*9uo@BRbl?$LS3pO0}rzWZ~17ydVr-qUJas_lXPPdYwkp5wjGkCYKg*EEK%H6OmB z{-bHpKfe2uxvOC18&$4fW6At9&rVGp$*jP+bHdrt@M_M9rB(m^Ca>H3G{@*?IS&Fl zX1@J)>lpKipFGr1TV3Sr4nUo7MgIE8(Wq}FhSyDkBR6Fq1~054eT?&)1*US$@QxPY z{%k}qAEpil$D_fqc?1>lOAe0;%%inaneqG5Q#g?{!5X{EDQSuj(npy~{~-0;QTP7- zk@w)YJ`|JRa%?E93aD}BYJ&9{UsC33t@_!r$Tfk%6$x zbT;c@0K#WZBo(RmPmZFw{u>(#@$cdWc@5m-EpQ-*x)0Q*psr@JtOWgONXl@U50jSR znEf7ZzuLfesOjt1i@Y~B@#L9D%Ijo7>r2US$o@R81SRM`=Rj9rZyGX`K=0>AqUUgW z6@&j#_rZT^6uFp$E@Q^5-hpGD|~ugMw} zuiwG7fb+O!_H!H&m=!GsFVNN4qy7k7P>}C9E|meAFEJEU_rAa@MD04V=RVBL{0OmS zV<;BCt+DuW1{MvcBKzzk+< zUZlvL|CL9Gpz;H;{P#{ZmUm&Ea^@q$rQ&#Y=~1&DN6!|bW6u`;4W7>$e9a1QScQo# zv-mJ{wtX~|!`CFaP))Mrgek}-KkRvmlNC7kmA$hcbZ>^MK(Wou|9Lqr>whQZdzKs9V0Vt0w2H1 zv0d5W<2C;LZsRy}+!1(WqoB;{JidFF6=fg&^f0OaAy-7_K2)nSjMSq%;PM1&y2TVv z0Gr7Z+0{q2iH|ya_yNEBJ9}KYJ$zH>M-lR`gtUAE2wLMr9xVMYC<-J71^Bpx{Ygz- zzRv}=siC`UKdKO(o)`nwY10JSY{qP;0zuC((=wXbIi8_7+OhwTmm5qD*-<|G???$9 z{yylNOe*{^0B6OXhW)P8r~*2w_8v_HvoFF9S3S-CNA(lg#*=?*;zR}j{+-Nrj~*7K z8Hpcq;gC4gzqnD`PsM~kddM5|h8|n2ArSgQ8mKy&G0#$`QFeO{=Q$^= zLVNtf){;l((dcHa#-)(?JFo6 zr?h>o(u&Rs zd#(Z-JB1$1?wJRB!Ck@u2R-iu6Ye|{E@9E0I<{~O`ML?i3j~T;=mFkw=L>GHvB2Y= z)=J?!?I5^|44YX2Ha!%!=+N4H7F?5D7m6@)Aln90$d?@F0K!yA!F7S*iWsh$4^h}o za`(~S7dTAC$2eyV6a$renJs?I6I6Hy<1sb3i(G>Z>0?Z}P$+kb9Ay~moN|OY7EC8T z?{G8Eu(~ipk0b2@_EY2IKhJlwa@+YwmZss3+DJK60U}PBDo$7joKE_xBS~Nj($YS> zDxGjVchSKB{>^?wEy+*jZkCN6XKjW_c#(gBf?wweG*A*hHh3(Wmw29dX1K%v3~=JW zLF1Av)OkYj3eOgEJdqd={;rmX)Sn{ReVw7WGIVtCn7B))Bav`@4tMN5FVmSj&Tcx2 zza#+A6*#X1?XeC?4{fqKPK09XOg3@colZBSBo}>2VU8Hz7FP#1K!jtjscJ z>gH=ViuQwx9r-ak#gf${{|Pi)VeY{7Xb9w26xFtoTF1fwrdmM%JkB+Jy07s5)M7Q= zy`vm@=bUd%6d3A==?;7SS6CvRP$&sL}iL{zGX&|aSipl-G*uObBg!6XGsc}C$I4w#9%i!*&57oA|`S7<_G?>EQ~Qsq{r5WhbZ|36W|Mb zi+@3ppMHg5$@BQifu(^-AM>p^s(ux@ub9VB4lP22^{mKY!5J&zu~s2ANNG_8le?63 zn&ffH412+$XPu7|{;fK;4BErDc3$SOfW|FntXO3HA2V$9?VK9IPrRSu7^liO%rd<$ zvo0BWrTbNE8OUzZH-c)8Oig2d_JhwQ`DP1^5%U=2^BU?IMel*bSn!>KN@^@4H%kA8 zJYF5)Ci$3hz9nLEGX=1qj(kFX1gsi-GX(R(A${uzycB-p7^)?yar69J4b8jM#H;Cy zZ*z!ebjCIK2Hbzvc!4t>x{*75JjKyf zg1Z|N?~Tnh-@Az9dp`5RuQRMKpJjOf*x_3gm=FM{b1l zogbqsSDk)mLbG=v!8^@fG0**6Vw-NhP4o)GHI`~$;{2Fm?`ryq7{A9EzfZ7TdW~sW zW7{wnn$?aZYm+8V>3CV-)sw6ze~N#f2+fK-;^mZMR{@_T9_LT-?-M*vEAcpU4u1mY z`G1Ld3(wQ41xi@Mv!CZ@ewk_UBtK*3DbVk${LHT~z2O<01?YRPao_*4{$1vKkLl~L zbANxDuRnpdXC9+vIR91syTsQo^YtaZ4&U~CDulgq=P~MoZ#(^nf0wxbH=OJ6&7rFp zrOacV_etma3Pg?iI;?htZ+QJ0UvB}P`uf|f-{v}elV(<5f5*9QzC$#lufNN7$Xvg{ z*WYoj!#Fn&xei|&nC5;i@pTvncGjNK*T2p-+FZZQ&%4(z^YwK9m-zZD;|14$o!i0n zIeq;t?)Nv4j&yxqU;hfj_ZuNadw2Nyn~djgu%G$_Uw?zI{~4q&?Z9w``Sm1Uhy8`0 zWq4j^zCu6vjXQ?_HI|bfh4iKGml)qKvQGSIgq!TsRO%WTUl#c+PZT#&2-`=^$G<8RDe0@;*pyjEE&N-dYZ4uw^sZ(UUL_h>Y7!wc`D1r$1 z0Nppsvh1N1QEGKqnQIJTj4_9b*kG+#OGg^U80(s@5~ju&LkuB=IhUOMZn-$(e_Q-( z*)KVt`@82R=XcKOJ->5r?jO~9&PU(kp4W5#o3@$P$MAYC&to5Ap4W5F{#tfrNG-o=Kbqh_wP6n8etCXeLpeKqM~_cHkXe!n=U=<0PybSoaSl z>^U3Za_)=M%X)N9h7I!9#Kbz%Y2g^q; z%Zr-jr-6i$q6wuN2-LmK=%=4aH{oNL&M2>&M(yx!c$sd&t7$T$sCg1uAh;aN*fNoBA2J4# zwW2M6tmP(u>NsHbqmKRUzSObLqN0v6tCDObHXj~)I~8Orw#&)3r%N`9?+d%x%!A!M zQXU1p-W;UVp>}vbgOsfKPVZ-s((OE#HwP(MINZv2$*A3fJhzN)@{p4`&#fR+zT1bc z^H5S-zFS2`wcD4jsoj3ms&@NROMyFpt`xWf=~AI9kS-Ux*lD55pRN?SeCcYDOGQ_U zohoWAb}FfLuhWOFl{gqm9SXWu=8%(dUoV^O@0E871`hVf?V^X}J<=Z}_ba-+e^m4x z>X!VZaKGQ>^|Ox)UE*JSoDkZ@PNf6lPO(eb3yDqqtEvayHqjkbH)K}v9p5e}EaE;t zJCyC>et#SM%wGKgRs@*5ehai9s7-P=$c$j4qQ-Z!?gM@xBtP?R+e*sZl9?@4j zi5hdrB6zT!=-W)9=J&`dc$C2~kWNNS zXPe;Hm(zv-_f8{%TzM@BcB(HU#Id^>Q+oF_;gz0}22AhXSBIHh2Mw5QKdi?b8$>$H tw?d}DQnn4o^ZhrOZI4^|o}1kW>|(vPzyOr6K6|+GUvIpN{{nOA_!O#UQJVk& literal 26386 zcmZ^}b8sb0@Gcx~Y}>YNb7R}~p4hgr(Z)W}$%*Z3tP^9CY|ITe+WY=)-LL9HegDjK zb#?Xh%yd^j^;G*6UiCSq*-U&V%(>|ccs##;%YXawC9n9b?pi2d5LQ5v6iyKe4jQ}1 zc-eGWTh><}R2TR~22Ms)I^#oO7o5|R)mv{$#=>M{+>eVc1Zl_3A=QhLesZFl2E4>& z%aj^K6AdOnyzmWBkKR+>x$kwq=|B2J!Z}hdXy4fO&%9sXOmp1-4*aZC=PX69?F zsM2w>28RTKx*!@ug+F)d_FVSWwCc_B3q&NU4^r5T^nRcJo<<=cAYh+gtGg%Awd-r7 zAP((s=?=PN3Pvg-4eVOn5Y^M3nzcKG$k&&T-`P|b)F;4H(thXn5 zB>%&}?L5Jn116Z)ZuSvR*K%E-WSV1d*TI3?!9&NgvL&Rit9!%Yf_>mmOhS_@pMI{c zPG1cY7-Do?18Z)$oYmdE=r#k<7jRoiWfO2CAE|y=?#Q1m5YTDk6sT?$AfC-8DPXQM zUCeTKca;4(@cLv|-Vf<|ecE2_5ZDB&p

tz3Iw+Y%e8`FBK4vSB@K52WKJ=_%{YT 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 diff --git a/assets/sprites/liquids/bound-aspect.png b/assets/sprites/liquids/bound-aspect.png new file mode 100644 index 0000000000000000000000000000000000000000..ecbb649b3f179003992706ba2931124522c68d53 GIT binary patch literal 351 zcmV-l0igbgP)Px$8A(JzR9J=Omb($cKnz3=h7uf8f^+xaoYZwtfa@T2?jFb~!7)9Uh#4&FyE+1f zjqr!tC+W^oDZi|FSk`%1*325mjCsa51yIWz29Si5Bn;p&h(Lq@xP|-M`4Cwn1)!Ou z`@#)C4Xnt$Ku`vkp8`4vTQ`G!AUp64`-;d|Leg-siDlQ`_ z0OVL95bjN=MUT9v0@Q3a)>^xb!~G!|RVk&6{j|B3j;UD!#5|&^?f6p^Tq?y;dr69Z z?5ACdxqBX&A0kbNAr({tDKp4^Q313FsTsZYX6Gx%kTaK#A$t>rkfPRFwfGelu!@%z(gmb@DL$E)SMIlOE0Px$yGcYrR9J=WS37FMKoA`TAH_J>X`&)v$Q?{dfnB5zhSWJgYJ+jFA_kYicMvS3 zuo|sV*t19}oK^NaJNkq)d6ib$(R=%5W>*6EV?@-6AFmI!I=*{(C&%^@U=q8~M+_QB zA@3`~8`Or}6wxMK&Iet{sp5hHo)(K50N` { int a = 0; for(int i = 0; i < 5; i++){ @@ -724,24 +746,9 @@ public static void load(){ a = (int)Math.max(a, b.getPin(i)); } b.setPin(ModOUT.FIVE, a); - - /* - int firstValid = -1; - for(int i = 0; i < 5; i++){ - if(firstValid != -1){ - b.setPin(i, 0); - continue; - } - - float pinValue = b.getPin(i); - if(pinValue > 0){ - firstValid = i; - } - } - */ }; }}, - new ConsumeLiquidModule(LiquidStack.with(MeldLiquids.aspect, outletRate * 2), ModIN.FIVE, ModOUT.SIX), + new ConsumeAspectModule(outletRate * 2, MeldLiquids.aspectEfficiencies, MeldLiquids.aspectDensities, ModIN.FIVE, ModOUT.SIX), new RecipeCraftingModule(){{ recipe = shadesteel; efficiencyPins = new int[]{ModIN.SIX, ModIN.ZERO}; @@ -785,7 +792,7 @@ public static void load(){ itemCapacity = 48; - acceptedLiquids.addAll(MeldLiquids.aspect); + acceptedLiquids.addAll(MeldLiquids.aspect, MeldLiquids.boundAspect); acceptedItems.addAll(MeldItems.tenbris, MeldItems.clayMallows, MeldItems.carbolith, MeldItems.debris, MeldItems.shadesteel, MeldItems.glassMallows, MeldItems.silver); dumpedItems.addAll(MeldItems.cruciblePlating, MeldItems.shadesteel, MeldItems.glassMallows, MeldItems.annealedSilver); @@ -802,7 +809,7 @@ public static void load(){ modules.addAll( //Set the base rate based on aspect intake - new ConsumeLiquidModule(LiquidStack.with(MeldLiquids.aspect, outletRate * 8), 0, 1), + new ConsumeAspectModule(outletRate * 8, MeldLiquids.aspectEfficiencies, MeldLiquids.aspectDensities, 0, 1), //Setup the flags for possible recipies new GateModule( ModOUT.TWO, @@ -888,7 +895,7 @@ public static void load(){ itemCapacity = 10; - acceptedLiquids.addAll(MeldLiquids.aspect); + acceptedLiquids.addAll(MeldLiquids.aspect, MeldLiquids.boundAspect); acceptedItems.addAll(MeldItems.shadesteel, MeldItems.elnarDust, MeldItems.debris, MeldItems.annealedSilver); dumpedItems.addAll(MeldItems.aspectPipe); @@ -958,12 +965,9 @@ public static void load(){ range = 220; liquidCapacity = 8 * outletRate * 60; + hasLiquids = true; - consume( - new ConsumeLiquid( - MeldLiquids.aspect, 2 * outletRate - ) - ); + consume(new ConsumeAspects(outletRate * 2, MeldLiquids.aspectEfficiencies, MeldLiquids.aspectDensities)); }}; movementAnchor = new MovementAnchor("movement-anchor"){{ @@ -975,11 +979,7 @@ public static void load(){ health = 1200; range = 22 * Vars.tilesize; - consume( - new ConsumeLiquid( - MeldLiquids.aspect, 3 * outletRate - ) - ); + consume(new ConsumeAspects(outletRate * 3, MeldLiquids.aspectEfficiencies, MeldLiquids.aspectDensities)); }}; nullifier = new Nullifier("nullifier"){{ diff --git a/src/meld/content/MeldLiquids.java b/src/meld/content/MeldLiquids.java index b6cdfba..76613d6 100644 --- a/src/meld/content/MeldLiquids.java +++ b/src/meld/content/MeldLiquids.java @@ -2,15 +2,20 @@ import arc.graphics.Color; import arc.struct.ObjectFloatMap; +import arc.struct.ObjectMap; import mindustry.type.Liquid; public class MeldLiquids { public static Liquid aether, aspect, meld, fumes, - pollutantMixture; + pollutantMixture, boundAspect; public static ObjectFloatMap aetherEfficiencies = new ObjectFloatMap<>(); + public static ObjectFloatMap aspectEfficiencies = new ObjectFloatMap<>(); + public static ObjectFloatMap aspectDensities = new ObjectFloatMap<>(); + public static ObjectMap outletMapping = new ObjectMap<>(); + public static void load(){ aether = new Liquid("aether"){{ gas = true; @@ -44,8 +49,25 @@ public static void load(){ temperature = 0.6f; }}; - aetherEfficiencies.put(aether, 1); - aetherEfficiencies.put(pollutantMixture, 0.5f); + boundAspect = new Liquid("bound-aspect"){{ + gas = true; + color = Color.valueOf("d7a9ef"); + temperature = 0.6f; + }}; + + aetherEfficiencies.put(aether, 10); + aetherEfficiencies.put(pollutantMixture, 1f); + + aspectEfficiencies.put(aspect, 1); + aspectEfficiencies.put(boundAspect, 1); + + aspectDensities.put(aspect, 1); + aspectDensities.put(boundAspect, 5); + + outletMapping.putAll( + aether, aspect, + pollutantMixture, boundAspect + ); } } diff --git a/src/meld/world/blocks/AspectPipe.java b/src/meld/world/blocks/AspectPipe.java index a9601ce..9f8bca3 100644 --- a/src/meld/world/blocks/AspectPipe.java +++ b/src/meld/world/blocks/AspectPipe.java @@ -6,6 +6,7 @@ import arc.math.geom.Geometry; import arc.util.Tmp; import meld.content.MeldLiquids; +import meld.world.blocks.crafting.RecipeCrafter; import mindustry.Vars; import mindustry.gen.Building; import mindustry.graphics.Drawf; @@ -16,6 +17,8 @@ import mindustry.world.blocks.liquid.Conduit; import mindustry.world.blocks.liquid.LiquidRouter; +import static meld.content.MeldLiquids.aetherEfficiencies; +import static meld.content.MeldLiquids.outletMapping; import static mindustry.Vars.renderer; import static mindustry.Vars.tilesize; @@ -45,7 +48,7 @@ public void updateTile() { //get the tile above and below the current pipe, accounting for rotation Tile t = Vars.world.tile(tile.x + Geometry.d4(1 + i * 2 + rotation).x, tile.y + Geometry.d4(1 + i * 2 + rotation).y); - if(t == null || t.build == null || !t.build.block.hasLiquids || t.build.liquids == null || t.build.block.consumers.length == 0) continue; + if(t == null || t.build == null || !t.build.block.hasLiquids || t.build.liquids == null || (!(t.build.block instanceof RecipeCrafter) && t.build.block.consumers.length == 0)) continue; moveLiquid(t.build, liquids.current()); } @@ -83,10 +86,11 @@ public float moveLiquid(Building other, Liquid liquid) { } } + Liquid outletProduct = outletMapping.get(liquid); //At the same time try dumping aspect - if(!(other instanceof ConduitBuild || other instanceof LiquidRouter.LiquidRouterBuild) && liquid == MeldLiquids.aether && this.canDumpLiquid(other, MeldLiquids.aspect)) { + if(outletProduct != null && !(other instanceof ConduitBuild || other instanceof LiquidRouter.LiquidRouterBuild) && this.canDumpLiquid(other, outletProduct)) { Liquid original = liquid; - liquid = MeldLiquids.aspect; + liquid = outletProduct; float ofract = other.liquids.get(liquid) / other.block.liquidCapacity; float fract = this.liquids.get(original) / this.block.liquidCapacity; @@ -97,7 +101,7 @@ public float moveLiquid(Building other, Liquid liquid) { float flow = Math.min(other.block.liquidCapacity - other.liquids.get(liquid), amount) * 10; if (other.acceptLiquid(this, liquid)) { other.handleLiquid(this, liquid, flow); - this.liquids.remove(original, flow/10); + this.liquids.remove(original, flow/aetherEfficiencies.get(outletProduct, 1)); total += amount; } @@ -106,33 +110,5 @@ public float moveLiquid(Building other, Liquid liquid) { } return total; } - - @Override - public void transferLiquid(Building next, float amount, Liquid liquid) { - transferLiquid(next, amount, liquid, false); - } - - //Translating original liquid to the pipe's target liquid; - public void transferLiquid(Building next, float amount, Liquid liquid, boolean translating){ - - if(translating){ - Liquid original = liquid; - liquid = MeldLiquids.aspect; - - float flow = Math.min(next.block.liquidCapacity - next.liquids.get(liquid), amount); - if (next.acceptLiquid(this, liquid)) { - next.handleLiquid(this, liquid, flow); - this.liquids.remove(original, flow/10); - } - - return; - } - - float flow = Math.min(next.block.liquidCapacity - next.liquids.get(liquid), amount); - if (next.acceptLiquid(this, liquid)) { - next.handleLiquid(this, liquid, flow); - this.liquids.remove(liquid, flow); - } - } } } diff --git a/src/meld/world/blocks/LiquidUtil.java b/src/meld/world/blocks/LiquidUtil.java index ed0d46f..2312a46 100644 --- a/src/meld/world/blocks/LiquidUtil.java +++ b/src/meld/world/blocks/LiquidUtil.java @@ -1,5 +1,6 @@ package meld.world.blocks; +import arc.util.Log; import mindustry.gen.Building; import mindustry.type.LiquidStack; import mindustry.world.modules.LiquidModule; @@ -8,14 +9,16 @@ public class LiquidUtil { public static boolean hasAll(LiquidStack[] liquids, Building build){ for(LiquidStack stack: liquids){ - if(build.liquids.get(stack.liquid) <= 0) return false; + if(!(build.liquids.get(stack.liquid) < stack.amount)) return false; } return true; } public static boolean has(LiquidStack[] liquids, Building build){ for(LiquidStack stack: liquids){ - if(!(build.liquids.get(stack.liquid) < 0)) return false; + if(build.liquids.get(stack.liquid) <= 0) { + return false; + } } return true; } @@ -30,4 +33,10 @@ public static void remove(LiquidStack[] liquids, LiquidModule module){ module.remove(liquid.liquid, liquid.amount); } } + + public static void add(LiquidStack[] liquids, Building build, Building source){ + for(var liquid: liquids){ + build.handleLiquid(source, liquid.liquid, liquid.amount); + } + } } diff --git a/src/meld/world/blocks/consumers/ConsumeAspects.java b/src/meld/world/blocks/consumers/ConsumeAspects.java index c6a18bc..3dc0d47 100644 --- a/src/meld/world/blocks/consumers/ConsumeAspects.java +++ b/src/meld/world/blocks/consumers/ConsumeAspects.java @@ -13,21 +13,22 @@ import mindustry.world.Block; import mindustry.world.consumers.*; -public class ConsumeAspects extends ConsumeLiquidBase implements MeldGenericCrafter.BarConsumer { +public class ConsumeAspects extends ConsumeLiquidFilter implements MeldGenericCrafter.BarConsumer { - public ObjectFloatMap efficiencyMap; + public ObjectFloatMap efficiencyMap, densityMap; - public ConsumeAspects(float amount, ObjectFloatMap efficiencyMap){ + public ConsumeAspects(float amount, ObjectFloatMap efficiencyMap, ObjectFloatMap densityMap){ super(); this.efficiencyMap = efficiencyMap; + this.densityMap = densityMap; this.amount = amount; + filter = efficiencyMap::containsKey; } private static Liquid currentBest; - - + @Override public void apply(Block block) { block.hasLiquids = true; Vars.content.liquids().each(l -> efficiencyMap.containsKey(l), (item) -> { @@ -40,11 +41,13 @@ public boolean consumes(Liquid liquid) { return efficiencyMap.containsKey(liquid); } + @Override public void update(Building build) { - build.liquids.remove(getConsumed(build), this.amount * build.edelta() * this.multiplier.get(build)); + Liquid consumed = getConsumed(build); + build.liquids.remove(consumed, this.amount * build.edelta()/densityMap.get(consumed, 1)); } - + @Override public Liquid getConsumed(Building build){ float highest = 0; currentBest = null; @@ -67,7 +70,9 @@ public float efficiency(Building build) { float ed = build.edelta(); if(Mathf.zero(ed)) return 0; else { + float multi = efficiencyMap.get(liq, 0); + return liq != null ? Math.min(build.liquids.get(liq) / (this.amount * ed * multi), multi) : 0; } } diff --git a/src/meld/world/blocks/crafting/ModularCrafter.java b/src/meld/world/blocks/crafting/ModularCrafter.java index fc836ce..a56528b 100644 --- a/src/meld/world/blocks/crafting/ModularCrafter.java +++ b/src/meld/world/blocks/crafting/ModularCrafter.java @@ -127,67 +127,6 @@ public void update(ModularCrafterBuild build){ public abstract void craft(ModularCrafterBuild build); } - public static class AttributeModule extends CrafterModule{ - public int efficiencyPin; - - public Attribute attribute; - public float baseEfficiency = 1; - public float boostScale = 1; - public float maxBoost = 1; - public float minEfficiency = -1; - - @Override - public void update(ModularCrafterBuild build) { - float efficiency = baseEfficiency + Math.min(maxBoost, boostScale * build.block.sumAttribute(attribute, build.tileX(), build.tileY()) + attribute.env()); - - Log.info(efficiency); - - if(minEfficiency != -1 && efficiency < minEfficiency) { - build.setPin(efficiencyPin, 0); - return; - } - - build.data.put(efficiencyPin, efficiency); - } - } - - public static class ItemCraftingModule extends CraftingModule{ - public ItemStack outputItem; - public ItemStack[] outputItems; - - public ItemStack[] inputItems; - - @Override - public void update(ModularCrafterBuild build) { - super.update(build); - } - - @Override - public boolean canCraft(ModularCrafterBuild build) { - if(outputItems != null){ - for(var output : outputItems){ - if(build.items.get(output.item) + output.amount >= build.block.itemCapacity){ - return false; - } - } - } - if(outputItem != null && build.items.get(outputItem.item) + outputItem.amount >= build.block.itemCapacity) return false; - return true; - } - - @Override - public void craft(ModularCrafterBuild build) { - if(outputItem != null) build.items.add(outputItem.item, outputItem.amount); - - if(inputItems != null) build.items.remove(inputItems); - - if(outputItems != null) { - for (ItemStack item : outputItems) { - build.items.add(item.item, item.amount); - } - } - } - } //Just some static finals to help readability public static class ModOUT{ diff --git a/src/meld/world/blocks/crafting/RecipeCrafter.java b/src/meld/world/blocks/crafting/RecipeCrafter.java new file mode 100644 index 0000000..80527b5 --- /dev/null +++ b/src/meld/world/blocks/crafting/RecipeCrafter.java @@ -0,0 +1,285 @@ +package meld.world.blocks.crafting; + +import arc.Core; +import arc.func.Func; +import arc.graphics.Color; +import arc.graphics.g2d.TextureRegion; +import arc.math.Mathf; +import arc.struct.ObjectMap; +import arc.struct.Seq; +import arc.util.Eachable; +import arc.util.io.Reads; +import arc.util.io.Writes; +import meld.world.blocks.crafting.recipe.ItemRecipe; +import meld.world.blocks.crafting.recipe.Recipe; +import meld.world.blocks.crafting.recipe.TimedRecipe; +import mindustry.Vars; +import mindustry.entities.units.BuildPlan; +import mindustry.gen.Building; +import mindustry.type.Item; +import mindustry.type.ItemStack; +import mindustry.type.Liquid; +import mindustry.type.LiquidStack; +import mindustry.ui.Bar; +import mindustry.world.Block; +import mindustry.world.blocks.production.GenericCrafter; +import mindustry.world.draw.DrawBlock; +import mindustry.world.draw.DrawDefault; + +//HAAHHHAHAHAHHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +//So on top of basic crafter functions we have... uh... yeah....... +public class RecipeCrafter extends Block { + + public ObjectMap outputDirections = new ObjectMap<>(); + + private static final Seq tmpSlots = new Seq<>(); + + public RecipeCrafter(String name) { + super(name); + update = true; + solid = true; + } + + public void setRecipes(TimedRecipe... recipies){ + this.recipes.set(recipies); + } + + public int inputLiquidSlots, outputLiquidSlots; + + //list of items/liquids which this block accepts + public Seq inputLiquids = new Seq<>(); + public Seq inputItems = new Seq<>(); + + //List of items/liquids which get dumped + public Seq outputLiquids = new Seq<>(); + public Seq outputItems = new Seq<>(); + + public Seq recipes = new Seq<>(); + + public DrawBlock drawer = new DrawDefault(); + + @Override + public void drawPlanRegion(BuildPlan plan, Eachable list){ + drawer.drawPlan(this, plan, list); + } + + @Override + public TextureRegion[] icons(){ + return drawer.finalIcons(this); + } + + @Override + public boolean outputsItems(){ + return outputItems != null; + } + + @Override + public void getRegionsToOutline(Seq out){ + drawer.getRegionsToOutline(this, out); + } + + @Override + public void init() { + super.init(); + + //MeldBlocks.aspectOutlet.inputLiquids.add(MeldLiquids.aether);MeldBlocks.aspectOutlet.outputLiquids.add(MeldLiquids.aspect) + recipes.each(recipe -> { + if(recipe.inputItems != null) for(ItemStack item: recipe.inputItems){ + inputItems.add(item.item); + itemFilter[item.item.id] = true; + } + if(recipe.outputItems != null) for(ItemStack item: recipe.outputItems){ + outputItems.add(item.item); + } + if(recipe.inputLiquids != null) for(LiquidStack item: recipe.inputLiquids){ + inputLiquids.add(item.liquid); + liquidFilter[item.liquid.id] = true; + } + if(recipe.outputLiquids != null) for(LiquidStack item: recipe.outputLiquids){ + outputLiquids.add(item.liquid); + } + }); + } + + //Just addLiquidBar but with a name + public void addLiquidBar(String name, Func current){ + addBar(name, entity -> new Bar( + () -> current.get((T)entity) == null || entity.liquids.get(current.get((T)entity)) <= 0.001f ? Core.bundle.get("bar.liquid") : current.get((T)entity).localizedName, + () -> current.get((T)entity) == null ? Color.clear : current.get((T)entity).barColor(), + () -> current.get((T)entity) == null ? 0f : entity.liquids.get(current.get((T)entity)) / liquidCapacity) + ); + } + + + @Override + public void setBars() { + super.setBars(); + + if(inputLiquidSlots + outputLiquidSlots > 0){ + removeBar("liquid"); + for(int i = 0; i < inputLiquidSlots; i++){ + final int j = i; + addLiquidBar("liquid-in" + i, build -> { + RecipeCrafterBuild crafter = ((RecipeCrafterBuild) build); + return crafter.inputSlots.size <= j ? null : crafter.inputSlots.get(j); + }); + } + + for(int i = 0; i < outputLiquidSlots; i++){ + final int j = i; + addLiquidBar("liquid-out" + i, build -> { + RecipeCrafterBuild crafter = ((RecipeCrafterBuild) build); + return crafter.outputSlots.size <= j ? null : crafter.outputSlots.get(j); + }); + } + } + } + + @Override + public void load(){ + super.load(); + + drawer.load(this); + } + + public class RecipeCrafterBuild extends Building{ + + RecipeCrafter crafter; + public TimedRecipe recipe = null; + + public int last = -1; + public float[] times; + + public Seq inputSlots = new Seq<>(), outputSlots = new Seq<>(); + + @Override + public void created() { + super.created(); + crafter = (RecipeCrafter) block; + times = new float[recipes.size]; + } + + @Override + public void draw(){ + drawer.draw(this); + } + + @Override + public void drawLight(){ + super.drawLight(); + drawer.drawLight(this); + } + + @Override + public void transferLiquid(Building next, float amount, Liquid liquid) { + super.transferLiquid(next, amount, liquid); + } + + @Override + public boolean acceptLiquid(Building source, Liquid liquid) { + //If the respective slot is full, don't accept any more liquids + if(source == this ? + !outputSlots.contains(liquid) && outputSlots.size >= outputLiquidSlots + : + !inputSlots.contains(liquid) && inputSlots.size >= inputLiquidSlots + ) return false; + + return super.acceptLiquid(source, liquid); + } + + + @Override + public void handleLiquid(Building source, Liquid liquid, float amount) { + //TODO: Handle multislot + if(inputLiquids.contains(liquid) && outputLiquids.contains(liquid)){ + + } + + Seq slots = source == this ? outputSlots : inputSlots; + if(!slots.contains(liquid)){ + slots.add(liquid); + } + + this.liquids.add(liquid, amount); + } + + @Override + public void updateTile() { + super.updateTile(); + + tmpSlots.set(inputSlots); + tmpSlots.each(l -> { + if(Mathf.zero(liquids.get(l))) inputSlots.remove(l); + }); + tmpSlots.set(outputSlots); + tmpSlots.each(l -> { + if(Mathf.zero(liquids.get(l))) outputSlots.remove(l); + }); + + if(recipe != null && recipe.valid(block, this)){ + recipe.update(block, this); + float time = times[last]; + time += efficiency; + if(time >= recipe.craftTime){ + recipe.apply(crafter, this); + time %= recipe.craftTime; + } + times[last] = time; + } + else { + recipe = recipes.find(r -> r.valid(crafter, this)); + if(recipe != null) last = recipes.indexOf(recipe); + } + + dumpOutputs(); + } + + + public void dumpOutputs(){ + if(outputSlots.size > 0){ + + for(Liquid output: outputSlots){ + if(!outputDirections.containsKey(output)) { + dumpLiquid(output); + continue; + } + + int[] dirs = outputDirections.get(output); + for(int dir: dirs){ + dumpLiquid(output, 2f, dir); + } + } + } + } + + @Override + public void write(Writes write) { + super.write(write); + write.i(last); + write.i(times.length); + for(float f: times){ + write.f(f); + } + } + + @Override + public void read(Reads read, byte revision) { + super.read(read, revision); + last = read.i(); + int length = read.i(); + + times = new float[recipes.size]; + for(int i = 0; i < length; i++){ + times[i] = read.i(); + } + rehashSlots(); + } + + public void rehashSlots(){ + Vars.content.liquids().each(l -> { + if(outputLiquids.contains(l)) outputSlots.add(l); + if(inputLiquids.contains(l)) inputSlots.add(l); + }); + } + } +} diff --git a/src/meld/world/blocks/crafting/modules/AttributeModule.java b/src/meld/world/blocks/crafting/modules/AttributeModule.java new file mode 100644 index 0000000..600085e --- /dev/null +++ b/src/meld/world/blocks/crafting/modules/AttributeModule.java @@ -0,0 +1,27 @@ +package meld.world.blocks.crafting.modules; + +import arc.util.Log; +import meld.world.blocks.crafting.ModularCrafter; +import mindustry.world.meta.Attribute; + +public class AttributeModule extends ModularCrafter.CrafterModule { + public int efficiencyPin; + + public Attribute attribute; + public float baseEfficiency = 1; + public float boostScale = 1; + public float maxBoost = 1; + public float minEfficiency = -1; + + @Override + public void update(ModularCrafter.ModularCrafterBuild build) { + float efficiency = baseEfficiency + Math.min(maxBoost, boostScale * build.block.sumAttribute(attribute, build.tileX(), build.tileY()) + attribute.env()); + + if(minEfficiency != -1 && efficiency < minEfficiency) { + build.setPin(efficiencyPin, 0); + return; + } + + build.data.put(efficiencyPin, efficiency); + } +} \ No newline at end of file diff --git a/src/meld/world/blocks/crafting/modules/ConsumeAspectModule.java b/src/meld/world/blocks/crafting/modules/ConsumeAspectModule.java new file mode 100644 index 0000000..3f32c21 --- /dev/null +++ b/src/meld/world/blocks/crafting/modules/ConsumeAspectModule.java @@ -0,0 +1,58 @@ +package meld.world.blocks.crafting.modules; + +import arc.math.Mathf; +import arc.struct.ObjectFloatMap; +import arc.struct.ObjectMap; +import meld.world.blocks.crafting.ModularCrafter; +import mindustry.type.Liquid; +import mindustry.type.LiquidStack; + +public class ConsumeAspectModule extends ModularCrafter.CrafterModule{ + public ObjectFloatMap efficiencyMap; + public ObjectFloatMap densityMap; + + float consumeRate; + public int efficiencyPin; + public int outputEfficiencyPin; + + public ConsumeAspectModule(float consumeRate, ObjectFloatMap efficiencyMap, ObjectFloatMap densityMap, int efficiencyPin, int outputEfficiencyPin) { + this.consumeRate = consumeRate; + this.efficiencyMap = efficiencyMap; + this.densityMap = densityMap; + this.efficiencyPin = efficiencyPin; + this.outputEfficiencyPin = outputEfficiencyPin; + } + + @Override + public void update(ModularCrafter.ModularCrafterBuild build) { + float efficiency = build.getPin(efficiencyPin); + if(efficiency == 0) return; + + float highest = 0; + Liquid liquid = null; + for(Liquid aspect: efficiencyMap.keys()){ + if(!Mathf.zero(build.liquids.get(aspect))){ + float current = efficiencyMap.get(aspect, 1); + if(current > highest){ + liquid = aspect; + highest = current; + } + } + } + + if(liquid == null){ + build.setPin(outputEfficiencyPin, 0); + return; + } + + float amount = build.liquids.get(liquid); + float consumeAmount = consumeRate * efficiency/densityMap.get(liquid, 1); + float maxEfficiency = Math.min(amount/consumeAmount, 1); + + consumeAmount *= maxEfficiency; + + build.liquids.remove(liquid, consumeAmount); + + build.setPin(outputEfficiencyPin, efficiency * maxEfficiency * efficiencyMap.get(liquid, 1)); + } +} diff --git a/src/meld/world/blocks/crafting/recipe/ItemRecipe.java b/src/meld/world/blocks/crafting/recipe/ItemRecipe.java index 3b887d3..97e5644 100644 --- a/src/meld/world/blocks/crafting/recipe/ItemRecipe.java +++ b/src/meld/world/blocks/crafting/recipe/ItemRecipe.java @@ -1,5 +1,7 @@ package meld.world.blocks.crafting.recipe; +import arc.util.Log; +import arc.util.Nullable; import meld.world.blocks.LiquidUtil; import mindustry.gen.Building; import mindustry.type.ItemStack; @@ -7,10 +9,15 @@ import mindustry.world.Block; public class ItemRecipe extends Recipe{ + + @Nullable public ItemStack[] inputItems; + @Nullable public ItemStack[] outputItems; + @Nullable public LiquidStack[] inputLiquids; + @Nullable public LiquidStack[] outputLiquids; public ItemRecipe(){ @@ -38,10 +45,12 @@ public boolean valid(Block block, Building build){ } } } - if(inputLiquids != null && !LiquidUtil.has(inputLiquids, build)) return false; + if(inputLiquids != null && !LiquidUtil.has(inputLiquids, build)) { + return false; + } //Set the output to zero if the build doesn't have the items, otherwise set it to whatever the out is - return build.items.has(inputItems); + return build.items == null || build.items.has(inputItems); } @Override @@ -55,7 +64,7 @@ public void apply(Block block, Building building) { } if(inputLiquids != null) LiquidUtil.remove(inputLiquids, building.liquids); - if(outputLiquids != null) LiquidUtil.add(outputLiquids, building.liquids); + if(outputLiquids != null) LiquidUtil.add(outputLiquids, building, building); } //Builder methods diff --git a/src/meld/world/blocks/crafting/recipe/Recipe.java b/src/meld/world/blocks/crafting/recipe/Recipe.java index f52eef3..846f8d1 100644 --- a/src/meld/world/blocks/crafting/recipe/Recipe.java +++ b/src/meld/world/blocks/crafting/recipe/Recipe.java @@ -7,6 +7,8 @@ public abstract class Recipe { public abstract boolean valid(T block, A building); public abstract void apply(T block, A building); - public void update(T block, A building) { - } + public void update(T block, A building) {} + //accepted liquids ey? + public void init(T block) {} + } diff --git a/src/meld/world/blocks/crafting/recipe/TimedRecipe.java b/src/meld/world/blocks/crafting/recipe/TimedRecipe.java new file mode 100644 index 0000000..f935a84 --- /dev/null +++ b/src/meld/world/blocks/crafting/recipe/TimedRecipe.java @@ -0,0 +1,10 @@ +package meld.world.blocks.crafting.recipe; + +import meld.world.blocks.crafting.RecipeCrafter; + +public class TimedRecipe extends ItemRecipe { + + + public float craftTime = 60; + +} diff --git a/src/meld/world/meta/ContentTags.java b/src/meld/world/meta/ContentTags.java new file mode 100644 index 0000000..2353291 --- /dev/null +++ b/src/meld/world/meta/ContentTags.java @@ -0,0 +1,9 @@ +package meld.world.meta; + +import arc.struct.ObjectMap; +import arc.struct.Seq; +import mindustry.ctype.UnlockableContent; + +public class ContentTags { + public ObjectMap>[] tagMap; +} From c39e5acdf68ab3e8f3150231fd9cf5e40be83118 Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Thu, 2 Apr 2026 11:48:31 +1100 Subject: [PATCH 10/17] Stat tweaking --- assets/bundles/bundle.properties | 2 +- src/meld/content/MeldBlocks.java | 12 +++++++----- src/meld/content/MeldLiquids.java | 24 +++++++++++++++++++++--- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index 725db31..cb6dd24 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -149,7 +149,7 @@ block.meld-channel-node.name = Channel Node block.meld-channel-node.description = Acts as a fluid router. Liquid can be input or output from any side. Stores a small amount of fluid. block.meld-aspect-outlet.name = Aspect Outlet -block.meld-aspect-outlet.description = Decompresses [#cb8650]Aether[] into highly volatile [#cbdbfc]Aspect[].\n\nWorks as an output terminal for a fluid network. +block.meld-aspect-outlet.description = Decompresses [#cb8650]Aether[] into highly volatile [#cbdbfc]Aspect[] at a ratio of 1:10.\n\nWorks as an output terminal for a fluid network. block.meld-aspect-channel.name = Aspect Channel block.meld-aspect-channel.description = Acts as a directional router.\n\nWhen transporting [#cb8650]Aether[], fills nearby buildings with highly volatile [#cbdbfc]Aspect[].\n\nWorks as an input/output terminal for a fluid network. diff --git a/src/meld/content/MeldBlocks.java b/src/meld/content/MeldBlocks.java index ecd878c..9417466 100644 --- a/src/meld/content/MeldBlocks.java +++ b/src/meld/content/MeldBlocks.java @@ -172,14 +172,16 @@ public static void load(){ new TimedRecipe(){{ craftTime = 10; float multi = MeldLiquids.aetherEfficiencies.get(MeldLiquids.aether, 1); - inputLiquids = LiquidStack.with(MeldLiquids.aether, outletRate); - outputLiquids = LiquidStack.with(MeldLiquids.aspect, outletRate * multi); + float density = MeldLiquids.aetherDensities.get(MeldLiquids.aether, 1); + inputLiquids = LiquidStack.with(MeldLiquids.aether, outletRate/density); + outputLiquids = LiquidStack.with(MeldLiquids.aspect, outletRate * multi * 10); }}, new TimedRecipe(){{ craftTime = 10; float multi = MeldLiquids.aetherEfficiencies.get(MeldLiquids.pollutantMixture, 1); - inputLiquids = LiquidStack.with(MeldLiquids.pollutantMixture, outletRate); - outputLiquids = LiquidStack.with(MeldLiquids.boundAspect, outletRate * multi); + float density = MeldLiquids.aetherDensities.get(MeldLiquids.pollutantMixture, 1); + inputLiquids = LiquidStack.with(MeldLiquids.pollutantMixture, outletRate/density); + outputLiquids = LiquidStack.with(MeldLiquids.boundAspect, outletRate * multi * 10); }} ); }}; @@ -644,7 +646,7 @@ public static void load(){ range = 8; - consume(new ConsumeLiquid(MeldLiquids.aether, outletRate/2)); + consume(new ConsumeAspects(outletRate/2, MeldLiquids.outletEfficiencies, MeldLiquids.outletDensities)); }}; earthboundInfuser = new ModularCrafter("earthbound-infuser"){{ diff --git a/src/meld/content/MeldLiquids.java b/src/meld/content/MeldLiquids.java index 76613d6..dc6e5d6 100644 --- a/src/meld/content/MeldLiquids.java +++ b/src/meld/content/MeldLiquids.java @@ -3,6 +3,7 @@ import arc.graphics.Color; import arc.struct.ObjectFloatMap; import arc.struct.ObjectMap; +import arc.struct.Seq; import mindustry.type.Liquid; public class MeldLiquids { @@ -11,10 +12,16 @@ public class MeldLiquids { pollutantMixture, boundAspect; public static ObjectFloatMap aetherEfficiencies = new ObjectFloatMap<>(); + public static ObjectFloatMap aetherDensities = new ObjectFloatMap<>(); public static ObjectFloatMap aspectEfficiencies = new ObjectFloatMap<>(); public static ObjectFloatMap aspectDensities = new ObjectFloatMap<>(); + + public static ObjectFloatMap outletEfficiencies = new ObjectFloatMap<>(); + public static ObjectFloatMap outletDensities = new ObjectFloatMap<>(); + public static ObjectMap outletMapping = new ObjectMap<>(); + public float outletRatio = 10; public static void load(){ aether = new Liquid("aether"){{ @@ -55,19 +62,30 @@ public static void load(){ temperature = 0.6f; }}; - aetherEfficiencies.put(aether, 10); - aetherEfficiencies.put(pollutantMixture, 1f); + aetherEfficiencies.put(aether, 1); + aetherEfficiencies.put(pollutantMixture, 1); + + aetherDensities.put(aether, 1); + aetherDensities.put(pollutantMixture, 1/5f); aspectEfficiencies.put(aspect, 1); aspectEfficiencies.put(boundAspect, 1); aspectDensities.put(aspect, 1); - aspectDensities.put(boundAspect, 5); + aspectDensities.put(boundAspect, 2.5f); outletMapping.putAll( aether, aspect, pollutantMixture, boundAspect ); + Seq outletLiquids = Seq.with(aether, pollutantMixture); + + outletLiquids.each(liquid -> { + Liquid aspecti = outletMapping.get(liquid); + outletEfficiencies.put(liquid, aetherEfficiencies.get(liquid, 1) * aspectEfficiencies.get(aspecti, 1)); + outletDensities.put(liquid, aetherDensities.get(liquid, 1) * aspectDensities.get(aspecti, 1)); + }); + } } From f35735543bbbb2e3b5a0edb329b8b6be736fa1ae Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Thu, 2 Apr 2026 19:12:20 +1100 Subject: [PATCH 11/17] I regret nothing. -Added a manual valve -channel vents now fully drain their contents -overflow ducts are priority input splitters, hehehe~ -I SPENT 3 HOURS ON VISUALS FOR A CONDUIT, I HOPE YALL ARE HAPPY -fixed aspect pipes not using a 1:10 conversion ratio --- src/meld/Meld.java | 6 + src/meld/content/MeldBlocks.java | 56 +++++--- src/meld/content/MeldFx.java | 10 ++ src/meld/world/WorldUtil.java | 27 ++++ .../world/blocks/{ => fluid}/AspectPipe.java | 20 +-- src/meld/world/blocks/fluid/ChannelValve.java | 55 ++++++++ .../world/blocks/{ => fluid}/ChannelVent.java | 21 +-- .../blocks/fluid/FlexibleSizeJunction.java | 35 +++++ .../blocks/{ => fluid}/VisualAspectPipe.java | 123 ++++++++++++++++-- .../blocks/items/PriorityInputSplitter.java | 28 ++++ 10 files changed, 327 insertions(+), 54 deletions(-) rename src/meld/world/blocks/{ => fluid}/AspectPipe.java (89%) create mode 100644 src/meld/world/blocks/fluid/ChannelValve.java rename src/meld/world/blocks/{ => fluid}/ChannelVent.java (55%) create mode 100644 src/meld/world/blocks/fluid/FlexibleSizeJunction.java rename src/meld/world/blocks/{ => fluid}/VisualAspectPipe.java (54%) create mode 100644 src/meld/world/blocks/items/PriorityInputSplitter.java diff --git a/src/meld/Meld.java b/src/meld/Meld.java index 74f62a2..8d76219 100644 --- a/src/meld/Meld.java +++ b/src/meld/Meld.java @@ -89,6 +89,12 @@ public void loadContent(){ MeldBlocks.load(); MeldEnvironment.load(); + Vars.content.blocks().each(b -> { + if(b.minfo.mod != null && b.minfo.mod.name.equals("meld")){ + b.deconstructDropAllLiquid = true; + } + }); + delayTime = 5; Events.run(Trigger.update, () -> { diff --git a/src/meld/content/MeldBlocks.java b/src/meld/content/MeldBlocks.java index 9417466..1c9a9c4 100644 --- a/src/meld/content/MeldBlocks.java +++ b/src/meld/content/MeldBlocks.java @@ -8,7 +8,6 @@ import meld.graphics.*; import meld.world.blocks.consumers.ConsumeAspects; import meld.world.blocks.*; -import meld.world.blocks.crafting.MeldGenericCrafter; import meld.world.blocks.crafting.ModularCrafter; import meld.world.blocks.crafting.RecipeCrafter; import meld.world.blocks.crafting.recipe.ItemRecipe; @@ -17,6 +16,10 @@ import meld.world.blocks.crafting.modules.GateModule.ConsumeCondition; import meld.world.blocks.crafting.modules.GateModule.OutputCondition; import meld.world.blocks.crafting.recipe.TimedRecipe; +import meld.world.blocks.fluid.ChannelValve; +import meld.world.blocks.fluid.ChannelVent; +import meld.world.blocks.fluid.VisualAspectPipe; +import meld.world.blocks.items.PriorityInputSplitter; import meld.world.blocks.production.SingleBeamDrill; import meld.world.meta.*; import mindustry.Vars; @@ -70,7 +73,7 @@ public class MeldBlocks { public static ModularCrafter gasKiln, rotaryKiln, pneumaticExtruder; - public static Block channelNode, channelFace, aspectOutlet, aspectChannel, channelVent; + public static Block channelNode, channelFace, aspectOutlet, aspectChannel, channelVent, manualValve; public static Block sunder, molotov, vivisection; @@ -114,23 +117,6 @@ public static void load(){ placeableLiquid = true; }}; - channelVent = new ChannelVent("pressure-vent"){{ - requirements(Category.liquid, with( - MeldItems.debris, 8, - MeldItems.carbolith, - 8 - )); - health = 180; - armor = 1; - - minPressure = 0.25f; - ventRate = 2; - - liquidCapacity = 100; - solid = false; - placeableLiquid = true; - }}; - aspectOutlet = new RecipeCrafter("aspect-outlet"){{ outputDirections.putAll(MeldLiquids.aspect, new int[]{0}, MeldLiquids.boundAspect, new int[]{0}); @@ -201,6 +187,34 @@ public static void load(){ junctionReplacement = channelFace; }}; + channelVent = new ChannelVent("pressure-vent"){{ + requirements(Category.liquid, with( + MeldItems.debris, 8, + MeldItems.carbolith, + 8 + )); + health = 180; + armor = 1; + + minPressure = -0.25f; + ventRate = 0.5f; + + liquidCapacity = 100; + solid = false; + placeableLiquid = true; + }}; + + manualValve= new ChannelValve("manual-valve"){{ + requirements(Category.liquid, with( + MeldItems.debris, 8 + )); + + health = 120; + + solid = false; + placeableLiquid = true; + }}; + sunder = new ItemTurret("sunder"){{ requirements(Category.turret, with( MeldItems.debris, 45, @@ -966,7 +980,7 @@ public static void load(){ range = 220; - liquidCapacity = 8 * outletRate * 60; + liquidCapacity = 1 * outletRate * 60; hasLiquids = true; consume(new ConsumeAspects(outletRate * 2, MeldLiquids.aspectEfficiencies, MeldLiquids.aspectDensities)); @@ -1048,7 +1062,7 @@ public static void load(){ ((Duct) chute).bridgeReplacement = this; }}; - chuteOverflow = new OverflowDuct("chute-overflow"){{ + chuteOverflow = new PriorityInputSplitter("chute-overflow"){{ requirements(Category.distribution, with(MeldItems.debris, 4)); health = 90; speed = 4f; diff --git a/src/meld/content/MeldFx.java b/src/meld/content/MeldFx.java index 58b23d3..9dcbef9 100644 --- a/src/meld/content/MeldFx.java +++ b/src/meld/content/MeldFx.java @@ -5,6 +5,7 @@ import arc.graphics.g2d.Draw; import arc.graphics.g2d.Fill; import arc.graphics.g2d.Lines; +import arc.math.Angles; import arc.math.Interp; import arc.math.Mathf; import arc.math.geom.Position; @@ -22,6 +23,15 @@ public class MeldFx { public static Effect + gasTransfer = new Effect(60, e -> { + Draw.z(Layer.blockUnder); + Draw.color(e.color); + Draw.alpha(e.finpowdown()); + Angles.randLenVectors(e.id, 2, e.fin() * Vars.tilesize * 1.5f, e.rotation,Vars.tilesize/4f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, 2 * e.foutpowdown()); + }); + }), + chain = new Effect(240, e -> { Draw.color(Color.red); if(e.data instanceof Position pos) { diff --git a/src/meld/world/WorldUtil.java b/src/meld/world/WorldUtil.java index 310f9fc..6eabd8d 100644 --- a/src/meld/world/WorldUtil.java +++ b/src/meld/world/WorldUtil.java @@ -1,7 +1,10 @@ package meld.world; +import arc.math.Mathf; +import arc.math.geom.Point2; import arc.struct.Seq; import arc.util.Nullable; +import arc.util.Tmp; import mindustry.world.Tile; import mindustry.world.meta.Attribute; @@ -19,4 +22,28 @@ public static float sumAttribute(@Nullable Attribute attr, int x, int y){ tile.getLinkedTiles(tempTiles); return tempTiles.sumf(other -> other.floor().attributes.get(attr)); } + + //Just to note + //Rotation 0/0: (1, 0) + //Rotation 90/1: (0, 1) + //Rotation 180/2: (-1, 0) + //Rotation 270/3: (0, -1) + + //Really hyper compact and im not sure this is the best way to do it but like + public static int relativeTo(int x1, int y1, int x2, int y2){ + int dx = x2 - x1, dy = y2 - y1; + int ax = Math.abs(dx), ay = Math.abs(dy); + + boolean up = ay > ax; + int rotation = 0; + if(up){ + rotation++; + if(Mathf.sign(dy) == -1) rotation += 2; + return rotation; + } + + //Flippies! + if(Mathf.sign(dx) == -1) rotation += 2; + return rotation; + } } diff --git a/src/meld/world/blocks/AspectPipe.java b/src/meld/world/blocks/fluid/AspectPipe.java similarity index 89% rename from src/meld/world/blocks/AspectPipe.java rename to src/meld/world/blocks/fluid/AspectPipe.java index 9f8bca3..5b2028c 100644 --- a/src/meld/world/blocks/AspectPipe.java +++ b/src/meld/world/blocks/fluid/AspectPipe.java @@ -1,26 +1,17 @@ -package meld.world.blocks; +package meld.world.blocks.fluid; -import arc.graphics.g2d.Draw; -import arc.graphics.g2d.TextureRegion; import arc.math.Mathf; import arc.math.geom.Geometry; -import arc.util.Tmp; -import meld.content.MeldLiquids; import meld.world.blocks.crafting.RecipeCrafter; import mindustry.Vars; import mindustry.gen.Building; -import mindustry.graphics.Drawf; -import mindustry.graphics.Layer; import mindustry.type.Liquid; import mindustry.world.Block; import mindustry.world.Tile; import mindustry.world.blocks.liquid.Conduit; import mindustry.world.blocks.liquid.LiquidRouter; -import static meld.content.MeldLiquids.aetherEfficiencies; -import static meld.content.MeldLiquids.outletMapping; -import static mindustry.Vars.renderer; -import static mindustry.Vars.tilesize; +import static meld.content.MeldLiquids.*; public class AspectPipe extends Conduit { static final float rotatePad = 6, hpad = rotatePad / 2f / 4f; @@ -37,10 +28,13 @@ public boolean blends(Tile tile, int rotation, int otherx, int othery, int other public class AspectPipeBuild extends ConduitBuild{ + public float lastMoved = 0; + public void updateTile() { + lastMoved = 0; this.smoothLiquid = Mathf.lerpDelta(this.smoothLiquid, this.liquids.currentAmount() / liquidCapacity, 0.05F); if (this.liquids.currentAmount() > 1.0E-4F && this.timer(timerFlow, 1.0F)) { - this.moveLiquidForward(leaks, this.liquids.current()); + lastMoved = moveLiquidForward(leaks, this.liquids.current()); this.noSleep(); //Attempt to push liquids to the sides @@ -101,7 +95,7 @@ public float moveLiquid(Building other, Liquid liquid) { float flow = Math.min(other.block.liquidCapacity - other.liquids.get(liquid), amount) * 10; if (other.acceptLiquid(this, liquid)) { other.handleLiquid(this, liquid, flow); - this.liquids.remove(original, flow/aetherEfficiencies.get(outletProduct, 1)); + this.liquids.remove(original, flow/aetherDensities.get(liquid, 1)/10); total += amount; } diff --git a/src/meld/world/blocks/fluid/ChannelValve.java b/src/meld/world/blocks/fluid/ChannelValve.java new file mode 100644 index 0000000..a260d65 --- /dev/null +++ b/src/meld/world/blocks/fluid/ChannelValve.java @@ -0,0 +1,55 @@ +package meld.world.blocks.fluid; + +import arc.Core; +import arc.audio.Sound; +import arc.graphics.g2d.Draw; +import arc.graphics.g2d.TextureRegion; +import mindustry.gen.Sounds; + +//A switch + liquid junction +public class ChannelValve extends FlexibleSizeJunction { + public Sound clickSound = Sounds.click; + + public TextureRegion onRegion; + + @Override + public void load() { + super.load(); + onRegion = Core.atlas.find(name + "-on", "clear"); + } + + public ChannelValve(String name) { + super(name); + configurable = true; + update = true; + drawDisabled = false; + autoResetEnabled = false; + configureSound = Sounds.none; + + config(Boolean.class, (ValveBuild entity, Boolean b) -> entity.enabled = b); + } + + public class ValveBuild extends FlexibleBuild{ + + @Override + public boolean configTapped(){ + configure(!enabled); + clickSound.at(this); + return false; + } + + @Override + public Boolean config(){ + return enabled; + } + + @Override + public void draw(){ + super.draw(); + + if(enabled){ + Draw.rect(onRegion, x, y); + } + } + } +} diff --git a/src/meld/world/blocks/ChannelVent.java b/src/meld/world/blocks/fluid/ChannelVent.java similarity index 55% rename from src/meld/world/blocks/ChannelVent.java rename to src/meld/world/blocks/fluid/ChannelVent.java index 52264af..1499aca 100644 --- a/src/meld/world/blocks/ChannelVent.java +++ b/src/meld/world/blocks/fluid/ChannelVent.java @@ -1,10 +1,9 @@ -package meld.world.blocks; +package meld.world.blocks.fluid; -import mindustry.Vars; +import arc.graphics.g2d.Draw; +import arc.math.Mathf; import mindustry.entities.Puddles; import mindustry.type.Liquid; -import mindustry.world.blocks.Attributes; -import mindustry.world.blocks.liquid.Conduit; import mindustry.world.blocks.liquid.LiquidRouter; import mindustry.world.meta.Attribute; @@ -12,6 +11,9 @@ public class ChannelVent extends LiquidRouter { public float minPressure = 0; public float ventRate = 1; + public float ventDelay = 10; + + int ventTimer = timers++; public ChannelVent(String name) { super(name); @@ -24,14 +26,17 @@ public void updateTile() { Liquid liquid = liquids.current(); - if(liquid.gas || liquid.boilPoint <= Attribute.heat.env()){ + if(timer.get(ventTimer, ventDelay) && liquid.gas || liquid.boilPoint <= Attribute.heat.env()){ float ventEfficiency = (liquids.get(liquid)/liquidCapacity - minPressure)/(1 - minPressure); if(ventEfficiency > 0){ - float leakAmount = ventEfficiency * ventRate; - Puddles.deposit(tile, tile, liquid, leakAmount, true, true); - liquids.remove(liquid, leakAmount); + float leakAmount = Math.min(ventEfficiency * ventRate * ventDelay, liquids.get(liquid)); + + if(leakAmount > 1E-4){ + Puddles.deposit(tile, tile, liquid, leakAmount, true, true); + liquids.remove(liquid, leakAmount); + } } } } diff --git a/src/meld/world/blocks/fluid/FlexibleSizeJunction.java b/src/meld/world/blocks/fluid/FlexibleSizeJunction.java new file mode 100644 index 0000000..e4a8337 --- /dev/null +++ b/src/meld/world/blocks/fluid/FlexibleSizeJunction.java @@ -0,0 +1,35 @@ +package meld.world.blocks.fluid; + +import arc.math.geom.Geometry; +import arc.math.geom.Point2; +import meld.world.WorldUtil; +import mindustry.Vars; +import mindustry.gen.Building; +import mindustry.type.Liquid; +import mindustry.world.blocks.liquid.LiquidJunction; + +public class FlexibleSizeJunction extends LiquidJunction { + public FlexibleSizeJunction(String name) { + super(name); + } + + public class FlexibleBuild extends LiquidJunctionBuild{ + + @Override + public Building getLiquidDestination(Building source, Liquid liquid){ + if(!enabled) return this; + + int dir = WorldUtil.relativeTo(source.tile.x, source.tile.y, tile.x, tile.y); + + Point2 offset = Geometry.d4(dir); + + Building next = Vars.world.build(source.tile.x + offset.x * (size + 1), source.tile.y + offset.y * (size + 1)); + + if(next == null || (!next.acceptLiquid(this, liquid) && !(next.block instanceof LiquidJunction))){ + return this; + } + return next.getLiquidDestination(this, liquid); + } + + } +} diff --git a/src/meld/world/blocks/VisualAspectPipe.java b/src/meld/world/blocks/fluid/VisualAspectPipe.java similarity index 54% rename from src/meld/world/blocks/VisualAspectPipe.java rename to src/meld/world/blocks/fluid/VisualAspectPipe.java index d8ef37b..03096d9 100644 --- a/src/meld/world/blocks/VisualAspectPipe.java +++ b/src/meld/world/blocks/fluid/VisualAspectPipe.java @@ -1,7 +1,6 @@ -package meld.world.blocks; +package meld.world.blocks.fluid; import arc.graphics.Blending; -import arc.graphics.Color; import arc.graphics.g2d.Draw; import arc.graphics.g2d.Fill; import arc.graphics.g2d.TextureRegion; @@ -10,18 +9,23 @@ import arc.math.Mathf; import arc.math.Rand; import arc.math.geom.Geometry; +import arc.math.geom.Point2; +import arc.util.Log; import arc.util.Time; import arc.util.Tmp; +import meld.content.MeldFx; +import mindustry.Vars; import mindustry.gen.Building; import mindustry.graphics.Drawf; import mindustry.graphics.Layer; import mindustry.type.Liquid; +import mindustry.world.draw.DrawLiquidTile; import static mindustry.Vars.renderer; import static mindustry.Vars.tilesize; //PLEASEWORKPLEAEWORKAPSLEAOSKOPK -public class VisualAspectPipe extends AspectPipe{ +public class VisualAspectPipe extends AspectPipe { protected static final Rand rand = new Rand(); public int sides = 12; @@ -29,32 +33,86 @@ public class VisualAspectPipe extends AspectPipe{ public float alpha = 0.1f; public int particles = 12; public float particleRotation = 0, particleLife = 70f, particleRad = 4.2f, particleSize = 3f, fadeMargin = 0.4f, rotateScl = 3f; + + //Life that additional particles get drawn at + public float flowingLife = 15; + + //Alpha which flowing particles get + public float flowAlpha = 0.1f; + + //Distance which additional particles travel + public float particleTravel = 16; + public float cone = 45; + + //How long a pipe can go without transporting fluid while still maintaining the flow visual + public float flowGrace = 5; + public boolean reverse = false, poly = false; public Interp particleInterp = new Interp.PowIn(1.5f); public Interp particleSizeInterp = Interp.slope; public Blending blendMode = Blending.additive; + public float effectChance = 0.1f; + public float visualFlowSpeed = 10; + + public boolean debugDraw = false; + public VisualAspectPipe(String name) { super(name); } public class VisualPipeBuild extends AspectPipeBuild{ - float warmup = 0; + public float warmup = 0; + public float flowWarmup = 0; + public float noflowTime; + public Building front; + public float effectTimer = Mathf.random(); @Override public void updateTile() { super.updateTile(); - warmup = Mathf.lerpDelta(warmup, liquids.currentAmount()/liquidCapacity, 0.1f); + + warmup = Mathf.lerpDelta(warmup, liquids.currentAmount()/liquidCapacity, 0.05f); + + //Keep the flow visual high as possible for as long as flowGrace in points of no flow + noflowTime += Time.delta; + if(lastMoved > 0) noflowTime = 0; + + float flowWarmupTarget = Mathf.clamp(lastMoved/liquidCapacity * visualFlowSpeed); + + if(flowWarmupTarget > flowWarmup || noflowTime > flowGrace) flowWarmup = Mathf.lerpDelta(flowWarmup, flowWarmupTarget, 0.05f); + else flowWarmup = Mathf.lerpDelta(flowWarmup, flowWarmupTarget, 0.01f); + + effectTimer += effectChance * lastMoved/liquidCapacity; + + if(Mathf.chance(effectTimer)){ + effectTimer = 0 ; + + //Stupid + //Rotation 0 faces right so randomise particle spawn top and bottom + Tmp.v1.set(-0.5f, Mathf.random(-0.5f, 0.5f)).rotate(rotation * 90).scl(tilesize/4f); + + MeldFx.gasTransfer.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation * 90, liquids.current().color); + } } @Override public float warmup() { - return Interp.pow5Out.apply(warmup); + return Math.max(Interp.pow5Out.apply(warmup), flowWarmup); } @Override public void draw(){ + if(debugDraw){ + + Draw.z(Layer.blockUnder); + + drawInbetween(); + Draw.reset(); + return; + } + int r = this.rotation; //draw extra conduits facing this one for tiling purposes @@ -67,7 +125,7 @@ public void draw(){ } } - Draw.z(Layer.block -0.001f); + Draw.z(Layer.blockUnder); drawInbetween(); Draw.z(Layer.block); @@ -117,35 +175,76 @@ public void drawInbetween(){ Draw.z(Layer.blockUnder + 0.01f); Liquid current = liquids.current(); + if(warmup() > 0f && current != null){ float a = alpha * warmup(); + float a2 = flowAlpha * Interp.pow5Out.apply(flowWarmup); Draw.blend(blendMode); Draw.color(current.color); float base = Time.time / particleLife; + float flowBase = Time.time/flowingLife; + rand.setSeed(id); for(int i = 0; i < particles; i++){ + float finFlow = (rand.random(2f) + flowBase) % 1f; + float fin = (rand.random(2f) + base) % 1f; if(reverse) fin = 1f - fin; float fout = 1f - fin; - float angle = rand.random(360f) + (Time.time / rotateScl) % 360f; + + float straightness = fin * flowWarmup; + + float particleAngle = rand.random(360f) + (Time.time / rotateScl) % 360f; float len = particleRad * particleInterp.apply(fout); + //1. Calculate offsets for regular draw particles + + Tmp.v1.set(len, 0).rotate(Mathf.clamp(particleAngle % 360, cone, 360-cone)); + + //2. calculate the stream offsets for steam particles + Tmp.v2.set(Tmp.v1); + Tmp.v2.y = -particleTravel + particleTravel * 2 * fin; + + //Lerp between the two, then rotatie properly + Tmp.v3.set(Tmp.v1).lerp(Tmp.v2, straightness); + Tmp.v3.rotate((rotation - 1) * 90); + + + //3. Rotate them for block + Draw.alpha(a * (1f - Mathf.curve(fin, 1f - fadeMargin))); if(poly){ Fill.poly( - px + x + Angles.trnsx(angle, len), - py + y + Angles.trnsy(angle, len), + x + Tmp.v3.x, + y + Tmp.v3.y, + sides, + particleSize * particleSizeInterp.apply(fin) * warmup(), + particleRotation + ); + }else{ + Fill.circle( + x + Tmp.v3.x, + y + Tmp.v3.y, + particleSize * particleSizeInterp.apply(fin) * warmup() + ); + } + //Here we go on this trip again + Draw.alpha(a2 * (1 - Mathf.curve(finFlow, 1 - fadeMargin))); + if(poly){ + Fill.poly( + x + Tmp.v3.x, + y + Tmp.v3.y, sides, particleSize * particleSizeInterp.apply(fin) * warmup(), particleRotation ); }else{ Fill.circle( - px + x + Angles.trnsx(angle, len), - py + y + Angles.trnsy(angle, len), + x + Tmp.v3.x, + y + Tmp.v3.y, particleSize * particleSizeInterp.apply(fin) * warmup() ); } diff --git a/src/meld/world/blocks/items/PriorityInputSplitter.java b/src/meld/world/blocks/items/PriorityInputSplitter.java new file mode 100644 index 0000000..579ddc6 --- /dev/null +++ b/src/meld/world/blocks/items/PriorityInputSplitter.java @@ -0,0 +1,28 @@ +package meld.world.blocks.items; + +import mindustry.gen.Building; +import mindustry.type.Item; +import mindustry.world.Block; +import mindustry.world.Edges; +import mindustry.world.blocks.distribution.DuctRouter; +import mindustry.world.blocks.distribution.OverflowDuct; + +//hdasdjcdf ok fine it's TIME +public class PriorityInputSplitter extends OverflowDuct { + public PriorityInputSplitter(String name) { + super(name); + itemCapacity = 4; + } + + public float threshold; + + public class PriorityInputBuild extends OverflowDuctBuild{ + @Override + public boolean acceptItem(Building source, Item item){ + return current == null && + items.total() < itemCapacity/2 ? + true : + items.total() < itemCapacity && (Edges.getFacingEdge(source.tile, tile).relativeTo(tile) == rotation); + } + } +} From 9b4a066631d97bf0bcd119777ba6f1caab9e6ef6 Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Fri, 3 Apr 2026 00:15:19 +1100 Subject: [PATCH 12/17] god is dead, and we have killed him --- assets/bundles/bundle.properties | 20 ++++-- assets/bundles/bundle.shitpost | 5 +- .../sprites/blocks/fluid/manual-valve-on.png | Bin 0 -> 478 bytes assets/sprites/blocks/fluid/manual-valve.png | Bin 0 -> 438 bytes .../blocks/fluid/valve/intake-valve-on.png | Bin 0 -> 8065 bytes .../blocks/fluid/valve/intake-valve.png | Bin 0 -> 8659 bytes assets/sprites/chute-bottom-0.png | Bin 500 -> 543 bytes assets/sprites/chute-bottom-1.png | Bin 525 -> 965 bytes assets/sprites/chute-bottom-2.png | Bin 522 -> 948 bytes assets/sprites/chute-bottom-3.png | Bin 531 -> 1221 bytes assets/sprites/chute-bottom-4.png | Bin 503 -> 976 bytes src/meld/Meld.java | 1 + src/meld/content/MeldBlocks.java | 38 +++++++--- src/meld/content/MeldBullets.java | 65 ++++++++++++++++++ .../blocks/{Bruiskit.java => Bruisekit.java} | 10 ++- src/meld/world/blocks/Gauze.java | 2 +- .../blocks/fluid/FlexibleSizeJunction.java | 35 ++++++++-- .../blocks/production/SingleBeamDrill.java | 37 +++++++--- 18 files changed, 179 insertions(+), 34 deletions(-) create mode 100644 assets/sprites/blocks/fluid/manual-valve-on.png create mode 100644 assets/sprites/blocks/fluid/manual-valve.png create mode 100644 assets/sprites/blocks/fluid/valve/intake-valve-on.png create mode 100644 assets/sprites/blocks/fluid/valve/intake-valve.png create mode 100644 src/meld/content/MeldBullets.java rename src/meld/world/blocks/{Bruiskit.java => Bruisekit.java} (87%) diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index cb6dd24..5335d91 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -33,7 +33,7 @@ block.meld-gas-kiln.name = Gas-fired Kiln block.meld-gas-kiln.description = Heats materials using [#cbdbfc]Aspect[][accent]\n\nCarbolith + Tenbris -> Shadesteel + [#5b4739]Fumes[]\nClay-Mallows -> Glass-Mallows\nSilver -> Annealed Silver\nDebris + Glass-Mallows -> Crucible Platings\nDebris + Shadesteel -> Crucible Platings block.meld-rotary-kiln.name = Rotary Kiln -block.meld-rotary-kiln.description = Constantly burns [#cbdbfc]Aspect[] as fuel, heats materials to process them in bulk. [accent]\n\nTenbris -> Shadesteel + [#5b4739]Fumes[]\nClay-Mallows -> Glass-Mallows\nSilver -> Annealed Silver\nDebris + Glass-Mallows -> Crucible Platings\nDebris + Shadesteel -> Crucible Platings +block.meld-rotary-kiln.description = Constantly burns [#cbdbfc]Aspect[] as fuel, heats materials to process them in bulk. [accent]\n\nTenbris -> Shadesteel\nClay-Mallows -> Glass-Mallows\nSilver -> Annealed Silver\nDebris + Glass-Mallows -> Crucible Platings\nDebris + Shadesteel -> Crucible Platings block.meld-pneumatic-extruder.name = Pneumatic Extruder block.meld-pneumatic-extruder.description = Extrudes insulated pipes, uses[#cbdbfc]Aspect[] to run. [accent]\n\nShadesteel + Elnar -> Aspect Pipe\n\nAnnealed Silver + Debris -> Aspect Pipe @@ -130,7 +130,7 @@ block.meld-chute-crossing.name = Chute Crossing block.meld-chute-crossing.description = Lets items cross through without intersecting with eachother. block.meld-chute-overflow.name = Chute Overflow -block.meld-chute-overflow.description = Routes items to the front, or to the sides if blocked. +block.meld-chute-overflow.description = Routes items to the front, or to the sides if blocked. \n\nAccepts items from the back, or the sides if empty. block.meld-chute-bridge.name = Chute Bridge block.meld-chute-bridge.description = Moves items over a single tile. Bypasses structures and terrain. @@ -146,13 +146,23 @@ block.meld-channel-face.name = Channel Face block.meld-channel-face.description = Acts as a fluid junction. Transmits fluid without storing it. No risk of explosion. block.meld-channel-node.name = Channel Node -block.meld-channel-node.description = Acts as a fluid router. Liquid can be input or output from any side. Stores a small amount of fluid. +block.meld-channel-node.description = Acts as a fluid router. Fluids can be input or output from any side. Stores a small amount of fluid. block.meld-aspect-outlet.name = Aspect Outlet block.meld-aspect-outlet.description = Decompresses [#cb8650]Aether[] into highly volatile [#cbdbfc]Aspect[] at a ratio of 1:10.\n\nWorks as an output terminal for a fluid network. block.meld-aspect-channel.name = Aspect Channel -block.meld-aspect-channel.description = Acts as a directional router.\n\nWhen transporting [#cb8650]Aether[], fills nearby buildings with highly volatile [#cbdbfc]Aspect[].\n\nWorks as an input/output terminal for a fluid network. +block.meld-aspect-channel.description = Acts as a directional router.\n\nWhen transporting [#cb8650]Aether[], fills nearby buildings with highly volatile [#cbdbfc]Aspect[].\n\nWorks as an insulated input/output terminal for a fluid network.\n\n[accent]Plated![] + +block.meld-pressure-vent.name = Pressure Vent +block.meld-pressure-vent.description = Acts as a fluid router. Releases stored vapor into the atmosphere. + +block.meld-manual-valve.name = Manual Valve +block.meld-manual-valve.description = Acts as a fluid junction. Can be toggled to control if fluids can pass through. + +block.meld-intake-valve.name = Intake Valve +block.meld-intake-valve.description = Acts as a fluid junction. Can be toggled to control if fluids can pass through.\n\n[accent]Plated![] +block.meld-intake-valve.details = Yes, it works. block.meld-channel-director.name = Channel Director block.meld-channel-director.description = [red]Restricts[] the flow of fluids from its input to output by half.\n\nCan [red]detonate[] Channel Nodes full of [#cbdbfc]Aspect[].\n[accent]Transports at 50% pressure.[]\n\n[red]Will chain destruct![] @@ -249,7 +259,7 @@ block.meld-elemental-blaster.name = Elemental Blaster block.meld-elemental-blaster.description = Blasts deposits for items indefinitely. Requires [#cbdbfc]Aspect[] to run.\n\nCan be boosted with [#ea9ad6]Meld[] to double harvesting speed. block.meld-pneumatic-pulsar.name = Pneumatic Pulsar -block.meld-pneumatic-pulsar.description = Blasts a single deposit for items indefinitely. Requires [#cb8650]Aether[] to run.\n\n[red]Explosions damage everything around them, high maintenance![] +block.meld-pneumatic-pulsar.description = Blasts a single deposit for items indefinitely while maintained. Requires [#cb8650]Aether[] to run.\n\n[red]Explosions damage everything around them, high maintenance![] block.meld-elemental-sampler.name = Elemental Sampler block.meld-elemental-sampler.description = Samples deposits for items indefinitely. Requires [#cbdbfc]Aspect[] and [#8872da]Rift[] to run.\n\nCan be boosted with [#b460e2]Warp[] to double harvesting speed.\n\n[accent]More efficient against soft tissue[] diff --git a/assets/bundles/bundle.shitpost b/assets/bundles/bundle.shitpost index 4e3cb48..4806279 100644 --- a/assets/bundles/bundle.shitpost +++ b/assets/bundles/bundle.shitpost @@ -2,4 +2,7 @@ item.meld-glass-mallow.name = Pan-fried Plates item.meld-crucible-plating.name = Boiled Plates -block.meld-sonar-spire.name = Slay the Sonar Spire \ No newline at end of file +block.meld-sonar-spire.name = Slay the Sonar Spire + +block.meld-manual-valve.name = Gabe Nuel's Wife +block.meld-pressure-vent.name = Amogus Escape route \ No newline at end of file diff --git a/assets/sprites/blocks/fluid/manual-valve-on.png b/assets/sprites/blocks/fluid/manual-valve-on.png new file mode 100644 index 0000000000000000000000000000000000000000..d0484bfc082a35f467ffad4fef135406007070d4 GIT binary patch literal 478 zcmV<40U`d0P)Px$m`OxIR9J=0S38b_Knyjjv|IzxqqKC~AX{m3~8?f;NX{&CV8UO%>aS~%= zY9I=_1(*;3psPyPvINmH;to)=^(HdH3c(gG@k7)C!SI_FG* zt}0Cu+P>m@>y&Wf(Nn;s^O#DC8OA9*95Vva>XC$Jat~3iP#_SKK4zk|B+NpD(xn*G zL&8OX?%AtIghJ#kENxRSoa}*iI)Vb;qLZtH2C))aWFFs_WjlsLzYWA`{-8jP(-EnP z(78U|j*~r*8?TKOJV}VNQh8}Pw ztoCf)3B7*cBmjKlf&wuE<@!S#NBhHU3!X)S##)ye*R`A`vt*Ts#>j_L0Es1)6G>5s zDy{w(yb@wF;^?X}tM8}gDLg-?d~0w8{MU>t=qX4p6VgO93HQM;PD!_C_z&&)4>%~> UG9Yp^?*IS*07*qoM6N<$f{dokRR910 literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/manual-valve.png b/assets/sprites/blocks/fluid/manual-valve.png new file mode 100644 index 0000000000000000000000000000000000000000..dfce84c5ba66baf7347736687292ae7f30e84e88 GIT binary patch literal 438 zcmV;n0ZIOeP)Px$a7jc#R9J<@S3SsoaN^%^|@Oot-49gnV#`zJS#S9F~ni-a&>!)mE6uUG{Da%hHjhPi;Nc$&2W2h?7Qs==q zKjM!fBfuR&AaOeEAwrfNE$T=>JO9+7<{Y(4Nfb3A&N;e9p%T!F65XwZin|LoL@K57 zMEVGH1SRrBn;1)g>){>}o(}3NLWG33egFJAb`d~|(W?lS0Cxp@l;9x&WuQccD2eKR zyFR5LZBwhkLs4orQc(t_sTn|m(`PS=RKNw~)?A$s-GydH-$`{)JP{!zEfTcLLSuQr zu&gEtZK&a3PDB)4Ke2s6TDJ&_-vtt^!t(kMRnRu|Tc%{oPeve2uJ6(~^}|iZP!Xn% g#u>Lo@bl~V1wd}1uFVN0<^TWy07*qoM6N<$f;rE-A^-pY literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/valve/intake-valve-on.png b/assets/sprites/blocks/fluid/valve/intake-valve-on.png new file mode 100644 index 0000000000000000000000000000000000000000..1c605fb354548276d953d0af70e936798b056a26 GIT binary patch literal 8065 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 P00000NkvXXu0mjf60(2K literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/valve/intake-valve.png b/assets/sprites/blocks/fluid/valve/intake-valve.png new file mode 100644 index 0000000000000000000000000000000000000000..cbc00fc3c93d0be090e5f9edb548cbead8349483 GIT binary patch literal 8659 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 literal 0 HcmV?d00001 diff --git a/assets/sprites/chute-bottom-0.png b/assets/sprites/chute-bottom-0.png index 300d1e1a69088fa4767141c599073b651a9fc7c5..741b4804587cb0b1957ff0bdca9367d1f108cdc9 100644 GIT binary patch delta 517 zcmV+g0{Z>*1D^ztB!72lLqkw=Qb$4n04R}tkvm8OK@>&LZVZYa0-8d^VvA^{ASz<1 zQ3yhW5ET-&a6cvnvYTZ$!6v0(8?f-x7`3pm*4DyS5ClIUc6L^ZHX}wO@Hh24oRH1!(vwRzCWwW zSa)@h6ktlXojgcuz{Fl=;<@;DGOOv?Z{QDsALQLvdU=(Tr>4LjGZr3Ik_{Y02!o)`)m1u|sGGfV~x z1(!Gx!cF{r6@Pz>0vcH|=qSvR!$ht45r6PITQ@Z}TAkDx2LH3?y$?X^4t$q9@9W6( zzK_B81eaFbpDV-U2lz^LEp!NhEjYibYuYYcY(wv(tvYH&@&R%x1#hR&m4u!fXkV%3 zR=elq9u|uby@ve*7)(Q8waMOXjk*2XQ_JrM#_MuoCVmu8M*si-V@X6oR9J=W)UgeK zFbqUd8ySZxVoJmeOpQ_z6Jf@*#?JSTtv0z^ctwHpiQ{UKm-Ktx~x zW4u^E<_87fL!^o|nAwU2xH}e5%0|HCfLeDb03IR&2q54G^~V~g?RN^M00000NkvXX Hu0mjf)_C2U delta 474 zcmV<00VV#Q1oQ)tB!7NsLqkw=Qb$4n04R}tkv&MmP!xqvQ;VV%K|6>zWT;LSL`596 z3Pq?8YK2xEOkVm2O&XFE7e~Rh;NZ_<)xpJCR|i)?5c~mgb8}L3krMAq3N2#1@OU5R z-E(;FK0v6KnPzp21DbA|sYG1NWLL$`SM(r+egqJZnPtpLQhyS@^>t5uRCh6+<=^*b z^{P3G0RfSCmKml^yg@v@X&apPi6g8itHkHTVt?1$8VeqE(<&}Vy08`#1Ue# z(8fv|v!baHPZ38|O{aVzj(dX-?O#ylM`N2I1Yqf9Oq*M=-dSwHOKir zcAUlu5PSx%^p?L;2WCD=ueG%35zw~{TwJ#_We>RA0S2E8*_2%=NK44)f%h}|rYtaU z3v{n}b8DXC^Z`iItdcjt!67hOpzL*@cXzeV?cbi}{8N4a#_Muo2hLeH0000nNklYwAzyLs!JRkG{v;?!t Q#Q*>R07*qoM6N<$g3$8PDgXcg diff --git a/assets/sprites/chute-bottom-1.png b/assets/sprites/chute-bottom-1.png index b95e3b790cba8541e862d7c8ab8a09fdc7831101..77d3b59bcdd72daefb1f5e18e4199bee80c93545 100644 GIT binary patch delta 943 zcmV;g15o^p1jPrCB!72lLqkw=Qb$4n04R}tkvm8OK@>&LZVZYa0-8d^VvA^{ASz<1 zQ3yhW5ET-&a6cvnvYTZ$!6v0(8?f-x7`3pm*4DyS5ClIUc6L^ZHX}wO@Hh24oRH1!(vwRzCWwW zSa)@h6ktlXojgcuz{Fl=;<@;DGOOv?Z{QDsALQLvdU=(Tr>4LjGZr3Ik_{Y02!o)`)m1u|sGGfV~x z1(!Gx!cF{r6@Pz>0vcH|=qSvR!$ht45r6PITQ@Z}TAkDx2LH3?y$?X^4t$q9@9W6( zzK_B81eaFbpDV-U2lz^LEp!NhEjYibYuYYcY(wv(tvYH&@&R%x1#hR&m4u!fXkV%3 zR=elq9u|uby@ve*7)(Q8waMOXjk*2XQ_JrM#_MuoCVv!9M*si<2}wjjR9J=WmQ8Nl zFbstsNzF_a={1X*np?d=us z?|(bL-|twK54bys0A|7Ea>ey}!|nF8`VH6X6P}-cYz+_Id^=(8fV;15jpye*I}AWH zf_QN=hku#D>_mXi7UDSraow|YM5;!g%V&&QRbi%3)pGz^bH^IJtpHX0TL9WDxEoY$ z6<@F{axOq#0qEvGN55cM7)1Leb^u@~fA|VwFe9ichzLXkfbjD22Ps{UQi6y;L_ow~ z&VYwA5Ru2dnFBBoDO3XhO?@at1k3{F0HA#U_kXcb`tZI5F|`Ja^Fvv!@UKV=mV`-%wf2@ zgMZl?aVi4`2)@`k+u)`EvY-qeMMov=EyR{En#}G3M6}VxLhhBGN^|ECpa})u#Y7 z!-I$*qUH2+IzX&~dQUKuA|6Nce#y;4>?i`HbeS6HsQt%N@dMxi@Blbw{{RfapFMXJ R*zy1X002ovPDHLkV1ft1t?2*& delta 499 zcmVzWT;LSL`596 z3Pq?8YK2xEOkVm2O&XFE7e~Rh;NZ_<)xpJCR|i)?5c~mgb8}L3krMAq3N2#1@OU5R z-E(;FK0v6KnPzp21DbA|sYG1NWLL$`SM(r+egqJZnPtpLQhyS@^>t5uRCh6+<=^*b z^{P3G0RfSCmKml^yg@v@X&apPi6g8itHkHTVt?1$8VeqE(<&}Vy08`#1Ue# z(8fv|v!baHPZ38|O{aVzj(dX-?O#ylM`N2I1Yqf9Oq*M=-dSwHOKir zcAUlu5PSx%^p?L;2WCD=ueG%35zw~{TwJ#_We>RA0S2E8*_2%=NK44)f%h}|rYtaU z3v{n}b8DXC^Z`iItdcjt!67hOpzL*@cXzeV?cbi}{A_*z#_Muo2hLeH0000=Nkl&LZVZYa0-8d^VvA^{ASz<1 zQ3yhW5ET-&a6cvnvYTZ$!6v0(8?f-x7`3pm*4DyS5ClIUc6L^ZHX}wO@Hh24oRH1!(vwRzCWwW zSa)@h6ktlXojgcuz{Fl=;<@;DGOOv?Z{QDsALQLvdU=(Tr>4LjGZr3Ik_{Y02!o)`)m1u|sGGfV~x z1(!Gx!cF{r6@Pz>0vcH|=qSvR!$ht45r6PITQ@Z}TAkDx2LH3?y$?X^4t$q9@9W6( zzK_B81eaFbpDV-U2lz^LEp!NhEjYibYuYYcY(wv(tvYH&@&R%x1#hR&m4u!fXkV%3 zR=elq9u|uby@ve*7)(Q8waMOXjk*2XQ_JrM#_MuoCVv!9M*si;_(?=TR9J=WmQ9Y^ zFbstsDax6}^a``+;fkK2hwWlcP|T{6T4Waz^vwIPP=>e!bS!Q# z%Yyl!vQFjP0SFS~0yC?^ss=NyYi0`75$I696J#b3aTO+FFpn^@ET=(GRiUaySfNS) zw8T`OuI|1)oWb0V{<;T})9IxGxVUOUN4hX?#U+W<{ z0JlD+RE1MoK}1NYub$?FL$n<=@el+d1c*pIcOXwi0XSXQeHLF=-W5(RN(ErUdbYla zi}(?D5WNesEH5?R?m$Wj>zYZujapH9vC{Cu>8nV;Cb%uYZ5&;Qn->H81%>|`rrC(h&j0`b07*qoM6N<$g5Z~^ A`Tzg` delta 496 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 delta 477 zcmV<30V4j;2loSzB!7NsLqkw=Qb$4n04R}tkv&MmP!xqvQ;VV%K|6>zWT;LSL`596 z3Pq?8YK2xEOkVm2O&XFE7e~Rh;NZ_<)xpJCR|i)?5c~mgb8}L3krMAq3N2#1@OU5R z-E(;FK0v6KnPzp21DbA|sYG1NWLL$`SM(r+egqJZnPtpLQhyS@^>t5uRCh6+<=^*b z^{P3G0RfSCmKml^yg@v@X&apPi6g8itHkHTVt?1$8VeqE(<&}Vy08`#1Ue# z(8fv|v!baHPZ38|O{aVzj(dX-?O#ylM`N2I1Yqf9Oq*M=-dSwHOKir zcAUlu5PSx%^p?L;2WCD=ueG%35zw~{TwJ#_We>RA0S2E8*_2%=NK44)f%h}|rYtaU z3v{n}b8DXC^Z`iItdcjt!67hOpzL*@cXzeV?cbi}{8oMd#_Muo2hLeH0000qNkl tmpDamaged = new Seq<>(); @@ -21,11 +18,12 @@ public class Bruiskit extends FieldPulsar{ public float recentDamageMultiplier = 0.1f; - public Bruiskit(String name) { + public Bruisekit(String name) { super(name); + fogRadius = 0; } - public class BruiskitBuild extends PulsarBuild{ + public class BruisekitBuild extends PulsarBuild{ public Building target; diff --git a/src/meld/world/blocks/Gauze.java b/src/meld/world/blocks/Gauze.java index 37bc601..aff2d37 100644 --- a/src/meld/world/blocks/Gauze.java +++ b/src/meld/world/blocks/Gauze.java @@ -121,7 +121,7 @@ public void propagate(){ /** * Max of a few numbers * -Missing health - * -maxFract * build.maxHealth + * -maxFract * Math.max(build.maxHealth pulseStrength) * -Remaining charge * -0 */ diff --git a/src/meld/world/blocks/fluid/FlexibleSizeJunction.java b/src/meld/world/blocks/fluid/FlexibleSizeJunction.java index e4a8337..c94fa78 100644 --- a/src/meld/world/blocks/fluid/FlexibleSizeJunction.java +++ b/src/meld/world/blocks/fluid/FlexibleSizeJunction.java @@ -2,8 +2,12 @@ import arc.math.geom.Geometry; import arc.math.geom.Point2; +import arc.math.geom.Position; +import arc.util.Log; +import arc.util.Tmp; import meld.world.WorldUtil; import mindustry.Vars; +import mindustry.content.Fx; import mindustry.gen.Building; import mindustry.type.Liquid; import mindustry.world.blocks.liquid.LiquidJunction; @@ -17,19 +21,42 @@ public class FlexibleBuild extends LiquidJunctionBuild{ @Override public Building getLiquidDestination(Building source, Liquid liquid){ + return getLiquidDestination(source, liquid, null); + } + + public Building getLiquidDestination(Building source, Liquid liquid, Position otherOffset){ if(!enabled) return this; + //Find which direction the offset should go int dir = WorldUtil.relativeTo(source.tile.x, source.tile.y, tile.x, tile.y); + Point2 direction = Geometry.d4(dir); + + //Direction offset vector + Tmp.v1.set(direction.x, direction.y).scl(size); - Point2 offset = Geometry.d4(dir); + //Tile offset vector, can grab from previous junction if it's already been calculated + if(otherOffset != null){ + Tmp.v2.set(otherOffset); + } + else { + int tolerance = size/2; + Tmp.v2.set(source.tile.x, source.tile.y).sub(tile.x, tile.y).clamp(-tolerance, -tolerance, tolerance, tolerance); + } - Building next = Vars.world.build(source.tile.x + offset.x * (size + 1), source.tile.y + offset.y * (size + 1)); + //Add the tile offset vector and the direction offset vectors to the tile + Tmp.v3.set(tile.x, tile.y).add(Tmp.v2).add(Tmp.v1); - if(next == null || (!next.acceptLiquid(this, liquid) && !(next.block instanceof LiquidJunction))){ + Tmp.v3.scl(Vars.tilesize); + + Building next = Vars.world.buildWorld(Tmp.v3.x, Tmp.v3.y); + + if(next == null || (!next.acceptLiquid(this, liquid) && !(next.block instanceof LiquidJunction)) && next != this){ return this; } + if(next instanceof FlexibleBuild b){ + return b.getLiquidDestination(this, liquid, Tmp.v2); + } return next.getLiquidDestination(this, liquid); } - } } diff --git a/src/meld/world/blocks/production/SingleBeamDrill.java b/src/meld/world/blocks/production/SingleBeamDrill.java index f4471f1..eea2d9f 100644 --- a/src/meld/world/blocks/production/SingleBeamDrill.java +++ b/src/meld/world/blocks/production/SingleBeamDrill.java @@ -12,9 +12,13 @@ import arc.util.Time; import arc.util.io.Reads; import arc.util.io.Writes; +import meld.content.MeldBullets; import mindustry.Vars; import mindustry.content.Fx; import mindustry.entities.Damage; +import mindustry.entities.Effect; +import mindustry.entities.bullet.BulletType; +import mindustry.game.Team; import mindustry.gen.Building; import mindustry.gen.Sounds; import mindustry.type.Item; @@ -26,17 +30,24 @@ //HAS TO be an odd number in size. public class SingleBeamDrill extends Block { - public int range = 5, tier = 4; + public int range = 10, tier = 4; - public float minHealthf = 0.25f; + public float minHealthf = 0.75f; //I know that sounds like a lot of items at once but well... yeah it's a lot of items at once - public int baseProductivity = 30; + public int baseProductivity = 50; + + //Additional items mined for each tile unused in the range + public int distanceProductivity = 5; public float selfDamage = 400; public float targetDamage = 2400; public ObjectFloatMap itemMultipliers = new ObjectFloatMap<>(); public ObjectMap transformItems = new ObjectMap<>(); public float drillTime = 300; + public BulletType bigExplosion; + + public Effect shootEffect = Fx.shootQuellPulse, trailEffect = Fx.explosion, hitEffect = Fx.massiveExplosion; + public SingleBeamDrill(String name) { super(name); hasItems = true; @@ -50,6 +61,7 @@ public SingleBeamDrill(String name) { ambientSound = Sounds.loopMineBeam; envEnabled |= 2; flags = EnumSet.of(new BlockFlag[]{BlockFlag.drill}); + bigExplosion = MeldBullets.pulsarBlast; } public class SingleBeamBuild extends Building{ @@ -76,18 +88,27 @@ public void drill(){ damage(selfDamage); Item found = null; + int unusedTiles = range + 1; int offset = (size + 1)/2; Point2 dir = Geometry.d4(rotation); int tx = tileX(), ty = tileY(); + Tile other = Vars.world.tile(tx + dir.x, ty + dir.y); + Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 3, 90000, Vars.tilesize * 3, true, shootEffect); + Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 5, 300, Vars.tilesize * 2, true, shootEffect); + for(int i = 0; i < range; i++){ + unusedTiles--; int j = i + offset; - Tile other = Vars.world.tile(tx + dir.x * j, ty + dir.y * j); + other = Vars.world.tile(tx + dir.x * j, ty + dir.y * j); if(other.solid()){ - Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 5, 30000, Vars.tilesize * 3, true); - Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 15, 0, Vars.tilesize * 2, true); + if(bigExplosion == null){ + Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 5, 30000, Vars.tilesize * 3, true, hitEffect); + Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 15, 0, Vars.tilesize * 2, true, hitEffect); + } + else bigExplosion.create(this, Team.derelict, other.worldx() - dir.x * Vars.tilesize, other.worldy() - dir.y * Vars.tilesize, 0); if(other.build != null) other.build.damage(targetDamage); Item drop = other.wallDrop(); @@ -99,7 +120,7 @@ public void drill(){ break; } else { - Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 2, 0, Vars.tilesize * 3, true); + Damage.dynamicExplosion(other.worldx(), other.worldy(), 5, 2, 0, Vars.tilesize * 3, true, trailEffect); } } @@ -108,7 +129,7 @@ public void drill(){ found = transformItems.get(found, found); - int mined = (int)(baseProductivity * itemMultipliers.get(found, 1)); + int mined = (int)((baseProductivity + distanceProductivity * unusedTiles) * itemMultipliers.get(found, 1)); mined = Mathf.ceilPositive(Math.min(itemCapacity - items.get(found), mined)); items.add(found, mined); From cb0d574b98defc12e14f2e7c0b0524802b64f116 Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Fri, 3 Apr 2026 13:50:42 +1100 Subject: [PATCH 13/17] logic gates. --- assets/bundles/bundle.properties | 8 +++- .../blocks/walls/shadesteel-shingles.png | Bin 264 -> 554 bytes .../sprites/items/heavy ind/ferric-geode.png | Bin 0 -> 584 bytes assets/sprites/items/heavy ind/motis.png | Bin 0 -> 464 bytes assets/sprites/items/stony-particulate.png | Bin 0 -> 378 bytes src/meld/content/MeldBlocks.java | 23 +++++++++-- .../world/blocks/fluid/ValveController.java | 39 ++++++++++++++++++ 7 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 assets/sprites/items/heavy ind/ferric-geode.png create mode 100644 assets/sprites/items/heavy ind/motis.png create mode 100644 assets/sprites/items/stony-particulate.png create mode 100644 src/meld/world/blocks/fluid/ValveController.java diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index 5335d91..bae631f 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -73,7 +73,11 @@ block.meld-brick-conglomerator.name = Conglomeration Rig block.meld-brick-conglomerator.description = Crushes up Carbolith and mixes it with vent fumes and [#e6c700]Ichor[], then presses the slurry into Bricks. Requires [#cbdbfc]Aspect[] to run. block.meld-silver-husk.name = Silver Husk -block.meld-silver-husk.description = Provides cover against enemy projectiles. Slowly regenerates when fed [#cbdbfc]Aspect[].\n\n[accent]Plated[] +block.meld-silver-husk.description = Buildable, [accent]insulated[] protection. Slowly regenerates when fed [#cbdbfc]Aspect[].\n\n[accent]Plated[] + +block.meld-shadesteel-shingles.name = Shadesteel Shingles +block.meld-shadesteel-shingles.description = Mundane and bulky. +block.meld-shadesteel-shingles.details = Brick of Shadesteel bricks of Shadesteel ingots. block.meld-barricade.name = Barricade block.meld-barricade.description = Provides cover against enemy projectiles.\nQuick to build.\n\nEasy way to store Compacted Bricks/Stony Gloop outside of the core for onsite use.\n\n[accent]Armored.[] @@ -161,7 +165,7 @@ block.meld-manual-valve.name = Manual Valve block.meld-manual-valve.description = Acts as a fluid junction. Can be toggled to control if fluids can pass through. block.meld-intake-valve.name = Intake Valve -block.meld-intake-valve.description = Acts as a fluid junction. Can be toggled to control if fluids can pass through.\n\n[accent]Plated![] +block.meld-intake-valve.description = Acts as a fluid junction, [purple]chain at your own expense[]. Can be toggled to control if fluids can pass through.\n\n[accent]Plated![] block.meld-intake-valve.details = Yes, it works. block.meld-channel-director.name = Channel Director diff --git a/assets/sprites/blocks/walls/shadesteel-shingles.png b/assets/sprites/blocks/walls/shadesteel-shingles.png index 694abd832bb624f75038dc875e7f5ff9f970ace3..c90d4e38752ae53bc41862157bc90191a39efc99 100644 GIT binary patch literal 554 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zpLn`BhE&XX zJ6qR}#ZjQO`osxegKh;!ho%Qi98C^N1ufAD9s)7V+7lEuc1)eHz=Ea2S3u!-^Q)9y z&zA45s;X!SpMUr5+Eb@zuX^?F=BuB-KHV1F+~~*PTUxhaec6F?Nrsjmj-K3Dd~WCM z<5R10PyYCN{CfI_gWrm>KlNuj9Osv7ywCSfe8GCg(sPSSFYj2rIr!_Y_T|&(6l^}W zyu5+4!HuSd@}84ha1Bps7GeExp!mcKUX?+w`Y zGW#%;FlB7|#+28Veo^za^A?kGspT9+lu_xYbEoO-x`SBcYe=M#kgwm)3gF>na$r`|Bk-& zJt;W#obE-L$y$4vt)4S3?VsEJ!EaK}-GJ?}##a;TY+-IW&mx%dDmcD(!*}K?uu~R_ zF9>F7FY}E`YCdt{fbi|7H=kxCzF_5$YrMgCzW2UEXL z^VQ1pSIS=8Hh~)26#Q_~e~FW_D}&P}$~=i|n(zEVHi2n@utPG4aMpKtUi4+ZLiDbj h)BEmTvTlfLkk@u<*6&>qVhN0V22WQ%mvv4FO#rFu{8#`0 literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}hdf;zLn2y} z&lns2IPajuv2nXvD7W7M7t_fnSb7|#v{c#~c=-8`iXC>E`1I%O>l#9nlop9d`*BHp z(2yu#-!NhE%ahafd06kgQ+XX-{6VAbMnn6770hgR73A3H8^C176xXQ-^f14V;Z44Ymtu?bybTK7seOrNKMqsOY@iHU*1T>X_!T7b>Y35|lDL~&ac)I$z JtaD0e0szKhVMYJ| diff --git a/assets/sprites/items/heavy ind/ferric-geode.png b/assets/sprites/items/heavy ind/ferric-geode.png new file mode 100644 index 0000000000000000000000000000000000000000..8e6c394a229daf8d06b1bffa660b3f9537706a8e GIT binary patch literal 584 zcmV-O0=NB%P)Px%0!c(cR7i=f)-g}pKp4jHf1-3lZ6&-whN#LyRRR&|6bU{8e1N1QLSn0eD%jXq z`UMbUiNwH?s;WA4LRBV$qO_Cxu=Q@XTLK-LwY8}i1rG*p0NiZ84>zD>)L$w_V3;Y0p(u>km(0tOQzz-BQ zX+?t+q)rJ6{2-RHxm=;Tv;@G;hjuDlOK7J0^Ygnl`Pb)9G?y!Ci`M%$4J#A|QlObC z#7uOOYHV&jiudrX_nddDs~VmLcBRDj&;S~mRQfKd4PpiueJB@ z<7ni%4u1H)+Om{NIKCNc15wmWX(Gp+4gkBY7Q3yM70j9Gyg85Z?QgZeUM{P4eS2F2 zw2L@9)Ak>#D( zNK3}IuV2)!s2UPzR_z}wmF;6Kf@x7(d2^l>i-FTXqqvEQ;Iz=Br{DTV_0WbcEP)Px$ib+I4R9J=OmoaX_KoCX87FUQ+xBwj_MLOgYqy^FC1e|~i8Nn5i%x~Ysw-u-*`A=a}T4DCX+&B!1{EG=3)?dd~>O|1i}UfL5**43b;04 z2nq^AaJObAslfB&IJP7h)cC$_w*Vl#2U1Uk6&C}U-27Q#lqf5+x7moM*mIiH0AQbS+>Zms8m-L6vq$)tp&VT{Q{f|AO(Zx@2H z>x?lOfZ)qW10fB!(yEfDfWU25_q+=P<*`;@HfPx$G)Y83R9J=Wm!S^AFc5|d;Sp-4nmH0I5{cj)(1d3qXx;&VL}E#BOBH7C0IE%Q zyS8_|4b1+81QN3U>%adFrqrZAYbL$G{&4(+pD*VV>zc&?(6|($2q0z7g { + if(b.liquids != null) total += b.liquids.currentAmount()/b.block.liquidCapacity; + }); + + boolean enable = total >= minPressure; + + if(invert) enable = !enable; + + for(Building b: proximity){ + if(b.block.configurable) b.configure(enable); + } + } + } +} From 55392a8dd1136baab93471f2af9081eb621891f9 Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Fri, 3 Apr 2026 21:43:26 +1100 Subject: [PATCH 14/17] Pipeboxes, More cursed logic on flexible junctions --- assets/bundles/bundle.properties | 4 + .../aspect-channel-bottom-0.png | Bin .../aspect-channel-bottom-1.png | Bin .../aspect-channel-bottom-2.png | Bin .../aspect-channel-bottom-3.png | Bin .../aspect-channel-bottom-4.png | Bin .../aspect-channel-top-0.png | Bin .../aspect-channel-top-1.png | Bin .../aspect-channel-top-2.png | Bin .../aspect-channel-top-3.png | Bin .../aspect-channel-top-4.png | Bin .../conduit/channel-director-bottom-0.png | Bin 0 -> 117 bytes .../conduit/channel-director-bottom-1.png | Bin 0 -> 117 bytes .../conduit/channel-director-bottom-2.png | Bin 0 -> 117 bytes .../conduit/channel-director-bottom-3.png | Bin 0 -> 117 bytes .../conduit/channel-director-bottom-4.png | Bin 0 -> 117 bytes .../conduit/channel-director-preview.png | Bin 0 -> 289 bytes .../fluid/conduit/channel-director-top-0.png | Bin 0 -> 279 bytes .../fluid/conduit/channel-director-top-1.png | Bin 0 -> 313 bytes .../fluid/conduit/channel-director-top-2.png | Bin 0 -> 307 bytes .../fluid/conduit/channel-director-top-3.png | Bin 0 -> 285 bytes .../fluid/conduit/channel-director-top-4.png | Bin 0 -> 294 bytes assets/sprites/blocks/fluid/pipebox-on.png | Bin 0 -> 1087 bytes assets/sprites/blocks/fluid/pipebox.png | Bin 0 -> 1095 bytes .../blocks/fluid/valve-controller-off.png | Bin 0 -> 152 bytes .../blocks/fluid/valve-controller-on.png | Bin 0 -> 177 bytes .../sprites/blocks/fluid/valve-controller.png | Bin 0 -> 956 bytes src/meld/content/MeldBlocks.java | 46 +++++++++-- .../blocks/fluid/FlexibleSizeJunction.java | 65 ++++++++++++--- src/meld/world/blocks/fluid/Pipebox.java | 22 +++++ .../world/blocks/fluid/ValveController.java | 75 +++++++++++++++++- 31 files changed, 192 insertions(+), 20 deletions(-) rename assets/sprites/blocks/fluid/{director => conduit}/aspect-channel-bottom-0.png (100%) rename assets/sprites/blocks/fluid/{director => conduit}/aspect-channel-bottom-1.png (100%) rename assets/sprites/blocks/fluid/{director => conduit}/aspect-channel-bottom-2.png (100%) rename assets/sprites/blocks/fluid/{director => conduit}/aspect-channel-bottom-3.png (100%) rename assets/sprites/blocks/fluid/{director => conduit}/aspect-channel-bottom-4.png (100%) rename assets/sprites/blocks/fluid/{director => conduit}/aspect-channel-top-0.png (100%) rename assets/sprites/blocks/fluid/{director => conduit}/aspect-channel-top-1.png (100%) rename assets/sprites/blocks/fluid/{director => conduit}/aspect-channel-top-2.png (100%) rename assets/sprites/blocks/fluid/{director => conduit}/aspect-channel-top-3.png (100%) rename assets/sprites/blocks/fluid/{director => conduit}/aspect-channel-top-4.png (100%) create mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-bottom-0.png create mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-bottom-1.png create mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-bottom-2.png create mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-bottom-3.png create mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-bottom-4.png create mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-preview.png create mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-top-0.png create mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-top-1.png create mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-top-2.png create mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-top-3.png create mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-top-4.png create mode 100644 assets/sprites/blocks/fluid/pipebox-on.png create mode 100644 assets/sprites/blocks/fluid/pipebox.png create mode 100644 assets/sprites/blocks/fluid/valve-controller-off.png create mode 100644 assets/sprites/blocks/fluid/valve-controller-on.png create mode 100644 assets/sprites/blocks/fluid/valve-controller.png create mode 100644 src/meld/world/blocks/fluid/Pipebox.java diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index bae631f..4964f03 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -168,6 +168,10 @@ block.meld-intake-valve.name = Intake Valve block.meld-intake-valve.description = Acts as a fluid junction, [purple]chain at your own expense[]. Can be toggled to control if fluids can pass through.\n\n[accent]Plated![] block.meld-intake-valve.details = Yes, it works. +block.meld-valve-controller.name = Valve Controller +block.meld-valve-controller.description = Acts as a fluid junction. Enables the targeted block when surounded by blocks with fluids of at least 10% pressure.\n\nCan be inverted! +block.meld-valve-controller.details = Scidustry players, Ikaru is calling YOU. + block.meld-channel-director.name = Channel Director block.meld-channel-director.description = [red]Restricts[] the flow of fluids from its input to output by half.\n\nCan [red]detonate[] Channel Nodes full of [#cbdbfc]Aspect[].\n[accent]Transports at 50% pressure.[]\n\n[red]Will chain destruct![] diff --git a/assets/sprites/blocks/fluid/director/aspect-channel-bottom-0.png b/assets/sprites/blocks/fluid/conduit/aspect-channel-bottom-0.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-channel-bottom-0.png rename to assets/sprites/blocks/fluid/conduit/aspect-channel-bottom-0.png diff --git a/assets/sprites/blocks/fluid/director/aspect-channel-bottom-1.png b/assets/sprites/blocks/fluid/conduit/aspect-channel-bottom-1.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-channel-bottom-1.png rename to assets/sprites/blocks/fluid/conduit/aspect-channel-bottom-1.png diff --git a/assets/sprites/blocks/fluid/director/aspect-channel-bottom-2.png b/assets/sprites/blocks/fluid/conduit/aspect-channel-bottom-2.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-channel-bottom-2.png rename to assets/sprites/blocks/fluid/conduit/aspect-channel-bottom-2.png diff --git a/assets/sprites/blocks/fluid/director/aspect-channel-bottom-3.png b/assets/sprites/blocks/fluid/conduit/aspect-channel-bottom-3.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-channel-bottom-3.png rename to assets/sprites/blocks/fluid/conduit/aspect-channel-bottom-3.png diff --git a/assets/sprites/blocks/fluid/director/aspect-channel-bottom-4.png b/assets/sprites/blocks/fluid/conduit/aspect-channel-bottom-4.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-channel-bottom-4.png rename to assets/sprites/blocks/fluid/conduit/aspect-channel-bottom-4.png diff --git a/assets/sprites/blocks/fluid/director/aspect-channel-top-0.png b/assets/sprites/blocks/fluid/conduit/aspect-channel-top-0.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-channel-top-0.png rename to assets/sprites/blocks/fluid/conduit/aspect-channel-top-0.png diff --git a/assets/sprites/blocks/fluid/director/aspect-channel-top-1.png b/assets/sprites/blocks/fluid/conduit/aspect-channel-top-1.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-channel-top-1.png rename to assets/sprites/blocks/fluid/conduit/aspect-channel-top-1.png diff --git a/assets/sprites/blocks/fluid/director/aspect-channel-top-2.png b/assets/sprites/blocks/fluid/conduit/aspect-channel-top-2.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-channel-top-2.png rename to assets/sprites/blocks/fluid/conduit/aspect-channel-top-2.png diff --git a/assets/sprites/blocks/fluid/director/aspect-channel-top-3.png b/assets/sprites/blocks/fluid/conduit/aspect-channel-top-3.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-channel-top-3.png rename to assets/sprites/blocks/fluid/conduit/aspect-channel-top-3.png diff --git a/assets/sprites/blocks/fluid/director/aspect-channel-top-4.png b/assets/sprites/blocks/fluid/conduit/aspect-channel-top-4.png similarity index 100% rename from assets/sprites/blocks/fluid/director/aspect-channel-top-4.png rename to assets/sprites/blocks/fluid/conduit/aspect-channel-top-4.png diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-bottom-0.png b/assets/sprites/blocks/fluid/conduit/channel-director-bottom-0.png new file mode 100644 index 0000000000000000000000000000000000000000..7e085ef1f6fc5248a63b609d826d7918b0b334ff GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`kpS1ArY-_ z&lxf@FmN2+&{%)onaw|I!OU%ElYd*X163dak4enF9V|BM&ZsnjL_J;oT-G@yGywo9 C#vL30 literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-bottom-1.png b/assets/sprites/blocks/fluid/conduit/channel-director-bottom-1.png new file mode 100644 index 0000000000000000000000000000000000000000..7e085ef1f6fc5248a63b609d826d7918b0b334ff GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`kpS1ArY-_ z&lxf@FmN2+&{%)onaw|I!OU%ElYd*X163dak4enF9V|BM&ZsnjL_J;oT-G@yGywo9 C#vL30 literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-bottom-2.png b/assets/sprites/blocks/fluid/conduit/channel-director-bottom-2.png new file mode 100644 index 0000000000000000000000000000000000000000..7e085ef1f6fc5248a63b609d826d7918b0b334ff GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`kpS1ArY-_ z&lxf@FmN2+&{%)onaw|I!OU%ElYd*X163dak4enF9V|BM&ZsnjL_J;oT-G@yGywo9 C#vL30 literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-bottom-3.png b/assets/sprites/blocks/fluid/conduit/channel-director-bottom-3.png new file mode 100644 index 0000000000000000000000000000000000000000..7e085ef1f6fc5248a63b609d826d7918b0b334ff GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`kpS1ArY-_ z&lxf@FmN2+&{%)onaw|I!OU%ElYd*X163dak4enF9V|BM&ZsnjL_J;oT-G@yGywo9 C#vL30 literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-bottom-4.png b/assets/sprites/blocks/fluid/conduit/channel-director-bottom-4.png new file mode 100644 index 0000000000000000000000000000000000000000..7e085ef1f6fc5248a63b609d826d7918b0b334ff GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`kpS1ArY-_ z&lxf@FmN2+&{%)onaw|I!OU%ElYd*X163dak4enF9V|BM&ZsnjL_J;oT-G@yGywo9 C#vL30 literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-preview.png b/assets/sprites/blocks/fluid/conduit/channel-director-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..3a596f8930334e02360463e0ee4e29d3ca0bc880 GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|6a#!hT!C~* zSmdP6#_Q|*mKZf$%G&sJ-Ss(z$tRcg|NsAAU)OR{DpVuK8gjD!O9Ekx;wT>3IxkeICY^4cAQ$ zH2Li~srt!{<$$f(P2Lv|8L!N0QaRbVM^kL#lc|yS15LPAb?+&76(03D>?DKA^H5zopr004)2A^-pY literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-top-0.png b/assets/sprites/blocks/fluid/conduit/channel-director-top-0.png new file mode 100644 index 0000000000000000000000000000000000000000..9dbc2c67eeffc28fe34a04871bd8c32b9f3054c3 GIT binary patch literal 279 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|sbKIQA;0`V5lwFN!eXDb^TPgRyH2_0ZAV6uDC z9C2blN4@7$btk4z9I;P+&HA*^Y<^Vjv|o8w4OTsMxqNEdeF+)MD*NTX8QyDiY~1o- Q6Ub8xp00i_>zopr02m2yhyVZp literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-top-1.png b/assets/sprites/blocks/fluid/conduit/channel-director-top-1.png new file mode 100644 index 0000000000000000000000000000000000000000..cc83ec7c13fd771de371bd7e77e28054d378f5d1 GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|6a#!hT!C~* zSmdP6#_Q|*mKZf$%G&sJ-Ss(z$tRcg|NsAAU)OR{#u|-N(wF{dtZP2uwt{)q5A%hL8ISspR|MWLS3bn}?M!FdlsK>N ztJ5d1c=eCjfN2BMI^~4@jbGF`ABRt2x$$bJS&{CQ<3aOhm1cd{G%zk&@FDPt(v}LH z=-tZSSX|yz7H~0|SQu8-NcYC^_r46*3#o$M%dRDr`eIHvGF_x~tXrmy^Gy-p@C5h?KPU7Fp!{s&V>hwGDzyY9BL zy5#&$`loUrQt4|Avm76T%#j7%KZB>W9Gto4ugD?=k+o3|=ZDlbG#=ciCCH}0=ykyH z)e-rZofoEC?HAC!U^g+#{x@q!g~_SKI|JpT@BUr$uDqOC`1ABy>75c$Rko8V-t4rJ vua27&Qpd2dYG>uXs*P)x?tcH)j?q5#567;E3 zFzE+Fe=LI=1LqTEj)co|#FzXF%4Of&_<^NnVtkAEgYG@DYTbt_Sp+!?#5_M-G~U1Y z#gQdUYD#J=YZO!z>=XaIe_g|HYQ0nG_vjU8gI1poy1rJ*ZR?zjsGHxUo0Z+)KQEcj Y`GI4vcEH*kpz|0!UHx3vIVCg!0AGo9PXGV_ literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-top-4.png b/assets/sprites/blocks/fluid/conduit/channel-director-top-4.png new file mode 100644 index 0000000000000000000000000000000000000000..d31af2ccf0cb257e60be412e48550d529ee60898 GIT binary patch literal 294 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|6a#!hT!C~* zSmdP6#_Q|*mKZf$%G&sJ-Ss(z$tRcg|NsAAU)OR{nlD7xtbhIsh#!ZjE8Gw*A~xRzcxh`F*8^&#_wcg z=ww~-lv9C8;efxz0dd#Ahcf?|Y;X2Zn9?Bkr~d-yi-Yga8i>4~ZQ0cDy~o9Lo|x+2 zM>iF^X6e7XPt literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/pipebox-on.png b/assets/sprites/blocks/fluid/pipebox-on.png new file mode 100644 index 0000000000000000000000000000000000000000..3444e334ebdefea0a15f3572b5ecb68b63427e51 GIT binary patch literal 1087 zcmV-F1i<@=P)Px&`AI}UR9J<@mrrOUMHI$=T~(c#$@C;EsEY>=D#Wly!^$3ZhYb=zWD#{yg6D*l zJ%~vzCfNwPaZeisVNqAF5*EcE9y|m|b|&~Q%uQkpc=aU6I?2q$>8kQD)03X=owD#nPLG3YtJ^WLVW@DJ!YX?qh){q+ zsee&n&bB0sI!(fl-)^w|{bqc?DdX!udd`n>bUg*JecmYGx(ZjtcW!9dBbW0iY!qT+ zh0<>8i=s_H(iQ|Fikn5GR465J-MD~U&cn-Pky26IEOuN}G^twxy6ykgy$1QIAqQ8* zBXD=;H*!OP0Ev`}t$Y26=y?&nv+^-QD9$|jAWAhNaCiCjHXARO#q+Xw-XKycq>u>F zJraEhSiW@!AtX;d{W!y?AL5C}9%1$Rl{TB=eU0Z0lJy43W(OPOQX+&v2$`4@VYDuy zXu^H^O zNC0!Evjyu#6naQL{r&FZTDN?Bvsnh@i11|1>LM5D<0Er_LBRM8! zUh6ms;P%&BJp1ws02pZi@O_2rDwNwGy>k9c+ngZL6R+ZK*JTuwOCKSGgA|PbKJ(%w zgcOZW2%dj*7#Qw2KR-6w64BRd7~t~!ZKPw1TeYuA;uVtF-_62s_#fZ zQo#VQIQIt2x9(uA!di*33S%U=RV)sUwK$FwbNJRLYiMoITJvWaw6^5O$76N@Z`Ye} zac&x8bYnGIqm4#u-6Sx4e)DRZ{q-+4k)Frthfi_848~~k9-?Z*XF zDh&aPbJMZ0{Mcygi^BPN?cLTH`6or`N#}O#3;s=nZ^DjSFfo$rt4i*LUVfZ@n$u`_ zgB3(uvuFgP#7SLNU$0@Px(0ZBwbR9J<@S6yfvRTTc_-aGr3-Inwzi9Zp+l7v=hOFvnVd=(L+N3 zfa>OU1QQTY1H6>NO98lEs}ko0HQ_jMnMUqL9(D^-}LfGNV6+qJuh zQmKgQN;NcB-Q4zvjt&A*Dey?Fudai00U(hKg=XIGHV=aA3mkjrP0%elk8c@sbU^g9@1FkoQm%&CykPquzVz1~2*b_?~| zE!1jt2;Q5lfL@{ec9dSxnHd4o6zILTANz(M0Ot&xGrYKPDP(kfcmUaK2APZrGb2Lj zic}z|g8r?Z|8&(?A)C!0lQq$}@dv)!{uuz^I1b*aOvXC#;1zl>SYLspb~%4y3}>Er z6pR_}Fc@~DJbO*$8q4O(5df^0$W!W9mKTa3m2Ebxj@EjgL4MP7(QQksbkICYu`dC z2P6r$EwQ$I4WtM}5=8EE^s&*9ZEs6X?1XbOQ&5Uv%d8)juEgo12Vhw(SgjT;s|8X7 zMRZ#MigX@C*S%nNx(ubHPl8C{$;x8K8mrlIht+Z;R|KUbj*K1YX8sO=q{GPBN*P2F zZ94-=1SzRwe*VN5nhgt9v*pWvwo;DmEjv09%}$s7yh@_be6wkx*|b0;F*{xM|JO3PlD6apOe-e0Al|Jb|V&c)I$ztaD0e0s!|$F<$@x literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/valve-controller-on.png b/assets/sprites/blocks/fluid/valve-controller-on.png new file mode 100644 index 0000000000000000000000000000000000000000..514ff15fb6384b87e1ac5a58bf7c4604c6fdb5be GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}*`6+rArY;~ z2@`rSYcz| zf)k8a3RsTvDLmnD;!9f8#;n1(m`~zX=Y(fB3j#!3n4?4{zv3v;S{!J=<#td*qJV*6 Y`2!uH%j=DrfYvg2y85}Sb4q9e0O24w^#A|> literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/valve-controller.png b/assets/sprites/blocks/fluid/valve-controller.png new file mode 100644 index 0000000000000000000000000000000000000000..7a5faaad969138cf17f9ef51c854bfaf8bcbec0a GIT binary patch literal 956 zcmV;t14I0YP)Px&c1c7*R9J<@S51!8I28VD$98(b5fIW0YI=c$Pz#pq`UX>7YD$1+!7*6Po(r%* zfJ!aIf&;MYC8*VEgfz`xX;5sKTD(O{ zB1KE$)rW7Lb9*!J>ch9*pg)2Khi}%%rXYX6d>Av3vdo$0c>nG-2=Uj>0avcx?46qv zXtRqv1AE&S)=1>|e0B`RD7H!g5*Rq=@XyB+7-RAK&hDUpy7(G_F6L<#zI-}CSqd;l zK?wn&fq-?e&cPUqFP~0u>GJiJIBAT%?bX6u*@j(D-=^<;aSAB~O36`5fvr+vO9m?? z$}lFS!1>~|_o4Eljs%8M|8?;eQgCllpe(yhN)hLMUA!GdVxtbsUp$8t971piQGgd5 zoHJ1BUjqPG=U}acrUsOfSR3byQ(XM*+F<-a0?(cwLP`P73kXp_a8INt7z##Lim)*j zl+t8p_`2w-i4;+Y@~!fCKKH2&?^Ox`DLDi$zjp|UsB4W{Db%$>Rcln0 z>fIf&2J$`67!Afy6bziVzr~=Xa~WeXP9Hi)9zA&qN(d++V3dMU3Q8%8NXlEmy6@58 z!$O@f1oMqT)HDW4X(+9O7HHJ9 z>J*~3Q5h`4JJSPb-FSgfO$@A*MpcJJYJaU%7}FX`HPLTK1ve4^fZ1f~7gsteTvfL! zw|ec>&y!KA+4vn;A&@r;DQ-{peL6!*tE$`TTE%&{C;PpvSlX entity.invert = b); } float total; public class ValveControllerBuild extends FlexibleBuild{ + public boolean invert = false; + @Override public void updateTile() { super.updateTile(); + enablingLogic(); + } + + public void enablingLogic(){ total = 0; proximity.each(b -> { @@ -31,9 +65,42 @@ public void updateTile() { if(invert) enable = !enable; - for(Building b: proximity){ - if(b.block.configurable) b.configure(enable); - } + Building b = tile.nearbyBuild(rotation); + if(b == null) return; + + if(b.block.configurable) b.configure(enable); + else b.enabled = enable; + } + + @Override + public boolean configTapped(){ + configure(!invert); + clickSound.at(this); + return false; + } + + @Override + public Boolean config(){ + return enabled; + } + + @Override + public void draw(){ + super.draw(); + + Draw.rect(signRegions[invert ? 1 : 0], x, y, rotation * 90); + } + + @Override + public void write(Writes write) { + super.write(write); + write.bool(invert); + } + + @Override + public void read(Reads read, byte revision) { + super.read(read, revision); + invert = read.bool(); } } } From d13328c34cb167c0cbef0997088da15901a2a177 Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Sat, 4 Apr 2026 02:29:04 +1100 Subject: [PATCH 15/17] Final batch of changes before gameplay test -Channel Directors are now diodes -Changed aspect channels so they can route backwards... yeah... -Valve controller has new sprites -Valve controllers now properly save config -Valve controllers have a bar to help show how much their threshold is met/isn't -Valve controllers have ui when clicked instead of being toggled -Have I mentioned valve controllers yet --- .../conduit/channel-director-bottom-0.png | Bin 117 -> 0 bytes .../conduit/channel-director-bottom-1.png | Bin 117 -> 0 bytes .../conduit/channel-director-bottom-2.png | Bin 117 -> 0 bytes .../conduit/channel-director-bottom-3.png | Bin 117 -> 0 bytes .../conduit/channel-director-bottom-4.png | Bin 117 -> 0 bytes .../fluid/conduit/channel-director-top-0.png | Bin 279 -> 0 bytes .../fluid/conduit/channel-director-top-1.png | Bin 313 -> 0 bytes .../fluid/conduit/channel-director-top-2.png | Bin 307 -> 0 bytes .../fluid/conduit/channel-director-top-3.png | Bin 285 -> 0 bytes .../fluid/conduit/channel-director-top-4.png | Bin 294 -> 0 bytes ...ector-preview.png => channel-director.png} | Bin .../blocks/fluid/valve-controller-bottom.png | Bin 0 -> 122 bytes .../blocks/fluid/valve-controller-off.png | Bin 152 -> 366 bytes .../blocks/fluid/valve-controller-on.png | Bin 177 -> 459 bytes .../sprites/blocks/fluid/valve-controller.png | Bin 956 -> 774 bytes src/meld/content/MeldBlocks.java | 6 +- src/meld/world/blocks/fluid/AspectPipe.java | 17 +++- .../world/blocks/fluid/ChannelDirector.java | 33 +++++++ .../blocks/fluid/FlexibleSizeJunction.java | 41 +++++--- src/meld/world/blocks/fluid/Pipebox.java | 21 +++- .../world/blocks/fluid/ValveController.java | 90 ++++++++++++++++-- 21 files changed, 174 insertions(+), 34 deletions(-) delete mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-bottom-0.png delete mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-bottom-1.png delete mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-bottom-2.png delete mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-bottom-3.png delete mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-bottom-4.png delete mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-top-0.png delete mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-top-1.png delete mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-top-2.png delete mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-top-3.png delete mode 100644 assets/sprites/blocks/fluid/conduit/channel-director-top-4.png rename assets/sprites/blocks/fluid/conduit/{channel-director-preview.png => channel-director.png} (100%) create mode 100644 assets/sprites/blocks/fluid/valve-controller-bottom.png create mode 100644 src/meld/world/blocks/fluid/ChannelDirector.java diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-bottom-0.png b/assets/sprites/blocks/fluid/conduit/channel-director-bottom-0.png deleted file mode 100644 index 7e085ef1f6fc5248a63b609d826d7918b0b334ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`kpS1ArY-_ z&lxf@FmN2+&{%)onaw|I!OU%ElYd*X163dak4enF9V|BM&ZsnjL_J;oT-G@yGywo9 C#vL30 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-bottom-1.png b/assets/sprites/blocks/fluid/conduit/channel-director-bottom-1.png deleted file mode 100644 index 7e085ef1f6fc5248a63b609d826d7918b0b334ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`kpS1ArY-_ z&lxf@FmN2+&{%)onaw|I!OU%ElYd*X163dak4enF9V|BM&ZsnjL_J;oT-G@yGywo9 C#vL30 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-bottom-2.png b/assets/sprites/blocks/fluid/conduit/channel-director-bottom-2.png deleted file mode 100644 index 7e085ef1f6fc5248a63b609d826d7918b0b334ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`kpS1ArY-_ z&lxf@FmN2+&{%)onaw|I!OU%ElYd*X163dak4enF9V|BM&ZsnjL_J;oT-G@yGywo9 C#vL30 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-bottom-3.png b/assets/sprites/blocks/fluid/conduit/channel-director-bottom-3.png deleted file mode 100644 index 7e085ef1f6fc5248a63b609d826d7918b0b334ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`kpS1ArY-_ z&lxf@FmN2+&{%)onaw|I!OU%ElYd*X163dak4enF9V|BM&ZsnjL_J;oT-G@yGywo9 C#vL30 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-bottom-4.png b/assets/sprites/blocks/fluid/conduit/channel-director-bottom-4.png deleted file mode 100644 index 7e085ef1f6fc5248a63b609d826d7918b0b334ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`kpS1ArY-_ z&lxf@FmN2+&{%)onaw|I!OU%ElYd*X163dak4enF9V|BM&ZsnjL_J;oT-G@yGywo9 C#vL30 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-top-0.png b/assets/sprites/blocks/fluid/conduit/channel-director-top-0.png deleted file mode 100644 index 9dbc2c67eeffc28fe34a04871bd8c32b9f3054c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 279 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|sbKIQA;0`V5lwFN!eXDb^TPgRyH2_0ZAV6uDC z9C2blN4@7$btk4z9I;P+&HA*^Y<^Vjv|o8w4OTsMxqNEdeF+)MD*NTX8QyDiY~1o- Q6Ub8xp00i_>zopr02m2yhyVZp diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-top-1.png b/assets/sprites/blocks/fluid/conduit/channel-director-top-1.png deleted file mode 100644 index cc83ec7c13fd771de371bd7e77e28054d378f5d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|6a#!hT!C~* zSmdP6#_Q|*mKZf$%G&sJ-Ss(z$tRcg|NsAAU)OR{#u|-N(wF{dtZP2uwt{)q5A%hL8ISspR|MWLS3bn}?M!FdlsK>N ztJ5d1c=eCjfN2BMI^~4@jbGF`ABRt2x$$bJS&{CQ<3aOhm1cd{G%zk&@FDPt(v}LH z=-tZSSX|yz7H~0|SQu8-NcYC^_r46*3#o$M%dRDr`eIHvGF_x~tXrmy^Gy-p@C5h?KPU7Fp!{s&V>hwGDzyY9BL zy5#&$`loUrQt4|Avm76T%#j7%KZB>W9Gto4ugD?=k+o3|=ZDlbG#=ciCCH}0=ykyH z)e-rZofoEC?HAC!U^g+#{x@q!g~_SKI|JpT@BUr$uDqOC`1ABy>75c$Rko8V-t4rJ vua27&Qpd2dYG>uXs*P)x?tcH)j?q5#567;E3 zFzE+Fe=LI=1LqTEj)co|#FzXF%4Of&_<^NnVtkAEgYG@DYTbt_Sp+!?#5_M-G~U1Y z#gQdUYD#J=YZO!z>=XaIe_g|HYQ0nG_vjU8gI1poy1rJ*ZR?zjsGHxUo0Z+)KQEcj Y`GI4vcEH*kpz|0!UHx3vIVCg!0AGo9PXGV_ diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-top-4.png b/assets/sprites/blocks/fluid/conduit/channel-director-top-4.png deleted file mode 100644 index d31af2ccf0cb257e60be412e48550d529ee60898..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 294 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|6a#!hT!C~* zSmdP6#_Q|*mKZf$%G&sJ-Ss(z$tRcg|NsAAU)OR{nlD7xtbhIsh#!ZjE8Gw*A~xRzcxh`F*8^&#_wcg z=ww~-lv9C8;efxz0dd#Ahcf?|Y;X2Zn9?Bkr~d-yi-Yga8i>4~ZQ0cDy~o9Lo|x+2 zM>iF^X6e7XPt diff --git a/assets/sprites/blocks/fluid/conduit/channel-director-preview.png b/assets/sprites/blocks/fluid/conduit/channel-director.png similarity index 100% rename from assets/sprites/blocks/fluid/conduit/channel-director-preview.png rename to assets/sprites/blocks/fluid/conduit/channel-director.png diff --git a/assets/sprites/blocks/fluid/valve-controller-bottom.png b/assets/sprites/blocks/fluid/valve-controller-bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..26bc929372184d211b8f67768682d3a9b0dac517 GIT binary patch literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}CY~;iArY-_ z&lxf@7;qdpuv|%dk@UZIrRJwe3gLg>oliVK$p0PF$Vz^vcvzTe$H ze8vb^>VVw71DqyV>Q)_gd2s#I%+$n+uM}epME~#ZUy4Kctqx1Q<(v zs}s-y_LD3fg$NK4SE0EsFV3VBa{-$w=i7YiqAfM%XaRqY7T{OB)7WWPHD>+7TaDK}iVeds Zj4z1$VnwgNJi`D0002ovPDHLkV1k0vmY@It delta 111 zcmV-#0FeLg0+<1iFlYc$Nklr6D$r9I& zLN{N)!58ROaCB{!ta$@Lgf5mkWE3qFsgR-6R$NZyQgV~qYN?u_=1Aiv>4^N+&8OVcT(j%arm5GI{)PcCw?hNL0IuB$*QaCTWfx#@Sw` zN&@~8D+y4xpen-@LowqIQd_G*3oZ$+Fn<7RNklma8MLP r16mZ5>IiZwqfsylM!_f;Z~y?O;4Bi;uQGxF0000nwish*}Gd3C4AB+`Fyi8-_Fg>?v@(O z=m`gV(MR{M6rJQG^WC3}E$4ds510=z%9{1&#ySAUr)OT6 z6=9(wj?O1u+sq6coli2Iz671*I7kkF5%693O{mW!v6;c~=~+q_GXi|G zR}sTOvJZ@fR)0hqT;GeW7j99f0`gKn93*?dh0qEZIlsqhCu0gl6gHw(ySoqk5MCM) zV#zo32^&1l=#j?>M^vt??)H^8zK*PU5<3mMCBMYt?uRgf2@uU|et zk0alhBeI*Qp7(M$#k zMC>{Fs;BkRQN>&K^OLH9w6SKp3*1F#}v UI)tn&&j0`b07*qoM6N<$f^ZdEf&c&j delta 922 zcmV;L17-Y%2D}H5Fn3$Q?dN-e~K1F-8QsMTtOG|gXWP;&zoBzA1i!j8-3N>Tx7hEIB`RP6Ws z<>mRyGx=lxz#+q52RHIt5f2XE^p5?EFCC2bKcE;hsqd+8?SJk70FI8&I_C~$qXkJ{ zK^qVN_O>sKTD(O{B1KE$)rW7Lb9*!J>ch9*pg)2Khi}%%rXYX6d>Av3vdo$0c>nG- z2=Uj>0avcx?46qvXtRqv1AE&S)=1>|e0B`RD7H!g5*Rq=@XyB+7-RAK&hDUpy7(G_ zF6L<#zI-}CS$_&JMnMSyp@D#Pu+G64i!Yx}aOv{(l{jgPz3tV)T-kR$r@Sm$7^g{B6Sl2{w(i+@vG{O#Ic{6PZGo*zO=0nQ5u zQ9y7{q$n5)MpufkF&324WM}xg=&FenQHb)b@_0V?sSWQ{3IQoO1TVmO0hSRk#zN}` zN;jx$jan(xwL(>ERF&%89kB-TJ8=eDSwJc%3Hy@@6q7HLY+`T@c!Lv+}hn)%XB1=4iEy6u+ItcM#=Iz|35UgjImra zUF(;Bjyr3>IbT@LI{zCg+PUukLu1Pr%SF?*Ix}$p-d(@9orAF!##&fw(HIMpSYx{H z+2CWWjd8AAy@{jav$bN6I*=E~GN?h*m>@EV_f z1oMqT)HDW4X(+9O7HHJ9>J*~3Q5h`4JJSPb-FSgfO$@A*MpcJJYJaU%7}FX`HPLTK z1ve4^fZ1f~7gsteTvfL!w|ec>&y!KA+4vn;A&@r;DQ-{peL6!*tE$`TTE%&{C;Ppv zSby5Au4G_{#B4HMYJ08ly{hrO4p!A68=l~7GL3#YiM&%D)t0xoGd;lL`FzHT|mNBgFk?mZX$m)NL;2rP$cVk|brA!81wedmSzXg1XU wqvw=0stD6SX^>pkkB-kqod;9=^3U entity.invert = b); + config(Float.class, (ValveControllerBuild entity, Float f) -> entity.threshold = f); + config(Float[].class, (ValveControllerBuild entity, Float[] floats) -> { + entity.threshold = floats[0]; + Log.info(floats[1]); + entity.invert = floats[1] == -1f; + }); } - float total; - public class ValveControllerBuild extends FlexibleBuild{ public boolean invert = false; + public float threshold = minPressure; + public float lastTotal = 0; @Override public void updateTile() { @@ -56,12 +82,12 @@ public void updateTile() { public void enablingLogic(){ - total = 0; + lastTotal = 0; proximity.each(b -> { - if(b.liquids != null) total += b.liquids.currentAmount()/b.block.liquidCapacity; + if(b.liquids != null) lastTotal += b.liquids.currentAmount()/b.block.liquidCapacity; }); - boolean enable = total >= minPressure; + boolean enable = lastTotal >= threshold; if(invert) enable = !enable; @@ -74,33 +100,79 @@ public void enablingLogic(){ @Override public boolean configTapped(){ + /* configure(!invert); + + */ clickSound.at(this); - return false; + return true; + } + + @Override + public void buildConfiguration(Table table){ + table.slider(0, 1, 0.1f, threshold, Vars.net.active(), this::configure).size(240, 40f); + table.row(); + table.button(Icon.pencil, Styles.cleari, () -> { + configure(!invert); + }).size(40f); + } + + @Override + public boolean onConfigureBuildTapped(Building other){ + if(this == other){ + deselect(); + return false; + } + + return true; } @Override - public Boolean config(){ - return enabled; + public Float[] config(){ + return new Float[]{ + threshold, invert ? -1f : 1f + }; } @Override public void draw(){ - super.draw(); + Draw.z(Layer.blockUnder); + + Draw.rect(bottomRegion, x, y); + + Draw.z(Layer.block); + + + //Im sure theres a simpler formula but like... come on + float fin = threshold; + Draw.color(indicatorColor); + Fill.rect(x, y - (1 - fin)/2f * (Vars.tilesize) - fin * padding + padding, Vars.tilesize, (Vars.tilesize - padding * 2) * fin); + + fin = Mathf.clamp(lastTotal); + Draw.color(fillColor); + Fill.rect(x, y - (1 - fin)/2f * (Vars.tilesize) - fin * padding + padding, Vars.tilesize, (Vars.tilesize - padding * 2) * fin); + + Draw.color(); + + //Draw.rect(region, x, y); Draw.rect(signRegions[invert ? 1 : 0], x, y, rotation * 90); + + Draw.rect(region, x, y); } @Override public void write(Writes write) { super.write(write); write.bool(invert); + write.f(threshold); } @Override public void read(Reads read, byte revision) { super.read(read, revision); invert = read.bool(); + threshold = read.f(); } } } From a1b41e0ed48f132a84d71a7a9eb7039d84f4c3fa Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Sat, 4 Apr 2026 13:12:15 +1100 Subject: [PATCH 16/17] plan regions, descriptions -Channel Valves now draw as their enabled selves -Pipeboxes overhauled- now has a direction and can be inverted. Rotating pipeboxes switches their connection paths. -Valve controllers now more clearly display their threshold, and the "fullness" visual can overlap with the threshold visual, drawing as yellow -Channel Vents don't take carbolith for now -Node capacity doubled! -Channel directors given new visual -Distrib block sprites now in distrib block folder... phew -Proper visuals for most custom liquid blocks in plans --- assets/bundles/bundle.properties | 9 +- .../{ => blocks/distrib}/chute-bottom-0.png | Bin .../{ => blocks/distrib}/chute-bottom-1.png | Bin .../{ => blocks/distrib}/chute-bottom-2.png | Bin .../{ => blocks/distrib}/chute-bottom-3.png | Bin .../{ => blocks/distrib}/chute-bottom-4.png | Bin .../distrib}/chute-bridge-arrow.png | Bin .../distrib}/chute-bridge-bottom.png | Bin .../distrib}/chute-bridge-bridge.png | Bin .../{ => blocks/distrib}/chute-bridge-dir.png | Bin .../{ => blocks/distrib}/chute-bridge.png | Bin .../distrib}/chute-crossing-bottom.png | Bin .../distrib}/chute-crossing-top.png | Bin .../{ => blocks/distrib}/chute-crossing.png | Bin .../distrib}/chute-overflow-top.png | Bin .../{ => blocks/distrib}/chute-overflow.png | Bin .../{ => blocks/distrib}/chute-router-top.png | Bin .../{ => blocks/distrib}/chute-router.png | Bin .../{ => blocks/distrib}/chute-top-0.png | Bin .../{ => blocks/distrib}/chute-top-1.png | Bin .../{ => blocks/distrib}/chute-top-2.png | Bin .../{ => blocks/distrib}/chute-top-3.png | Bin .../{ => blocks/distrib}/chute-top-4.png | Bin .../distrib}/chute-unloader-center.png | Bin .../{ => blocks/distrib}/chute-unloader.png | Bin .../distrib}/unloading-hub-center.png | Bin .../{ => blocks/distrib}/unloading-hub.png | Bin .../sprites/blocks/fluid/channel-director.png | Bin 0 -> 1121 bytes .../blocks/fluid/conduit/channel-director.png | Bin 289 -> 0 bytes .../sprites/blocks/fluid/manual-valve-on.png | Bin 478 -> 1262 bytes assets/sprites/blocks/fluid/manual-valve.png | Bin 438 -> 967 bytes .../blocks/fluid/pipebox-direction.png | Bin 0 -> 941 bytes .../blocks/fluid/pipebox-marker-on.png | Bin 0 -> 201 bytes .../sprites/blocks/fluid/pipebox-marker.png | Bin 0 -> 226 bytes assets/sprites/blocks/fluid/pipebox-on.png | Bin 1087 -> 1256 bytes assets/sprites/blocks/fluid/pipebox.png | Bin 1095 -> 1282 bytes .../blocks/fluid/pressure-vent-bottom.png | Bin 0 -> 1026 bytes .../{ => blocks/fluid}/pressure-vent.png | Bin .../blocks/fluid/valve-controller-bottom.png | Bin 122 -> 1112 bytes .../blocks/fluid/valve-controller-off.png | Bin 366 -> 0 bytes .../blocks/fluid/valve-controller-on.png | Bin 459 -> 0 bytes .../fluid/valve-controller-sign-inverted.png | Bin 0 -> 152 bytes .../blocks/fluid/valve-controller-sign.png | Bin 0 -> 177 bytes .../sprites/blocks/fluid/valve-controller.png | Bin 774 -> 660 bytes assets/sprites/pressure-vent-bottom.png | Bin 328 -> 0 bytes src/meld/content/MeldBlocks.java | 7 +- src/meld/world/blocks/fluid/ChannelValve.java | 13 +++ src/meld/world/blocks/fluid/Pipebox.java | 102 +++++++++++++++++- .../world/blocks/fluid/ValveController.java | 56 ++++++++-- 49 files changed, 167 insertions(+), 20 deletions(-) rename assets/sprites/{ => blocks/distrib}/chute-bottom-0.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-bottom-1.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-bottom-2.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-bottom-3.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-bottom-4.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-bridge-arrow.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-bridge-bottom.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-bridge-bridge.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-bridge-dir.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-bridge.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-crossing-bottom.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-crossing-top.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-crossing.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-overflow-top.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-overflow.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-router-top.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-router.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-top-0.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-top-1.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-top-2.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-top-3.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-top-4.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-unloader-center.png (100%) rename assets/sprites/{ => blocks/distrib}/chute-unloader.png (100%) rename assets/sprites/{ => blocks/distrib}/unloading-hub-center.png (100%) rename assets/sprites/{ => blocks/distrib}/unloading-hub.png (100%) create mode 100644 assets/sprites/blocks/fluid/channel-director.png delete mode 100644 assets/sprites/blocks/fluid/conduit/channel-director.png create mode 100644 assets/sprites/blocks/fluid/pipebox-direction.png create mode 100644 assets/sprites/blocks/fluid/pipebox-marker-on.png create mode 100644 assets/sprites/blocks/fluid/pipebox-marker.png create mode 100644 assets/sprites/blocks/fluid/pressure-vent-bottom.png rename assets/sprites/{ => blocks/fluid}/pressure-vent.png (100%) delete mode 100644 assets/sprites/blocks/fluid/valve-controller-off.png delete mode 100644 assets/sprites/blocks/fluid/valve-controller-on.png create mode 100644 assets/sprites/blocks/fluid/valve-controller-sign-inverted.png create mode 100644 assets/sprites/blocks/fluid/valve-controller-sign.png delete mode 100644 assets/sprites/pressure-vent-bottom.png diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index 4964f03..10d0f44 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -165,15 +165,18 @@ block.meld-manual-valve.name = Manual Valve block.meld-manual-valve.description = Acts as a fluid junction. Can be toggled to control if fluids can pass through. block.meld-intake-valve.name = Intake Valve -block.meld-intake-valve.description = Acts as a fluid junction, [purple]chain at your own expense[]. Can be toggled to control if fluids can pass through.\n\n[accent]Plated![] +block.meld-intake-valve.description = Acts as a fluid junction. Can be toggled to control if fluids can pass through.\n\n[accent]Plated![] block.meld-intake-valve.details = Yes, it works. block.meld-valve-controller.name = Valve Controller -block.meld-valve-controller.description = Acts as a fluid junction. Enables the targeted block when surounded by blocks with fluids of at least 10% pressure.\n\nCan be inverted! +block.meld-valve-controller.description = Acts as a fluid junction. Enables the targeted block when surrounded by blocks with fluids over its threshold.\n\nThreshold/State can be configured. block.meld-valve-controller.details = Scidustry players, Ikaru is calling YOU. block.meld-channel-director.name = Channel Director -block.meld-channel-director.description = [red]Restricts[] the flow of fluids from its input to output by half.\n\nCan [red]detonate[] Channel Nodes full of [#cbdbfc]Aspect[].\n[accent]Transports at 50% pressure.[]\n\n[red]Will chain destruct![] +block.meld-channel-director.description = When used with other fluid blocks, [red]restricts[] the flow of fluids to one direction only. + +block.meld-pipebox.name = Pipebox +block.meld-pipebox.description = Routes fluids to the sides.\n\nCan be toggled to rotate the connections. block.meld-channel-director-pressurized.name = Pressurized Channel Director block.meld-channel-director-pressurized.description = Acts as a conduit. Transmits fluid from one side to the other. Stores a tiny amount of fluid.\n[accent]Transports at 200% pressure.[]\n\n[red]Will chain destruct![] diff --git a/assets/sprites/chute-bottom-0.png b/assets/sprites/blocks/distrib/chute-bottom-0.png similarity index 100% rename from assets/sprites/chute-bottom-0.png rename to assets/sprites/blocks/distrib/chute-bottom-0.png diff --git a/assets/sprites/chute-bottom-1.png b/assets/sprites/blocks/distrib/chute-bottom-1.png similarity index 100% rename from assets/sprites/chute-bottom-1.png rename to assets/sprites/blocks/distrib/chute-bottom-1.png diff --git a/assets/sprites/chute-bottom-2.png b/assets/sprites/blocks/distrib/chute-bottom-2.png similarity index 100% rename from assets/sprites/chute-bottom-2.png rename to assets/sprites/blocks/distrib/chute-bottom-2.png diff --git a/assets/sprites/chute-bottom-3.png b/assets/sprites/blocks/distrib/chute-bottom-3.png similarity index 100% rename from assets/sprites/chute-bottom-3.png rename to assets/sprites/blocks/distrib/chute-bottom-3.png diff --git a/assets/sprites/chute-bottom-4.png b/assets/sprites/blocks/distrib/chute-bottom-4.png similarity index 100% rename from assets/sprites/chute-bottom-4.png rename to assets/sprites/blocks/distrib/chute-bottom-4.png diff --git a/assets/sprites/chute-bridge-arrow.png b/assets/sprites/blocks/distrib/chute-bridge-arrow.png similarity index 100% rename from assets/sprites/chute-bridge-arrow.png rename to assets/sprites/blocks/distrib/chute-bridge-arrow.png diff --git a/assets/sprites/chute-bridge-bottom.png b/assets/sprites/blocks/distrib/chute-bridge-bottom.png similarity index 100% rename from assets/sprites/chute-bridge-bottom.png rename to assets/sprites/blocks/distrib/chute-bridge-bottom.png diff --git a/assets/sprites/chute-bridge-bridge.png b/assets/sprites/blocks/distrib/chute-bridge-bridge.png similarity index 100% rename from assets/sprites/chute-bridge-bridge.png rename to assets/sprites/blocks/distrib/chute-bridge-bridge.png diff --git a/assets/sprites/chute-bridge-dir.png b/assets/sprites/blocks/distrib/chute-bridge-dir.png similarity index 100% rename from assets/sprites/chute-bridge-dir.png rename to assets/sprites/blocks/distrib/chute-bridge-dir.png diff --git a/assets/sprites/chute-bridge.png b/assets/sprites/blocks/distrib/chute-bridge.png similarity index 100% rename from assets/sprites/chute-bridge.png rename to assets/sprites/blocks/distrib/chute-bridge.png diff --git a/assets/sprites/chute-crossing-bottom.png b/assets/sprites/blocks/distrib/chute-crossing-bottom.png similarity index 100% rename from assets/sprites/chute-crossing-bottom.png rename to assets/sprites/blocks/distrib/chute-crossing-bottom.png diff --git a/assets/sprites/chute-crossing-top.png b/assets/sprites/blocks/distrib/chute-crossing-top.png similarity index 100% rename from assets/sprites/chute-crossing-top.png rename to assets/sprites/blocks/distrib/chute-crossing-top.png diff --git a/assets/sprites/chute-crossing.png b/assets/sprites/blocks/distrib/chute-crossing.png similarity index 100% rename from assets/sprites/chute-crossing.png rename to assets/sprites/blocks/distrib/chute-crossing.png diff --git a/assets/sprites/chute-overflow-top.png b/assets/sprites/blocks/distrib/chute-overflow-top.png similarity index 100% rename from assets/sprites/chute-overflow-top.png rename to assets/sprites/blocks/distrib/chute-overflow-top.png diff --git a/assets/sprites/chute-overflow.png b/assets/sprites/blocks/distrib/chute-overflow.png similarity index 100% rename from assets/sprites/chute-overflow.png rename to assets/sprites/blocks/distrib/chute-overflow.png diff --git a/assets/sprites/chute-router-top.png b/assets/sprites/blocks/distrib/chute-router-top.png similarity index 100% rename from assets/sprites/chute-router-top.png rename to assets/sprites/blocks/distrib/chute-router-top.png diff --git a/assets/sprites/chute-router.png b/assets/sprites/blocks/distrib/chute-router.png similarity index 100% rename from assets/sprites/chute-router.png rename to assets/sprites/blocks/distrib/chute-router.png diff --git a/assets/sprites/chute-top-0.png b/assets/sprites/blocks/distrib/chute-top-0.png similarity index 100% rename from assets/sprites/chute-top-0.png rename to assets/sprites/blocks/distrib/chute-top-0.png diff --git a/assets/sprites/chute-top-1.png b/assets/sprites/blocks/distrib/chute-top-1.png similarity index 100% rename from assets/sprites/chute-top-1.png rename to assets/sprites/blocks/distrib/chute-top-1.png diff --git a/assets/sprites/chute-top-2.png b/assets/sprites/blocks/distrib/chute-top-2.png similarity index 100% rename from assets/sprites/chute-top-2.png rename to assets/sprites/blocks/distrib/chute-top-2.png diff --git a/assets/sprites/chute-top-3.png b/assets/sprites/blocks/distrib/chute-top-3.png similarity index 100% rename from assets/sprites/chute-top-3.png rename to assets/sprites/blocks/distrib/chute-top-3.png diff --git a/assets/sprites/chute-top-4.png b/assets/sprites/blocks/distrib/chute-top-4.png similarity index 100% rename from assets/sprites/chute-top-4.png rename to assets/sprites/blocks/distrib/chute-top-4.png diff --git a/assets/sprites/chute-unloader-center.png b/assets/sprites/blocks/distrib/chute-unloader-center.png similarity index 100% rename from assets/sprites/chute-unloader-center.png rename to assets/sprites/blocks/distrib/chute-unloader-center.png diff --git a/assets/sprites/chute-unloader.png b/assets/sprites/blocks/distrib/chute-unloader.png similarity index 100% rename from assets/sprites/chute-unloader.png rename to assets/sprites/blocks/distrib/chute-unloader.png diff --git a/assets/sprites/unloading-hub-center.png b/assets/sprites/blocks/distrib/unloading-hub-center.png similarity index 100% rename from assets/sprites/unloading-hub-center.png rename to assets/sprites/blocks/distrib/unloading-hub-center.png diff --git a/assets/sprites/unloading-hub.png b/assets/sprites/blocks/distrib/unloading-hub.png similarity index 100% rename from assets/sprites/unloading-hub.png rename to assets/sprites/blocks/distrib/unloading-hub.png diff --git a/assets/sprites/blocks/fluid/channel-director.png b/assets/sprites/blocks/fluid/channel-director.png new file mode 100644 index 0000000000000000000000000000000000000000..35b1b9668c2e0cb3aa478270e704fb6bbc1aa94c GIT binary patch literal 1121 zcmV-n1fKheP)Px(8%ab#R9J=0S6hfxRT%!(|F3;cbIy$8V?;zHRz!q32tAaD)Ffk~qfE`y49L z1&g)!{x9G6|7)$i{v|eTZaB2H1C2H9pVGGX!*hkQe_~6e-u{OsvoC9hZUX?!&Mo2o zTLwxE6WyeJeg3CX{n@#t)F!K&W}w~S?A%h%;6>kxd}Vb@ry!3+8Bm_AED!(?Kc1O( z-4wIaQKq;5$Qy9Z;hU3ty6PrAQv$sj6zLqCej6_KxsPZ?Dkx6 z5;E-pmJif1(YOavN-s}z;_=}0JB7Y;7h${Np;t~~`9KYW{WXj|dN(9{#~g!sSsi;v z*Mm7|%43qu5--2{Zf;L`!LwwhpjK3z%TPZ zv;ebgKHvBB@!kmlz|rIHrx6YI*V8O4tJiRN>;W({m>C20KJ?eFN$q~V@LepEEnTwg zzz`FUZFEEek_nO-k{Ln32&6AP=3?w5FftYdjt1tf( zkPRab!59r=42&_b#=uw$YYfDyyM~Kv7ABFJP&}*Z7{rH1lHP?sEyXJ)~4U(>6e}; zOx^JKj6ZyYz;!oV3${Lbp9PDBi@!ra;Kmi#ci`W;@=n^4E?Ag%wJeY=Tyb3J83Id+!4!kOV>tsU=$Kaj^#Z&M`4Uc6orVQ z2vHPaVg5H5t-NEa5h?$D?Yi~2`KH@bFk>`~Za#l8Gu|74_L^XFVk^SXgIrp?+~VA5 zoo43O`NcG2*{F@tc>b9ua|7)lP*jkNZP|=JF8>Lwn~r@~h@udS7cW6;?d6G1JWlP} zR_OccDao!_QJP%MipuTw>Zn_p-K&0bIVs(Sc{NSXg4l1%mXST*6u5- nEAs?pH{4zTi%49Rx8uJ7omo%iOPt}W00000NkvXXu0mjfH**QO literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/conduit/channel-director.png b/assets/sprites/blocks/fluid/conduit/channel-director.png deleted file mode 100644 index 3a596f8930334e02360463e0ee4e29d3ca0bc880..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|6a#!hT!C~* zSmdP6#_Q|*mKZf$%G&sJ-Ss(z$tRcg|NsAAU)OR{DpVuK8gjD!O9Ekx;wT>3IxkeICY^4cAQ$ zH2Li~srt!{<$$f(P2Lv|8L!N0QaRbVM^kL#lc|yS15LPAb?+&76(03D>?DKA^H5zopr004)2A^-pY diff --git a/assets/sprites/blocks/fluid/manual-valve-on.png b/assets/sprites/blocks/fluid/manual-valve-on.png index d0484bfc082a35f467ffad4fef135406007070d4..1b212ed8826bfb8dbc4e6d70b7e48495bd4a102f 100644 GIT binary patch delta 1230 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 diff --git a/assets/sprites/blocks/fluid/pipebox-direction.png b/assets/sprites/blocks/fluid/pipebox-direction.png new file mode 100644 index 0000000000000000000000000000000000000000..74c36fa00bf5de42517d82ade704157d575493fa GIT binary patch literal 941 zcmV;e15*5nP)Px&XGugsR9JS^=}Y72sz~-h#*lgd(lJ|v+Tyn&g^t|)%SVmna%EIb5LrEs_ug3UysX z8Qa_Myf>6Ml2ij)hp+)?OTZR@?GOfEoz)aM0RRXBAxRJ+5kLY!K1|irm1S><~qY%6b!RrvL-rIfn z`6=jJ008jHl}p&)bIhhQbZrYJLXrtG2oPXrHCZ>|<;xeby}fChn`>BGt5J_fR@Eh{ zs>G-&Z8RF<+Kua{JdhK>Ha5q$b#cQkY;D;3#@N=@Ya5R%tH&d&>(Z*aw5lrYjaxUr zUW&4Ype%16Um+UqxOd;$P(zI7`*005W=w_-5xVL32B?(P;n8I#-f z*RFnXR*>5RaCa+;V1uGCkp{rb%&uH}^_%lV`90un3V??I4*`LFdU}x{cQX3VEqgX3 zDW-(wNGXAd&z*p)01yC>RE$YojOx0m*!AxRzwO*!H2?sJiHcpvw&~P1E!(zL*LLc< zPQUzo|KqcQoSRSp6jNf;v~1>cHchM8C6bAxNK!xE`{@p;?YrOKy`38XDN)V5(QJC8 z>EV&urd3QyOccq!RwG3|`zx{nG)=4N(<4nLQ%#@F)ODRwOnrUQ_r+s10Gd3R>R^AO z$v+bv&E|?R9k00UrW~g`scHxJcfH#kU-9}1o3N=qW{<2MKn=Q3zr;NF?WAQ~Fuwv4HMhQU^c(!bvVSVR9ab;>%W3Qbx)mdKI;Vst02GT;Z~y=R literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/pipebox-on.png b/assets/sprites/blocks/fluid/pipebox-on.png index 3444e334ebdefea0a15f3572b5ecb68b63427e51..4669183e26104c67b365fbc7f7f9eeb748e70bdb 100644 GIT binary patch delta 1224 zcmV;(1ULJ?2a+3pYk^C#`N;U0GLF&{d&!<3cxzRSP0wNt=Y0mIkW^t&Oo&O0^(uYLa{B zW@f(6#mt>d=00*2)IXfXz2BU3{@*!g&Ya`yc={Pj4$r^%SbzSn6bJVoZhQ7mbVWyN z{{d7t54F4X(57_&j82?w`D~|XG~i@Y&@c$FX3Jn#&Kt;*$f7~w+^MOS&$f-gxl>bZ zjs6`R+<&-sanLG`fYyq^ft#87c9L?XOu5n^Adylret)bx63aHCH{N;|AryD4y&k0+ z5s<7|y^^9^py(Fx%Ds4AFP_(flnN;%LUfKqR|NL%JAe?9d$tVFx8ep?-F_2FN!AYD zLebT@uI8b~AHnl_==FN&?d^%3ONkHyA!N&%$Rce-`GR}@(?gU>MM|Y2#ga?07)x;N z8d@u)6n{95!~KtL$3%u82=V$q5e{POcfR3-%*H>?8S^qDDS#^|=K8vyv~#JoAy!OgVv0^JRCUIym#u7$`C?jEHm_C0AV`3r=a$E0vxMe#| zQ;;tXV=W>vV2s6aOq_o#V6Z~qUlFMs{c^!eWi!;qOjEm0IQ^x#mF?Z%+eu@k=f z@(UOf#kYwfA`=lsQ5x<$*WX6H9^lslRHcmX*O8vbiW~d6HVei?EuCkv?6+Xgu3?M` z6X#*#JSO7T7x3!~NYBHs)$#p0b-&K{KmLI+A=@5kuKKnF@`FMayLS#J&LhGoB7Y2H z`DSt&r_@8WTBBC=@oRM^PEHd=A-i`Dw;jc@!|IXL}LM1E3UG83}QTmZ0l-#ZA$0ms1sR<9q3-+dFO=GiBn?5Ll=WXGYj6JCGwZ2)c^ zSc$ck=XN~RwQiO~+r8l5#Il``gh6Gen&=kG*>SpAPTTDZ`PHn`{7;)LtE=5GYba|Z m-`7Vc&UUpAX7Rso$A1Azzh9D{`GHFS0000wD#nPLG3YtJ^WL zVW@DJ!YX?qh){q+see&n&bB0sI!(fl-)^w|{bqc?DdX!udd`n>bUg*JecmYGx(Zjt zcW!9dBbW0iY=0DDV};Ug>x-gIK++ZjB8ro^JE_SaiH`|=9_7-<0TeTC~Pl-nS^a{f%)oFLH?ui|dk zWfYT3A0dQ;6pa8r^Wr6h6pc>^o_};0816VfKQ`JD(bsDj;PU)!q-c;NVNCr6!}2&T zj|3D-yB(u&Y4*M5`4%*uPK&h;#qWLsKpVr==YP)kP1^G{T;D5mbLD-clBi}fT5B7h zF&IZ6Fj(sVB$B_n_yKj_r(XA|`#xvS#gmwBIbf_sSc|b1V=Rtia2y8*3mB{rIM~>w z1TeYuA;uVtF-_62s_#fZQo#VQIQIt2x9(uA!di*33S%U=RV)sUwK$FwbNJRLYiMoI zT7UCr8ML4#5ozYNA` z^5gk#6usYqh1n^L@tfp+Yjs-dHoLb!`-WQWki*&`JHPynF+LYAUg+iiNIlIyEV?uA}{oPL_qXn2DaL|e0H1f#@BT~=SOVc1dFNwkP5ly>{-2gCT^yBFiX Y0YtFE0@@>&g#Z8m07*qoM6N<$f=rG8p8x;= diff --git a/assets/sprites/blocks/fluid/pipebox.png b/assets/sprites/blocks/fluid/pipebox.png index 3a7d68b5500d3c439327cc746f3badd6a221dbcc..be38a29b021cf60029cb3363b7eabfad6c07bf1d 100644 GIT binary patch delta 1249 zcmV<71Rndx2!aZbF@L;CL_t(og~gXmY*bYkhM)6u=dUwUF+nI)ODew&2nm{KkVXT< zr7?mDxNue126O|m0#~BZEv{S`7Mh?N7ZL-s4JgnGNCa9yAO&nt6#FwXz4x5!;&d*T zJ3k#w)VFzalg|0R^Pcy7_uTJ@t*>nlNnqdhXOjPlu=mjEhJU~PlUUg_+kXJv%AiK8 z?p?nUfc~LNb;mYyqY4qyHSM@A;Nt_(~76Gh%`YEinwB;5w9GetSb(f?ATb37UL?m(Q#8HG4c%DW8 z#bO?7LyVaq2!8^!n%6WwJ~?x}1vUG8v>(sYcv_Rv8qf16wihV2=P9=5DHQVbAMLNn z(?4`6ViFGtsJHs6h=F4RD5cR_IT5og7V{K~Zt{Gg4W%>##|9cMDp}N#fM(VY9(R)~ zrSPUa zPVv*3Ve*o>6TooGqG{sRY*QX!>8Dut2?trc3i=Z&$uq|+Xmw8#1H zPSMtuBbUpP&1HFY`zEARb!#Gy=pafK+-F}MCY#NW&1T4C(_}J^{{8!0yYUNBN(2Ic z70VW5jDN-V1J-SLmZ_;}CMTzvoS0&AVv320$%b!7Qzfn zN=6*Lb~`G{;lY!n(`nM_6seSlm(pn6_{6Wf1)qNLxwBnLq>?D59JPBs(%He9o+S^) z2+8FuV<;ujN-{in60KdmRAZ;6$LU?avc~C1K!5xPA%vq8NFgcR`<>FS_mEOJ3Q7Co zMXc%RVogt%8;jub=q-d0NFg|T;`;{zr9jFDYmLuU*P9#H#-c*gTCsNZlK@PP-zELT z;)Zqtj9k4R%Xg<>xzGzd7!L!!XKKZ?3vEu=ky}Twsi6f4oXyEXG*=7`sDY z3?^{QJvN^eOFOaF2@6AuwIMbPBjL|Izp3tVT(<^*DA0zXOJ*%YXGdo(4Y+sn7Be$5 zjuoHuqx0zQT8Obuq_vJ=7!ul=t}jCLIe)Hq6z@N95T!IJZw94YK`EtJzit^?NrVvO z7tD8G!@%JC0mqMAz*vJZ0misz?~A=PxvPyz)06Psx8KBCgCC@$RT*PA^TP<`ich8D z^V`kal*<*$l?vr@1!E1?m{|u*-O1~2K_l$h)rYk~B*M`!d~TF-WyY~oaV%Hd%73lF z+JKEO)K+~%0m()oj@>)^FeYHePZ1bH5ICN@a21iwF+E+PG+m}#szkQ$-r3i%6^l2k z4>{0G#GYM!(Y^*%28QX9o4izVG$vrruD&QPDI(b^KhzU4M_&N2|G>vcAwalK(b84j z?roW^kJn#*rD=R}kxiS@X4v=sM_K@Mb$1emA#ZHm)^coIM8kW*zlk|dLS|JqtBF=I zS02&I<+Ra#A$c`x*8kJsmetbTFrFx$Bzdm)4_#{MJ{ZUUemnjPFD`CK(D=Ls00000 LNkvXXu0mjf`W{}& delta 1061 zcmV+=1ls$83dabLF@FI`L_t(og~eB0XdG1({^s60`ADTvN z9|V1=HIPVAgbfINaT5wQX&!1-kS2nNNEA_|6nwCVzU3jwrid7#FU5okq9`i$LCbD; zXLs(ogIOj+9WkR7{L^H1_9vs-cl;(9)cu-@JK9QuSKqnRbcsgE!ODW z;N0bn5ZNF^P^KWuZtxWHP~A*VD(JJL2z8@T`1;EgY<#sEo-k^V^k>)ibsvdeK`75F zRhXuLDZ-iCwST*aQmKgQN;NcB-Q4zvjt&A*Dey?Fudai00Ux<6w+O)1k;}QmzIhWr{Pa5*V=!P~>CCB+ z(NDI1MZMlYy><)r+AY*-bqL;@tbksj{C1RH(U}ASIw=-))-W~Afz-cqVlayN9dW2Cv9>hgLK=vOmcLEUlGEi2V-7&H_#qHkc;%^vMk f_rW0k_uKK`$wAmPx&yh%hsR9J<*SIcf4MG!qz({ry)ka2t+1c`!CU=hU|B(?}C{sI>9SHd^ISHK^D zfPifha2(Hc9TwHkYb%MdP02OgGk3=4)T6tq<;yR=qJa!gux&NK!Fej#TXQeali-55t|!J9KZMnXsmDZpvP@Ikf-_m zAD^MjH@DnRm%4yvdm1VbY8Xtl&A zAMZk>TK_iiN>IA*BmtL@O3E<-RMXPSDvf@=yTso8dkOsbt>Bf!ak5e_gih9SOOcrh zy2Q)!*=lhm@Sa33g0-9yKvjDWsECImEyZuY|MAM;J&7h9S?k0@kT;*a{__Xd0q;qm zCiB{crXnb@R{_#4jPHK<>Du6x#7RRT(MgG^`Ik4BnA?+F_ujnG+@!1(v$P7DB_ncs zMCwLR9_j5My}Kxya_IxnmA0Fd+^jTBi>BVBtKqjQ>?fM%{{!@;qNLYlk}v|6m^^#> zBCs1Kp23 zyDa~O#Noj{_U`X?&)5VZW9qu~Y_x{tYMwYe*at~G+8Ociqg5AuHbxSJMl+ZZb2N8- zG(^iv%+b}1@06I&o<2$c&vkEm#Dfoadf;Rf2!sl5m}6G&V9DB+lfG4d^Y!Bft{y_N z%+bG##sckghDz3|W`4RbW;EKrHXS|dx7s;N8C+_YSBQfhZmBal}XnpHJN!`1?L_1+SH zy*zb-0Kya_r0EApBAS&pU32#;O~-Vhd?#zu_mzMflS6zyMQkW>HU^xYox2BOBql$p zfyw%4?t$Dd_92kcz|{O;S>AP5byAiH&CxK;5z}l4LIhQu+l&w`gQpMDjySbB;r)9d wgSF#YIfkcjWYA0~ue53QB%fl0fKUkj1#|d#5fCl_8UO$Q07*qoM6N<$f{LZzR{#J2 literal 0 HcmV?d00001 diff --git a/assets/sprites/pressure-vent.png b/assets/sprites/blocks/fluid/pressure-vent.png similarity index 100% rename from assets/sprites/pressure-vent.png rename to assets/sprites/blocks/fluid/pressure-vent.png diff --git a/assets/sprites/blocks/fluid/valve-controller-bottom.png b/assets/sprites/blocks/fluid/valve-controller-bottom.png index 26bc929372184d211b8f67768682d3a9b0dac517..c16ba8a3ffd3fd732604c97fc78b5990cdc7a069 100644 GIT binary patch delta 1078 zcmV-61j+k)*a(m?e*_XqL_t(og~eCPa^o-z10T-+e{U^py zK}Y~30Eh_sBO(y#Z-I(H^ti8w=wBoNWFj-c`JFuOGm!~o=8Dnx{yF##rYcZXs1^tn zeE{smIslUuToOWpOc2>HS6~rAX2O38ZYmH}m@3Q)fSE#Me}Z{qATvQGGKq)^93g-Z zLL!K7yBCpS;0&%hcWxcr;I7bl-@x<$4xs2J5lpBCNYkjU2 zaI?uoJr@-;2Z_pgkRXW&#fX4NOb~&9%;$>oIU3k5GgK(S0s1F8$L`2{=J$5fA^E0?1bEbjUZv&_SdU{Y!L3B0gN%J zm!m*uddR5}4{=JkXjgv$@s)xd@b&V|gkQKWD{-0tDgbe7Ja(Sw!1cU3gis|^1K`xv*EKICLntQ zV8O*mel;|i!J4t07i=i0J{8ARaHQrt5E$0*jPO1`URGoS$Y z;n{PIEl6if#ee>IkJ7dZ55?l{SHATxGZ*?#f6wwTCd)6hCpcm{9%iDQ46B%0;bsqy zU{!k;+$ls+?KXm|&4PQKWmFD_giQEC&7S9NCT9OeV2qd|a}*xmlrV_<9`){Bzln&o z4(GVex&BhZg)YlXkgSnvQG?~7?VIvXLNrF;>+8lnZru04J!*|H0x@DTQ?995_RdpD ze`G8(VG%XeTH7BYLyS*Sd!BrdH2C|iFnTZ)#^=+^)5&U@= zb>Jt6Vqrwgnb0YpDG(A7-LFwXq|aVYY;7OoFXQ+Fh)zRYT@yzN$Sn67?GK+es^4jC zH;aE5k^{uu^)P1eScRSo0456pNW?cAf5pRcx%2OqY*O7jUv=)vGb(^O(9ln zmS01^WJ_p%doYPv?T?%Xmo@9)=!3~Sh@2;xVqnjEl4T}-eKh0BdGNXOJ&ZCRFvZlL wU|Hur^{NVj{QcpSxqCi82hU8%|304o0mG~{pVZHGZ~y=R07*qoM6N<$f@+iX`v3p{ delta 80 zcmcb?Q8mH9i^0Ux#W5tJ_3b%BMg{|pBL|i%X)lug*RIt3G)W=+@4NF!>BW2uC}4sL Xa~KCxLGxL?`5Px$C`m*?R9J=Wl(9+!K@f&NjY801W3VwGXkn2$MeqTxz2affDf7quY;I0S&#;?{#;8HgE(S%j&3g0PF$Vz^vcvzTe$He8vb^>VVw71DqyV z>Q)_gd2s#I%+$n+uM}epME~#ZUy4Kctqx1Q<(vs}s-y_LD3fg$NK4 zSE0EsFV3VBa{-$w=i7YiqAfM%XaRqY7T{OBuFNphMMX$d+!vFvP M07*qoM6N<$f;0P^ZvX%Q diff --git a/assets/sprites/blocks/fluid/valve-controller-on.png b/assets/sprites/blocks/fluid/valve-controller-on.png deleted file mode 100644 index 3095d5e129535a697e756793d524ce4cca1354a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 459 zcmV;+0W|)JP)Px$g-Jv~R9J=Wma$61P!xtgHDHGhMTENBA&@~A2k8R@amf?u_=119$m zPoJ3?$b(|iBcPs@iG{4xfw4`f18I4`?_!7Fp@FP8F30{#*!2~f76D#H{* zG2;(XTdP3}E(x)dQwi5fcN~g=lUxBxBU(!t8VhiJud5@-LKK9TK-Z)t>pU<8rcn^O z>m<(;kN_h&U`)vy%aHSLkK+XqYyBZ9P@urZ@eR94q_&`;62|}l002ovPDHLkV1h;J By$%2X diff --git a/assets/sprites/blocks/fluid/valve-controller-sign-inverted.png b/assets/sprites/blocks/fluid/valve-controller-sign-inverted.png new file mode 100644 index 0000000000000000000000000000000000000000..e3f23a4bc22acd4985ad4c00da94e7a1c0b39b79 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}L7py-ArY-_ zFK^@ps&WY|F}6-Ga7f=!Y!b`R#98w1x)euTkrG40ebLv6Z!7mayw_&=f0bKXeBYN9 x_9r6NTomF~ozTeaq&uNStwrd>3PlD6apOe-e0Al|Jb|V&c)I$ztaD0e0s!|$F<$@x literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/valve-controller-sign.png b/assets/sprites/blocks/fluid/valve-controller-sign.png new file mode 100644 index 0000000000000000000000000000000000000000..514ff15fb6384b87e1ac5a58bf7c4604c6fdb5be GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}*`6+rArY;~ z2@`rSYcz| zf)k8a3RsTvDLmnD;!9f8#;n1(m`~zX=Y(fB3j#!3n4?4{zv3v;S{!J=<#td*qJV*6 Y`2!uH%j=DrfYvg2y85}Sb4q9e0O24w^#A|> literal 0 HcmV?d00001 diff --git a/assets/sprites/blocks/fluid/valve-controller.png b/assets/sprites/blocks/fluid/valve-controller.png index 72a8348f170a95ef8d7712e0ae373ffdb016670a..08a87d356a051cc676fb6b272d4258704a869f1d 100644 GIT binary patch delta 622 zcmV-!0+IcO29yPmF@H`;L_t(og~gY@OCv!P$3KxE63mfw!WGwvV4)zkcK!#;!u}I! zQ%ML{rMV*i#6k$%A7GbO0;UKCdqHfBu6T!tUU6@h*~!fA?8ZC4u*J@g_x;YBH*en5 zf-ri=!1w6bY)Ww!UpV`!%-zVf_8(C98RS~^$3N?KTltF;g-KH10 zf-XXb5^;W=SjRd&aDJUQjh4Y#e6b={M_qT5uCfT7ZtnnimfuDYMl;{JI%mcMr@PHU z5#v#O2;2h+@LQU<#-sQf&;z#nH#^mp zoV&-vL4OYHh@mo`$R*cN7-SVhc#~%Yn1w<`5h?j_(4V_XF})(nc)(Lc%W_23QEMr3 z)nSS-D`(|22o;J-GP$HyN-{aN?ctzbswB$@Sf?nJ+~EaXg!5hSFHx8Y5tVr{;fo?W zHJ`_+xixA9=F`mdph;|dWqBnR-H>j?%KUxe6bR^{@i~s-t07*qo IM6N<$f;z+@k^lez delta 737 zcmV<70v`R81%?KYF@L~GL_t(og~gY@P8&fG#(y^d0~Y3XfUUJ^P;iA6 zVWA?9&L>{m%nTfzPcogp1fAsMnOKW?nBzwSx&cD&9hpg3+X24USw-V$Ra1HzvPEA%^PJfNvwT!(HU*VrXn#{fMP8_J9 z5UTy1`WX(A!_AHLXPHg~I4>TB4?_DplgyBcj%5M!QA+QvvQl!4c6hGu6PWM!>2OQU~gBzt_n+irEv z>^d`Fb(m&CY{669?nyZ1Jai&}BN_o5@&jDWv6luGXif)$Z@FZh=z z?1YHQyqX9_k)Kk?<<$K&Is^A==4Q|h?7L+J-3_fH>%{Hr$ERmO_d$zS-;RF+up(nR Tgsd#j00000NkvXXu0mjf@kLu! diff --git a/assets/sprites/pressure-vent-bottom.png b/assets/sprites/pressure-vent-bottom.png deleted file mode 100644 index 11609fd5cdf00f7af6df9bd6faced400f616f249..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 328 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^TkH(1Dh;kKa84VGA- zA_)l-i49NtZeN#wU>Xn_+^E8y(891u`GRxPgr`SVDV}0{(Wh`UA?V7ZQid~vOMZ2U zxC@jxxZKT}q^o{ZutL_M^XU;Qrsd2l5-kn;6eL);ur213C_S)(xxgyHHCW@S&cSf! zN4$(#7EJ+PeGIrX3Rw(unHODRu entity.enabled = b); } + @Override + public TextureRegion[] icons() { + return new TextureRegion[]{onRegion}; + } + + public TextureRegion getPlanRegion(BuildPlan plan, Eachable list){ + if(plan.config instanceof Boolean b && b) return onRegion; + return fullIcon; + } + + public class ValveBuild extends FlexibleBuild{ @Override diff --git a/src/meld/world/blocks/fluid/Pipebox.java b/src/meld/world/blocks/fluid/Pipebox.java index 1946356..d92e12e 100644 --- a/src/meld/world/blocks/fluid/Pipebox.java +++ b/src/meld/world/blocks/fluid/Pipebox.java @@ -1,18 +1,75 @@ package meld.world.blocks.fluid; +import arc.Core; +import arc.audio.Sound; +import arc.graphics.g2d.Draw; +import arc.graphics.g2d.TextureRegion; import arc.math.geom.Point2; import arc.math.geom.Position; +import arc.util.Eachable; +import arc.util.Log; import arc.util.Tmp; +import arc.util.io.Reads; +import arc.util.io.Writes; import mindustry.Vars; import mindustry.content.Fx; +import mindustry.entities.units.BuildPlan; +import mindustry.game.Team; import mindustry.gen.Building; +import mindustry.gen.Sounds; import mindustry.type.Liquid; +import mindustry.world.Tile; +import mindustry.world.blocks.production.BeamDrill; + +public class Pipebox extends FlexibleSizeJunction{ + public Sound clickSound = Sounds.click; + + public TextureRegion onRegion, directionRegion; + + public TextureRegion[] markerRegions = new TextureRegion[2]; + + @Override + public void load() { + super.load(); + onRegion = Core.atlas.find(name + "-on", "clear"); + markerRegions[0] = Core.atlas.find(name + "-marker"); + markerRegions[1] = Core.atlas.find(name + "-marker-on"); + directionRegion = Core.atlas.find(name + "-direction", "clear"); + } -public class Pipebox extends ChannelValve{ public Pipebox(String name) { super(name); + configurable = true; + update = true; + drawDisabled = false; + autoResetEnabled = false; + configureSound = Sounds.none; + enabledToggles = false; saveConfig = true; + rotate = true; + + config(Boolean.class, (PipeboxBuild entity, Boolean b) -> { + entity.invert = b; + }); + } + + @Override + public TextureRegion[] icons() { + return new TextureRegion[]{region, markerRegions[0], directionRegion}; + } + + @Override + public void drawPlanRegion(BuildPlan plan, Eachable list){ + if(plan.config instanceof Boolean b && b) { + Draw.rect(onRegion, plan.drawx(), plan.drawy()); + Draw.rect(markerRegions[1], plan.drawx(), plan.drawy(), plan.rotation * 90); + } + else { + Draw.rect(region, plan.drawx(), plan.drawy()); + Draw.rect(markerRegions[0], plan.drawx(), plan.drawy(), plan.rotation * 90); + } + Draw.rect(directionRegion, plan.drawx(), plan.drawy(), plan.rotation * 90); } //The rotation offsets themselves @@ -25,15 +82,52 @@ public Pipebox(String name) { 1, -1, 1, -1 }; - public class PipeboxBuild extends ValveBuild{ + public class PipeboxBuild extends FlexibleBuild{ + + public boolean invert = false; + + @Override + public boolean configTapped(){ + configure(!invert); + clickSound.at(this); + return false; + } + + @Override + public Boolean config(){ + return invert; + } + + @Override + public void draw(){ + super.draw(); + + if(invert){ + Draw.rect(onRegion, x, y); + } + Draw.rect(markerRegions[invert ? 1 : 0], x, y, rotation * 90); + Draw.rect(directionRegion, x, y, rotation * 90); + } @Override public float addedRotation(Building source, int dir) { - return rotMappings[dir] * (enabled ? 1 : -1); + return rotMappings[dir] * (invert ^ rotation % 2 == 0 ? -1 : 1); } @Override public int transportRotation(Building source, int dir) { - return (dir + dirMappings[dir] * (enabled ? 1 : -1)) % 4; + return (dir + dirMappings[dir] * (invert ^ rotation % 2 == 0 ? -1 : 1)) % 4; + } + + @Override + public void write(Writes write) { + super.write(write); + write.bool(invert); + } + + @Override + public void read(Reads read, byte revision) { + super.read(read, revision); + invert = read.bool(); } } } diff --git a/src/meld/world/blocks/fluid/ValveController.java b/src/meld/world/blocks/fluid/ValveController.java index 826aaa0..9009c2a 100644 --- a/src/meld/world/blocks/fluid/ValveController.java +++ b/src/meld/world/blocks/fluid/ValveController.java @@ -9,11 +9,13 @@ import arc.math.Mathf; import arc.scene.ui.layout.Table; import arc.struct.Seq; +import arc.util.Eachable; import arc.util.Log; import arc.util.Tmp; import arc.util.io.Reads; import arc.util.io.Writes; import mindustry.Vars; +import mindustry.entities.units.BuildPlan; import mindustry.gen.Building; import mindustry.gen.Icon; import mindustry.gen.Sounds; @@ -37,14 +39,19 @@ public class ValveController extends FlexibleSizeJunction{ public TextureRegion[] signRegions = new TextureRegion[2]; public TextureRegion bottomRegion = new TextureRegion(); - public Color indicatorColor = Pal.health, fillColor = Pal.heal; + public Color indicatorColor = Pal.health, overflowColor = Pal.surge, fillColor = Pal.heal; @Override public void load() { super.load(); bottomRegion = Core.atlas.find(name + "-bottom"); - signRegions[0] = Core.atlas.find(name + "-on", "clear"); - signRegions[1] = Core.atlas.find(name + "-off", "clear"); + signRegions[0] = Core.atlas.find(name + "-sign", "clear"); + signRegions[1] = Core.atlas.find(name + "-sign-inverted", "clear"); + } + + @Override + public TextureRegion[] icons() { + return new TextureRegion[]{bottomRegion, signRegions[0], region}; } public ValveController(String name) { @@ -63,11 +70,37 @@ public ValveController(String name) { config(Float.class, (ValveControllerBuild entity, Float f) -> entity.threshold = f); config(Float[].class, (ValveControllerBuild entity, Float[] floats) -> { entity.threshold = floats[0]; - Log.info(floats[1]); entity.invert = floats[1] == -1f; }); } + public void drawThreshold(float x, float y, float threshold){ + Fill.rect(x, y - (1 - threshold)/2f * (Vars.tilesize) - threshold * padding + padding, Vars.tilesize, (Vars.tilesize - padding * 2) * threshold); + } + + @Override + public void drawPlanRegion(BuildPlan plan, Eachable list){ + float threshold = minPressure; + boolean invert = false; + + if(plan.config instanceof Float[] floats){ + threshold = floats[0]; + invert = floats[1] == -1f; + } + + Draw.z(Layer.blockUnder); + Draw.rect(bottomRegion, plan.drawx(), plan.drawy()); + + Draw.z(Layer.block); + + Draw.color(indicatorColor); + drawThreshold(plan.drawx(), plan.drawy(), threshold); + Draw.color(); + Draw.rect(signRegions[invert ? 1 : 0], plan.drawx(), plan.drawy(), plan.rotation * 90); + Draw.rect(region, plan.drawx(), plan.drawy()); + } + + public class ValveControllerBuild extends FlexibleBuild{ public boolean invert = false; @@ -143,15 +176,20 @@ public void draw(){ Draw.z(Layer.block); - //Im sure theres a simpler formula but like... come on + + // + float fin2 = Mathf.clamp(lastTotal); + Draw.color(fillColor); + drawThreshold(x, y, fin2); + float fin = threshold; Draw.color(indicatorColor); - Fill.rect(x, y - (1 - fin)/2f * (Vars.tilesize) - fin * padding + padding, Vars.tilesize, (Vars.tilesize - padding * 2) * fin); + drawThreshold(x, y, fin); - fin = Mathf.clamp(lastTotal); - Draw.color(fillColor); - Fill.rect(x, y - (1 - fin)/2f * (Vars.tilesize) - fin * padding + padding, Vars.tilesize, (Vars.tilesize - padding * 2) * fin); + float finFree = Math.min(fin, fin2); + Draw.color(overflowColor); + drawThreshold(x, y, finFree); Draw.color(); From 0c2e6a6f398e6952b14557d180e6ec0328689642 Mon Sep 17 00:00:00 2001 From: Sh1p*nfire Date: Sat, 4 Apr 2026 13:14:31 +1100 Subject: [PATCH 17/17] Hunt towards the Intake's true purpose --- assets/bundles/bundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index 10d0f44..34732a3 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -165,7 +165,7 @@ block.meld-manual-valve.name = Manual Valve block.meld-manual-valve.description = Acts as a fluid junction. Can be toggled to control if fluids can pass through. block.meld-intake-valve.name = Intake Valve -block.meld-intake-valve.description = Acts as a fluid junction. Can be toggled to control if fluids can pass through.\n\n[accent]Plated![] +block.meld-intake-valve.description = Acts as a fluid junction. Can be toggled to control if fluids can pass through.\n\n[accent]Can compact/de-compact incoming sources of fluids into the channel network.[]\n\n[accent]Plated![] block.meld-intake-valve.details = Yes, it works. block.meld-valve-controller.name = Valve Controller