From 2466cad155ac426223e0ccb0b1f65dacdfe18d0c Mon Sep 17 00:00:00 2001 From: Monty Marz Date: Thu, 29 Jul 2021 22:38:35 +0000 Subject: [PATCH] Remove sceptre, add swords --- CHANGELOG.md | 6 + .../common/items/weapons/sword_1h/starter.ron | 21 ++++ assets/common/recipe_book.ron | 11 +- .../ui/char_select/portraits/danari_f.png | Bin 6323 -> 685 bytes .../ui/char_select/portraits/danari_m.png | Bin 12016 -> 676 bytes assets/voxygen/element/weapons/swords.png | Bin 0 -> 316 bytes assets/voxygen/i18n/en/common.ron | 6 +- assets/voxygen/item_image_manifest.ron | 4 + .../voxygen/voxel/biped_weapon_manifest.ron | 4 + .../voxygen/voxel/weapon/sword_1h/starter.vox | Bin 0 -> 1304 bytes client/src/bin/bot/main.rs | 1 + client/src/lib.rs | 15 ++- common/net/src/msg/client.rs | 3 +- server/src/character_creator.rs | 68 +++++++---- server/src/sys/msg/character_screen.rs | 23 +++- voxygen/src/menu/char_selection/mod.rs | 9 +- voxygen/src/menu/char_selection/ui/mod.rs | 111 +++++++++++------- 17 files changed, 205 insertions(+), 77 deletions(-) create mode 100644 assets/common/items/weapons/sword_1h/starter.ron create mode 100644 assets/voxygen/element/weapons/swords.png create mode 100644 assets/voxygen/voxel/weapon/sword_1h/starter.vox diff --git a/CHANGELOG.md b/CHANGELOG.md index 4845b4b3ab..a748274fc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Quotes and escape codes can be used in command arguments - Toggle chat with a shortcut (default is F5) - Pets are now saved on logout 🐕 🦎 🐼 +- Dualwielded, one-handed swords as starting weapons (Will be replaced by daggers in the future!) +- Healing sceptre crafting recipe ### Changed @@ -41,10 +43,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Trades now consider if items can stack in full inventories. - The types of animals that can be tamed as pets are now limited to certain species, pending further balancing of pets + ### Removed - Enemies no longer spawn in dungeon boss room - Melee critical hit no longer applies after reduction by armour +- Enemies no more spawn in dungeon boss room +- Melee critical hit no more applies after reduction by armour +- Removed Healing Sceptre as a starting weapon as it is considered an advanced weapon ### Fixed diff --git a/assets/common/items/weapons/sword_1h/starter.ron b/assets/common/items/weapons/sword_1h/starter.ron new file mode 100644 index 0000000000..665c22a547 --- /dev/null +++ b/assets/common/items/weapons/sword_1h/starter.ron @@ -0,0 +1,21 @@ +ItemDef( + name: "Damaged Gladius", + description: "This blade has seen better days.", + kind: Tool(( + kind: Sword, + hands: One, + stats: Direct(( + equip_time_secs: 0.3, + power: 0.5, + effect_power: 1.0, + speed: 1.0, + crit_chance: 0.16, + range: 1.0, + energy_efficiency: 1.0, + buff_strength: 1.0, + )), + )), + quality: Low, + tags: [], + ability_spec: None, +) diff --git a/assets/common/recipe_book.ron b/assets/common/recipe_book.ron index 5a1f2a8515..b46eece6a9 100644 --- a/assets/common/recipe_book.ron +++ b/assets/common/recipe_book.ron @@ -506,6 +506,15 @@ craft_sprite: Some(CraftingBench), is_recycling: false, ), + "Healing Sceptre": ( + output: ("common.items.weapons.sceptre.starter_sceptre", 1), + inputs: [ + (Item("common.items.crafting_ing.twigs"), 10), + (Item("common.items.crafting_ing.stones"), 0), + ], + craft_sprite: None, + is_recycling: false, + ), "Soothing Loop": ( output: ("common.items.weapons.sceptre.loops0", 1), inputs: [ @@ -514,7 +523,7 @@ (Item("common.items.mineral.gem.ruby"), 4), (Item("common.items.tool.craftsman_hammer"), 0), ], - craft_sprite: None, + craft_sprite: Some(CraftingBench), is_recycling: false, ), "Hunting Bow": ( diff --git a/assets/voxygen/element/ui/char_select/portraits/danari_f.png b/assets/voxygen/element/ui/char_select/portraits/danari_f.png index d7f9949e36477b305f25a2669ab7ecb3963cd433..817c446bd63022feef422f101f88f092e84d7170 100644 GIT binary patch literal 685 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 E0KuqDl>h($ diff --git a/assets/voxygen/element/ui/char_select/portraits/danari_m.png b/assets/voxygen/element/ui/char_select/portraits/danari_m.png index 5587eae34be154118a1b7dcf2c7c152a8e6c3ec9..57d9bddb4eba0e15b19839eb95305ffadffc4ed2 100644 GIT binary patch literal 676 zcmV;V0$crwP)(_`g8%^e{{R4h=>PzAFaQARU;qF*m;eA5Z<1fd zMgRZ;DoI2^RCwC#lut-hQ5eO4_fB))JZGA58ea=z7C|6Ln|Ny>X=QE_!ENEDl6L-q zpg$DaN)$IOMO(OV5fNB|fr~aJJ(sS67R4hTgAUF(@6C05uSHrTqN9P(!n3>F^L^(# z-0xfgeBl%!Ic1y){O1CF?HBDv4H|Kd6qsN0oZhzFp$&T5a`yb1=N#2T)aRgkdf5ip z{QixPPy3x)SDJ056s1y$8#~#3g&*WP>2w;cHE+HaosMVIb~=9JJP3ozC^q zS-Vgua4D6dsuUf?IGaLXm=$23jy`TV}=4+sE+VMwJ?!Sj7A z)8uW>eKxnY*wNdBb+%(FP9~M2>-9@K-=|Wk5QgE=4gi9U0zwD`P)ugfRx6wjhylq& z;x{J<0H`Js6q6Z55Fmsg*eEpKqLs;Er=_KZoKn2&8K8S=gn^my1BC-K<8)7ru-N;6 z3-LIXWwA0j>>PVdf9_5>G&jLuUlGGF{@fXc!C+sJp}7eFJgrZbgU@649CLe{a=DC@ z5|vX3A^z^R5U89&N=dm~CZRQ-M(;Web5M_mmSqbecz^p5N~wJg0IJn0T5E2;8Y7A# zUU=Tg1orTxwbfp{^O(f$1Mk82eY$2xdG5N$Px9G!eJ1cv_%#4{Gr$o00N9}b0000< KMNUMnLSTXdH6|7S literal 12016 zcmbVycU05Qw_rl(geE9Kx_&95LXcjh3reqo^ctEp0SP^H5Cj#Zca+|g-UERky%*^a zARsV#u4Gy(ID0}S)LiBcM$+0 z2}uzEpezEwE(@Sx2awVL2uT41ga9DHe>MHzUH8ACCjHj{|8MmF-}LiJ%{x{ogcU@lICGLdAQnf}1IX|QQL(RMMy_8AxSrt8v9xlsI{R})yP+`YQ_LL;c znM3V|lZqT*Xv$3D*xg(?`aCf6jf_e@A&I`QlkeWE<-jlOu84hx`uX@zqOt%e0zhx^ z_lgM+KtceB6hKS^0J8%i|MBHtKU_QT>^RS;_K3v1NVEq`^Pc4ET`PQDaAe-~J{z>t zrLGK~%zX8+dZ`>eWQJmrb!cYpnREWU0If9V913g}LP$906LOCzec_=&(bN8{HHC(; zbpQ~+FtKD&*$f$C8YzJLHAHp~Fkl1FWjM40bT9#i*#46$#r@lcT;{1(@J}sUml^FUWAwN6%0CxI3z{h89&!N=sm4(I*08(YGIzP-21{L zY0bI!)BI_=T|NN@2gx6`cMTs7>Pg=%2{IN-$~m725s7C6v>gn(w%%YCPmeET&^7ui z^Zr=lMc*4I>!uhX*Yx8hToQKI`{OYOwVbBk$Bo+GQq22;6892o=l9R!*v_hV+An%; zIxozd8;CQ;gvo~4372nH8CUFXKHs=KiB{_dBqX=T_LlO8nglbm2L8@J4Q}7}Gn3_V zg`zsrll`O!$inBRCiZS3)t2($X20Yq?+DpR|>fd<|Y`^ssAe<5#S?yhKG(+Zy!*)HyiK2c4<} zGnijmy=6QbS~{HDS@JoV<{+uyjm>V4jG1mHYfHoEo!Yf;a<^Fs%VK7|9;ImVj}q~> zorW_!i7WT;+1*+%5W(ap!V~UYnGh>D(zU0)B^j@P=F`c)+G-zB7>ZyaT#DFSa!?xx0_XX%Wb zi*(q#8T@QHC8CD-ONJJFOF6F*2*qr~T|Jx`F z455^*p544N?jQ=^b$S7ct(9}R80h=*qkac~iWb`Z`V+^<8;K`s)c=G6E%#yg>}@gQ zTgMQc;sR~yA7ZjhBtN{AzjQT{l<-z~6IJt&7||8|s5I?-e(h4naTkVwxw-$8;44y| zfc@mNT-1LpkwP=5sog_dBrMG8@rL}H9tH`e9{^Ck`oNx+7v~KBfXg%ow8n20r{%P5}r#SdS{7_sH4!162`Zd19*BSiKB~5T?Kb)4`N7@<&#nDiD{8{h6`H5 zGuHzOTV-t}eiwLX(OFelAv0P2UNX(-0~vpY@HVHEqd2JkB)xfmx>0m!q6gXIYuT=> zlAbQVB||E2wix>q;9W;LO<$QH9gn~#`S-hsUfS2gU3I$hLSsI>ZIgUPRW7z;;Su*V zt`^tKA{zad#}K(UYmHSph}+^HjYRc zUv~-ZDz3}l?(;b}8G>zkNSB7|r_pjSDGg|9$Bso`^3-E|wG6_(-|5TXiODNd>3+jH zMG`tGY#~J6zkSzLzhx&QGkn-?-W>vhNUjir{I9LqI@S}o`v*+Si>-qzr?+OA?pJ{H zc6XUede`?U#})a6=jB-V#c*NXpHTb_0od#HpW&}Xj=*SNKbD=!YqYPp)$&5+%c2$% z{{-wB_adud2%eh2#}CB|vnnE~KQAHlF@WXdgT zb5bNT@=J-E$~-SQ7yv!C8wkVpaPCk(j8zFgta?O~i+H z-^EbLDkI8HN#HT=_ruDN03x$U_wO0gj~{wLlJxY$4~*;glDvb2{n>oRz$0$Yg82i_ zb>Zv%=ACX*^2m=MQuZzadLs5m29l3Z^Abb1K}d1gAxlX8Z7xXU>kCM zyl{DwGpD-NgyeKZ!Oavc7N<{ie@F~dFQj{aM=)Ij*Cg7`=z5V>DG2&gOg3R*CZZ5K zJS-q>%qtR^cNI5hkS4q#4~#XRAxr+FN< zy&A^_F%t<+y4^=Sh}E$bj~`11l#>Y+#cnZS`P~ESo$A!6vu_rENXUppPn}hbbVuoM zooV#=Q4=+qNS9$oH{U`$xS&{`}ZoR?V7sqHz|8 zmmo!JE~2-w$(D~Pn2s@5zdJ4yjSz;eS{UyiF%7AfLzG1Kn&*pn9QZrW1(0>S z&GRsX`*iFRCe*&#h*%rYNY_5F1w1UmSlR6tw6Nr5XkOGUB4{TRoK~}8>$9VIlj+l< z*{^uLlygj_zLKGf0fxB$0}^`fkcG$aQ(0K~jsnv}M^oNewesu)@7q$Mw0-^Ji$7T+ zzRs=Qpf#iBYtwBtzUHzX=u=iXrAlIZEs~8wyHhm5o!o7rR}Th+TZ%Dl3RR_c2&;t& zoecj6E*pZ#g(bc*;YYQ0t`08;UFjAE_FdE7OH+>g>c5lXbhf zNK|;zSy*n0f0k?S*rPDpHCI;k{-3KeHoFM|5Mi)YU~_7YN5$0W`qaJy`4n~tf+tB7>HNi1(x zdtL3*Uz_m5SJn*+K*T8HTwhI->jj(y^PJc|!Lm6~yW5#lnwEP?IDrsi4)bl ze8K>1EhwA@Go??3{NA?r2atR-^AN~=8L*=$aeDY=s~GOwc@Q|Dse+!|NS4}JPtv)= z;n@6Gvh52RSduMVQ3{-ug_pBOcP7d@H(AQ62q3SyyQWaH6!NonYR~Pl8qXxZmJ7Y# zS*g3{$fN4T7_ON8=Nv)j0FBK8kIYz()CPK&E|3uyCu}}J^pW`F`siB@wcM)GtDU+m zIsPpkRh~x2t>4M7?`l9LAmw-)%_?aAIJwr!@Nv9&XIpG4HGzn*X;B%k-of{Dh8}{# zFB;bcZZ4hTX)g^OH!9z0zjpfY1 zCHyDjBw$Av^y!-nNJ`;y+5B4JM|cK`Y4=9Vq-9eb|9VJR3wkIVd<9dWMKU!6(g$lE zeKy!UMUzio@Z|8<)@uYsE2;Q_N)WK0Z&-sWQB911wmFYzb6&{~YO z(?CBDx`ny2&wT?$cvInynE(*AsIC>3A_K_BcZ`)x)O$_ML>mLI)RzQdV5|p?28ej? z(gLBq5z7v`=MOS~gN9K}r_FK(^$uGibh$;m-~tb1V=K2Wm2H1AC+oDUX(c9jU8Fm` z%jgK(?fY%Sz%Twx{+Se4!yv{YE}Lu)aoT2_P}yo$jFdCD|11 z6HvR%${t>^OFq4BKP5pfqU^iCdxAIH*{ujFIHrEFJ?MhcwQomOH^~+nQ&llfSwJ=# znupA+7Hq)1YW`;UhHaup07A8r*Wo}6N!Hiz;itsDp9JKe0ra1}A{Kj$F496E0k_n( z=#z^N;L^-|LI7_I#KF%$U%-3E_KD62#W2xCk9l6zUxVA5?8Ldt;z}Mij20b4Fc0)U zW#+=Qc~M(UKt3;TA)_?HuW>J2UAml0ppVGERDTe9@ZynE2cWd1&+$0m@FxRq^JZVu z3^8gzSJbg^*rW?XB@csiPrVYVD1wbYu^y7)lEr=-X8(&^)h#bNv-p$l(n zZh-ySkd&$4-K<1QPuaMY=-HR5#qG)F6_kRq`NdEte#(VXuGAaY?lB$^5!mzTsQ04u zcHxO2oe)Uq7{Xo=*?Z0AOi>M06BxE`?)d#)$qAA<@;1-0H9_Bco9bhodd@8exQdU+ z0N{N_NUlF$nvS9gY1c8OPfw2JkKV@d@g}0^tBc25c)$MXoYw9?>$e&QlNZ`WNFzom z{jFFmU;a6ZQ#~{N8yi^!CXhu_ghNRAodRpae!{#Z5SE^x%FmMzR5woa3X{=OwCyA0 z@}P1v(${!b-Z$65A#A}LyeA$(iu$3X;g__e`f9_Qv2e|=Hd?n7n1=t|Rh&5NOF4EY zbkh}#@xSxk+4zpXZBF20S~gpV&lj$ese}9|h4a*tscpm-)p~q6xjZ_+)%+IY>IkAidrZXtms2)VRHO=Qz+QD1tIA^Z(V zOU6f0L5&Bg0V&<#N`lUeu8@U}*(wg(JO60>=rLM8*06@2qroF-(kFrA1b&r${DhW) zPQ7xd**fTm@7x*rGvUbomqgeT1KQ-XTT9-GM|<^+0s2IP)p}uHE489qZr9uD2Kvr{ zG)%g-#pN#jNpm9 zKOm@28CgU;C%mNh&D7RpL)CwYb`rHD;yT98^HBt4`L-#UB79e6ou6SXBTdH1kgoqp zSowvQZrl5D3joF_^(*2jFBU2(iSqX+zN0JJ-E2azY{fzN`1Z7ND9~l8jk5AkezNn2 z-(`LF+1B3a4%2d9@$v6MG`!t}O9G3i1QWd&Zd!?wC7rWZ-6zhmLO;-^v5kLvpFoPF z8#tRDK^J8S_#IH?%!ULCNLAD?9-{^OMz@j%|EMP8|wcXIjZLj($F5!ZDT4!zcGF*owpIC0LFXtHfin zj$2+#$Ng@tN2+rhQ$}}Kn7eYXitmK7mr&1v4AcaqcP%XfIFzrLyub>P6)vB?_v2P< z#9~;4?YAxH@5BMhVhQwmR51kMUr|q@rn9{%IQT#{R3yqM)$R)%V@V$JryE2Kt3oxt zpFdDt!NVSJTmln}-Lln2(76Ux3RvT{{=EHsQt8fDrkuoC#eB^RMZ&5R$Up%^gMZ~t ze;57h+L}|eH~m!9@H;VqE0gy{D@E$a!uV6B#2UH_aV)~o$s+oA6?2vQN=I zYgUqg)p^zNCY`a|_hsLAvXG}1#P+o^PvbO7-}adWYvN?V3NUh6(OsWuHE`tB_@%qaMhdT)`aow2P4+Q16$HEy4a7RMM)iE(8uppBG!9U z9e&J4n}IkI-dunBljb6hD|gLkQWS~y*jT&$H^nhpqaskofEh>a^Z7T))s;8?afS~y z4j!rZR$)|GE5UQqG<53Oj%@>?a%`whUv}$RQpRPQ)xocfG{A;^v z@liC?bo5c!PgA_%Y2;HkO@5;>dHAE^>i$>(*Nm!%^=sRe*yI&_mO?4wtZQARl~pr= zWBQf?P17Hm{LuhA23^%BW3Qr>_dWV34NssD#A!JwtqPwnffc2&vmKG zIC;N$;Q5B@v-FUjbKOJC7I$kv^~%xnd|GeU&cAj!!zFM&zoXaIb%R0MFBB#eo|bq} z^i|Hf$#?f8dbls1R3aA0+w;Nt1AcL8o>2qRU#iPp4z@1`YX>fJUOdT79%R1{5|k}Hb0F5Gn2!M#s)^ZO zeB+3)eH%53_7m1v(jUjk9_R{pX3UzGI;>Z)N3?p*th}I3SYOv7{=!^o?J6Hl?I z!jH~4PC{ls=@A8y7+!{iG9YeMJncy`Y(`qRxON7Kev6*Zo>e!#mWA&ISZCeK%O3!# z?87H8P?rqgT^AuGt~_G>nAH5l)Ac$#__2Eud0y)?fYQ3B-Fs~H`WvzIvN{G{5(TwL zYqg|)?FoyppZBC5ad$%>(T%Nc?K0;xXHG6Po5sLpAR!+VQ^KL0TjLZpo33OkX7g8W zVQ>7~Mi^Jm64I`NOkY%XK>3UdT?eSs&ungWF0ikC4L3_~A5+;?`1X3u{(y7vy=`qt z3Hr1u0Pk`LAifDEB)5S@A@?Hlco1jI`J<#mjZGhT2A}W0ih9V*O#9>FRL5i&L*e2L z=h$h1EI&M1Y!aF<{Bbp9y;lt1mCJI+uBbvHj?P}Q@H=_X41PhBZ4(jcsQZ+9K>>{I zi6HAI57{X0 zgd(~c*H>t;@n#(iJ8iTk^w9f?^;igEnRD$8A7#T<}tBmlq2xnr88^(98epM;WFvM^{Rrc(I+y+Xlm=8KU4zM zZGeVoa6!JSZZn}oFhF=&D+n1nN_34HzEtn;e6@=`6V7Jnxt~Na2)vxSIT*%86jtVW zf|%1|daW=eQVUE|WA)orIjZar(_SkR=fqOET&7aQ9=^Vqj&j*sHx-u&U z7J!`RLNB%sa_=B5qIS<>+F9zerHc;E-)z3z8qHZfalXpz@C-RvAst?54UO5XiqpIb zd?Nj;o9)ybJ}h&t%8!J)e|IpoY37}=J(tLpCUJZ%(vy!QxPhT`oR>ZU1 z+hLE^eO}$+@P+ZVg@FanzL`m1OLCldPPr1vy;mX#Uq%{t3(~iIC`G75CwPQC?`kz~ z?80&PgXHyr0BXM>$~9wK>5L`BT^$M%I&?P^zGrebXP&_xqREA!%(osN-+!yy0F@#* z9R6oDmJScW0>J(%#k3zd4tzJp2Yrvj`4og&dfFfsNN4mO>UK}Lg}BS(y(+>#u$P-L zp)ajpv$#T@rdae#l`Q?Lt+eeF6Tqkb$s7E()kTp3V15@maK6*Q+!Bqg?#)h!`zQR? zM4WHB^DrROW7fME7x7WkKVY0M)57ymYG;kaA_H%&iGlVd?|~}L?{zXk$BV?I5g#dN zZL*x(%WK~VVOJUgR)+z9eamSWM>pUgs}Z6kl6a-o)C)Ly#1BA1H3$V|LjhtAj?Jdf zRbSB%%QbnHBNZ;oz>BmJ_cwU_V|zLDFzvnS9@A%xN+K*+<<7K>S+>}OF8uLr1KXy0 zIfFLdgHp3CiBqzbU)-=9HOK1WzvZ;{0MX9ujr_OVRaz`@83vlQ_*{Rq&pGv^BdFN{j=a+CL)5RozLpjlzcxZ+=U!NugA|KYa|5JYtf>KY|vB zrlMBcK@hJEgrw|hn<4&EiYi0z_6Yu_m}!Zh1qXW=>xbEflHa2TkaKhOFE;l&?5{oG zW0OX&=X1YMulxOgE8f8O{FeZl4xRZuDy??fLsfh}Qz8~is0qCVmlsp+_c)p_o6^8G zYvg}`acs-qReDP9d(Sg<47HAxbo%7&#mar_jpS>(js`ifg^3esn2-L-icLsQ)^e-) zyVTHC5t{mGcW}-k7a%!nlxQHf@_NU$!`LoffHM;Et#SFN&5)xLVlCQr#$630_rVsj(4CUmhP$h8Pf9OX5p==PuDV`xRuc`;loW(#$BE&Tf0^ma|K$z+YQ! zOuFW16O|`85fo_@4b&>0pUO2j6(}zv2vY-8ojg<^49SxtaPI|UGoskw)YQZsVvKkZ zi~jXJ15;fog6dJEX;d5O`Nb`Wa^Z)FnTHRl4H@3 z6?MN}HS*@TqVP1*HIQ_K6Uj_u^2&9D{*=-D>g8n|+rie}*cwpwd3^u<5Y>s*p-3X> z^P;dD26IC4WZMwJ<&P(&HT2yHj^(zL0o?3tySk5B z*OF8*YgKlL4aAyBbMXlKQXI?V?RjmeQ&L$8|ZEPrAWzWy! zh3}D0v-64>hB5&*DU2++vdTB%)E6H(zq zEl`(>Zeg#TV*gQy8Zru=<}bkaVq--0?%>F+D%48DenHl_+%hT;50zoe#7$qFGO0w$@RxP2)M{kt{s36m*F zI%R|`;(BfnSFs?5OpBd0*PT%pc={FHJbpIb1B3;|;~CLh;eMOLIeybNN9Bz5q;YG)$PFE9hYE z)WTS)ICc|JmR4=%wENFs8NPmvr(yu`!J7PvDaSvFo|8X>N=tfrG@V#+o^qSz5$3Id z#Gn>au2cFHK2qR~UtKPD^&Pl<_3BeJf^}Bld9Fg@H$j=s3I)!K9ObVgfhN=H^%x2e^k?rNWlSH*LBA zL(y(Pz%z~rSXn*hNf&MODV97knYHB|H`}S1UUlyqnF*YMAA_!;caHP$GRq1MD@}v~ z@1<@~EM2gfAy4k5H}77eFR&=u2A;eXfzZ~3&_F& zQM+PF$$-P61Xu%BLGYt$wm=}-!9qO;Ey>y*(t{G<-S~QG^jS++N^3J>TAI}~l^vM{ zjF%FKed)aEV>Qf@=``k2_x4?72*Sqa!^#us#BcR7K166Td;pW!4bTFse4gRo4FN@1 zuH8!i-8$UNK|!!8jgw5+H>mqIGEZrdL4$WQKr9n8A1vXk&CRSvt|??N(cbE|%4^nrF+2G@41Nhd3qYfyUjOYvbSUkV3o;rkabRR{K=4Wf_9*Wwf~b6w9TL2@?R-*des-4N|%V zkrg%&ma58?UJX83?%~Gw<9G+`N4rAB$!67fu;p5H{i_#1ZSh(pJ7x{<6x3{J;B(W< zi+EgKyD*#At^%@0siG;iQn9*ti}PcPlfl#0d^bQTUJ~`|&Tc@@Q=ucN9m@=97y=zQ zC_cO3z9FN|TobsPUc|<17*8SUW%V%i9Zx;5~erE_vm{V2%jQq8rqO-0wIxW=0l{ z`SR<#?i~=AgNZa~8=p`}0q$zYq{ta`DoXvM7KV5DQ!-4K|At=OR#z_#E4rk&^$ME1re4CP!F&VTY@s8v7)s*X20|tJH$} zXp($>;oLrFXT|0H_GhRuF?Z>y@@jkUMp85`xI~sMBZD|!D*aBkJw0zB-kuG_uAb>Uof{l#|*0LTlI2^++7uoy)r?)OT zLxFwCY^w}y*rm?fL{X%MQHaU!W+W9|z%YHO-vOq<9cuywfcf+4qfY=aY*L=YP~+N| z0TntLFZRTSltrU}Mzi*&RRqZth zI}9GUHwgE`W$tCwr?JxJV3q}f3;WlbIB+S;1m=-*ry@`Tdr-BIf^t};RO*VW6g5Jmxb|qe^BNCeob`Iv0kCnXjDDT0#lPljr1b=ye0%(G$uW{}|A0 zeL-pk&8ZHMAtt7RqkeEiIs)cdX<6S7t(XG;cq`mF@j0XqE2%gt?`oNanUO`!A*VQH zp%t{pco+U&Bg?dCt*$cDj|S<9({yyl$XG7*gEN6aST(m*n`Tn{SBrTbyld_QM9e4E z2xhbLg*mIw`~old`)c|vgmJuB_oH<&(ZtJmSaI}G;$ciS>r_8cRl%l}z0J6df8Vj? zAa#?tDn_+b|4g8Q8vkUJ?7j6N$*`2*K4C%+YFP&px{HrL^Q4yO)xD78eDDDU0Uag0XS;)A9UiXb87bq{r6f!!;C0+bF( z57WY3HXAdVt*1r3v9%h|JY`Q6v|un}4hKIe?N5Imb>eh)FGDtlw#@j^8OCiXwji#Q z!eol;vhv` zPu;Y=C)*DMw^5(E4rJEFYFd_>)V{DoM7L+pf-Ft^+Kv~EcLixy8aO-YEZOB(nBU&8 zGF~SvUUJP#v;$_W&6UPgFOk$2o2RSIZDgpQUnVnKj&}MBud2n0-+0E=2X2I(#@!t8 z3ovC{yZ%_|UDv&A<_}<`r(=kU+JkVRLLEYUjOR6$Zg9!%djzpeC;Gb-CK*4 z>{4!hcUwd?6Lf(wzOn=TLg`rxov;0IH?!YB6aWiIR9@uUo9-sV`#7u-d^Gh~VSb`u8yY74W|S`L9U+A2ax- t-~Z{5#kY0;PshJ9@!y~MAG1sD`-ie>l`LQ#-=Pk8@k~RpLf#_ee*vVk1~mWx diff --git a/assets/voxygen/element/weapons/swords.png b/assets/voxygen/element/weapons/swords.png new file mode 100644 index 0000000000000000000000000000000000000000..f61c7a9350046df4a7b5768956c1b92cfd2c5571 GIT binary patch literal 316 zcmeAS@N?(olHy`uVBq!ia0vp^G9b*s1|*Ak?@s|zoCO|{#S9GG!XV7ZFl&wkP*5S+ zBgmJ5p-Pp3p`n?9;pcxK{gQ#9)PRBERRRNp)eHs(@%%~gN8NyG4|%#chE&|Ta&05; z5d#j^fcFKZ%XaF%*nA-V!L&u^Shfp?D@F#MV`G{Y6yW+uGAAG^`|WNEIUb|U2Ag#l zXGSutVXWqH(0y^_T_d9oAKONWjH4YdURCpctK9!@?=4G#gC=)$Lk~2|{#HA_&+`W# zV@gOGvuWd^aCXBmGj`L)c@-^ETGGwazJ1BvXZqv$skDgyEAA}VzUlLg9S*)i2c1^) zHV6c&rp4!a&Zzw`+2D7U_n~76jAm@y8!Tt^*#2?9A+(>7L8vr5uRB3|A<#Drp00i_ I>zopr0N6Bf*#H0l literal 0 HcmV?d00001 diff --git a/assets/voxygen/i18n/en/common.ron b/assets/voxygen/i18n/en/common.ron index 1dd6bf2c10..efbffbcda5 100644 --- a/assets/voxygen/i18n/en/common.ron +++ b/assets/voxygen/i18n/en/common.ron @@ -61,12 +61,14 @@ Is the client up to date?"#, "common.species.danari": "Danari", "common.weapons.axe": "Axe", + "common.weapons.greatsword": "Greatsword", + "common.weapons.shortswords": "Shortswords", "common.weapons.sword": "Sword", - "common.weapons.staff": "Staff", + "common.weapons.staff": "Firestaff", "common.weapons.bow": "Bow", "common.weapons.hammer": "Hammer", "common.weapons.general": "General Combat", - "common.weapons.sceptre": "Sceptre", + "common.weapons.sceptre": "Healing Sceptre", "common.weapons.shield": "Shield", "common.weapons.spear": "Spear", "common.weapons.hammer_simple": "Simple Hammer", diff --git a/assets/voxygen/item_image_manifest.ron b/assets/voxygen/item_image_manifest.ron index 303028d56e..bf44608ff0 100644 --- a/assets/voxygen/item_image_manifest.ron +++ b/assets/voxygen/item_image_manifest.ron @@ -437,6 +437,10 @@ "voxel.weapon.sword_1h.cobalt-3", (1.0, -1.0, 0.0), (-135.0, 90.0, 0.0), 1.2, ), + Tool("common.items.weapons.sword_1h.starter"): VoxTrans( + "voxel.weapon.sword_1h.starter", + (-1.0, 1.0, 0.0), (-135.0, 90.0, 0.0), 1.2, + ), Tool("common.items.weapons.sword_1h.iron-0"): VoxTrans( "voxel.weapon.sword_1h.iron-0", (1.0, -1.0, 0.0), (-135.0, 90.0, 0.0), 1.2, diff --git a/assets/voxygen/voxel/biped_weapon_manifest.ron b/assets/voxygen/voxel/biped_weapon_manifest.ron index 74cca7017f..ffc7128cf7 100644 --- a/assets/voxygen/voxel/biped_weapon_manifest.ron +++ b/assets/voxygen/voxel/biped_weapon_manifest.ron @@ -224,6 +224,10 @@ vox_spec: ("weapon.sword_1h.iron-4", (-2.0, -4.5, -3.0)), color: None ), + "common.items.weapons.sword_1h.starter": ( + vox_spec: ("weapon.sword_1h.starter", (-2.0, -4.5, -3.0)), + color: None + ), "common.items.weapons.sword_1h.obsidian-0": ( vox_spec: ("weapon.sword_1h.obsidian-0", (-2.0, -4.5, -3.0)), color: None diff --git a/assets/voxygen/voxel/weapon/sword_1h/starter.vox b/assets/voxygen/voxel/weapon/sword_1h/starter.vox new file mode 100644 index 0000000000000000000000000000000000000000..d37c36336fa37a6ecc4a8b03225ffd10f4fcdf9e GIT binary patch literal 1304 zcmbu8Z%Ex`6vxl+ckgwk)4BXNwbaa|SI3rrrkQ5f^tP_cEoaGgXA&{l#6~7@aUzTD z=ETJ2Oq@Z>G(;n3PVABdnmDnEjA54wLL{R1>5E?U!cXV7y@|EzMGt)Vp7WgZ{GR7L zzvt8*J)SxsB2{IcBPwEdh}3wz?wyvS!={8NG0O21UQbZf8u^N0$d;J0Whkbi$yMi{ zifPxlLy-{8Q*0rdhQqRVsJ#Qj3{?$PeF(#*m|@$7Elln3ZNuEDwqizTPK0WtYNYBe z)m<8k+CFyZxiYceEl);AM+pXltgNgsH#bKh5MW|rf{~FC1_uYZ?)mb840N>8+}uo* zD~{s2gSg))#W_@jxE)AS7&81YvJ^*Dl@Nbc$aZJ2Z%PPl5+eLUbgvNixsYEKPUYDs zyceQ*FYqW8?Lu|G@cN{1?vAdlP9(W8jr8^`3T9j+wZxFtlStNR3OUOe#McSw7leHS zLdm=!FYEqop-6uuG95!##%{)*j3xL?5>!4$u?QaJd*xT9zg3w0Kv)ik3+-D$K{XEM-`OZzK@44f&aub~W9 zhsl0Cj*{FI4nLboLv0~Vm4g3OVd!mP{<2VzoQNkYow|bkv{V#Pn-xc6eiA*0_A*m{ z0Pjm>G`)6&_U4mxpFd68n_hZ5nwS~8#M@rhCu#h6D~t8p*?gpX&WsAHUkkr{C$u$YGU(4^>3TW8{ZvCscN9IJ#c<KOh{XLx^lkq^IF<6v_ar5A@d{P8?BQ){?fE`HXdNT|Z^*w%!N*?Z^P(D(IU zaqU8^ali6|&RaYn_Sf9b&Q9L(z4f>CR*u!5R(~%nEHFDe%lP;>Q&UrS)#`1{kv{>% Co?00I literal 0 HcmV?d00001 diff --git a/client/src/bin/bot/main.rs b/client/src/bin/bot/main.rs index c6a4f5b63a..d4362b9b12 100644 --- a/client/src/bin/bot/main.rs +++ b/client/src/bin/bot/main.rs @@ -174,6 +174,7 @@ impl BotClient { client.create_character( cred.username.clone(), Some("common.items.weapons.sword.starter".to_string()), + None, body.into(), ); client.load_character_list(); diff --git a/client/src/lib.rs b/client/src/lib.rs index 4a6a823c1e..ae69cbf55a 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -826,9 +826,20 @@ impl Client { } /// New character creation - pub fn create_character(&mut self, alias: String, tool: Option, body: comp::Body) { + pub fn create_character( + &mut self, + alias: String, + mainhand: Option, + offhand: Option, + body: comp::Body, + ) { self.character_list.loading = true; - self.send_msg(ClientGeneral::CreateCharacter { alias, tool, body }); + self.send_msg(ClientGeneral::CreateCharacter { + alias, + mainhand, + offhand, + body, + }); } /// Character deletion diff --git a/common/net/src/msg/client.rs b/common/net/src/msg/client.rs index 0cc811ceb9..4f7b18ffa0 100644 --- a/common/net/src/msg/client.rs +++ b/common/net/src/msg/client.rs @@ -51,7 +51,8 @@ pub enum ClientGeneral { RequestCharacterList, CreateCharacter { alias: String, - tool: Option, + mainhand: Option, + offhand: Option, body: comp::Body, }, DeleteCharacter(CharacterId), diff --git a/server/src/character_creator.rs b/server/src/character_creator.rs index 688b0829fd..9c193262df 100644 --- a/server/src/character_creator.rs +++ b/server/src/character_creator.rs @@ -4,45 +4,54 @@ use common::comp::{ }; use specs::{Entity, WriteExpect}; -const VALID_STARTER_ITEMS: [&str; 6] = [ - "common.items.weapons.hammer.starter_hammer", - "common.items.weapons.bow.starter", - "common.items.weapons.axe.starter_axe", - "common.items.weapons.staff.starter_staff", - "common.items.weapons.sword.starter", - "common.items.weapons.sceptre.starter_sceptre", +const VALID_STARTER_ITEMS: &[[Option<&str>; 2]] = &[ + [None, None], // Not used with an unmodified client but should still be allowed (zesterer) + [Some("common.items.weapons.hammer.starter_hammer"), None], + [Some("common.items.weapons.bow.starter"), None], + [Some("common.items.weapons.axe.starter_axe"), None], + [Some("common.items.weapons.staff.starter_staff"), None], + [Some("common.items.weapons.sword.starter"), None], + [ + Some("common.items.weapons.sword_1h.starter"), + Some("common.items.weapons.sword_1h.starter"), + ], ]; +#[derive(Debug)] +pub enum CreationError { + InvalidWeapon, + InvalidBody, +} + pub fn create_character( entity: Entity, player_uuid: String, character_alias: String, - character_tool: Option, + character_mainhand: Option, + character_offhand: Option, body: Body, character_updater: &mut WriteExpect<'_, CharacterUpdater>, -) { +) -> Result<(), CreationError> { // quick fix whitelist validation for now; eventually replace the // `Option` with an index into a server-provided list of starter // items, and replace `comp::body::Body` with `comp::body::humanoid::Body` // throughout the messages involved - let tool_id = match character_tool { - Some(tool_id) if VALID_STARTER_ITEMS.contains(&&*tool_id) => tool_id, - _ => return, - }; if !matches!(body, Body::Humanoid(_)) { - return; + return Err(CreationError::InvalidBody); } - - let stats = Stats::new(character_alias.to_string()); - let skill_set = SkillSet::default(); - + if !VALID_STARTER_ITEMS.contains(&[character_mainhand.as_deref(), character_offhand.as_deref()]) + { + return Err(CreationError::InvalidWeapon); + }; + // The client sends None if a weapon hand is empty let loadout = LoadoutBuilder::empty() .defaults() - .active_mainhand(Some(Item::new_from_asset_expect(&tool_id))) + .active_mainhand(character_mainhand.map(|x| Item::new_from_asset_expect(&x))) + .active_offhand(character_offhand.map(|x| Item::new_from_asset_expect(&x))) .build(); - let mut inventory = Inventory::new_with_loadout(loadout); - + let stats = Stats::new(character_alias.to_string()); + let skill_set = SkillSet::default(); // Default items for new characters inventory .push(Item::new_from_asset_expect( @@ -61,4 +70,21 @@ pub fn create_character( character_alias, (body, stats, skill_set, inventory, waypoint, Vec::new()), ); + Ok(()) +} + +// Error handling +impl core::fmt::Display for CreationError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + CreationError::InvalidWeapon => write!( + f, + "Invalid weapon.\nServer and client might be partially incompatible." + ), + CreationError::InvalidBody => write!( + f, + "Invalid Body.\nServer and client might be partially incompatible" + ), + } + } } diff --git a/server/src/sys/msg/character_screen.rs b/server/src/sys/msg/character_screen.rs index 5610bfedf2..b2b2618c5a 100644 --- a/server/src/sys/msg/character_screen.rs +++ b/server/src/sys/msg/character_screen.rs @@ -115,19 +115,34 @@ impl Sys { character_loader.load_character_list(entity, player.uuid().to_string()) } }, - ClientGeneral::CreateCharacter { alias, tool, body } => { + ClientGeneral::CreateCharacter { + alias, + mainhand, + offhand, + body, + } => { if let Err(error) = alias_validator.validate(&alias) { debug!(?error, ?alias, "denied alias as it contained a banned word"); client.send(ServerGeneral::CharacterActionError(error.to_string()))?; } else if let Some(player) = players.get(entity) { - character_creator::create_character( + if let Err(error) = character_creator::create_character( entity, player.uuid().to_string(), alias, - tool, + mainhand.clone(), + offhand.clone(), body, character_updater, - ); + ) { + debug!( + ?error, + ?mainhand, + ?offhand, + ?body, + "Denied creating character because of invalid input." + ); + client.send(ServerGeneral::CharacterActionError(error.to_string()))?; + } } }, ClientGeneral::DeleteCharacter(character_id) => { diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index e2c67b6c42..8941cfc8bf 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -109,10 +109,15 @@ impl PlayState for CharSelectionState { ui::Event::Logout => { return PlayStateResult::Pop; }, - ui::Event::AddCharacter { alias, tool, body } => { + ui::Event::AddCharacter { + alias, + mainhand, + offhand, + body, + } => { self.client .borrow_mut() - .create_character(alias, Some(tool), body); + .create_character(alias, mainhand, offhand, body); }, ui::Event::DeleteCharacter(character_id) => { self.client.borrow_mut().delete_character(character_id); diff --git a/voxygen/src/menu/char_selection/ui/mod.rs b/voxygen/src/menu/char_selection/ui/mod.rs index b26d7c8fbe..083086848c 100644 --- a/voxygen/src/menu/char_selection/ui/mod.rs +++ b/voxygen/src/menu/char_selection/ui/mod.rs @@ -52,7 +52,8 @@ const STARTER_BOW: &str = "common.items.weapons.bow.starter"; const STARTER_AXE: &str = "common.items.weapons.axe.starter_axe"; const STARTER_STAFF: &str = "common.items.weapons.staff.starter_staff"; const STARTER_SWORD: &str = "common.items.weapons.sword.starter"; -const STARTER_SCEPTRE: &str = "common.items.weapons.sceptre.starter_sceptre"; +const STARTER_SWORDS: &str = "common.items.weapons.sword_1h.starter"; + // TODO: what does this comment mean? // // Use in future MR to make this a starter weapon @@ -67,9 +68,9 @@ image_ids_ice! { slider_range: "voxygen.element.ui.generic.slider.track", slider_indicator: "voxygen.element.ui.generic.slider.indicator", - selection: "voxygen.element.ui.generic.frames.selection", - selection_hover: "voxygen.element.ui.generic.frames.selection_hover", - selection_press: "voxygen.element.ui.generic.frames.selection_press", + char_selection: "voxygen.element.ui.generic.frames.selection", + char_selection_hover: "voxygen.element.ui.generic.frames.selection_hover", + char_selection_press: "voxygen.element.ui.generic.frames.selection_press", delete_button: "voxygen.element.ui.char_select.icons.bin", delete_button_hover: "voxygen.element.ui.char_select.icons.bin_hover", @@ -78,7 +79,7 @@ image_ids_ice! { name_input: "voxygen.element.ui.generic.textbox", // Tool Icons - sceptre: "voxygen.element.weapons.sceptre", + swords: "voxygen.element.weapons.swords", sword: "voxygen.element.weapons.sword", axe: "voxygen.element.weapons.axe", hammer: "voxygen.element.weapons.hammer", @@ -124,7 +125,8 @@ pub enum Event { Play(CharacterId), AddCharacter { alias: String, - tool: String, + mainhand: Option, + offhand: Option, body: comp::Body, }, DeleteCharacter(CharacterId), @@ -148,7 +150,8 @@ enum Mode { name: String, body: humanoid::Body, inventory: Box, - tool: &'static str, + mainhand: Option<&'static str>, + offhand: Option<&'static str>, body_type_buttons: [button::State; 2], species_buttons: [button::State; 6], @@ -178,11 +181,15 @@ impl Mode { } pub fn create(name: String) -> Self { - let tool = STARTER_SWORD; + // TODO: Load these from the server (presumably from a .ron) to allow for easier + // modification of custom starting weapons + let mainhand = Some(STARTER_SWORD); + let offhand = None; let loadout = LoadoutBuilder::empty() .defaults() - .active_mainhand(Some(Item::new_from_asset_expect(tool))) + .active_mainhand(mainhand.map(Item::new_from_asset_expect)) + .active_offhand(offhand.map(Item::new_from_asset_expect)) .build(); let inventory = Box::new(Inventory::new_with_loadout(loadout)); @@ -191,7 +198,8 @@ impl Mode { name, body: humanoid::Body::random(), inventory, - tool, + mainhand, + offhand, body_type_buttons: Default::default(), species_buttons: Default::default(), tool_buttons: Default::default(), @@ -244,7 +252,7 @@ enum Message { Name(String), BodyType(humanoid::BodyType), Species(humanoid::Species), - Tool(&'static str), + Tool((Option<&'static str>, Option<&'static str>)), RandomizeCharacter, RandomizeName, CancelDeletion, @@ -468,12 +476,12 @@ impl Controls { .padding(10) .style( style::button::Style::new(if Some(i) == selected { - imgs.selection_hover + imgs.char_selection_hover } else { - imgs.selection + imgs.char_selection }) - .hover_image(imgs.selection_hover) - .press_image(imgs.selection_press) + .hover_image(imgs.char_selection_hover) + .press_image(imgs.char_selection_press) .image_color(Rgba::new( select_col.0, select_col.1, @@ -485,7 +493,7 @@ impl Controls { .height(Length::Fill) .on_press(Message::Select(character_id)), ) - .ratio_of_image(imgs.selection), + .ratio_of_image(imgs.char_selection), ) .padding(0) .align_x(Align::End) @@ -514,9 +522,9 @@ impl Controls { .center_y(), ) .style( - style::button::Style::new(imgs.selection) - .hover_image(imgs.selection_hover) - .press_image(imgs.selection_press) + style::button::Style::new(imgs.char_selection) + .hover_image(imgs.char_selection_hover) + .press_image(imgs.char_selection_press) .image_color(Rgba::new(color.0, color.1, color.2, 255)) .text_color(iced::Color::from_rgb8(color.0, color.1, color.2)) .disabled_text_color(iced::Color::from_rgb8( @@ -531,7 +539,7 @@ impl Controls { button } }) - .ratio_of_image(imgs.selection) + .ratio_of_image(imgs.char_selection) .into(), ); characters @@ -710,7 +718,8 @@ impl Controls { name, body, inventory: _, - tool, + mainhand, + offhand: _, ref mut scroll, ref mut body_type_buttons, ref mut species_buttons, @@ -863,30 +872,30 @@ impl Controls { ]) .spacing(1); - let [ref mut sword_button, ref mut sceptre_button, ref mut axe_button, ref mut hammer_button, ref mut bow_button, ref mut staff_button] = + let [ref mut sword_button, ref mut swords_button, ref mut axe_button, ref mut hammer_button, ref mut bow_button, ref mut staff_button] = tool_buttons; let tool = Column::with_children(vec![ Row::with_children(vec![ icon_button_tooltip( sword_button, - *tool == STARTER_SWORD, - Message::Tool(STARTER_SWORD), + *mainhand == Some(STARTER_SWORD), + Message::Tool((Some(STARTER_SWORD), None)), imgs.sword, - "common.weapons.sword", + "common.weapons.greatsword", ) .into(), icon_button_tooltip( hammer_button, - *tool == STARTER_HAMMER, - Message::Tool(STARTER_HAMMER), + *mainhand == Some(STARTER_HAMMER), + Message::Tool((Some(STARTER_HAMMER), None)), imgs.hammer, "common.weapons.hammer", ) .into(), icon_button_tooltip( axe_button, - *tool == STARTER_AXE, - Message::Tool(STARTER_AXE), + *mainhand == Some(STARTER_AXE), + Message::Tool((Some(STARTER_AXE), None)), imgs.axe, "common.weapons.axe", ) @@ -896,25 +905,26 @@ impl Controls { .into(), Row::with_children(vec![ icon_button_tooltip( - sceptre_button, - *tool == STARTER_SCEPTRE, - Message::Tool(STARTER_SCEPTRE), - imgs.sceptre, - "common.weapons.sceptre", + swords_button, + *mainhand == Some(STARTER_SWORDS), + Message::Tool((Some(STARTER_SWORDS), Some(STARTER_SWORDS))), + imgs.swords, + "common.weapons.greatsword + ", ) .into(), icon_button_tooltip( bow_button, - *tool == STARTER_BOW, - Message::Tool(STARTER_BOW), + *mainhand == Some(STARTER_BOW), + Message::Tool((Some(STARTER_BOW), None)), imgs.bow, "common.weapons.bow", ) .into(), icon_button_tooltip( staff_button, - *tool == STARTER_STAFF, - Message::Tool(STARTER_STAFF), + *mainhand == Some(STARTER_STAFF), + Message::Tool((Some(STARTER_STAFF), None)), imgs.staff, "common.weapons.staff", ) @@ -1076,8 +1086,8 @@ impl Controls { let column_content = vec![ body_type.into(), - species.into(), tool.into(), + species.into(), slider_options.into(), rand_character.into(), ]; @@ -1300,12 +1310,17 @@ impl Controls { }, Message::CreateCharacter => { if let Mode::Create { - name, body, tool, .. + name, + body, + mainhand, + offhand, + .. } = &self.mode { events.push(Event::AddCharacter { alias: name.clone(), - tool: String::from(*tool), + mainhand: mainhand.map(String::from), + offhand: offhand.map(String::from), body: comp::Body::Humanoid(*body), }); self.mode = Mode::select(Some(InfoContent::CreatingCharacter)); @@ -1330,13 +1345,21 @@ impl Controls { }, Message::Tool(value) => { if let Mode::Create { - tool, inventory, .. + mainhand, + offhand, + inventory, + .. } = &mut self.mode { - *tool = value; + *mainhand = value.0; + *offhand = value.1; inventory.replace_loadout_item( EquipSlot::ActiveMainhand, - Some(Item::new_from_asset_expect(*tool)), + mainhand.map(|specifier| Item::new_from_asset_expect(specifier)), + ); + inventory.replace_loadout_item( + EquipSlot::ActiveOffhand, + offhand.map(|specifier| Item::new_from_asset_expect(specifier)), ); } },