From 83dd4a23ad4cbb33c4ef57d0aa3eab3ed4526486 Mon Sep 17 00:00:00 2001 From: jshipsey Date: Sat, 25 May 2019 23:31:41 -0400 Subject: [PATCH] add wolf Former-commit-id: b16aa2e7c382710c0705371cd36d57ddf62cf13c --- assets/voxygen/voxel/npc/wolf/wolf_ears.vox | Bin 0 -> 1160 bytes assets/voxygen/voxel/npc/wolf/wolf_jaw.vox | Bin 0 -> 1280 bytes .../voxygen/voxel/npc/wolf/wolf_lb_foot.vox | Bin 0 -> 1344 bytes .../voxygen/voxel/npc/wolf/wolf_lf_foot.vox | Bin 0 -> 1344 bytes .../voxel/npc/wolf/wolf_lower_head.vox | Bin 0 -> 3552 bytes .../voxygen/voxel/npc/wolf/wolf_rb_foot.vox | Bin 0 -> 1344 bytes .../voxygen/voxel/npc/wolf/wolf_rf_foot.vox | Bin 0 -> 1344 bytes assets/voxygen/voxel/npc/wolf/wolf_tail.vox | Bin 0 -> 1672 bytes .../voxel/npc/wolf/wolf_torso_back.vox | Bin 0 -> 5504 bytes .../voxygen/voxel/npc/wolf/wolf_torso_mid.vox | Bin 0 -> 5932 bytes .../voxel/npc/wolf/wolf_upper_head.vox | Bin 0 -> 4656 bytes common/src/comp/actor.rs | 111 +++++++++++ common/src/comp/mod.rs | 3 + server/src/cmd.rs | 41 +++- voxygen/src/anim/mod.rs | 1 + voxygen/src/anim/quadrupedmedium/idle.rs | 105 ++++++++++ voxygen/src/anim/quadrupedmedium/jump.rs | 84 ++++++++ voxygen/src/anim/quadrupedmedium/mod.rs | 92 +++++++++ voxygen/src/anim/quadrupedmedium/run.rs | 116 +++++++++++ voxygen/src/scene/figure.rs | 185 +++++++++++++++++- 20 files changed, 726 insertions(+), 12 deletions(-) create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_ears.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_jaw.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_lb_foot.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_lf_foot.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_lower_head.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_rb_foot.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_rf_foot.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_tail.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_torso_back.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_torso_mid.vox create mode 100644 assets/voxygen/voxel/npc/wolf/wolf_upper_head.vox create mode 100644 voxygen/src/anim/quadrupedmedium/idle.rs create mode 100644 voxygen/src/anim/quadrupedmedium/jump.rs create mode 100644 voxygen/src/anim/quadrupedmedium/mod.rs create mode 100644 voxygen/src/anim/quadrupedmedium/run.rs diff --git a/assets/voxygen/voxel/npc/wolf/wolf_ears.vox b/assets/voxygen/voxel/npc/wolf/wolf_ears.vox new file mode 100644 index 0000000000000000000000000000000000000000..019d9f07a538809d1fc53f290c8f1a6ada120cf7 GIT binary patch literal 1160 zcmc(eUu=s}7{=fFyBJc|b=t92x6yWj{jonbbhe_KjTuADf)J~cN+SzRLnvZo%rqMb zW@H%=!_qFq#Wb>rL_|hJB8!NKTNfhke$HpEB)Ie@Po6x_^PTtozVn?^zh;xALqw{} z+%<~iz&MdQx5qVE6RHvv#{9yj%^r7!W~$PUl7FIze}Yc8ccQ|0ohX*Q6EshhR;*LL zD2!3QDCjg#WvZut-OA-u@= zK4D5&NK)E(Tgb0Yq;j7g&(S1K56q$>B-BQP9eu)~muhXTnKZAJ%#eeEsFT!y0c)!n zM^8FAPv?@-AY>j@y*q@`K|$85`N0GvG8O4J&@y)#y$h3hy(ASXXA==&K;ezTCxysC zq3?na?-iciSK29byMzbpgpu8XN9lw0LfcN|Hw)!g=SYaU?6k(vo&|o;k^k#uQ%M&0@e~qFwFP@B6Pkr}f%g_nbfz9O~>P zd?U)){wG{|Jj|l~Ei66OMb*_o>h2BWbUOJUAPEY5W9+c-{^98Ry;tY!U%9%1KkwO} SSPTD@Y5w1`pN;>%UVZ=|1|+8d literal 0 HcmV?d00001 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_jaw.vox b/assets/voxygen/voxel/npc/wolf/wolf_jaw.vox new file mode 100644 index 0000000000000000000000000000000000000000..d128dd62061c8fca3bac23941b1a719c837e115e GIT binary patch literal 1280 zcmc(eZ%Eu_9KgT#``v|Ph09ZSy7W4=-D$Y_C;z0aGrhLcbUDkm%gGiSdEFfw60*s$ z*sex4EVDxwY&jQVF=m_G$)doHA!9Jcun|GX7!kecMK2#bMZEVqvq#9EylN z>QGFv#q3#(m?;u74b?VV%&<`3CWd0!Hq~a-W;3IP&4`NHhSu5)GiDg(6+`2uh1zzF z*|WZ(^NpxoYaNPd^<>ewU2Vm5sJ1Y5mZ`H$?N@E8Z>qg(`wQ)&`?RFFxtVx8&fO_t z$JtfNoqzF%(@7@NgC!S(X?nZ2vVU(Y@zHM5<3Z9>`$^9nrYU`hJbxjseQw;xs`1UX zAOQywc^H{{99b1)-rQm#$bIq2u{{u>1s_aiK3M zys;=8y`{Z<#gv9URK%-jO!+ApapIXMrfR;7+H0FB8Wbvy>+ETvZAFk*bp5d$B>5P! zD328782 z8Xpxpe8Nz(Fxn}c)_7k-G2wuRu|6-;2kVHx+Qjs52buR@)s@lxyqALm zO+>nc#9m?cZDHjjp|P}>U{wW!jWvvPwlGjtNVuVdiS3o7hPDuBt7YelErecfC$g`X zu|pvy-;0o1ILX@8v!u=plKJ8-a&vRpn7;wH+fA*{Lu1WTJX_~u^4(1=p7ZeI^(xkH zR&z$zOw9{7z7c-@UKk5|Ii09y^l zXdOR+E8*hWdExf!!UeAvpU=l|`6w^#SV9tG6pR$GJag|K9xK+nQ(DS9l}Wa>PI2JW zNj44@ar3K6mP0P4^sN4U{#KneYft|TMuy?&%mRteQ+&8|l~2E07VyygtF~JG-B@lK0D5@dxFygCE>4e*=~}G<5&~ literal 0 HcmV?d00001 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_lb_foot.vox b/assets/voxygen/voxel/npc/wolf/wolf_lb_foot.vox new file mode 100644 index 0000000000000000000000000000000000000000..6ea9dcc9c1793a13f16839b868da55df8c1c5ca6 GIT binary patch literal 1344 zcmc(eZ%CYV9KgTN^PEev!sV&+TzZ|_?#{8zKlvxk&h*+&)8#DNE+<=Tq+PokN603} zV!ImIaG4#tV9PATV$3$VlcERiPz&8V10)X-d0v1}}jDTX4J#=6KmkPu+_+Cv;+t+nf>}u9VPxiUWTk-IE}`&PlRM{N?o5Z6n^^ zNT0ueq1s}`c2&Fa+)q|f)W{NPt>d-d=AxAW{?`+9E> zAB5vmb0oh=b9Uh>pM1Z{(?>^XIWCp74Cd{@B8lP`TDQ8 YUc&Wzc0X+g?-#TE4~nffesI0~1M!_YVE_OC literal 0 HcmV?d00001 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_lf_foot.vox b/assets/voxygen/voxel/npc/wolf/wolf_lf_foot.vox new file mode 100644 index 0000000000000000000000000000000000000000..8651d40dba3459f91382a09d91753196ee73a23a GIT binary patch literal 1344 zcmc(ee@LBW6vxl=zSkvL;qt1xy7cCccJFm;^GE(jvuk?WuBOXbw%wd;v5{u;4hh-h zve<5oY`Dxs7i^h@Sd7^w_e#+pb{R4TV+AHk>dy8nW$KRfVwpYJ*6 zJ?D9z_kEu3-Fv-LBGTRz?$ANDripZgBcVqeM@?NxS8QePzDW3Q9UW_Q9!3Ujmlbun zBAGH)CGHBGdoR~9ey-{r2idu?MY)iFbENf6KGbq|m zT-r-}8`Va&rP@+$skT+y&YY@6*I*P&u@zmo)~K)8is)L6Vkx$xACk9h#iVI3#a49F zQKMLjt;hz=Z%|*cl|4J3Z_+;NR$E(3EEePLgs|(v3dQcf_`~fcm1@VaOW`CPZ96!) zzn<7|8_Cfy$%%s`r;k#TjFK75!E?Zi_e2@~nK~qth73H6%s!5+2_=%;JNkCuoTYos+`r3&QbRTHBdNL4Oe?u>jSHAo)XX zipKH?%oS38Z40?QLdi+(JtZ_O3-YqgKa!42K87s18Qrpx`5oEZel{OkpJY;mCFMuu zS7q{;u<)^vnisBLQ9mfmhJbiR-8jaMImj^`8eEN!$7ML-!II(Ei8X1R2SqC4wTSS zy^W!kI=TZn^jGCGwzHH(?{-2Bt<*3>@fSBpPA-y#W&Qr&+yvfyDV9QeVDF zMn(pkvNq!NdMWo8QN8Uco~iIN{_bWLJ}cs<>jBnomT_L^Ow0*4z7u}=K^W=xaV}oT z%B5z0|GA5yGntHi<>tyQ4{H?u@B6Q;tmLDb8Mc?tQa^eMPu#<`&xPBs2^W1n{C+=u z#lyU~YY~Z$kUf;m()7K5cp^{FPC)_hlupuEKf$3hr`gn-%gwJ#S&Dd=&~Nqc@9(_l z^xD^TgP}e+K0QzTiv(vEuky+Ft2}*ll*Ustw0*iv*X31$!60`9BwgW8>{a2;xA)d} dN6*)P<@FM--?RITPV#;^C;p(^dgBMz%RlHOI%EI< literal 0 HcmV?d00001 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_lower_head.vox b/assets/voxygen/voxel/npc/wolf/wolf_lower_head.vox new file mode 100644 index 0000000000000000000000000000000000000000..eecc957007fd2f28068eaeb3c99fa7b223afabac GIT binary patch literal 3552 zcmc(hTZ~p$7035?_Vt`^rlB$n9jGvJu?(2DT;w8H2Z6Q&LZv9SBPFeA6=WvU5JOrr zscAEu949#JvQKX8`RLiBae=boVEeKZ&uEAQ$1cm zHzJ{S^>~2{2_gh&I;=r~3<)9x@K9CQfR2YykM|&ZkQK5*c9C6VgH8wSA%KU5GixZ2Awh%y9vX`o3S>wSA%KU5+|*DYLxKna zJk*_p-GKeTIe{4CL=z(4kyw!)=?k$&@|MV78t-=Uc;#5DY@Ru&p@Hm?vBQ}iWQG3~ zHW-HvYZY|JjbZbEZix=*@PlvDYv+*I@TH80lA(;n;>lTrKt0V5JFjpqIvr0e9v?f@ zwnJ?z>RHHZ#%Iojgnnve<}B7y#?Oq8*a+xFn`bT-Y?-vZo?I4kTId1jl<}UbOcZ>} z37^exbP`0UJCQw>Gi>2=Ms_RCfI=LZwVW+K7E2kcQ=k{}SgwfOus!5Hp%+^_#9D#J zc2yCl)y2-Sn%P+ao7jM8bL6~WzgP^JHS%Aq2Atg_;v^qUwtNNp9$SXxnA~{FDQjKy zde~pF)=O^c?8keFqnG#tIqiimYYyq!-rx*;a~3ncI`(AZ>R_WVuCP~Ow;^VateMNi zP%MsC;zQeeVZ!5|N57z(6S<0(r%caB?ic&XgJ-|@^lRIn^cy`_neX(Zr+0$&4SDdy z9q6?{PbGRS@f}-i9?*@{FF-;knqE7H#72ZfE+YhT5U`nY#n>b@C%@5TVr=z92B_`q zcFZ1RK+ltph)g*$rf!zE))sZni8*?c*dhd@^&NfUjF7My?R@4VB)hkLF1;1eEp1=Zx2zTNTVpTV-KAbN<4le-H7aecIm7zjYRTS!T@Mu`auFebhYs&a z#{Wo+wb^2SV>ax4uzDAKE7ZL3ZqN(a`k|d8Zr;Ld`QmL%)*L_)^Rcx&`~0Gc#uvdvlpf+`9+?lHFT78@6i|=4%Ea$MUQkCchCuu^C0jxNAP_6R&r*< zCf^l#Pd1;>15bVe#1_ku-8aUN=-UW2xo9jO)G8Bimpf62Clh0#W*G{;6nx9bF83uk zY(RpB{AFZ;+N9Za=(hc3>)7Et5<_M!ljoXoZFd1b3i}(z8Q-$?II?C>jec#lK{ohb zGvAmF@pXx_OT1m;ZuoBaZkVshVQsZ!e-HM1*jsEKGCdL)`xeWw`DAy1vxz<7b4C3; zBBxvK9e+ZXPCczPmnJl0xL*U04{Gqa zWg0rOPHsz-JJ86T{e;}Le$CkKG<)3X&SOrWdBdq3aO$0Mn#s8THK$eEyV^QFL!-~n z)DJIzQky58cAjwh#s#Nm-(&C2IhwbBffh|J)#~YC%{|zs1xM#->ACq@{`Os(y~kbUwVW*qlavEj)%xD zMcsJoRZXAXqpQFAwz}P}?wEPI1_uYVd}x7I-~DNQZpDy}eeX_P`1u0;`JJV@`R+2E z=FI7HPS=0$^w&Q+9p1l0FHf!1wbwW4AAi}UgD=g{(O>uJ&G!a$Q}h4t@vmIDQa@R9 zM)xc~tMx}-(7@Dy-u{Kt`(Jl@ZOIZ14Gn4E!bAGfgBRtd4r|uIS-O1cRt=w3s5|z~*1Nx1tjnVVI!>onxCn@<*DT>9w7v%UQNvPPW)cbGsWy$aWly z?P_GhGCOp^mRX3!m~C=O(I0jU8G|u~jR-=rerFXvUgu7__wMvS`;J0h#0mJF;z`f zOVv`f72_c}Vma8R#!SsKBVtR$uryb(6nkAYZfRW6CW;XeLn5YOgbhRMY|wATQtS+x|j9Q(9l3U9_Q|aulyl~={&h06rc&L=}xR1J&pQ5OX z(y>B(vn5nr+d_W7P<~2lPYTV;g1oH#W0^?uF=WBT=$4Jl?a1Z!vqjMHBuNpLlpmE} zmE>_@{$n9MCtSaxwqKYD2;b}x*4_|8Y9H?t#t*4~L}>F00}aARyKqkZJ+*}l1xkta zc$hp~P5hO5CI{O{zxOJ?%??pnmPd1S37yY*INVpyaEFlCFHFBBEPp7}6&DipmD69h zjc9u#eZD+~YKs`#SwU)GJAvjZcE8X_=%rSM4|EfYgcyH!nAF@EReWa!Y@Avu^|uV5;d$` zYUB5xdx@USX6!2$S8f%sM#=xa|C*W_KB}K)d({k0qo*lI6macx;r467MUMxs*UMnp z2ruqhKoT)>qq!_i-TQ|p3-#_47xQ*Sl9r|k4xK&2rh$BJeqF&*sDKGQtAC%rljqdh z*L#ELAe@+*Bk@Iw4;HTS$@i-~eQcDL)6;Z*x=iooRs4QGcLgL<;ZLkp;m)`B)^|tm b*MG(J5w5?p`>7MWU(E48D7Ies!Sm%GGPOEx literal 0 HcmV?d00001 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_rf_foot.vox b/assets/voxygen/voxel/npc/wolf/wolf_rf_foot.vox new file mode 100644 index 0000000000000000000000000000000000000000..ce1539279697ff8dbbe68b025ae30d087596ec4a GIT binary patch literal 1344 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 literal 0 HcmV?d00001 diff --git a/assets/voxygen/voxel/npc/wolf/wolf_torso_mid.vox b/assets/voxygen/voxel/npc/wolf/wolf_torso_mid.vox new file mode 100644 index 0000000000000000000000000000000000000000..38f9cb80cc850ac5d6c70b9d7f7a1fc25844147a GIT binary patch literal 5932 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 xHg4P~9~cpnApa73%ET z?zwa3%$b?{?T*{;Tyn%1v*pH3TM_1x3yj&mX=-Du6aK~km1*G4yQVh%eZYXfeb$(e zd>2yad~u!e5t*k=2%QNYT<3G{Ok^IJN7uO$yU?Vr;+=|jtK_;m#;#^wXFz8>y6hRN zbX_)aR99hStI#DAy9my(Cj^M9hYT^Nt{|H#3=qM;A>$_m_VW<% zF|eP9ka&hKp#;{)ZopYW6FP@q1I{$yOasm{;5;Gmp5Z-k&|uq})Y%H(d*aYmap)@i z01pPA2E-v$scYG%#csVSb92#^DJ~ikY^{2ugXjtR0)ew)s9)TG6J{Fmnq)~(I z0vS@3MzP9_)5u}NVb5{igf3R4%QbV(=Qx*7iL((?;uN`;%>8)wa1HB;OX5C#P9G-j zH*tQK)8BF|qsX}RzO&f3>T5p^T|s7u#5-Us=@>g+?P4=BckJ0ZKMI^VLejH4-xbIz zW0+1g&!8e+H6-*=Y20+f9a!R2kXgr^&2k3InX1~4>KdQGfrkKzbrFI^2M(-C?yyF- z$7fiCxySqH}c~X7mYtjKo~$yj$^(Q)==GoK3_6AF&_Fp~yI*EB&6#$wRAa zkgc9s^Cu8@?kF*K_?fFX@|x$wD{vRy74}dcOBa0UJY;evYK;`)MV@5r1;;%?;2u5p zJkN^eq~%Iu~s>jHcD9^$~<_qs@ovE_IV z9C!!{&nxb<=6wx5~q+zXM&55A++4 zv|97vA?R~UtigeYOdeI*5Bf3tYF|>D+*>Hzo!)aDhmmnZ%p>}mUSQEV2&`@KBatVq z)@)7RfrhcAwk$Q~dKr<_m-Z~)ci`t8T+0V=xcGhVct@^ zS?h6)Ag&%=(3lbpraa1Nw(b z)+NS~acH&2l~EYe-vD70iA#bE1sVtwVQ(0x9>$Rq*yMW_dRs`wt@c)WY=X$$<$la> z68+BW_Z}Y#IzP^L8`;vY!$jO0**kF;LBGlR-DI4pt%xs~o)XzNvTx#>k+D-C;zMK} z@gu4a7kNDQJ%YAW`1iLdmP)b|(d zRrsv^4-!P3bJq?1t#Gf2{R)0Gy>B|t!&b-roLXZ4ihh&(-vaE-yM=dikLFJ48g!0x zTd1KT?*hMXJUIQm12t4o^g98W_lnjGzX=lkA<|P5}U^teVSkgBB5nX11)PBXj#)h%bEsS)-+IR_Jjlx0(fv>puZ@g^ek#~7_+d^5qYpGl|yF%8S*dUAc%#)>0FO(H8Tq-Nyyh1Lz+sI{)Vf%=Y z>rWdoUt#}!NzCCfF|W;&16RzE|6{Ytt0i|b|T%QwpId$-EI(Uctg z-flT@{0TYx`tx$)xx3}eFTW*C)5yhh=g5*JOJwEbQdx7=r{uHOPRhaWULr65Y^nU| ztrc?aoh#)z_B`=|k+*+m>?!e=+VE+Pn^XEq1`?`@AmoJye$w_%|*%Veto%|npz--h}D0`U)QOvySBeA zdma>d Self { + Self { + race: *thread_rng().choose(&ALL_QMRACES).unwrap(), + body_type: *thread_rng().choose(&ALL_QMBODY_TYPES).unwrap(), + wolf_upperhead: *thread_rng().choose(&ALL_QMWOLF_UPPERHEADS).unwrap(), + wolf_jaw: *thread_rng().choose(&ALL_QMWOLF_JAWS).unwrap(), + wolf_lowerhead: *thread_rng().choose(&ALL_QMWOLF_LOWERHEADS).unwrap(), + wolf_tail: *thread_rng().choose(&ALL_QMWOLF_TAILS).unwrap(), + wolf_torsoback: *thread_rng().choose(&ALL_QMWOLF_TORSOBACKS).unwrap(), + wolf_torsomid: *thread_rng().choose(&ALL_QMWOLF_TORSOMIDS).unwrap(), + wolf_ears: *thread_rng().choose(&ALL_QMWOLF_EARS).unwrap(), + wolf_lffoot: *thread_rng().choose(&ALL_QMWOLF_LFFEET).unwrap(), + wolf_rffoot: *thread_rng().choose(&ALL_QMWOLF_RFFEET).unwrap(), + wolf_lbfoot: *thread_rng().choose(&ALL_QMWOLF_LBFEET).unwrap(), + wolf_rbfoot: *thread_rng().choose(&ALL_QMWOLF_RBFEET).unwrap(), + } + } +} #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Body { Humanoid(HumanoidBody), Quadruped(QuadrupedBody), + QuadrupedMedium(QuadrupedMediumBody), } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 03fb57f617..8de7e629d3 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -11,6 +11,7 @@ pub use actor::Actor; pub use actor::Body; pub use actor::HumanoidBody; pub use actor::QuadrupedBody; +pub use actor::QuadrupedMediumBody; pub use agent::Agent; pub use animation::Animation; pub use animation::AnimationInfo; @@ -19,6 +20,8 @@ pub use inputs::Control; pub use inputs::Gliding; pub use inputs::Jumping; pub use inputs::Respawning; +pub use agent::{Agent, Control}; +>>>>>>> add wolf pub use player::Player; pub use stats::Dying; pub use stats::Stats; diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 1c420cc701..bc8f64e740 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -82,10 +82,16 @@ lazy_static! { handle_kill ), ChatCommand::new( - "pet", + "pig", "{}", - "/pet : Spawn a test pet NPC", - handle_pet + "/pig : Spawn a test pig NPC", + handle_petpig + ), + ChatCommand::new( + "wolf", + "{}", + "/wolf : Spawn a test wolf NPC", + handle_petwolf ), ChatCommand::new( "help", "", "/help: Display this message", handle_help) @@ -206,7 +212,7 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat } } -fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { +fn handle_petpig(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { match server .state .read_component_cloned::(entity) @@ -233,6 +239,33 @@ fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &Cha .notify(entity, ServerMsg::Chat("You have no position!".to_owned())), } } +fn handle_petwolf(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { + match server + .state + .read_component_cloned::(entity) + { + Some(pos) => { + server + .create_npc( + "Tobermory".to_owned(), + comp::Body::QuadrupedMedium(comp::QuadrupedMediumBody::random()), + ) + .with(comp::Control::default()) + .with(comp::Agent::Pet { + target: entity, + offset: Vec2::zero(), + }) + .with(pos) + .build(); + server + .clients + .notify(entity, ServerMsg::Chat("Spawned pet!".to_owned())); + } + None => server + .clients + .notify(entity, ServerMsg::Chat("You have no position!".to_owned())), + } +} fn handle_help(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) { for cmd in CHAT_COMMANDS.iter() { diff --git a/voxygen/src/anim/mod.rs b/voxygen/src/anim/mod.rs index 7bbee6358b..6908d9b002 100644 --- a/voxygen/src/anim/mod.rs +++ b/voxygen/src/anim/mod.rs @@ -1,3 +1,4 @@ +pub mod QuadrupedMedium; pub mod character; pub mod fixture; pub mod quadruped; diff --git a/voxygen/src/anim/quadrupedmedium/idle.rs b/voxygen/src/anim/quadrupedmedium/idle.rs new file mode 100644 index 0000000000..3bbfa0d7ef --- /dev/null +++ b/voxygen/src/anim/quadrupedmedium/idle.rs @@ -0,0 +1,105 @@ +// Standard +use std::{f32::consts::PI, ops::Mul}; + +// Library +use vek::*; + +// Local +use super::{super::Animation, QuadrupedMediumSkeleton, SCALE}; + +pub struct IdleAnimation; + +impl Animation for IdleAnimation { + type Skeleton = QuadrupedMediumSkeleton; + type Dependency = (f64); + + fn update_skeleton( + skeleton: &Self::Skeleton, + global_time: Self::Dependency, + anim_time: f64, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let wave = (anim_time as f32 * 14.0).sin(); + let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin(); + let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos(); + let wave_cos = (anim_time as f32 * 14.0).cos(); + let wave_slow = (anim_time as f32 * 3.5 + PI).sin(); + let wave_slow_cos = (anim_time as f32 * 3.5 + PI).cos(); + let wave_dip = (wave_slow.abs() - 0.5).abs(); + + let wolf_look = Vec2::new( + ((global_time + anim_time) as f32 / 8.0) + .floor() + .mul(7331.0) + .sin() + * 0.5, + ((global_time + anim_time) as f32 / 8.0) + .floor() + .mul(1337.0) + .sin() + * 0.25, + ); + let wolf_tail = Vec2::new( + ((global_time + anim_time) as f32 / 2.0) + .floor() + .mul(7331.0) + .sin() + * 0.25, + ((global_time + anim_time) as f32 / 2.0) + .floor() + .mul(1337.0) + .sin() + * 0.125, + ); + + next.wolf_upperhead.offset = Vec3::new(0.0, 7.5, 15.0 + wave_ultra_slow * 0.4) / 11.0; + next.wolf_upperhead.ori = + Quaternion::rotation_z(wolf_look.x) * Quaternion::rotation_x(wolf_look.y); + next.wolf_upperhead.scale = Vec3::one() / 10.88; + + next.wolf_jaw.offset = + Vec3::new(0.0, 4.5 - wave_ultra_slow_cos * 0.12, 2.0 + wave_slow * 0.2); + next.wolf_jaw.ori = Quaternion::rotation_x(wave_slow * 0.05); + next.wolf_jaw.scale = Vec3::one() * 1.01; + + next.wolf_lowerhead.offset = Vec3::new(0.0, 3.1, -4.5 + wave_ultra_slow * 0.20); + next.wolf_lowerhead.ori = Quaternion::rotation_z(0.0); + next.wolf_lowerhead.scale = Vec3::one() * 0.98; + + next.wolf_tail.offset = Vec3::new(0.0, -13.0, 8.0 + wave_ultra_slow * 1.2) / 11.0; + next.wolf_tail.ori = Quaternion::rotation_z(0.0 + wave_slow * 0.2 + wolf_tail.x) + * Quaternion::rotation_x(wolf_tail.y); + next.wolf_tail.scale = Vec3::one() / 11.0; + + next.wolf_torsoback.offset = Vec3::new(0.0, -9.5, 11.0 + wave_ultra_slow * 1.2) / 11.0; + next.wolf_torsoback.ori = Quaternion::rotation_y(wave_slow_cos * 0.015); + next.wolf_torsoback.scale = Vec3::one() / 11.0; + + next.wolf_torsomid.offset = Vec3::new(0.0, 0.0, 12.0 + wave_ultra_slow * 0.7) / 11.0; + next.wolf_torsomid.ori = Quaternion::rotation_y(wave_slow * 0.015); + next.wolf_torsomid.scale = Vec3::one() / 10.9; + + next.wolf_ears.offset = Vec3::new(0.0, 0.75, 6.25); + next.wolf_ears.ori = Quaternion::rotation_x(0.0 + wave_slow * 0.1); + next.wolf_ears.scale = Vec3::one() * 1.05; + + next.wolf_LFFoot.offset = Vec3::new(-5.0, 5.0, 2.5) / 11.0; + next.wolf_LFFoot.ori = Quaternion::rotation_x(0.0); + next.wolf_LFFoot.scale = Vec3::one() / 11.0; + + next.wolf_RFFoot.offset = Vec3::new(5.0, 5.0, 2.5) / 11.0; + next.wolf_RFFoot.ori = Quaternion::rotation_x(0.0); + next.wolf_RFFoot.scale = Vec3::one() / 11.0; + + next.wolf_LBFoot.offset = Vec3::new(-5.0, -10.0, 2.5) / 11.0; + next.wolf_LBFoot.ori = Quaternion::rotation_x(0.0); + next.wolf_LBFoot.scale = Vec3::one() / 11.0; + + next.wolf_RBFoot.offset = Vec3::new(5.0, -10.0, 2.5) / 11.0; + next.wolf_RBFoot.ori = Quaternion::rotation_x(0.0); + next.wolf_RBFoot.scale = Vec3::one() / 11.0; + + next + } +} diff --git a/voxygen/src/anim/quadrupedmedium/jump.rs b/voxygen/src/anim/quadrupedmedium/jump.rs new file mode 100644 index 0000000000..0ed7c70ee8 --- /dev/null +++ b/voxygen/src/anim/quadrupedmedium/jump.rs @@ -0,0 +1,84 @@ +// Standard +use std::f32::consts::PI; + +// Library +use vek::*; + +// Local +use super::{super::Animation, QuadrupedMediumSkeleton, SCALE}; + +pub struct JumpAnimation; + +impl Animation for JumpAnimation { + type Skeleton = QuadrupedMediumSkeleton; + type Dependency = (f32, f64); + + fn update_skeleton( + skeleton: &Self::Skeleton, + global_time: Self::Dependency, + anim_time: f64, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let wave = (anim_time as f32 * 14.0).sin(); + let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin(); + let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos(); + let wave_cos = (anim_time as f32 * 14.0).cos(); + let wave_slow = (anim_time as f32 * 3.5 + PI).sin(); + let wave_slow_cos = (anim_time as f32 * 3.5 + PI).cos(); + let wave_stop = (anim_time as f32 * 5.0).min(PI / 2.0).sin(); + + next.wolf_upperhead.offset = Vec3::new(0.0, 7.5, 15.0 + wave_stop * 4.8) / 11.0; + next.wolf_upperhead.ori = + Quaternion::rotation_z(0.0) * Quaternion::rotation_x(wave_slow * -0.25); + next.wolf_upperhead.scale = Vec3::one() / 10.88; + + next.wolf_jaw.offset = Vec3::new(0.0, 4.5, 2.0); + next.wolf_jaw.ori = Quaternion::rotation_x(0.0); + next.wolf_jaw.scale = Vec3::one() * 1.01; + + next.wolf_lowerhead.offset = Vec3::new(0.0, 3.1, -4.5); + next.wolf_lowerhead.ori = Quaternion::rotation_x(wave_stop * -0.1); + next.wolf_lowerhead.scale = Vec3::one() * 0.98; + + next.wolf_tail.offset = Vec3::new(0.0, -12.0, 8.0) / 11.0; + next.wolf_tail.ori = + Quaternion::rotation_z(0.0) * Quaternion::rotation_x(wave_slow * -0.25); + next.wolf_tail.scale = Vec3::one() / 11.0; + + next.wolf_torsoback.offset = + Vec3::new(0.0, -9.5 + wave_stop * 1.0, 11.0 + wave_stop * 2.2) / 11.0; + next.wolf_torsoback.ori = Quaternion::rotation_x(wave_slow * -0.25); + next.wolf_torsoback.scale = Vec3::one() / 11.0; + + next.wolf_torsomid.offset = Vec3::new(0.0, 0.0, 12.0 + wave_stop * 3.6) / 11.0; + next.wolf_torsomid.ori = Quaternion::rotation_x(wave_slow * -0.25); + next.wolf_torsomid.scale = Vec3::one() / 10.9; + + next.wolf_ears.offset = Vec3::new(0.0, 0.75, 6.25); + next.wolf_ears.ori = Quaternion::rotation_x(0.0); + next.wolf_ears.scale = Vec3::one() * 1.05; + + next.wolf_LFFoot.offset = + Vec3::new(-5.0, 5.0 + wave_stop * 3.0, 5.0 + wave_stop * 7.0) / 11.0; + next.wolf_LFFoot.ori = Quaternion::rotation_x(wave_stop * 1.0 + wave * 0.15); + next.wolf_LFFoot.scale = Vec3::one() / 11.0; + + next.wolf_RFFoot.offset = + Vec3::new(5.0, 5.0 - wave_stop * 3.0, 5.0 + wave_stop * 5.0) / 11.0; + next.wolf_RFFoot.ori = Quaternion::rotation_x(wave_stop * -1.0 + wave * 0.15); + next.wolf_RFFoot.scale = Vec3::one() / 11.0; + + next.wolf_LBFoot.offset = + Vec3::new(-5.0, -10.0 - wave_stop * 2.0, 5.0 + wave_stop * 0.0) / 11.0; + next.wolf_LBFoot.ori = Quaternion::rotation_x(wave_stop * -1.0 + wave * 0.15); + next.wolf_LBFoot.scale = Vec3::one() / 11.0; + + next.wolf_RBFoot.offset = + Vec3::new(5.0, -10.0 + wave_stop * 2.0, 5.0 + wave_stop * 2.0) / 11.0; + next.wolf_RBFoot.ori = Quaternion::rotation_x(wave_stop * 1.0 + wave * 0.15); + next.wolf_RBFoot.scale = Vec3::one() / 11.0; + + next + } +} diff --git a/voxygen/src/anim/quadrupedmedium/mod.rs b/voxygen/src/anim/quadrupedmedium/mod.rs new file mode 100644 index 0000000000..78ec5764a6 --- /dev/null +++ b/voxygen/src/anim/quadrupedmedium/mod.rs @@ -0,0 +1,92 @@ +pub mod idle; +pub mod jump; +pub mod run; + +// Reexports +pub use self::idle::IdleAnimation; +pub use self::jump::JumpAnimation; +pub use self::run::RunAnimation; + +// Crate +use crate::render::FigureBoneData; + +// Local +use super::{Bone, Skeleton}; + +const SCALE: f32 = 11.0; + +#[derive(Clone)] +pub struct QuadrupedMediumSkeleton { + wolf_upperhead: Bone, + wolf_jaw: Bone, + wolf_lowerhead: Bone, + wolf_tail: Bone, + wolf_torsoback: Bone, + wolf_torsomid: Bone, + wolf_ears: Bone, + wolf_LFFoot: Bone, + wolf_RFFoot: Bone, + wolf_LBFoot: Bone, + wolf_RBFoot: Bone, +} + +impl QuadrupedMediumSkeleton { + pub fn new() -> Self { + Self { + wolf_upperhead: Bone::default(), + wolf_jaw: Bone::default(), + wolf_lowerhead: Bone::default(), + wolf_tail: Bone::default(), + wolf_torsoback: Bone::default(), + wolf_torsomid: Bone::default(), + wolf_ears: Bone::default(), + wolf_LFFoot: Bone::default(), + wolf_RFFoot: Bone::default(), + wolf_LBFoot: Bone::default(), + wolf_RBFoot: Bone::default(), + } + } +} + +impl Skeleton for QuadrupedMediumSkeleton { + fn compute_matrices(&self) -> [FigureBoneData; 16] { + let ears_mat = self.wolf_ears.compute_base_matrix(); + let upperhead_mat = self.wolf_upperhead.compute_base_matrix(); + let lowerhead_mat = self.wolf_lowerhead.compute_base_matrix(); + + [ + FigureBoneData::new(upperhead_mat), + FigureBoneData::new( + upperhead_mat * lowerhead_mat * self.wolf_jaw.compute_base_matrix(), + ), + FigureBoneData::new(upperhead_mat * lowerhead_mat), + FigureBoneData::new(self.wolf_tail.compute_base_matrix()), + FigureBoneData::new(self.wolf_torsoback.compute_base_matrix()), + FigureBoneData::new(self.wolf_torsomid.compute_base_matrix()), + FigureBoneData::new(upperhead_mat * ears_mat), + FigureBoneData::new(self.wolf_LFFoot.compute_base_matrix()), + FigureBoneData::new(self.wolf_RFFoot.compute_base_matrix()), + FigureBoneData::new(self.wolf_LBFoot.compute_base_matrix()), + FigureBoneData::new(self.wolf_RBFoot.compute_base_matrix()), + FigureBoneData::default(), + FigureBoneData::default(), + FigureBoneData::default(), + FigureBoneData::default(), + FigureBoneData::default(), + ] + } + + fn interpolate(&mut self, target: &Self) { + self.wolf_upperhead.interpolate(&target.wolf_upperhead); + self.wolf_jaw.interpolate(&target.wolf_jaw); + self.wolf_lowerhead.interpolate(&target.wolf_lowerhead); + self.wolf_tail.interpolate(&target.wolf_tail); + self.wolf_torsoback.interpolate(&target.wolf_torsoback); + self.wolf_torsomid.interpolate(&target.wolf_torsomid); + self.wolf_ears.interpolate(&target.wolf_ears); + self.wolf_LFFoot.interpolate(&target.wolf_LFFoot); + self.wolf_RFFoot.interpolate(&target.wolf_RFFoot); + self.wolf_LBFoot.interpolate(&target.wolf_LBFoot); + self.wolf_RBFoot.interpolate(&target.wolf_RBFoot); + } +} diff --git a/voxygen/src/anim/quadrupedmedium/run.rs b/voxygen/src/anim/quadrupedmedium/run.rs new file mode 100644 index 0000000000..f9ac6c77f0 --- /dev/null +++ b/voxygen/src/anim/quadrupedmedium/run.rs @@ -0,0 +1,116 @@ +// Standard +use std::{f32::consts::PI, ops::Mul}; + +// Library +use vek::*; + +// Local +use super::{super::Animation, QuadrupedMediumSkeleton, SCALE}; + +pub struct RunAnimation; + +impl Animation for RunAnimation { + type Skeleton = QuadrupedMediumSkeleton; + type Dependency = (f32, f64); + + fn update_skeleton( + skeleton: &Self::Skeleton, + (velocity, global_time): Self::Dependency, + anim_time: f64, + ) -> Self::Skeleton { + let mut next = (*skeleton).clone(); + + let wave = (anim_time as f32 * 14.0).sin(); + let wave_ultra_slow = (anim_time as f32 * 1.0 + PI).sin(); + let wave_ultra_slow_cos = (anim_time as f32 * 1.0 + PI).cos(); + let wave_cos = (anim_time as f32 * 14.0).cos(); + let wave_slow = (anim_time as f32 * 3.5 + PI).sin(); + let wave_slow_cos = (anim_time as f32 * 3.5 + PI).cos(); + let wave_dip = (wave_slow.abs() - 0.5).abs(); + let wave_quick = (anim_time as f32 * 18.0).sin(); + let wave_med = (anim_time as f32 * 12.0).sin(); + let wave_med_cos = (anim_time as f32 * 12.0).cos(); + + let wave_quick_cos = (anim_time as f32 * 18.0).cos(); + + let wolf_look = Vec2::new( + ((global_time + anim_time) as f32 / 4.0) + .floor() + .mul(7331.0) + .sin() + * 0.25, + ((global_time + anim_time) as f32 / 4.0) + .floor() + .mul(1337.0) + .sin() + * 0.125, + ); + let wolf_tail = Vec2::new( + ((global_time + anim_time) as f32 / 2.0) + .floor() + .mul(7331.0) + .sin() + * 0.25, + ((global_time + anim_time) as f32 / 2.0) + .floor() + .mul(1337.0) + .sin() + * 0.125, + ); + + next.wolf_upperhead.offset = + Vec3::new(0.0, 9.5 + wave_quick_cos * 2.0, 15.0 + wave_med * 3.0) / 11.0; + next.wolf_upperhead.ori = + Quaternion::rotation_x(-0.12 + wave_quick_cos * 0.12 + wolf_look.y) + * Quaternion::rotation_z(wolf_look.x); + next.wolf_upperhead.scale = Vec3::one() / 10.88; + + next.wolf_jaw.offset = Vec3::new(0.0, 4.5, 2.0 + wave_slow_cos * 1.0); + next.wolf_jaw.ori = Quaternion::rotation_x(wave_slow * 0.05); + next.wolf_jaw.scale = Vec3::one() * 1.01; + + next.wolf_lowerhead.offset = Vec3::new(0.0, 3.1, -4.5 + wave_med * 1.0); + next.wolf_lowerhead.ori = Quaternion::rotation_z(0.0); + next.wolf_lowerhead.scale = Vec3::one() * 0.98; + + next.wolf_tail.offset = Vec3::new(0.0, -12.0, 10.0) / 11.0; + next.wolf_tail.ori = Quaternion::rotation_x(wave_quick * 0.18); + next.wolf_tail.scale = Vec3::one() / 11.0; + + next.wolf_torsoback.offset = + Vec3::new(0.0, -9.5 + wave_quick_cos * 2.2, 13.0 + wave_med * 2.8) / 11.0; + next.wolf_torsoback.ori = Quaternion::rotation_x(-0.15 + wave_med_cos * 0.14); + next.wolf_torsoback.scale = Vec3::one() / 11.0; + + next.wolf_torsomid.offset = + Vec3::new(0.0, 0.0 + wave_quick_cos * 2.2, 14.0 + wave_med * 3.2) / 11.0; + next.wolf_torsomid.ori = Quaternion::rotation_x(-0.15 + wave_med_cos * 0.12); + next.wolf_torsomid.scale = Vec3::one() / 10.9; + + next.wolf_ears.offset = Vec3::new(0.0, 0.75 + wave * 0.4, 6.25); + next.wolf_ears.ori = Quaternion::rotation_x(wave * 0.2); + next.wolf_ears.scale = Vec3::one() * 1.05; + + next.wolf_LFFoot.offset = + Vec3::new(-5.0, 5.0 + wave_quick * 3.0, 7.0 + wave_quick_cos * 4.0) / 11.0; + next.wolf_LFFoot.ori = Quaternion::rotation_x(0.0 + wave_quick * 0.8); + next.wolf_LFFoot.scale = Vec3::one() / 11.0; + + next.wolf_RFFoot.offset = + Vec3::new(5.0, 5.0 - wave_quick_cos * 3.0, 7.0 + wave_quick * 4.0) / 11.0; + next.wolf_RFFoot.ori = Quaternion::rotation_x(0.0 - wave_quick_cos * 0.8); + next.wolf_RFFoot.scale = Vec3::one() / 11.0; + + next.wolf_LBFoot.offset = + Vec3::new(-5.0, -10.0 - wave_quick_cos * 3.0, 7.0 + wave_quick * 4.0) / 11.0; + next.wolf_LBFoot.ori = Quaternion::rotation_x(0.0 - wave_quick_cos * 0.8); + next.wolf_LBFoot.scale = Vec3::one() / 11.0; + + next.wolf_RBFoot.offset = + Vec3::new(5.0, -10.0 + wave_quick * 3.0, 7.0 + wave_quick_cos * 4.0) / 11.0; + next.wolf_RBFoot.ori = Quaternion::rotation_x(0.0 + wave_quick * 0.8); + next.wolf_RBFoot.scale = Vec3::one() / 11.0; + + next + } +} diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index fb57e018dd..171c7b09d2 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -2,7 +2,9 @@ use crate::{ anim::{ character::{self, CharacterSkeleton}, quadruped::{self, QuadrupedSkeleton}, - Animation, Skeleton, + Animation, + QuadrupedMedium::{self, QuadrupedMediumSkeleton}, + Skeleton, }, mesh::Meshable, render::{ @@ -17,9 +19,10 @@ use common::{ self, actor::{ Belt, Chest, Draw, Foot, Hand, Head, Pants, PigChest, PigHead, PigLegL, PigLegR, - Shoulder, Weapon, + Shoulder, Weapon, WolfEars, WolfJaw, WolfLBFoot, WolfLFFoot, WolfLowerHead, WolfRBFoot, + WolfRFFoot, WolfTail, WolfTorsoBack, WolfTorsoMid, WolfUpperHead, }, - Body, HumanoidBody, QuadrupedBody, + Body, HumanoidBody, QuadrupedBody, QuadrupedMediumBody, }, figure::Segment, msg, @@ -95,6 +98,24 @@ impl FigureModelCache { None, None, ], + Body::QuadrupedMedium(body) => [ + Some(Self::load_wolf_upperhead(body.wolf_upperhead)), + Some(Self::load_wolf_jaw(body.wolf_jaw)), + Some(Self::load_wolf_lowerhead(body.wolf_lowerhead)), + Some(Self::load_wolf_tail(body.wolf_tail)), + Some(Self::load_wolf_torsoback(body.wolf_torsoback)), + Some(Self::load_wolf_torsomid(body.wolf_torsomid)), + Some(Self::load_wolf_ears(body.wolf_ears)), + Some(Self::load_wolf_lffoot(body.wolf_lffoot)), + Some(Self::load_wolf_rffoot(body.wolf_rffoot)), + Some(Self::load_wolf_lbfoot(body.wolf_lbfoot)), + Some(Self::load_wolf_rbfoot(body.wolf_rbfoot)), + None, + None, + None, + None, + None, + ], }; let mut mesh = Mesh::new(); @@ -220,9 +241,9 @@ impl FigureModelCache { fn load_weapon(weapon: Weapon) -> Mesh { Self::load_mesh( match weapon { - Weapon::Sword => "weapon/sword/sword_wood_2h.vox", + Weapon::Sword => "weapon/sword/sword_rusty_2h.vox", // TODO actually match against other weapons and set the right model - _ => "weapon/sword/sword_wood_2h.vox", + _ => "weapon/sword/sword_rusty_2h.vox", }, Vec3::new(-6.5, -1.5, -4.0), ) @@ -258,8 +279,8 @@ impl FigureModelCache { fn load_left_equip(weapon: Weapon) -> Mesh { Self::load_mesh( match weapon { - Weapon::Sword => "weapon/sword/sword_wood_2h.vox", - _ => "weapon/sword/sword_wood_2h.vox", + Weapon::Sword => "weapon/sword/sword_rusty_2h.vox", + _ => "weapon/sword/sword_rusty_2h.vox", }, Vec3::new(-6.5, -1.5, -5.0), ) @@ -272,7 +293,7 @@ impl FigureModelCache { Vec3::new(-2.0, -2.5, -2.0), ) } - + ///////// fn load_pig_head(pig_head: PigHead) -> Mesh { Self::load_mesh( match pig_head { @@ -326,12 +347,102 @@ impl FigureModelCache { Vec3::new(0.0, -1.0, -1.5), ) } + ////// + fn load_wolf_upperhead(wolf_upperhead: WolfUpperHead) -> Mesh { + Self::load_mesh( + match wolf_upperhead { + WolfUpperHead::Default => "npc/wolf/wolf_upper_head.vox", + }, + Vec3::new(-7.0, -6.0, -5.5), + ) + } + fn load_wolf_jaw(wolf_jaw: WolfJaw) -> Mesh { + Self::load_mesh( + match wolf_jaw { + WolfJaw::Default => "npc/wolf/wolf_jaw.vox", + }, + Vec3::new(-3.0, -3.0, -2.5), + ) + } + fn load_wolf_lowerhead(wolf_lowerhead: WolfLowerHead) -> Mesh { + Self::load_mesh( + match wolf_lowerhead { + WolfLowerHead::Default => "npc/wolf/wolf_lower_head.vox", + }, + Vec3::new(-7.0, -6.0, -5.5), + ) + } + fn load_wolf_tail(wolf_tail: WolfTail) -> Mesh { + Self::load_mesh( + match wolf_tail { + WolfTail::Default => "npc/wolf/wolf_tail.vox", + }, + Vec3::new(-2.0, -12.0, -5.0), + ) + } + fn load_wolf_torsoback(wolf_torsoback: WolfTorsoBack) -> Mesh { + Self::load_mesh( + match wolf_torsoback { + WolfTorsoBack::Default => "npc/wolf/wolf_torso_back.vox", + }, + Vec3::new(-7.0, -6.0, -6.0), + ) + } + fn load_wolf_torsomid(wolf_torsomid: WolfTorsoMid) -> Mesh { + Self::load_mesh( + match wolf_torsomid { + WolfTorsoMid::Default => "npc/wolf/wolf_torso_mid.vox", + }, + Vec3::new(-8.0, -5.5, -6.0), + ) + } + fn load_wolf_ears(wolf_ears: WolfEars) -> Mesh { + Self::load_mesh( + match wolf_ears { + WolfEars::Default => "npc/wolf/wolf_ears.vox", + }, + Vec3::new(-4.0, -1.0, -1.0), + ) + } + fn load_wolf_lffoot(wolf_lffoot: WolfLFFoot) -> Mesh { + Self::load_mesh( + match wolf_lffoot { + WolfLFFoot::Default => "npc/wolf/wolf_lf_foot.vox", + }, + Vec3::new(-2.5, -4.0, -2.5), + ) + } + fn load_wolf_rffoot(wolf_rffoot: WolfRFFoot) -> Mesh { + Self::load_mesh( + match wolf_rffoot { + WolfRFFoot::Default => "npc/wolf/wolf_rf_foot.vox", + }, + Vec3::new(-2.5, -4.0, -2.5), + ) + } + fn load_wolf_lbfoot(wolf_lbfoot: WolfLBFoot) -> Mesh { + Self::load_mesh( + match wolf_lbfoot { + WolfLBFoot::Default => "npc/wolf/wolf_lb_foot.vox", + }, + Vec3::new(-2.5, -4.0, -2.5), + ) + } + fn load_wolf_rbfoot(wolf_rbfoot: WolfRBFoot) -> Mesh { + Self::load_mesh( + match wolf_rbfoot { + WolfRBFoot::Default => "npc/wolf/wolf_rb_foot.vox", + }, + Vec3::new(-2.5, -4.0, -2.5), + ) + } } pub struct FigureMgr { model_cache: FigureModelCache, character_states: HashMap>, quadruped_states: HashMap>, + QuadrupedMedium_states: HashMap>, } impl FigureMgr { @@ -340,6 +451,7 @@ impl FigureMgr { model_cache: FigureModelCache::new(), character_states: HashMap::new(), quadruped_states: HashMap::new(), + QuadrupedMedium_states: HashMap::new(), } } @@ -440,6 +552,57 @@ impl FigureMgr { state.skeleton.interpolate(&target_skeleton); state.update(renderer, pos.0, dir.0, col); } + Body::QuadrupedMedium(body) => { + let state = + self.QuadrupedMedium_states + .entry(entity) + .or_insert_with(|| { + FigureState::new(renderer, QuadrupedMediumSkeleton::new()) + }); + + let target_skeleton = match animation_history.current { + comp::Animation::Run => QuadrupedMedium::RunAnimation::update_skeleton( + state.skeleton_mut(), + (vel.0.magnitude(), time), + animation_history.time, + ), + comp::Animation::Idle => { + QuadrupedMedium::IdleAnimation::update_skeleton( + state.skeleton_mut(), + time, + animation_history.time, + ) + } + comp::Animation::Jump => { + QuadrupedMedium::JumpAnimation::update_skeleton( + state.skeleton_mut(), + (vel.0.magnitude(), time), + animation_history.time, + ) + } + + // TODO! + _ => state.skeleton_mut().clone(), + }; + + state.skeleton.interpolate(&target_skeleton); + + // Change in health as color! + let col = stats + .and_then(|stats| stats.hp.last_change) + .map(|(change_by, change_time)| Rgba::new(1.0, 0.7, 0.7, 1.0)) + .unwrap_or(Rgba::broadcast(1.0)); + + // Change in health as color! + let col = stats + .and_then(|stats| stats.hp.last_change) + .map(|(change_by, change_time)| Rgba::new(1.0, 0.7, 0.7, 1.0)) + .unwrap_or(Rgba::broadcast(1.0)); + + state.update(renderer, pos.0, dir.0, col); + + state.update(renderer, pos.0, dir.0, col); + } }, // TODO: Non-character actors } @@ -450,6 +613,8 @@ impl FigureMgr { .retain(|entity, _| ecs.entities().is_alive(*entity)); self.quadruped_states .retain(|entity, _| ecs.entities().is_alive(*entity)); + self.QuadrupedMedium_states + .retain(|entity, _| ecs.entities().is_alive(*entity)); } pub fn render( @@ -483,6 +648,10 @@ impl FigureMgr { .quadruped_states .get(&entity) .map(|state| (state.locals(), state.bone_consts())), + Body::QuadrupedMedium(_) => self + .QuadrupedMedium_states + .get(&entity) + .map(|state| (state.locals(), state.bone_consts())), } { let model = self.model_cache.get_or_create_model(renderer, *body, tick);