From e2885a912db5f609dcb1185fc22451d0adcc5996 Mon Sep 17 00:00:00 2001 From: Regalis Date: Fri, 26 Aug 2016 20:52:44 +0300 Subject: [PATCH] Husk infections, manually attacking when controlling a creature --- Subsurface/Barotrauma.csproj | 10 + .../Content/Characters/Human/humanhusk.xml | 118 +++++++++++ .../Characters/Human/huskappendage.xml | 13 ++ .../Content/Characters/Husk/DivingSuit.png | Bin 15346 -> 17576 bytes Subsurface/Content/Characters/Husk/husk.xml | 2 +- Subsurface/Content/InfoTexts.xml | 11 ++ .../Source/Characters/AI/AIController.cs | 4 + Subsurface/Source/Characters/AICharacter.cs | 17 +- .../Source/Characters/Animation/Ragdoll.cs | 92 +++++---- Subsurface/Source/Characters/Attack.cs | 14 +- Subsurface/Source/Characters/Character.cs | 173 +++++++++++++--- Subsurface/Source/Characters/CharacterHUD.cs | 1 + Subsurface/Source/Characters/HuskInfection.cs | 186 ++++++++++++++++++ Subsurface/Source/Characters/Limb.cs | 5 +- .../Source/GameSession/InfoTextManager.cs | 8 +- Subsurface/Source/GameSettings.cs | 6 + Subsurface/Source/Networking/GameServer.cs | 2 +- Subsurface/Source/Networking/NetworkMember.cs | 7 +- Subsurface/Source/PlayerInput.cs | 1 + 19 files changed, 586 insertions(+), 84 deletions(-) create mode 100644 Subsurface/Content/Characters/Human/humanhusk.xml create mode 100644 Subsurface/Content/Characters/Human/huskappendage.xml create mode 100644 Subsurface/Source/Characters/HuskInfection.cs diff --git a/Subsurface/Barotrauma.csproj b/Subsurface/Barotrauma.csproj index 633791f28..bb1f7e392 100644 --- a/Subsurface/Barotrauma.csproj +++ b/Subsurface/Barotrauma.csproj @@ -93,6 +93,7 @@ + @@ -391,6 +392,14 @@ PreserveNewest + + Designer + PreserveNewest + + + Designer + PreserveNewest + PreserveNewest @@ -482,6 +491,7 @@ PreserveNewest + Designer PreserveNewest diff --git a/Subsurface/Content/Characters/Human/humanhusk.xml b/Subsurface/Content/Characters/Human/humanhusk.xml new file mode 100644 index 000000000..6e8779705 --- /dev/null +++ b/Subsurface/Content/Characters/Human/humanhusk.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Subsurface/Content/Characters/Human/huskappendage.xml b/Subsurface/Content/Characters/Human/huskappendage.xml new file mode 100644 index 000000000..4a8a23841 --- /dev/null +++ b/Subsurface/Content/Characters/Human/huskappendage.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Subsurface/Content/Characters/Husk/DivingSuit.png b/Subsurface/Content/Characters/Husk/DivingSuit.png index f95c2e62e1e7bf5bea8d36500ba65e2d26601474..076b6f7e8892677f3fdf3f491012b183175cc9f3 100644 GIT binary patch literal 17576 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 P00000NkvXXu0mjfQ+b2P literal 15346 zcma)@R!8Ii4;)LJ?O>hVv-0gDf z{sZ^JoT=(MRWo(YO!xHjn~v3ZtALF`h5-NowvwW()=Lln--ZTxdG<+I{(R}s-4qQy z005KVe;X2zolEj!q_I}iQUd^g#+R4F0pRxerQZVpFD?Msw*UZtDQu8k41ITKA|wFQ9csee6kWmanu=%s{9_ zXV0$ch{QrdV@xKhz~D+qPO_!a`$sqDR@xSlS zJt$&HRm(0_Sy@>@$05)6akxRdGPqXT{(8i^kdqH=oU8LLt&;C*f(*^+rCND$C*VFf z0FrF|APf!Z3qK5FWz$0N_^J2w8g+VsXj!)d^bAeCc3Wc>F%KWiSltW769-O#yAxBd8w_Z$u%GM(*Rj?A6Cv)ZQbr#_QsOob2rH0|C#CPkIn% z3}zOtg^@{B0=`DDvhu|xKP@D;N6>4YA!!Ff=GQ438Bs*!>&wOVKlf8OeCdz+l&EXprA`uQp+Kl-Qw}$5SPI zjC_70D(86cpyTqpM0`SyfSqCXLvG7I)A6NeoHbl?cFZ3Wn=LEI#Q%cOJ*(nCxGUfP zBt445aknbU>qI0Xu#GB)0xuqrfowxPR>q$E@Spa*Q`*|!4yNdRA8uFzH-Btq{!0_$ z^2Vr&LZyk(NFy2~vr$5(-D-4cpB;YVG%*qKhvXyHl_0m+B)I)#b6nJ5C)r1Y`5dRC ziEHp-EvN4OiQ4ZCuH|`o0y#mM%jL>r%JhHHsr#Kdf-VbJR@{Kx#POxv)WF*0lAA1h zP#$o?0EqMR^74p^#w{)`<|BEYcW4qqu%ft$9O-&SNeXfY*H3wceBU8oOZ*3IU43Sz z685Cffs{*7^WH@&<#*CcfSw0e>-?eF;%g(~+J91?<2FEbnzHk!K{UM90P~E;q5(j}~ z<=CPp3BE?c6%o&Kid5g{i;Kf+j?3CHyN?l2*Q*ult{J)39C}V=DBi;TntMmI9=>BS z&00}xQTm@^u-W}s{!k*NC=dR|aa{2q%Y;xim6v(CRDgC43ooB$4(4iaU1els_C@C( zd7Gyfc)-<;;&DyAAg&$~$UQ(jfx9E#$PV)STKW;Go|R1Vz8V_?7Y9g&cz@8n*pVxIORLXK}4@F%TC|+st!4SEeb8cB)cBuj8DnJfdk`94+{ym;a35dGEb` z;7M!nnbU2aC)UG&0?vkt;I&xTIo!5T1W(5cE_YnpSD`M*X417}Wt=Kdkt=$Sy?4r)GXl1_@v^bz8O_eho-%2uxJk}of`>u7p9;^>}SABNDrT&9J zur4YUQp4uWw_2~1AW<)27_jr}<4x!5{LCj#pXIY#XB_eWh|9+*qSD}mmtP(v;BQdf zND!0&>=8l!^jNuqr$N>q|s~h1UDY* z!hTtoAiS>opEx8?+|8mbi)SLG6#bYImSMuonC>Fi0()X@Uc5`JiIghd(gmJQMIF~Aubv;jzOl0pzU7#A@jLFRqu$HmL2T>C zTV01mD&7|cMy2$4kt{V3R|y=3HBwUeA1by)&4Ywc&}|H5;tMh#M$76Jd}hg4FL3?@ ztcn9}>@;DBZBCG0(nZNhtq+)MC=VMFS`vV3|HVTh_e;8<1thWnqah3?EV^nq4T`4} zrW;qbD48GrnLOlsTvP_L6d!y&zIKsi2t^uWFxXk|Q^=6&{=@i{Z`V_V8549MR^3ov zJ_2S>BP7{%rklbT7ug!zoH|80loUwtZhsUFxl(bx8Nz+8I3Qa^k9%ILY3=y${nx(| z5?&8J=`435L^lw4U-a+c9R2mHQ;wURAtvtM`BKxZNKC|;E}wiIdaala_a#x_%kA?P z-e2#v^QKK_R|NswP~M7b5MtG)#KAlW#d7B>Ugn=vA)7B(fYHIGma@>nn(#kOoZ2># zJ~=d;FoK;mq!<8Sr?-#eW2-V$YOv`W56^MvTfw0<7KO3V(?rEc~fA;>gl^y&|Zzpnu86q0xz>(rl4z*CWSf9}}Md zc=x^J_nV}rnVN1sQNJzRzZFTC+T$CcsOszaHw&&=?4du%dv9^qCh41)?RGTSM>i)! ztt|jyF7&kquPUS6=JTmVmh-OTfaPlhS6{j?5mRE;nEsk}J4DY?Tc$+(PiQvdFw4&t zB(6>07O5H^cS{tT2T@#@BHnT<>OGVha$opg;07Tl=s!i^WMzIw5=zu(5G|`r;k&`y z$R}l%mYJPDu)i+Fplt2t$zT5W@23m)(G@sJKB=5pzem1Byi`*ix}CfwrAXwL83Q_W z2v;8OKT%Ie82sm({-LMCW!DEz!;Bz#=F8~go0@~y-Fa~#TkH3Ns`-J3tsKp6G{a9` z-#pe+7(=cq<8r=Tl2cMpN`9cf4y3r|W|gf7QKSD}tZh@Z!!*%xf2QB*__#mo?0$9% z%H(e`fvZEg$V>q z|8mZT(*D#+lZ*JVk+R)^n-WdqOWZN3iuC8PpHyh)bQ*IsvZN%udqt4z1b6k{H;XRg zE_DG^qvb4KMaaD6b>gQrUBTd2t%(JX9*Hha;9t}Vx6|zd37XH{#2|P-9xX!* znneC>4@Pe>CLUM70ec`HMEWr|&bG)|>Obyy4lAr4?mk5V>@S37|E=RxlTpES$g1=b zB1HQ88T4w5yeu61imj!UnaivVNCUO!6hUwBth4#1CXEy(2oTJ6xZYH}--njf-)_8| zj;sT%$nxIqh(B-6*WQ=8&TmYp|8~ZLYk=Cza9-z3I^f8Wl$NZzFm4aB({(B*^9UaxP`#d z5_y8JquPg_w??-vW?PV$zr4l37oK;d(LKOD?#pt`t0Erf9dd&s60w{*FGqxz+eT4zLy#xs%A@mfk53)yl_Xc(;@+EPCoAFo+1f4^ijW7q$ ztw))IGPqQO+BZzc9p{r?|Jzz&eDTeqA3ujH7co#o%Uw21?}`tt zrPF|E%HSTfRV)c89*91BjOgD5nGu$Q5^EzVDMfW5C!a#rP=imCBmyXar?q8QzwNq* z^@``)NC7wx=M@jyxKP@%FjnnQEq&gH; z)u7|(5m69$q2dPo`+i(r(K*pzXn}z!&%|T}4tfg$XwG_MtT9*Gl@6r2BeM<=YB9id z6zqeOD!en=9>)5eoi;Yclhe&OLQ;X*xAtR6y3&wum zKjQI2F*6rhw7QxGH$2fsJg-uR=9K_6|3uexph$8FTqtp@{Ef zSjde6!Di-%ETWxPT zUh`yLPXA!WC4|8z8&+`h{W<3OUZERx zzPi$N6|y!2n6yKL9O1ce!NB8d8eOsqb=ACucJgi$Y9t_e*E2qOo}?fd59RQ^z0fhO zoET1J>7=`lA5RPks#}kt89eMB*DJCf7F5HOmg>OI)4W5BP=YXSFZ6_?{@mWgyiQ{1 ze`Tb!^QDXyUjx1L?bI$cY)%r(`Klxr^$vKagWzaARB)cPPf?E62Cf(p zDo?Yzz7Ni=eSZ!BH&zAxCLT`GRaOg_^mVOTnfghQezUWK7iVP#sp zOO+OvVME^$6QXjJ)gc$s)dS?`g~Z(3!hiUMPxE@Fc5LsgTr^tSGYwJS_sWV*<`KhZ_}h^1N5Y%B_2hM`XLJCV2Ep*6sp4m)a>o3kS!qByxl z@l9XnJE+4%q{Bo@L(sLYfhbS%WU{og+pD{Ib7bbVj0s6NuW8_J@$#9tbjcAthdR4R z9WFZlEH5y$TR@y1AqA%H^G!qzgiunis_46^QO^Xib~GW<9m{x>(887vS-}4E zm0`Y%X0phPm+#3iyGz&cWRke&+A!te-tI()-Q&`ZGZ6GRCXHcb7v%$SoQ7+Wss=#D z*)5K%>JX8iOtF!|TY$N0&^X{rh){Ssm0$pZx3b@V_Fi3mI4}8joQUc^_0ue&c`D)) zI$4#E4DLI`pFb2-od+2+KcFkO)B0b`lNpwRHND<){5N4O4b7E_ydF4ndnK!D?>pf& zxZlGI4qfObtojnnh@?HkE5tvAxEdqpE+7_iTSHG)&P224_c8I`TY2Aq@f7LuRN|-E zYmE7oXvMJJgVxwmK7?0>&D!8t(+Jg?f&}h`g-^95jg{*3>HxC-jixyB^dkNvf;oO* z>IcdwKcNj>*Ub;n!~%cX#L&IdJ`YxM5-`Jux2QwZ?bHfX53F}&ID04Zh)!~WC zeW?CrmY_Ashq(|r-t%wIU#~YT!9-KotG>uHAy1!fZm&CtiB0e6Gjl{DHRX7A&{z{9=g7v5n%hz08|uePq$Qfzr3{x0)^Yx^kO*Gx)Ancn1FU&B!t_n=o!Txl za&B+Q5LwpINhy=z=S`GCLCS@k zjOd%kPfb~h{WtUa#I0lA2XE4LZEjP+?QHqDH>vy9D4yES!8>q&iyGHOZKZ;8^e`5G zDv0wv05E|ybHMVJ0WMG)Gz_?gmz^^0T2_^omHnc}()W+j8viH+$K}DGQg*A9FRq2S z6@#xQ$w>O6_^T#eIGfW6FAZ~;enk42y|Xx8&x_x2{P? zAva%7>7&WWul|87>is5uo+1|Lhsjt*#@R<2VT%&sUc^9^c)i_@8J6oxxJ+vhmQUcm z9)RG2uj5&;_C_eENnAIm|GD`Wq`y(+EO1Hvh7YmbXlXP75ViRkqq|3umc*OgYoYzA zOm$x%73b_tmS#Udnr6sq9-k1}39!}2fG{w_5|ou+z!VHWHqD^h8ykmGT;hIjBBdZ(cV2f3v!b~|70&2*K0C&W1 z)Onon9gcCUO?K?c$b*Z$8CBWM+3_8@ZHro=(9>KnvLOQ?^0OlJ<4luj?;=#d10Je! zu-2iF>YzIDm0S3C)Gzc>9fKDCSwr3L+7+)`)zs9i{l6x7SHw*Vvu~la$&nK2ejq!p zAbCj9YKTs;sE%xTLzWBYP!T$&Nr#!g@JIR={>X1V>98&}8Cz>a+pLRd=};l z01F+qkLE0L)H=xQrSP{}rF}W|!N;@AO9W7*51yXn(_K=0kf`;b*#BHGw9pPsKqgDL z4!B#UYtR!K_&n$vr36=D{upDvmW^d-u)RtmN zl3;uTPeV2=rj3Mi6RiYLP!}MGU7tk6;4fP?PZv}_cZ5dHd-Bjs2yN(E6Z-Xd-XU9& z)7O^VYeZmS83k{_nKLptwv3k{Hsn9Z?q>L zDN39ZaZQwvY6v~SArK>M2NqalbTWSIoP8O5Wl{1^o8xB63nHlcKoU#1>+PXB+N_xY zVO8ll)J%hDq478#YZN8MX_Hzs zQy9+rby>H1gi&w4KiFP_d=JE1S6DlnKBeuQ=>ERy{I~zTxx?0z5pacm8LyT#hYME9!MY*&XuHuV__U z9K}q0D~lGrKL21?GF9FQJj6Xjg9F?@eE7-v%V+g`VMfBl+?=|ZkaI=}*?t5z9D{49 zjMs>zj?`rfPm^z&H8Nlx30Dsf?(Eiq_S_=a6!EbcO9b(02?|#x!mCX9N>$}CX>X56X zZvS@}MTOVzoUtbMnqr#JDTHXjs-06)m|!+0evY#j#R6LFV6&H6^f#8^^}CERb8Tf> zHEm^2x0X4hn_*6h3$%!qC@#?+j~Z^IE86NE!Md_)9UF2?G_ScxvMMg*YlP=4S^Hb+pf7K~eZyLj6a zojljOUN5N$DZDvN+ZaRVm{rwfHp@ljRmk?m9R~#*=bmrZw2Ifivq)nO>eRx}QnpFJ zQl6v>b6X=KKX{@3Bn3hVuM5O36x2J1CY}z}u`84sB~p;F8Q1d^9N$ysMdN!L^vg!B zO^de1Ea30HS7u?Zp)ISvMH&>^l8bHR3xz2oD=R}uY#lX7$Y&6f0bB*2h{rq!sB=F; zG}64K(72-&|3Dj9BCN0rm7D2algMsK`3{C_GX4M=W{hFb_Pr&bBh%XDp5)<*QnBV1 z6};|`)g~|x_SaPUH>sRZk2}i1f&Kwtk#4E0R73sOtKIPE7LSf+MSg6GO(9p0F$l>+ zo}fq!#W;_FrJqwt<5#n+=gGO;wzs-2Py39MB5wK}^}?uLeu82wD@C;-EQQ3#2Nm72 zbZ)|cvi&#|wIYoWS3j-hgJm_nS`}A$B7Y-$`(=5KOQX6vE}peL=(>VcR1xYfX>ztd50nm>XqC3>ObO{*@Xd3H?hrc z%fD-yrBQ>v(Nq$}S}22*kR4NDERl9i+%+v`jjuY`N5uVBA{!t|*pHc7d;eYvc22_%+Y@m_+_}{%lwT z-%lM7X-;o4=KHj)3x7JZYseg#-^#`V{!Saox(jch!mss{W<1GUf$X z@sTAk83hG-NDt$(-y)&Z@XK`xOn8iPdZrMgm^jj=MI;!3WZ~{bvL?C(2ZM8!Gr~sE z_K+Wd7aOB<-|3tjp_Zj*VdVF>p^+VEa%IV{&}=#lN&?dQ`YYH)IiV(BCX6kjR(>8_@A+57kOKgrd9)s$|BDLbZ$ zES45d2}PA+rev5(PI%>bzf=*ruL+#4UFj*6F^~?z0u$y~3Bx*~z2YycqNcbZubIlF zvBUgJ@vJ#wz_~uI;FDF+ynh$MUf@8sTJzhnRpyYtdB<(rm#+Tz4b9)L4CoI+=u}dl zIm&K=4;~6Qu0^buBjq%U#eYW$hJK@^tJSc59XhEL>S{30R#}`55WSzOd?OWevp|GhR>1b{I+Zj1w+83yE}7bMl43xm5Cr7*d^TD1`VEp&wv(-QSX+%8b0aFe427YXS?f= zK|9E-5~s&og{Yp#!p0sUu0je_K_P5?x5U-I(mCKCOc2m*hVE{}_+!)JVRpS_C||cE z(%rlBoXY6MTO;Or1&(p{U;eY97kImfMKWkdJwQz7##KTKOzMT`Th-5ZW499Ks z84I}F+;0E#yI#HyE}c?z{iqC+!*gbof$PmOReQJzz(j6cgo2;>gf+Z&Q}0|YI8P{ryyI)H~+ayb$D1D z``-jI82Ap=&mjyjt*Zs*o~FKX+PkhS)FfS@$5i7U ziShXwzt{a6!V$A{n7+z`?UQ3NBP802$1m!XEOsA_;Ohu9t#48m_$w$Q29so5ZsXdH zM@cmlNcpSVdFqwCyaHOeC_Ps0$EMXypioDG4{T=~>YYcSkEjO9w|FpEOg(+onTy*V zcQ0xQ7ZU|i9MOH21!H)eYpCB5xdWP1Kz+OAMl{ zoEuWDEt)KMyofU?4k(Or%eadC{v;00bAAToB9WDzQk4jiw=Mn;9RdLEsr<3YOuI(3 zdJBdkg}z#by=8sp*QS`i4fX~HmI>|e`r29!^8KHqsr@~flr9o@{vH*-J+>+c#b8|a zzaF~cWsy5{*dG97r5>!@4~zqfFbSLi2I(24G6B7o9|X}4ZBmqc2hyXU?{C0FL_PY!GS>cFA? zvib^?2_@HHXiiH`4Qq>qrc5l%Nd6~L>N}@rs0_{d+^NKnipFByhdxiKHhNgYax7Md z4TJtj)>kPtqHPr*v?zs7v%+e;eB6_=O z0KniRhS~C81QONAO;987D$v!);>d{Q7zM*K>B2Zo_OYqHJr`*yU6RsDqf81XMZP5^ zg^7=wzjD=~`a%rOA6xpoqK{#CEj&8r<1B1!e2QyrLIAPj8Y#wVt~c<`kZz7GcoX4n zMhfr_d8;KNC$E1UM-`_cUUtl2A|X3Og)x`3oAQM)K*GK6_jT!2f@^z1Q*t8Fj!Y!v zcjJ2U2Xx#fD0--g9XI}LB5N>4{uafkv}k00e*yjF43FjG#n++6o(%yOPS5`PzM}vg zW~YJ5WrG}L*mQl?^m;7tMZ5yZhL9hbxlFbxrN@ZaVlJkmM-)x!s((+ZJ-*BJ#Lq(7Qi>TIcSm|&CZkag~ zVyj__PY>N0yH8G|nFh~tooYvN7x|lil)L&*q1?;!U%t8ML4; z?#ACT5rF<6$(<#Gh3yMV@U(5WIT8DqWgg;jc_&s{DjyWtHMQ8pW`f7izj&1Cz#})q zZsb0y#pGucLo_}>|2)%yz99Eg8Ij7?%j8weQ<-yz&C<;_GYd?ioJ!_hL)O;i7^yj# zWq*!~EKDQE)9lgtZ-#f+Z^_}cM9bEQ9@3o)sC;B>x#>C?nBYV!j%J&#NLudb+`yfu zKXP&cBwylXMh=K_nxGtV z$*`c%qOhYPRcJ`3yCWM~oG`^g^uJieuh<3#JtGi%+bakCvGgHEX^=q!&-Rx)0?Wha z=FQ*IzrCs)*z#AS43hndp?B)2;_m--Gb;WGCnf(^e!F=9hxah5+5#YHRF5 zj7&sm3q8>uhMo&azVi<~V&i%-ZbCdFBBBg_cx0qsdopp+Z^6Wf61iK+Ax8lToWy;{ z)iC{1grV&OJ#?2C@KxCQFRzA z+>fz0x-h63Mt$`_u6EaiiwsZ24UfLEd^^>c%8d12It5m^lX?et_Tuc)k>JPMJP5v804m&u0%yCpSn*fY=D_81 zzF2^%e~ng4Whc4V_do=?{*k9q^8v9sAE^^R*RR$1T?_uNa|2d{bm0p~gkm3CXm>a_ z|48A-XydU^(F3}Dyq)2Ml`ibG0E6u6%Muou`j|$nX()rZhc&8tLXG(b5t(MTH5;eD zhc`<;53=lUo482e(?oDxo_uM$Q=!4oOLvOAtcosTwCvKBz2=xw0Gz(x&_oPi*~CUw zXt0QR?_>QH^|JwFi(`$!^l|x`Xm}BfR%Pd@=Sx6ZDGO8W{VAOa)88@o(a~aM@?vGw zS-#q)>8~be-1k_JwKN^eJK{^(YUV~ic~s+2N)saosS`8`3B07x%H&d;ND>~|+}|so z96ir@d_yy9bT;s$M_?Z36k>UL78pyi;~R2pWS3z!NORwmyhq=Re63_&VL-3f)GfgP zSM820=36Pq{fUWNC==T9-J5~vDH}Qi%6MnzldE+ppJ|S>88BqRABVLfRoP%*ZU=p` zdJnEam?E|o*<1zN;QhI zbC_xlVME1){Fkr8C{UeaF47!%8Z@Jk$nC)?5G>nv?i*Lt+B;X!n`c=KCO z0d9nRcCYt;3`QUc@PAT3FL1aN#cPPOQ?k~ja?kKx3^|qmEBgv_io+Dabd|mgJ7~RG}*t5 zcIfbhOtDy7QZL6Z(6DpMxoB|u)ek73v)wI(iluNmnxFU#vGS=*0FpE-7It%T|NRsl zGOH{@v(`J>xH89@f%S7SNWJMqy-5*#Hj{M6ifeWTwVH5PR@TkN=2l)EnPt}Tz;6*9 zH9CocTwD1`dklj~x>AQQ{(>7bR*TC>VNV}(C+u@t3r=2f#3VXd0v4;%8jR+6U5SPh z`;H9zf)&L1XOwglL8MF%~4dM7A1GeX?;sLfbV;-vflK zLkrm?>nO1vtE$Q;K#}bw4YKfcDBS7Uc(+{%?Z% zv4!kQei_AQm~yTXGwd$~Fpf2T^H6;KV^r{Ql0jm1xbcTPy-d|?gmNk~(JRK?>KY{~ zV7?GH(^6=-b78uWU4?KEZkowfnhw{%K#rK2b*^{mgOn=qq?hh>d;l?*YE9(~Ab%=M zmAcL+fVlk_AjUQeT#pRtybsG$@cy@8_HXHXQ>XoP?eA-|<{hsI5+!`|cI%<9QwijH zGF-{*PMu5<&vjfz$0llHe`9v^x91Dj*}A{*T%8hZ@=8x%GJqqnHvfJniaOEMm{yon z8oYx=_<$^dL9(<4_w)sYYC6@UVWXg3auPWIU(S2uguKU^!2v`1d+jp*(m4$!8<|Axk({DSHoCS~#A1SL+ zcC2O^8>6TZDm3XY{twFHkyTn7pCfWN4hx5IvIF(pqj$`go89|dFRriED-y7vbiR}k zN~jc;#&${5U|I*_iFE%TmX!{$OIl1ck6b@Wl(~ zJ08J*bhe;CiXh+_eeJnINiOL=-SHWFt#`S7HJNzeURBdUo2Y&ek%cdp(npA*YFNlT za&6XOe{G!65$B_j>%mnfRji9W361uwHcsnYlAJZPIGjdjHr8dUUn%etpbq@cs?lTh z5%+Q4>)<8$c=1%FVMuFsd<&*_0>*E-o@pQ-q;L`8dEsf5daqvNl$U%2J7z4O+;Rqf z@4OLDq7uDDn&>cAZqrh_V`SNq^gQ2?J9t8Z9W6A3gHMpIaBL0XriIS>bU$=k-hxKZ zPIG>@x^}Nm7Rg}R8>SE@>DR0dMrDaR7Ef_tiA7Vsp+6Eqq9fGfWW1Q~Z zLkEmoU23XMmR)?hwMO)J&9iMo5Ai1M`IKaG(!G+UY1H^_(rjfIxBrn!f2h^i7bb_d z{))KM zyKv8awH7HaiPWfW)8*lO&;yv;Oivq453&P%YCkPUj?>~7A7vJ$mg4NIMmWf{9XprR zCXW>5@8gN#^aZRkt_iE}bZyoK5PKH8zH7-Qp(Hy*SCap{cniC#X78$0a)0QedyDUm z1!IN8b`SXdhmPh1)r4v!!UZ{`|FW{`!xkv2oAi-h_;N(R#!c3L4xSues=00R#Ffx6 zRu09r7+>lnqPz6yDNq}fnu_g}%KS@yM}8jc_Ka(M_pH(tWB(L!9{6a}JwSM2rU{S8t@91er$Er@vjxy}x)}_nao~iUm{go1QgoMyjf_ zyVo!wNy@h&1GkOZru?f02r5w#GAs1Oe<)sFA38TZ_#cSaoQg{a5h}S`}7?h@O zORR^U{=IGyK@p8WAb@yI`9mTj^_ojv~`E2$N^TrA3+MOW^x2-(SMK z-0ca6aUl3ZjRakBiujoWnq7Ko{a`V(vPS(E5*Oved*Q*MdFFH*`mmWx&6~-E$Pyj*aZon$$dfh_xnie%;&aD9zHt@l<*oy;=HVw-RrtCYE zVj~5dbi8);J-Hmc(JgEK56I=7LbDpAWsC`8H;}^#d%M=z?R>a!Iy4~&f+qelp5~LP zB)DiHv*Zd(oebOG%N{NIC@|Ok=>mAkMI$uSKcM~7nG)0|bhDluo~EJP6f4z1O4r60 zQKE?$PH34hcE6uepzbzTx&^>RvraGam-LV1odYyNM#reoBB}WJ#KOgS)I5e{tstzO zb;b{k9iOL03h_~{;Q07seCYJQX25eIo|xh6Qx1GugnkV+X-|t2fwg@I{Ro{Gb&r*V z_yac(ncWH1a11L=p&ip=aQt9bLRy~6a+x(mC3^FNctb_0OoBNgmuFN}S;n4JCzVc# zcb7qK+M)OY_5-%$&>QeiRW<*1^wt4r_U;og6BR+$_mmo!|3t}ZU*3$QN^4=`OQKXo zjanddA^Q3?({sVLi|Eu5)Lq z;F|{GcQ@0uroXQhdvO@O{;s10z!ays2~vz$rBc^&KS4JxK-ZEF1LsqKPE|?~A7o3| z;wh$&G!3IKGfUGTx|liT3P~yB2@1Exrr{iGPt%ER)H}FOCk#ORA|_)Mv%x5Jgn&8n zk>$9@Dua|2bX3Cy@kxZF!TLP-bW+ zZc&O4z=jAp#wFxz1Xb({amCR?jlkleu6f^ z$BHCs>h6&3hCG>_G>k1syhaGqC-(D56!36u*q&QXW4IOEH7Q*uDA~gz~{k}7NU&+-+#N86X%RZ z&lKa0)G0&%@(OyAdk$c^;0?nyX1?cMYiLOyXbcr(=7wo(Y!%5w`@T%Y8nPx%4%N&k z^TLA3D$Wo-J_ac^L7KIgN6w1U6})lCV3voW@^iUHyPhC>&bPY}Iu;en7t05v|Bqqk@8vTtpsnt{mWh8f^ir=2D9OE*t(CS2`ybL>u>}AC diff --git a/Subsurface/Content/Characters/Husk/husk.xml b/Subsurface/Content/Characters/Husk/husk.xml index 043704787..e3cbf0e71 100644 --- a/Subsurface/Content/Characters/Husk/husk.xml +++ b/Subsurface/Content/Characters/Husk/husk.xml @@ -23,7 +23,7 @@ - + diff --git a/Subsurface/Content/InfoTexts.xml b/Subsurface/Content/InfoTexts.xml index 9e8e83c1a..f854b81e5 100644 --- a/Subsurface/Content/InfoTexts.xml +++ b/Subsurface/Content/InfoTexts.xml @@ -21,4 +21,15 @@ You have burned to death. You have been disconnected from the server. + Your throat feels sore + Your feel feverish + It feels as if something was stuck in your throat + Your muscles are aching + + You feel something moving in your throat. You try to scream but no sound comes out. + + + A strange chitinous appendage bursts out from your mouth. Use it to inject eggs into a living body by pressing [Attack]! + + \ No newline at end of file diff --git a/Subsurface/Source/Characters/AI/AIController.cs b/Subsurface/Source/Characters/AI/AIController.cs index 8e6cfd932..165579fff 100644 --- a/Subsurface/Source/Characters/AI/AIController.cs +++ b/Subsurface/Source/Characters/AI/AIController.cs @@ -10,6 +10,8 @@ namespace Barotrauma public enum AiState { None, Attack, GoTo, Escape } public enum SteeringState { Wander, Seek, Escape } + public bool Enabled; + public readonly Character Character; protected AiState state; @@ -51,6 +53,8 @@ namespace Barotrauma public AIController (Character c) { Character = c; + + Enabled = true; } public virtual void DebugDraw(SpriteBatch spriteBatch) { } diff --git a/Subsurface/Source/Characters/AICharacter.cs b/Subsurface/Source/Characters/AICharacter.cs index 4e9ecb0bb..1997289d1 100644 --- a/Subsurface/Source/Characters/AICharacter.cs +++ b/Subsurface/Source/Characters/AICharacter.cs @@ -49,7 +49,7 @@ namespace Barotrauma if (isDead || health <= 0.0f) return; - if (Controlled == this) return; + if (Controlled == this || !aiController.Enabled) return; if (soundTimer > 0) { @@ -117,6 +117,12 @@ namespace Barotrauma aiController.FillNetworkData(message); return true; case NetworkEventType.EntityUpdate: + message.Write(Controlled == this); + + if (Controlled == this) + { + return base.FillNetworkData(type, message, data); + } message.Write(AnimController.Dir > 0.0f); message.WriteRangedSingle(MathHelper.Clamp(AnimController.TargetMovement.X, -1.0f, 1.0f), -1.0f, 1.0f, 4); @@ -215,6 +221,15 @@ namespace Barotrauma case NetworkEventType.EntityUpdate: if (sendingTime <= LastNetworkUpdate) return false; + bool playerControlled = message.ReadBoolean(); + if (playerControlled) + { + aiController.Enabled = false; + return base.ReadNetworkData(type, message, sendingTime, out data); + } + + aiController.Enabled = true; + Vector2 targetMovement = Vector2.Zero, pos = Vector2.Zero; bool targetDir = false,inSub = false; diff --git a/Subsurface/Source/Characters/Animation/Ragdoll.cs b/Subsurface/Source/Characters/Animation/Ragdoll.cs index 938838203..9420c33de 100644 --- a/Subsurface/Source/Characters/Animation/Ragdoll.cs +++ b/Subsurface/Source/Characters/Animation/Ragdoll.cs @@ -30,8 +30,8 @@ namespace Barotrauma protected float strongestImpact; - float headPosition, headAngle; - float torsoPosition, torsoAngle; + public float headPosition, headAngle; + public float torsoPosition, torsoAngle; protected double onFloorTimer; @@ -231,8 +231,7 @@ namespace Barotrauma byte ID = Convert.ToByte(subElement.Attribute("id").Value); Limb limb = new Limb(character, subElement, scale); - - + limb.body.FarseerBody.OnCollision += OnLimbCollision; Limbs[ID] = limb; @@ -240,38 +239,7 @@ namespace Barotrauma if (!limbDictionary.ContainsKey(limb.type)) limbDictionary.Add(limb.type, limb); break; case "joint": - Byte limb1ID = Convert.ToByte(subElement.Attribute("limb1").Value); - Byte limb2ID = Convert.ToByte(subElement.Attribute("limb2").Value); - - Vector2 limb1Pos = ToolBox.GetAttributeVector2(subElement, "limb1anchor", Vector2.Zero) * scale; - limb1Pos = ConvertUnits.ToSimUnits(limb1Pos); - - Vector2 limb2Pos = ToolBox.GetAttributeVector2(subElement, "limb2anchor", Vector2.Zero) * scale; - limb2Pos = ConvertUnits.ToSimUnits(limb2Pos); - - RevoluteJoint joint = new RevoluteJoint(Limbs[limb1ID].body.FarseerBody, Limbs[limb2ID].body.FarseerBody, limb1Pos, limb2Pos); - - joint.CollideConnected = false; - - if (subElement.Attribute("lowerlimit")!=null) - { - joint.LimitEnabled = true; - joint.LowerLimit = float.Parse(subElement.Attribute("lowerlimit").Value) * ((float)Math.PI / 180.0f); - joint.UpperLimit = float.Parse(subElement.Attribute("upperlimit").Value) * ((float)Math.PI / 180.0f); - } - - joint.MotorEnabled = true; - joint.MaxMotorTorque = 0.25f; - - GameMain.World.AddJoint(joint); - - for (int i = 0; i < limbJoints.Length; i++ ) - { - if (limbJoints[i] != null) continue; - - limbJoints[i] = joint; - break; - } + AddJoint(subElement, scale); break; } @@ -308,6 +276,58 @@ namespace Barotrauma FindLowestLimb(); } + + public void AddJoint(XElement subElement, float scale = 1.0f) + { + byte limb1ID = Convert.ToByte(subElement.Attribute("limb1").Value); + byte limb2ID = Convert.ToByte(subElement.Attribute("limb2").Value); + + Vector2 limb1Pos = ToolBox.GetAttributeVector2(subElement, "limb1anchor", Vector2.Zero) * scale; + limb1Pos = ConvertUnits.ToSimUnits(limb1Pos); + + Vector2 limb2Pos = ToolBox.GetAttributeVector2(subElement, "limb2anchor", Vector2.Zero) * scale; + limb2Pos = ConvertUnits.ToSimUnits(limb2Pos); + + RevoluteJoint joint = new RevoluteJoint(Limbs[limb1ID].body.FarseerBody, Limbs[limb2ID].body.FarseerBody, limb1Pos, limb2Pos); + + joint.CollideConnected = false; + + if (subElement.Attribute("lowerlimit") != null) + { + joint.LimitEnabled = true; + joint.LowerLimit = float.Parse(subElement.Attribute("lowerlimit").Value) * ((float)Math.PI / 180.0f); + joint.UpperLimit = float.Parse(subElement.Attribute("upperlimit").Value) * ((float)Math.PI / 180.0f); + } + + joint.MotorEnabled = true; + joint.MaxMotorTorque = 0.25f; + + GameMain.World.AddJoint(joint); + + for (int i = 0; i < limbJoints.Length; i++) + { + if (limbJoints[i] != null) continue; + + limbJoints[i] = joint; + return; + } + + Array.Resize(ref limbJoints, limbJoints.Length + 1); + limbJoints[limbJoints.Length - 1] = joint; + + } + + public void AddLimb(Limb limb) + { + limb.body.FarseerBody.OnCollision += OnLimbCollision; + + Array.Resize(ref Limbs, Limbs.Length + 1); + + Limbs[Limbs.Length-1] = limb; + + Mass += limb.Mass; + if (!limbDictionary.ContainsKey(limb.type)) limbDictionary.Add(limb.type, limb); + } public bool OnLimbCollision(Fixture f1, Fixture f2, Contact contact) { diff --git a/Subsurface/Source/Characters/Attack.cs b/Subsurface/Source/Characters/Attack.cs index df02b6d1e..226c91c8e 100644 --- a/Subsurface/Source/Characters/Attack.cs +++ b/Subsurface/Source/Characters/Attack.cs @@ -136,22 +136,24 @@ namespace Barotrauma { sound.Play(1.0f, 500.0f, worldPosition); } + + var attackResult = target.AddDamage(attacker, worldPosition, this, deltaTime, playSound); + + var effectType = attackResult.Damage > 0.0f ? ActionType.OnUse : ActionType.OnFailure; foreach (StatusEffect effect in statusEffects) { if (effect.Targets.HasFlag(StatusEffect.TargetType.This) && attacker is Character) { - effect.Apply(ActionType.OnUse, deltaTime, (Character)attacker, (Character)attacker); + effect.Apply(effectType, deltaTime, (Character)attacker, (Character)attacker); } if (effect.Targets.HasFlag(StatusEffect.TargetType.Character) && target is Character) { - effect.Apply(ActionType.OnUse, deltaTime, (Character)target, (Character)target); - } + effect.Apply(effectType, deltaTime, (Character)target, (Character)target); + } } - - - return target.AddDamage(attacker, worldPosition, this, deltaTime, playSound); + return attackResult; } } } diff --git a/Subsurface/Source/Characters/Character.cs b/Subsurface/Source/Characters/Character.cs index fc748ec24..3cffae273 100644 --- a/Subsurface/Source/Characters/Character.cs +++ b/Subsurface/Source/Characters/Character.cs @@ -112,6 +112,8 @@ namespace Barotrauma //which AIstate each sound is for private AIController.AiState[] soundStates; + private float attackCoolDown; + public Entity ViewTarget { get; @@ -248,6 +250,7 @@ namespace Barotrauma public bool NeedsAir { get { return needsAir; } + set { needsAir = value; } } public float Oxygen @@ -298,6 +301,38 @@ namespace Barotrauma } } + public HuskInfection huskInfection; + public float HuskInfectionState + { + get + { + return huskInfection == null ? 0.0f : huskInfection.IncubationTimer; + } + set + { + if (ConfigPath != humanConfigFile) return; + + if (value <= 0.0f) + { + if (huskInfection != null && huskInfection.State == HuskInfection.InfectionState.Active) return; + huskInfection = null; + } + else + { + if (huskInfection == null) huskInfection = new HuskInfection(this); + huskInfection.IncubationTimer = MathHelper.Clamp(value, 0.0f, 1.0f); + } + } + } + + public bool CanSpeak + { + get + { + return !IsUnconscious && Stun <= 0.0f && (huskInfection == null || huskInfection.CanSpeak); + } + } + public bool DoesBleed { get; @@ -310,7 +345,6 @@ namespace Barotrauma private set; } - public float PressureTimer { get; @@ -474,13 +508,17 @@ namespace Barotrauma Properties = ObjectProperty.GetProperties(this); - if (file == humanConfigFile) + if (file == humanConfigFile && characterInfo == null) { - Info = characterInfo == null ? new CharacterInfo(file) : characterInfo; + Info = new CharacterInfo(file); } + Info = characterInfo; + XDocument doc = ToolBox.TryLoadXml(file); if (doc == null || doc.Root == null) return; + + SpeciesName = ToolBox.GetAttributeString(doc.Root, "name", "Unknown"); @@ -696,6 +734,49 @@ namespace Barotrauma } } + if (attackCoolDown >0.0f) + { + attackCoolDown -= deltaTime; + } + else if (IsKeyDown(InputType.Attack)) + { + var attackLimb = AnimController.Limbs.FirstOrDefault(l => l.attack != null); + + if (attackLimb != null) + { + Vector2 attackPos = + attackLimb.SimPosition + Vector2.Normalize(cursorPosition - attackLimb.Position) * ConvertUnits.ToSimUnits(attackLimb.attack.Range); + + var body = Submarine.PickBody( + attackLimb.SimPosition, + attackPos, + AnimController.Limbs.Select(l => l.body.FarseerBody).ToList(), + Physics.CollisionCharacter | Physics.CollisionWall); + + IDamageable attackTarget = null; + if (body != null) + { + if (body.UserData is IDamageable) + { + attackTarget = (IDamageable)body.UserData; + } + else if (body.UserData is Limb) + { + attackTarget = ((Limb)body.UserData).character; + } + attackPos = Submarine.LastPickedPosition; + } + + attackLimb.UpdateAttack(deltaTime, attackPos, attackTarget); + + if (attackLimb.AttackTimer > attackLimb.attack.Duration) + { + attackLimb.AttackTimer = 0.0f; + attackCoolDown = 1.0f; + } + } + } + for (int i = 0; i < selectedItems.Length; i++ ) { if (selectedItems[i] == null) continue; @@ -859,7 +940,7 @@ namespace Barotrauma foreach (Limb limb in selectedCharacter.AnimController.Limbs) { - limb.pullJoint.Enabled = false; + if (limb.pullJoint != null) limb.pullJoint.Enabled = false; } selectedCharacter = null; @@ -923,7 +1004,6 @@ namespace Barotrauma } } - if (!LockHands) { //find the closest item if selectkey has been hit, or if the Character is being @@ -1014,9 +1094,9 @@ namespace Barotrauma // new Character(NewCharacterQueue.Dequeue(), Vector2.Zero); //} - foreach (Character c in CharacterList) + for (int i = 0; i 0.0f) - //{ - // message.Write(Math.Max((byte)((health / maxHealth) * 255.0f), (byte)1)); - //} - //else - //{ - // message.Write((byte)0); - // message.WriteRangedInteger(0, Enum.GetValues(typeof(CauseOfDeath)).Length-1, (int)lastAttackCauseOfDeath); - //} - if (AnimController.StunTimer <= 0.0f && bleeding <= 0.0f && oxygen > 99.0f) { message.Write(true); @@ -1519,6 +1603,12 @@ namespace Barotrauma bleeding = MathHelper.Clamp(bleeding, 0.0f, 5.0f); message.WriteRangedSingle(bleeding, 0.0f, 5.0f, 8); + + message.Write(huskInfection != null); + if (huskInfection!=null) + { + message.WriteRangedSingle(HuskInfectionState, 0.0f, 1.0f, 4); + } } return true; @@ -1536,8 +1626,15 @@ namespace Barotrauma message.Write(keys[(int)InputType.Run].Held); - message.Write(((HumanoidAnimController)AnimController).Crouching); + if (AnimController.Limbs.Any(l => l.attack != null)) + { + message.Write(keys[(int)InputType.Attack].Held); + } + if (AnimController is HumanoidAnimController) + { + message.Write(((HumanoidAnimController)AnimController).Crouching); + } if (secondaryHeld) { @@ -1587,7 +1684,6 @@ namespace Barotrauma public override bool ReadNetworkData(NetworkEventType type, NetIncomingMessage message, float sendingTime, out object data) { - Enabled = true; data = null; if (GameMain.Server != null && type != NetworkEventType.InventoryUpdate) @@ -1729,13 +1825,20 @@ namespace Barotrauma Oxygen = message.ReadRangedSingle(-100.0f,100.0f, 8); Bleeding = message.ReadRangedSingle(0.0f, 5.0f, 8); + if (message.ReadBoolean()) + { + HuskInfectionState = message.ReadRangedSingle(0.0f, 1.0f, 4); + } + break; case NetworkEventType.EntityUpdate: + Enabled = true; + Vector2 relativeCursorPos = Vector2.Zero; bool actionKeyState, secondaryKeyState; bool leftKeyState, rightKeyState, upKeyState, downKeyState; - bool runState, crouchState; + bool runState, crouchState = false, attackState = false; try { @@ -1750,7 +1853,16 @@ namespace Barotrauma downKeyState = message.ReadBoolean(); runState = message.ReadBoolean(); - crouchState = message.ReadBoolean(); + + if (AnimController.Limbs.Any(l => l.attack != null)) + { + attackState = message.ReadBoolean(); + } + + if (AnimController is HumanoidAnimController) + { + crouchState = message.ReadBoolean(); + } } catch (Exception e) @@ -1769,6 +1881,9 @@ namespace Barotrauma keys[(int)InputType.Aim].Held = secondaryKeyState; keys[(int)InputType.Aim].SetState(false, secondaryKeyState); + keys[(int)InputType.Attack].Held = attackState; + keys[(int)InputType.Attack].SetState(false, attackState); + if (sendingTime <= LastNetworkUpdate) return false; keys[(int)InputType.Left].Held = leftKeyState; diff --git a/Subsurface/Source/Characters/CharacterHUD.cs b/Subsurface/Source/Characters/CharacterHUD.cs index b4ae4ed91..2f8eb43c2 100644 --- a/Subsurface/Source/Characters/CharacterHUD.cs +++ b/Subsurface/Source/Characters/CharacterHUD.cs @@ -197,6 +197,7 @@ namespace Barotrauma if (Character.Controlled != null) { Character.Controlled.Kill(Character.Controlled.CauseOfDeath); + Character.Controlled = null; } return true; }; diff --git a/Subsurface/Source/Characters/HuskInfection.cs b/Subsurface/Source/Characters/HuskInfection.cs new file mode 100644 index 000000000..b370efaad --- /dev/null +++ b/Subsurface/Source/Characters/HuskInfection.cs @@ -0,0 +1,186 @@ +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Barotrauma +{ + class HuskInfection + { + public enum InfectionState + { + Dormant, Transition, Active + } + + const float IncubationDuration = 300.0f; + + private InfectionState state; + + private float incubationTimer; + public float IncubationTimer + { + get { return incubationTimer; } + set + { + incubationTimer = MathHelper.Clamp(value, 0.0f, 1.0f); + } + } + + public InfectionState State + { + get { return state; } + } + + public bool CanSpeak + { + get { return IncubationTimer < 0.5f; } + } + + public HuskInfection(Character character) + { + character.OnDeath += CharacterDead; + } + + public void Update(float deltaTime, Character character) + { + if (IncubationTimer < 0.5f) + { + UpdateDormantState(deltaTime, character); + } + else if (IncubationTimer < 1.0f) + { + UpdateTransitionState(deltaTime, character); + } + else + { + UpdateActiveState(deltaTime, character); + } + } + + private void UpdateDormantState(float deltaTime, Character character) + { + float prevTimer = IncubationTimer; + + state = InfectionState.Dormant; + + IncubationTimer += 100* deltaTime / IncubationDuration; + + if (Character.Controlled != character) return; + + if (prevTimer % 0.1f > 0.05f && IncubationTimer % 0.1f < 0.05f) + { + GUI.AddMessage(InfoTextManager.GetInfoText("HuskDormant"), Color.Red, 4.0f); + } + } + + private void UpdateTransitionState(float deltaTime, Character character) + { + IncubationTimer += deltaTime*10.0f/ IncubationDuration; + + if (state == InfectionState.Dormant && Character.Controlled == character) + { + new GUIMessageBox("", InfoTextManager.GetInfoText("HuskCantSpeak")); + } + + state = InfectionState.Transition; + } + + private void UpdateActiveState(float deltaTime, Character character) + { + if (state != InfectionState.Active) + { + if (Character.Controlled==character) new GUIMessageBox("", InfoTextManager.GetInfoText("HuskActivate")); + ActivateHusk(character); + state = InfectionState.Active; + } + + character.AddDamage(CauseOfDeath.Damage, 0.5f*deltaTime, null); + + if (character.AnimController.limbJoints[0].LimitEnabled && + (character.AnimController.CurrentHull == null || + character.AnimController.CurrentHull.LethalPressure > 50.0f)) + { + character.BreakJoints(); + character.AnimController.limbJoints.Last().LimitEnabled = true; + } + } + + + private void ActivateHusk(Character character) + { + character.NeedsAir = false; + AttachHuskAppendage(character); + } + + private void AttachHuskAppendage(Character character) + { + XDocument doc = ToolBox.TryLoadXml(Path.Combine("Content", "Characters", "Human", "huskappendage.xml")); + if (doc == null || doc.Root == null) return; + + var limbElement = doc.Root.Element("limb"); + if (limbElement == null) + { + DebugConsole.ThrowError("Error in huskappendage.xml - limb element not found"); + return; + } + + var jointElement = doc.Root.Element("joint"); + if (jointElement == null) + { + DebugConsole.ThrowError("Error in huskappendage.xml - joint element not found"); + return; + } + + character.StartStun(0.5f); + if (character.AnimController.Dir < 1.0f) + { + character.AnimController.Flip(); + } + + var torso = character.AnimController.GetLimb(LimbType.Torso); + torso.body.SetTransform(torso.SimPosition, 0.0f); + + var newLimb = new Limb(character, limbElement); + newLimb.body.Submarine = character.Submarine; + newLimb.body.SetTransform(torso.SimPosition, 0.0f); + + character.AnimController.AddLimb(newLimb); + character.AnimController.AddJoint(jointElement); + } + + private void CharacterDead(Character character, CauseOfDeath causeOfDeath) + { + var husk = Character.Create( + Path.Combine("Content", "Characters", "Human", "humanhusk.xml"), + character.WorldPosition, + character.Info, + false, true); + + foreach (Limb limb in husk.AnimController.Limbs) + { + if (limb.type == LimbType.None) + { + limb.body.SetTransform(character.SimPosition, 0.0f); + continue; + } + + var matchingLimb = character.AnimController.GetLimb(limb.type); + limb.body.SetTransform(matchingLimb.SimPosition, matchingLimb.Rotation); + } + + for (int i = 0; i < character.Inventory.Items.Length; i++) + { + if (character.Inventory.Items[i] == null) continue; + husk.Inventory.TryPutItem(character.Inventory.Items[i], i, false, true); + } + + character.Enabled = false; + + husk.SpawnedMidRound = true; + } + } +} diff --git a/Subsurface/Source/Characters/Limb.cs b/Subsurface/Source/Characters/Limb.cs index 4ebd2a76e..242846285 100644 --- a/Subsurface/Source/Characters/Limb.cs +++ b/Subsurface/Source/Characters/Limb.cs @@ -499,12 +499,10 @@ namespace Barotrauma float dist = ConvertUnits.ToDisplayUnits(Vector2.Distance(SimPosition, attackPosition)); AttackTimer += deltaTime; + body.ApplyTorque(Mass * character.AnimController.Dir * attack.Torque); if (dist < attack.Range * 0.5f) { - AttackTimer += deltaTime; - body.ApplyTorque(Mass * character.AnimController.Dir * attack.Torque); - if (AttackTimer >= attack.Duration && damageTarget != null) { attack.DoDamage(character, damageTarget, WorldPosition, 1.0f, (soundTimer <= 0.0f)); @@ -520,7 +518,6 @@ namespace Barotrauma body.ApplyLinearImpulse(Mass * attack.Force * Vector2.Normalize(attackPosition - SimPosition), pos); } - } public void Draw(SpriteBatch spriteBatch) diff --git a/Subsurface/Source/GameSession/InfoTextManager.cs b/Subsurface/Source/GameSession/InfoTextManager.cs index 78bca7b25..cd3a1167c 100644 --- a/Subsurface/Source/GameSession/InfoTextManager.cs +++ b/Subsurface/Source/GameSession/InfoTextManager.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml.Linq; @@ -51,6 +52,11 @@ namespace Barotrauma string text = infoList[Rand.Int(infoList.Count)]; + foreach (InputType inputType in Enum.GetValues(typeof(InputType))) + { + text = text.Replace("[" + inputType.ToString() + "]", GameMain.Config.KeyBind(inputType).ToString()); + } + if (Submarine.MainSub != null) text = text.Replace("[sub]", Submarine.MainSub.Name); if (GameMain.GameSession != null && GameMain.GameSession.Map != null) { diff --git a/Subsurface/Source/GameSettings.cs b/Subsurface/Source/GameSettings.cs index b965a7e8e..0316a206d 100644 --- a/Subsurface/Source/GameSettings.cs +++ b/Subsurface/Source/GameSettings.cs @@ -383,6 +383,12 @@ namespace Barotrauma { new GUITextBlock(new Rectangle(x, y, 100, 20), inputNames[i]+": ", GUI.Style, settingsFrame); var keyBox = new GUITextBox(new Rectangle(x + 100, y, 120, 15), GUI.Style, settingsFrame); + + if (keyMapping[i]==null) + { + keyMapping[i] = new KeyOrMouse(Keys.D1); + } + keyBox.Text = keyMapping[i].ToString(); keyBox.UserData = i; keyBox.OnSelected += KeyBoxSelected; diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs index 873cf8d62..fc705291f 100644 --- a/Subsurface/Source/Networking/GameServer.cs +++ b/Subsurface/Source/Networking/GameServer.cs @@ -1623,7 +1623,7 @@ namespace Barotrauma.Networking public void SendCharacterSpawnMessage(Character character, List recipients = null) { - if (recipients == null || !recipients.Any()) return; + if (recipients != null && !recipients.Any()) return; NetOutgoingMessage message = server.CreateMessage(); message.Write((byte)PacketTypes.NewCharacter); diff --git a/Subsurface/Source/Networking/NetworkMember.cs b/Subsurface/Source/Networking/NetworkMember.cs index 9b6ac1dad..55cb4ff48 100644 --- a/Subsurface/Source/Networking/NetworkMember.cs +++ b/Subsurface/Source/Networking/NetworkMember.cs @@ -340,15 +340,12 @@ namespace Barotrauma.Networking { if (gameStarted && Screen.Selected == GameMain.GameScreen) { - chatMsgBox.Visible = Character.Controlled == null || - (!Character.Controlled.IsUnconscious && Character.Controlled.Stun <= 0.0f); + chatMsgBox.Visible = Character.Controlled == null || Character.Controlled.CanSpeak; inGameHUD.Update(deltaTime); GameMain.GameSession.CrewManager.Update(deltaTime); - - //if (crewFrameOpen) crewFrame.Update(deltaTime); - + if (Character.Controlled == null || Character.Controlled.IsDead) { GameMain.GameScreen.Cam.TargetPos = Vector2.Zero; diff --git a/Subsurface/Source/PlayerInput.cs b/Subsurface/Source/PlayerInput.cs index 8ce5e59c0..99d54c936 100644 --- a/Subsurface/Source/PlayerInput.cs +++ b/Subsurface/Source/PlayerInput.cs @@ -10,6 +10,7 @@ namespace Barotrauma Use, Aim, Up, Down, Left, Right, + Attack, Run, Crouch, Chat, CrewOrders }