From 95c8e0f48630763332b97115570bb432301bf9fe Mon Sep 17 00:00:00 2001 From: Regalis Date: Sat, 6 Jun 2015 14:38:25 +0300 Subject: [PATCH] Md5 hashes for maps, enemy AI changes HumanoidAnimController bugfixes, HitArmor sounds --- Subsurface/Characters/AI/EnemyAIController.cs | 27 +-- .../Characters/{LimbAttack.cs => Attack.cs} | 31 ++- Subsurface/Characters/Character.cs | 4 +- .../Characters/HumanoidAnimController.cs | 4 +- Subsurface/Characters/Limb.cs | 16 +- Subsurface/Characters/Ragdoll.cs | 2 +- .../Content/Characters/Crawler/crawler.xml | 8 +- .../Content/Sounds/Damage/HitArmor1.ogg | Bin 0 -> 9615 bytes .../Content/Sounds/Damage/HitArmor2.ogg | Bin 0 -> 8978 bytes .../Content/Sounds/Damage/HitArmor3.ogg | Bin 0 -> 7822 bytes Subsurface/Content/Sounds/sounds.xml | 4 + Subsurface/DebugConsole.cs | 4 +- Subsurface/Game1.cs | 2 + Subsurface/GameSession/GameSession.cs | 2 +- Subsurface/Items/Components/Container.cs | 2 + Subsurface/Items/Components/Projectile.cs | 31 +-- .../Items/Components/Signal/Connection.cs | 9 +- Subsurface/Items/Item.cs | 4 +- Subsurface/Map/IDamageable.cs | 2 +- Subsurface/Map/Map.cs | 193 ++++++++++++++---- Subsurface/Map/MapHash.cs | 65 ++++++ Subsurface/Map/Structure.cs | 8 +- Subsurface/Networking/GameClient.cs | 13 +- Subsurface/Networking/GameServer.cs | 10 +- Subsurface/Screens/LobbyScreen.cs | 4 +- Subsurface/Screens/MainMenu.cs | 23 ++- Subsurface/Screens/NetLobbyScreen.cs | 74 +++++-- Subsurface/Sounds/AmbientSoundManager.cs | 6 +- 28 files changed, 411 insertions(+), 137 deletions(-) rename Subsurface/Characters/{LimbAttack.cs => Attack.cs} (77%) create mode 100644 Subsurface/Content/Sounds/Damage/HitArmor1.ogg create mode 100644 Subsurface/Content/Sounds/Damage/HitArmor2.ogg create mode 100644 Subsurface/Content/Sounds/Damage/HitArmor3.ogg create mode 100644 Subsurface/Map/MapHash.cs diff --git a/Subsurface/Characters/AI/EnemyAIController.cs b/Subsurface/Characters/AI/EnemyAIController.cs index e80f694f3..3e18ecebf 100644 --- a/Subsurface/Characters/AI/EnemyAIController.cs +++ b/Subsurface/Characters/AI/EnemyAIController.cs @@ -380,27 +380,30 @@ namespace Subsurface Body closestBody = Map.CheckVisibility(rayStart, rayEnd); Structure closestStructure = (closestBody == null) ? null : closestBody.UserData as Structure; - if (targetCharacter != null) - { - //if target is a character that isn't visible, ignore - if (closestStructure != null) continue; + //if (targetCharacter != null) + //{ + // //if target is a character that isn't visible, ignore + // if (closestStructure != null) continue; - //prefer targets with low health - valueModifier = valueModifier / targetCharacter.Health; - } - else - { + // //prefer targets with low health + // valueModifier = valueModifier / targetCharacter.Health; + //} + //else + //{ if (targetDamageable != null) { - valueModifier = valueModifier / targetDamageable.Health; - + valueModifier = valueModifier / targetDamageable.Health; } else if (closestStructure!=null) { valueModifier = valueModifier / (closestStructure as IDamageable).Health; } + else + { + valueModifier = valueModifier / 1000.0f; + } - } + //} diff --git a/Subsurface/Characters/LimbAttack.cs b/Subsurface/Characters/Attack.cs similarity index 77% rename from Subsurface/Characters/LimbAttack.cs rename to Subsurface/Characters/Attack.cs index 3aa4f2968..650f17a03 100644 --- a/Subsurface/Characters/LimbAttack.cs +++ b/Subsurface/Characters/Attack.cs @@ -8,12 +8,26 @@ using System.Xml.Linq; namespace Subsurface { - public enum DamageType { None, Blunt, Slash }; + public enum DamageType { None, Blunt, Slash }; + + struct AttackResult + { + public readonly float damage; + public readonly float bleeding; + + public readonly bool hitArmor; + + public AttackResult(float damage, float bleeding, bool hitArmor=false) + { + this.damage = damage; + this.bleeding = bleeding; + + this.hitArmor = hitArmor; + } + } class Attack { - - public enum Type { None, PinchCW, PinchCCW @@ -67,7 +81,7 @@ namespace Subsurface priority = ToolBox.GetAttributeFloat(element, "priority", 1.0f); } - public void DoDamage(IDamageable target, Vector2 position, float deltaTime, bool playSound=true) + public AttackResult DoDamage(IDamageable target, Vector2 position, float deltaTime, bool playSound=true) { float damageAmount = 0.0f; //DamageSoundType damageSoundType = DamageSoundType.None; @@ -89,7 +103,14 @@ namespace Subsurface if (duration > 0.0f) damageAmount *= deltaTime; float bleedingAmount = (duration == 0.0f) ? bleedingDamage : bleedingDamage * deltaTime; - if (damageAmount>0.0f) target.AddDamage(position, damageType, damageAmount, bleedingAmount, stun, playSound); + if (damageAmount > 0.0f) + { + return target.AddDamage(position, damageType, damageAmount, bleedingAmount, stun, playSound); + } + else + { + return new AttackResult(0.0f, 0.0f); + } } } } diff --git a/Subsurface/Characters/Character.cs b/Subsurface/Characters/Character.cs index cbabf9a79..7130bbc6c 100644 --- a/Subsurface/Characters/Character.cs +++ b/Subsurface/Characters/Character.cs @@ -654,7 +654,7 @@ namespace Subsurface } } - public void AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound = false) + public AttackResult AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound = false) { animController.StunTimer = Math.Max(animController.StunTimer, stun); @@ -675,7 +675,7 @@ namespace Subsurface closestLimb.body.ApplyForce(pull*Math.Min(amount*100.0f, 100.0f)); - closestLimb.AddDamage(position, damageType, amount, bleedingAmount, playSound); + return closestLimb.AddDamage(position, damageType, amount, bleedingAmount, playSound); } diff --git a/Subsurface/Characters/HumanoidAnimController.cs b/Subsurface/Characters/HumanoidAnimController.cs index 7cf77748b..e2fe94c63 100644 --- a/Subsurface/Characters/HumanoidAnimController.cs +++ b/Subsurface/Characters/HumanoidAnimController.cs @@ -33,7 +33,7 @@ namespace Subsurface { case Physics.CollisionStairs: Structure structure = fixture.Body.UserData as Structure; - if (stairs == null) + if (stairs == null && (!inWater || TargetMovement.Y>0.0f)) { if (LowestLimb.SimPosition.Y=100.0f) //{ // bloodAmount *= 2; @@ -311,6 +317,8 @@ namespace Subsurface { Game1.particleManager.CreateParticle("waterblood", SimPosition, Vector2.Zero); } + + return new AttackResult(amount, bleedingAmount, hitArmor); } public void Update(float deltaTime) diff --git a/Subsurface/Characters/Ragdoll.cs b/Subsurface/Characters/Ragdoll.cs index 98f28e7d2..aabff7ca5 100644 --- a/Subsurface/Characters/Ragdoll.cs +++ b/Subsurface/Characters/Ragdoll.cs @@ -442,7 +442,7 @@ namespace Subsurface inWater = false; headInWater = false; - if (ConvertUnits.ToSimUnits(currentHull.Surface)-floorY> HeadPosition) + if (ConvertUnits.ToSimUnits(currentHull.Surface)-floorY> HeadPosition*0.95f) inWater = true; } diff --git a/Subsurface/Content/Characters/Crawler/crawler.xml b/Subsurface/Content/Characters/Crawler/crawler.xml index 6123d043a..f51510ed6 100644 --- a/Subsurface/Content/Characters/Crawler/crawler.xml +++ b/Subsurface/Content/Characters/Crawler/crawler.xml @@ -10,17 +10,17 @@ flip="true"> - + - + - + @@ -70,7 +70,7 @@ - diff --git a/Subsurface/Content/Sounds/Damage/HitArmor1.ogg b/Subsurface/Content/Sounds/Damage/HitArmor1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..a085ff2e5cda7f125f676f271de62648e388a584 GIT binary patch literal 9615 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 QAm8fKN49OEtajkP07`*A(*OVf literal 0 HcmV?d00001 diff --git a/Subsurface/Content/Sounds/Damage/HitArmor2.ogg b/Subsurface/Content/Sounds/Damage/HitArmor2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..6c5e91e5cfce5b72f90e19383a50e9e2bcdca5fe GIT binary patch literal 8978 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 HDXRYh{6h8R literal 0 HcmV?d00001 diff --git a/Subsurface/Content/Sounds/Damage/HitArmor3.ogg b/Subsurface/Content/Sounds/Damage/HitArmor3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..89e13d4220930a54fa5123b1a4357ea2070183a8 GIT binary patch literal 7822 zcmb7p2UJtbyYCKCLJ^QAC_+FG0z?T#2uklA0--4)1O%i>RhlBbNezgAQbPv?2~CP3 zy-6>kV4))dg7ors@SJnc```8MU2oQ8)?|NszW$r}CegLEH2_F}zgn~BpNW~HCKZGO z;^pFIW$#XW1Oe_tPDsaKBTi}{y2O?LG~!C)8;5BhrRWgExBh7hr~dG{0Fq7Y@7Z0} zb+d&z+FKc&aEGbGM1+MUgs+N-5Sc;9{=5uVP&9%7Q1A&-3)ULYABO<|dH}f11E)>A zqYlU8viQAIaB9R^t8hdLE~1qc8;xxHdw_{qGXnrA5Wr6vlQXA&w-05@$`|97iL%#` z%!g4#>VH8|Hvhhab~?{?|ZxVh0S= zMS+~nnqC1)WFHRCOK}5P{V@v$1b}7&s_{(f?7ag#y1#_<8N~-gl?@EFF<|pF zH}{G#^B_x0~(Iqg-1a5djj(XmmyJhxiRd&TyPTdtk-4!$^uYf@$C29j?+Nb9Iw|>Vo z+2()ma&{d8fE?({c31XxR~}_FPrI8C#fgVI05GOdM{;dIOCZauYXpmmYK19s^xL^vM6*9-rh3Xb9KyJIQwgprUb> zCvFJ<*|KIq6>0uR0$&Kvnt`SEr*8D3Xj5l13z^b}-bEOu@zoZlq@6_2v5)OL7)yB9 zv)0UK{i*JK>NKhNKQnKJG>X!~LGT&dd^&9#n-3+!l*DKMnLcu0+$_gg+nxu){A0+i zn7Hz|5;;6#X%jP%9q?R^Cow7-g+Y2~Ha@&Z;EClh00^c($>P6s7(aZ)w@7wH5KR?A+8cjtlpX*b>Y;r0-vI!C zw{bL@C;Ny#8Zm+vA3-B9hSL8tVnFJMnD&qu=-4CxU;_Z_ciXUFdfJ>}1z~x+9(nS@ znM`?g{K#m~9KC2XYBec1L0v=Iq))yjZUe^E&V<#l7ev?$v%Zs?|KvJLPYP~(q<}sE z1Rz6^Ev#;R>YceteMtCoTn9=OpE#%vML@Brk zpa4JAS^aU$5IH6Qu%baz!9#H9KKNW5x(hkWj@Cfsr5p62pcjI>kmS#U=;3&FgFg5? zdvK5ZY7BGGCt_qnJ)i!0p zjEriJ5Io0{{Vl3I%~QmB#fYr5nJ^kOK7Ct zNloRiE4ma};?IP-IA+gu?lBQi`=2@OoR9Vq--qKQY$#R>^ejPHpXbEJxfid0!Wm3NRdH(%E zQQfPqiq+z(ANzGb&v&~V)Kv9W`)430>vVUX_*s~ARUs-vGTfHy%4wS7%MQR3f%P7E zb_i$DFrBO52ErME+w^WaNU|(6jRFN1o>oDf8A~rRpKI77Pl>N&QBW_nqEVPl3GP9` zvx1Wq;0RB8G!;nDutyMB95fJZvWi5<2`K(Ta0MLR3TkyB7$*gVCmC7^!U>>Or67SH-^y~M z6izTwJYgjSZymQPCbSx1K?C(P96%Xp2l2d7D;iKZ`b2nC`QO3?%99ezw8}@u%}T@x zEZDo{qb%4`rRv-a2I*Kh7-#)RNs4jl=E@=5VqHu;A{Dnl}pd(I%oBb`^ z#NjTY?L;dRY?*Ys5mvVp)T)F)FmfmnpEtq21gj<*N$`A1(IcliZAu9!K>+$-{?>FH zIahmn4i46m5`+_Ihv5dzTG?@Ev*q-}L3H%BzY7U{BCi2P2px%>&sEYu&ZXmekn=pbIOIG#4yORc=MJKwSvVY8 z5G-6ya8Irs(Fy?-Izv*j!X~wb5O1%9Ss#c&d97g7niKza3)ws zLk*sTHWMtgNzib>Cy@YeY1zS#P%yZYkpSLcrGO;LbtmV-vx6seP#n4kJf^KcgB#qemGEowwe_a za0zHf!rVs;lu74<=_fw_i5hro4g%)dD}8JC!1&C+ji6D`AQs7L@RLe8 zmw2GIr4R>Jcb${!8P(2;1znp?ET+Lqgh&9(5wNT#)+Es&0sIOYODs|TA4bq~6AK3W z+>@$7j95CH%>I7{UeHP4nNLpzxYpkTHlO|5h(h9-LWLrG9&C6HpB@yap#c}yK=E;b zQi_S5awu;#LGkh8N6kvg!LLz-(NuRnUJw$c1n}^PCd_?w@8`m^IP`)}(sU>XBT6Te zGHzAcu>HbU4>@`>=%+k1%c=wgMvATx01}}TKnvM$=#tUK_AJu^!E7sZFIc*nDtKYby)oy8>x0l+H` z>D?YeyU9fm7KUb*nbA}l5e!HR*S{mFB4++msHWSQJ z>`?DQwvEEcLF-|_Te;vKQW7$~+ptprEj>dn5YSAb*naN}eVk?ozc4>LW1o8dX+Vyi zTU3eL3aO@5Kpq*n2;6pk%*6?ah+Q4Ld^xilIP2j$_Lx49J{ZPAp(jT|t5fqeLgM;Y za=rzoB&k0YI4SS|0MxDqgooSBNlIOpkyB7oQPa@U(fe~@gaR@EkiZ1v=1xV$(8kim z(Z`=jU`S-dfmQaO27|#)Cg9BtfWb~~jHE(3e`v%TBazRP@YpZjD+mNa1*5F2WNK_? zYGP!p+R)znzNfYG{i3CHiiMt$j=71EtdRDm*11skBLkB7Pl=1&-WLEGlFi$(ZrPu2!%<@Mtja zvhK|@EiCXC8X5IXS`=F5Vl9%DPwH>0UtT*qrv!4=FQQ|~3d4%Qtq>3Tx5o9pBuq)3 zz1|y1;YS{AuY||>Fg$hOsby`Hup;iTlk=BQ)$$+P@!P%l>4MYUt)CrP_M?5TX8vu>)T4n4 zMvpC`JvH&swLa5Pin{bk*3SlnwxWi62F;^zh4$b+Qb20G!B1@WV5hnN-S6Uzp5`zM zAexp$Ul;ZCQ4qK2;rCJ(RnuA9_v<3V-%DPbILIhH2S`TJv6Uq^VN`TW#jAOqEky_2 zLLZRPIee;t5MZ@eb2Cv-$x4itl-q`L-32Pha_U1@cfk>dihzatikEdsL;7+w85G+% zDLpBTU%Vlr7jc{v@z$!mc9+5?fsh=Ux0;Rb8RCJ|h(hW~pj1npM`7~ukVgVdg2w&@ zvcG5cqumXcY@v!g0MGb?`?7cWx*nKjaJFqnZ0)De_0Atfd=fVx2WalOyJsJy|CZ3A z5?lD{*m_K&q~?6;QTF-!lFLSf zb?2Pl!ajd@l=H>0Wbii*$t~p@KGmmxj_5vglPhxuUM$LzRZ@|X_+=eGQFKEd{qi)| zcV)Za;_hdJ7`rTz|9*EALSh-;=gxdXJl?-+RyNfCXk9laB711~Wolb*(l6oi1jHe& zj*E z=(9!RMF99jE7_apI{zpna8CBvvvH^JU>Pe@_ArgF@S#PpTOTQ@+a|-r_dZMaPlqaS z=L$v^_ArC{Bg_mZc01BmfBGRabvI*z_HV=F%YIqzevLd@s@U(3bRt*Q6Yi zCq#X%K9z~i?_Bf^z3siN$M_&euZ*u`8A^uzhQ2Jj zD^s0~3}=DskJ8-GpYv^>_MLwye8>u{Ewe*#=h(ZfjQ2Td)toE$_KS~x`;-pY)iiRX zx#YjLuWrbihQ%rR?d^$`hP-?OZbEcDZjN_BfKLq3b8%yvpo62JZ0S z=alJ>4y#lzX`2m2D4$s-#tz{`MBfFVj10z@N2*~WgTv^aXr z%vDS4s<_N-9LE-5X=4cQCpshFEO=pm)>nycS}q3OS+gl_2x1GSc(8dDIee{eUdl*J z*_yc@u@Lxbhk1yLewnPjRwJs!&|Kv~%hhYEI~P9tOo)29MTpZDTAb}Ji0;}dRCK75 zC^e#!A1bvpIsK^dqna-E{3cZWH)Z{9MRn1s4JUbHE2C@h%R~Nor`2+{r;=Ex|MzM zOG0gPbI3V=o#)KgWUZVmRmOV9WsK;^unn}s=25(ZTUjai4?S1zwGG^^d2ea`8W}JZ zXWZK|FSg5pMOv8u;Fo;*Fo960lG5t!VrtX*0g?LfV*mx~^}qqsw-u!qJDIicc4YUq zI}dE|g__dGrxeL~;uber8b06m!?p3F`LU75sNt>U;cH!#z^&c4!g(ZF->v}BnXR^A zyhigRr!v!R&_Hy2dRNaZc5nZq(~D~VvdFZm2VTh^_HS4G5Yk?h{eaWR$jIG^I2XQe z$0sPOt0E^a`{vfF>800|rn>j|Cz)@39*`Lv3>VQ3YkT)0+{l-iL~7GedfeGFq1g5g z)k>Jt9s6#`MS>6~jfdI(^C2em*7q~le3r>eWY*i3#|E!lVd=t2XYB)xeLoU9cBoaB z;|T1y+zs>Nf+nA+8kH)_CLPD0ETZdt3_g=f4MzdPg<|jMWIDe@uo8{2Ylen2rGyba zt_cHOi!5Yv*3oBwNM4)HxIRcd?Ihu5FfeZR>~phBHQF|;QuK7%9nqgx=VX)R@`Q3=1r*t5WNq!kcW zFpQAQM#E(b2rZFf@a~{-ifk06@K5Itko-P&!R|a4kI0v2T`w$5CZ~NaKeSG1k7rAm z$zoF9HvjAA-H_onJv!IZ}zp~K>l-f`+i);60 zJw&f`+}s*uupK-)2>-x+Z}fR*CIMBqzj9N#W?b=MZaLlW2QQ>5GafidSAHhUe1}$D zYKq67kK}L`pNf=UpMQ_HORl2z_eM3s*{-ONU{Lh8Xv3l1% zZS=oN?RWMnJuCq_XIrRe;@>w1)9rs%k74&{98M4$aKOKO-tReB-5Ga(?6`#@rP0_T z``(=`WrI1tYa`lS?=wuA?dME@7aelpp0`7OQ3DqrWE>Xj@j}SuP(yMMVea_vHC^q4 ziBWiE{D*Ya3mepJ`0ZpZWxjUNGFd?=q%B!TQbBbvsq2URk^C$tbDWpoP8BWp=t4l!W%H zo!v9O5K2RN?d2wsG``n+b(+vj?#XQj>3OyVxhwU*2s{Dr-WWcg zaO~oad8>=ZrA^GfhhQ|4fhSb`-$&X~0 zrlsme)|g%@)r;@R2J^aZ>}&S!Zaw_L@-DjXBFn30X-3_Vk5BJI@3v$)&E~06SY*8Z z>EWPxm3pcjhIwj4-vuIFZ~e9RO()A>2tAd1APJ0tP5)kBti^A5?P_e*^{so#vF0Od z9oTOo-CVKV_N3CwJ9NpHef7O+b#8h|JO2#XMOo~`#eh7E?rHgiA*X7*%~~d#Sw2;aQZ2sm(iPw-p;svnZ+<Z=I1Yob>GV#AxR$9^L{D> zGu&m4&K#Pbk6b5Mvfi;OCs_kejKxc2ZzXN{vSabhi2}-LG?T)P5tx@qQhZ(jA#)10D9L z?<%gH^4VmMSvT8%TD?;`;Z7RyXyST~z5S41CDW8K;uqd$^|j>w-IT}MlYie4>s*s4(B~C!fh`<(MhVMMwLko?>Fgg zG_25dW?gEIiybBDREwK)JJoq#1^vd> z3p8`BRubZ;-9se>lAbcQiE3X=#bAVsy$&z;c{!KcJXrZMkSpD|M$Y*16`oOF!FJQD zU@lv-_fi>&%*=xo?^{cceU3;Ts0jZuWdnaI1+ew`u4Cz>05sF6tn5y6CWoSsxcF48 zv)TEw=T%L-pU^%ck-5BULc+$sA4c9BqixU536qYx{WK*nl zv-3%xx>&<6BGO_eo;&OMNOeGXnnP~1jf?Z%Qn}wms5$44toHkKC2yPEFm(L-N0r}c zcQV53f&a#p6J&Z@sm(C-DYvYzwM`l7nu14?0{41T>6GnM{c)SUj}E8N1KGu(v9dIJ z_U1O5tF*(Ty8&3Y`^s~W7n?iv|E1&Ynb(;hw`lb~Yf_e}SN#X+YW0P?l$%YL@YIKM z$Tc)|bK82sYdlSHvE2LuX0bfW%|blwCtF6Ry{&B;u6jCNK-+N@;<;UITN&-o`GR!! z6VaikP8@K1W&`96U=wUB-gR%eEOEY1@%N%pJvVO_bXHGc&oJOKVS0y^)KvEITgwLR zy9rK{gq}^E_X~(Nhu?U+W5;8dfuxiKbTf_gZ>9e)zTd-juy>q zA_oaa72jgU%39W1$buQ%bI+^Wzw|Kv!LjALdnrt<{fp{SympGd%HGfc>hK@Og5giH zC4K*ac)^Fs;aE>yS)=xo)lt0dHh7S-CMn(9t1lCvqQ7HyATN0%+q23;^CsOY9q@ku D6awXh literal 0 HcmV?d00001 diff --git a/Subsurface/Content/Sounds/sounds.xml b/Subsurface/Content/Sounds/sounds.xml index 34fa04a62..c9c2fa3b6 100644 --- a/Subsurface/Content/Sounds/sounds.xml +++ b/Subsurface/Content/Sounds/sounds.xml @@ -20,5 +20,9 @@ + + + + \ No newline at end of file diff --git a/Subsurface/DebugConsole.cs b/Subsurface/DebugConsole.cs index f49882672..a4c2e7dd0 100644 --- a/Subsurface/DebugConsole.cs +++ b/Subsurface/DebugConsole.cs @@ -209,11 +209,11 @@ namespace Subsurface Game1.lobbyScreen.Select(); break; case "savemap": - Map.Save("Content/SavedMaps/", commands[1]); + Map.Loaded.SaveAs("Content/SavedMaps/" + commands[1]); NewMessage("map saved", Color.Green); break; case "loadmap": - Map.Load("Content/SavedMaps/", commands[1]); + Map.Load("Content/SavedMaps/" + commands[1]); break; case "debugdraw": Hull.DebugDraw = !Hull.DebugDraw; diff --git a/Subsurface/Game1.cs b/Subsurface/Game1.cs index 1d94139f3..40837c7a5 100644 --- a/Subsurface/Game1.cs +++ b/Subsurface/Game1.cs @@ -145,6 +145,7 @@ namespace Subsurface AmbientSoundManager.Init("Content/Sounds/Sounds.xml"); + Map.PreloadMaps("Content/SavedMaps"); gameScreen = new GameScreen(graphics.GraphicsDevice); mainMenuScreen = new MainMenuScreen(this); lobbyScreen = new LobbyScreen(); @@ -152,6 +153,7 @@ namespace Subsurface editMapScreen = new EditMapScreen(); editCharacterScreen = new EditCharacterScreen(); + mainMenuScreen.Select(); } diff --git a/Subsurface/GameSession/GameSession.cs b/Subsurface/GameSession/GameSession.cs index 122b53868..47b8fd635 100644 --- a/Subsurface/GameSession/GameSession.cs +++ b/Subsurface/GameSession/GameSession.cs @@ -116,7 +116,7 @@ namespace Subsurface { if (saveFile == null) return false; - Map.Save(Path.GetDirectoryName(saveFile) + "/", Path.GetFileName(saveFile)); + Map.Loaded.SaveAs(Path.GetDirectoryName(saveFile) + "/"+ Path.GetFileName(saveFile)); crewManager.EndShift(); diff --git a/Subsurface/Items/Components/Container.cs b/Subsurface/Items/Components/Container.cs index 8536adae7..3e4e74a9e 100644 --- a/Subsurface/Items/Components/Container.cs +++ b/Subsurface/Items/Components/Container.cs @@ -242,6 +242,8 @@ namespace Subsurface.Items.Components public override void OnMapLoaded() { + if (itemIds == null) return; + for (int i = 0; i < itemIds.Length; i++) { Item item = MapEntity.FindEntityByID(itemIds[i]) as Item; diff --git a/Subsurface/Items/Components/Projectile.cs b/Subsurface/Items/Components/Projectile.cs index be4299b2b..8857103a7 100644 --- a/Subsurface/Items/Components/Projectile.cs +++ b/Subsurface/Items/Components/Projectile.cs @@ -157,37 +157,18 @@ namespace Subsurface.Items.Components //float damage = f1.Body.LinearVelocity.Length(); + AttackResult attackResult = new AttackResult(0.0f, 0.0f); if (attack!=null) { Limb limb; Structure structure; if ((limb = (f2.Body.UserData as Limb)) != null) { - attack.DoDamage(limb.character, item.SimPosition, 0.0f); - //limb.Damage += damage; - //limb.Bleeding += bleedingDamage; - - //if (bleedingDamage>0.0f) - //{ - // for (int i = 0; i < 5; i++ ) - // { - // Game1.particleManager.CreateParticle(limb.SimPosition, - // ToolBox.VectorToAngle(-f1.Body.LinearVelocity*0.5f) + ToolBox.RandomFloat(-0.5f, 0.5f), - // ToolBox.RandomFloat(1.0f, 3.0f), "blood"); - // } - - // Game1.particleManager.CreateParticle(limb.SimPosition, - // 0.0f, - // Vector2.Zero, "waterblood"); - //} - - //AmbientSoundManager.PlayDamageSound(DamageType.LimbBlunt, damage, limb.body.FarseerBody); + attackResult = attack.DoDamage(limb.character, item.SimPosition, 1.0f); } else if ((structure = (f2.Body.UserData as Structure)) != null) { - attack.DoDamage(structure, item.SimPosition, 0.0f); - - //AmbientSoundManager.PlayDamageSound(DamageType.StructureBlunt, damage, f2.Body); + attackResult = attack.DoDamage(structure, item.SimPosition, 1.0f); } } @@ -200,7 +181,11 @@ namespace Subsurface.Items.Components ignoredBodies.Clear(); - if (doesStick) + if (attackResult.hitArmor) + { + item.body.LinearVelocity *= 0.5f; + } + else if (doesStick) { Vector2 normal = contact.Manifold.LocalNormal; Vector2 dir = new Vector2( diff --git a/Subsurface/Items/Components/Signal/Connection.cs b/Subsurface/Items/Components/Signal/Connection.cs index 355ac550e..fe8330e78 100644 --- a/Subsurface/Items/Components/Signal/Connection.cs +++ b/Subsurface/Items/Components/Signal/Connection.cs @@ -398,6 +398,13 @@ namespace Subsurface.Items.Components { XElement newElement = new XElement(isOutput ? "output" : "input", new XAttribute("name", name)); + Array.Sort(wires, delegate(Wire wire1, Wire wire2) + { + if (wire1 == null) return 1; + if (wire2 == null) return -1; + return wire1.Item.ID.CompareTo(wire2.Item.ID); + }); + for (int i = 0; i < MaxLinked; i++ ) { if (wires[i] == null) continue; @@ -406,7 +413,7 @@ namespace Subsurface.Items.Components //int connectionIndex = recipient.item.Connections.FindIndex(x => x == recipient); newElement.Add(new XElement("link", - new XAttribute("w", (wires[i] == null) ? "-1" : wires[i].Item.ID.ToString()))); + new XAttribute("w", wires[i].Item.ID.ToString()))); } parentElement.Add(newElement); diff --git a/Subsurface/Items/Item.cs b/Subsurface/Items/Item.cs index c87ccf2ec..b7285b9c5 100644 --- a/Subsurface/Items/Item.cs +++ b/Subsurface/Items/Item.cs @@ -370,9 +370,11 @@ namespace Subsurface } - public void AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound = true) + public AttackResult AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound = true) { Condition -= amount; + + return new AttackResult(amount, 0.0f, false); } diff --git a/Subsurface/Map/IDamageable.cs b/Subsurface/Map/IDamageable.cs index b737175f5..29af336d4 100644 --- a/Subsurface/Map/IDamageable.cs +++ b/Subsurface/Map/IDamageable.cs @@ -14,6 +14,6 @@ namespace Subsurface get; } - void AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound=true); + AttackResult AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound=true); } } diff --git a/Subsurface/Map/Map.cs b/Subsurface/Map/Map.cs index b471e873e..ccd5a536b 100644 --- a/Subsurface/Map/Map.cs +++ b/Subsurface/Map/Map.cs @@ -17,18 +17,36 @@ namespace Subsurface None = 0, Left = 1, Right = 2 } - static class Map + class Map { - static string MapFolder = "Content/SavedMaps"; + static string MapFolder; + MapHash mapHash; - public static Vector2 gridSize = new Vector2(16.0f, 16.0f); + public static List SavedMaps = new List(); + + private static Map loaded; + + //public static Map Loaded + //{ + // get { return loaded; } + // set { loaded = value; } + //} + + + public static readonly Vector2 gridSize = new Vector2(16.0f, 16.0f); private static Vector2 lastPickedPosition; private static float lastPickedFraction; - private static Rectangle borders; + private Rectangle borders; - private static string filePath; + private string filePath; + private string name; + + public string Name + { + get { return name; } + } public static Vector2 LastPickedPosition { @@ -40,12 +58,31 @@ namespace Subsurface get { return lastPickedFraction; } } - public static Rectangle Borders + public MapHash MapHash { - get { return borders; } + get + { + XDocument doc = OpenDoc(filePath); + mapHash = new MapHash(doc); + + return mapHash; + } } - public static string FilePath + public static Map Loaded + { + get { return loaded; } + } + + public static Rectangle Borders + { + get + { + return (loaded==null) ? Rectangle.Empty : loaded.borders; + } + } + + public string FilePath { get { return filePath; } } @@ -223,38 +260,51 @@ namespace Subsurface return true; } - public static void Save(string filePath, string fileName) + + public void Save() { - if (fileName==null) - { - DebugConsole.ThrowError("No save file selected"); - return; - } + SaveAs(filePath); + } + + public void SaveAs(string filePath) + { + //if (filePath=="") + //{ + // DebugConsole.ThrowError("No save file selected"); + // return; + //} XDocument doc = new XDocument( - new XElement((XName)fileName)); + new XElement((XName)name)); foreach (MapEntity e in MapEntity.mapEntityList) { e.Save(doc); } + mapHash = new MapHash(doc); + doc.Root.Add(new XAttribute("md5hash", mapHash.MD5Hash)); + try { string docString = doc.ToString(); - ToolBox.CompressStringToFile(filePath+fileName+".gz", doc.ToString()); + ToolBox.CompressStringToFile(filePath+".gz", doc.ToString()); } catch { - DebugConsole.ThrowError("Saving map ''" + filePath + fileName + "'' failed!"); + DebugConsole.ThrowError("Saving map ''" + filePath + "'' failed!"); } - //doc.Save(filePath + fileName); + doc.Save(filePath); } - public static string[] GetMapFilePaths() + public static void PreloadMaps(string mapFolder) { - string[] mapFilePaths; + MapFolder = mapFolder; + + //string[] mapFilePaths; + Unload(); + SavedMaps.Clear(); if (!Directory.Exists(MapFolder)) { @@ -266,10 +316,12 @@ namespace Subsurface { DebugConsole.ThrowError("Directory ''Content/SavedMaps'' not found and creating the directory failed."); - return null; + return; } } + string[] mapFilePaths; + try { mapFilePaths = Directory.GetFiles(MapFolder); @@ -277,21 +329,42 @@ namespace Subsurface catch (Exception e) { DebugConsole.ThrowError("Couldn't open directory ''Content/SavedMaps''!", e); - return null; + return; } - return mapFilePaths; + foreach (string mapPath in mapFilePaths) + { + //Map savedMap = new Map(mapPath); + SavedMaps.Add(new Map(mapPath)); + } } - public static void Load(string filePath, string fileName) + public Map(string filePath, string mapHash="") { - Load(filePath + fileName); + this.filePath = filePath; + this.name = Path.GetFileNameWithoutExtension(filePath); + + if (mapHash != "") + { + this.mapHash = new MapHash(mapHash); + } + else + { + //XDocument doc = OpenDoc(filePath); + + //string md5Hash = ToolBox.GetAttributeString(doc.Root, "md5hash", ""); + //if (md5Hash == "" || md5Hash.Length < 16) + //{ + // DebugConsole.ThrowError("Couldn't find a valid MD5 hash in the map file"); + //} + + //this.mapHash = new MapHash(md5Hash); + } + } - public static void Load(string file) + private XDocument OpenDoc(string file) { - Clear(); - filePath = file; XDocument doc = null; string extension = ""; @@ -302,16 +375,16 @@ namespace Subsurface catch { DebugConsole.ThrowError("Couldn't load map ''" + file + "! (Unrecognized file extension)"); - return; + return null; } - if (extension==".gz") + if (extension == ".gz") { Stream stream = ToolBox.DecompressFiletoStream(file); if (stream == null) { DebugConsole.ThrowError("Loading map ''" + file + "'' failed!"); - return; + return null; } try @@ -325,19 +398,37 @@ namespace Subsurface catch { DebugConsole.ThrowError("Loading map ''" + file + "'' failed!"); - return; + return null; } } - else if (extension ==".xml") + else if (extension == ".xml") { - doc = XDocument.Load(file); + try + { + doc = XDocument.Load(file); + } + + catch + { + DebugConsole.ThrowError("Loading map ''" + file + "'' failed!"); + return null; + } } else { - DebugConsole.ThrowError("Couldn't load map ''"+file+"! (Unrecognized file extension)"); - return; + DebugConsole.ThrowError("Couldn't load map ''" + file + "! (Unrecognized file extension)"); + return null; } - + + return doc; + } + + public void Load() + { + //string file = filePath; + + XDocument doc = OpenDoc(filePath); + if (doc == null) return; foreach (XElement element in doc.Root.Elements()) { @@ -350,13 +441,13 @@ namespace Subsurface t = Type.GetType("Subsurface." + typeName + ", Subsurface", true, true); if (t == null) { - DebugConsole.ThrowError("Error in " + file + "! Could not find a entity of the type ''" + typeName + "''."); + DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type ''" + typeName + "''."); continue; } } catch (Exception e) { - DebugConsole.ThrowError("Error in " + file + "! Could not find a entity of the type ''" + typeName + "''.", e); + DebugConsole.ThrowError("Error in " + filePath + "! Could not find a entity of the type ''" + typeName + "''.", e); continue; } @@ -390,13 +481,29 @@ namespace Subsurface ic.OnMapLoaded(); } } + + loaded = this; } - - - public static void Clear() + public static void Load(string file) { - Map.filePath = ""; + Unload(); + + Map map = new Map(file); + map.Load(); + + } + + public static void Unload() + { + if (loaded==null)return; + loaded.Clear(); + loaded = null; + } + + private void Clear() + { + filePath = ""; if (Game1.gameScreen.Cam != null) Game1.gameScreen.Cam.TargetPos = Vector2.Zero; diff --git a/Subsurface/Map/MapHash.cs b/Subsurface/Map/MapHash.cs new file mode 100644 index 000000000..e82fa2a03 --- /dev/null +++ b/Subsurface/Map/MapHash.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml.Linq; + +namespace Subsurface +{ + class MapHash + { + private string md5Hash; + private string shortHash; + + public string MD5Hash + { + get + { + return md5Hash; + } + } + + public string ShortHash + { + get + { + return shortHash; + } + } + + public MapHash(string md5Hash) + { + this.md5Hash = md5Hash; + + shortHash = GetShortHash(md5Hash); + } + + public MapHash(XDocument doc) + { + string docString = Regex.Replace(doc.ToString(), @"\s+", ""); + // step 1, calculate MD5 hash from input + + MD5 md5 = MD5.Create(); + byte[] inputBytes = Encoding.ASCII.GetBytes(docString); + byte[] hash = md5.ComputeHash(inputBytes); + + // step 2, convert byte array to hex string + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < hash.Length; i++) + { + sb.Append(hash[i].ToString("X2")); + } + + md5Hash = sb.ToString(); + + shortHash = GetShortHash(md5Hash); + } + + private string GetShortHash(string fullHash) + { + return fullHash; + } + } +} diff --git a/Subsurface/Map/Structure.cs b/Subsurface/Map/Structure.cs index 7547fa831..d80521510 100644 --- a/Subsurface/Map/Structure.cs +++ b/Subsurface/Map/Structure.cs @@ -378,12 +378,12 @@ namespace Subsurface sections[sectionIndex].rect.Y - sections[sectionIndex].rect.Height / 2.0f); } - public void AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound = false) + public AttackResult AddDamage(Vector2 position, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound = false) { - if (!prefab.HasBody || prefab.IsPlatform) return; + if (!prefab.HasBody || prefab.IsPlatform) return new AttackResult(0.0f, 0.0f); int i = FindSectionIndex(ConvertUnits.ToDisplayUnits(position)); - if (i == -1) return; + if (i == -1) return new AttackResult(0.0f, 0.0f); Game1.particleManager.CreateParticle("dustcloud", ConvertUnits.ToSimUnits(SectionPosition(i)), 0.0f, 0.0f); @@ -394,6 +394,8 @@ namespace Subsurface } AddDamage(i, amount); + + return new AttackResult(amount, 0.0f); } private void SetDamage(int sectionIndex, float damage) diff --git a/Subsurface/Networking/GameClient.cs b/Subsurface/Networking/GameClient.cs index e3c6d7e38..4d7af6dca 100644 --- a/Subsurface/Networking/GameClient.cs +++ b/Subsurface/Networking/GameClient.cs @@ -225,8 +225,15 @@ namespace Subsurface.Networking int seed = inc.ReadInt32(); Game1.random = new Random(seed); - string mapFile = inc.ReadString(); - Map.Load(mapFile); + string mapName = inc.ReadString(); + string mapHash = inc.ReadString(); + + Game1.netLobbyScreen.TrySelectMap(mapName, mapHash); + + + //Map.Load(mapFile); + + double durationMinutes = inc.ReadDouble(); @@ -316,7 +323,7 @@ namespace Subsurface.Networking public void EndGame(string endMessage) { - Map.Clear(); + Map.Unload(); Game1.netLobbyScreen.Select(); diff --git a/Subsurface/Networking/GameServer.cs b/Subsurface/Networking/GameServer.cs index 7bd5ded11..a4b782e35 100644 --- a/Subsurface/Networking/GameServer.cs +++ b/Subsurface/Networking/GameServer.cs @@ -271,7 +271,9 @@ namespace Subsurface.Networking int seed = DateTime.Now.Millisecond; Game1.random = new Random(seed); - Map.Load(Game1.netLobbyScreen.SelectedMap); + Map selectedMap = Game1.netLobbyScreen.SelectedMap as Map; + + selectedMap.Load(); Game1.gameSession = new GameSession("", false, Game1.netLobbyScreen.GameDuration, Game1.netLobbyScreen.SelectedMode); Game1.gameSession.StartShift(1); @@ -305,7 +307,9 @@ namespace Subsurface.Networking msg.Write(seed); - msg.Write(Game1.netLobbyScreen.SelectedMap); + msg.Write(Game1.netLobbyScreen.SelectedMap.Name); + msg.Write(Game1.netLobbyScreen.SelectedMap.MapHash.MD5Hash); + msg.Write(Game1.netLobbyScreen.GameDuration.TotalMinutes); WriteCharacterData(msg, client.name, client.character); @@ -336,7 +340,7 @@ namespace Subsurface.Networking public void EndGame(string endMessage) { - Map.Clear(); + Map.Unload(); gameStarted = false; diff --git a/Subsurface/Screens/LobbyScreen.cs b/Subsurface/Screens/LobbyScreen.cs index c91b3f346..5477bbc9f 100644 --- a/Subsurface/Screens/LobbyScreen.cs +++ b/Subsurface/Screens/LobbyScreen.cs @@ -96,7 +96,7 @@ namespace Subsurface { base.Select(); - Map.Clear(); + Map.Unload(); UpdateCharacterLists(); @@ -213,7 +213,7 @@ namespace Subsurface private bool StartShift(GUIButton button, object selection) { - Map.Load("", Game1.gameSession.SaveFile); + Map.Load(Game1.gameSession.SaveFile); Game1.gameSession.StartShift(); diff --git a/Subsurface/Screens/MainMenu.cs b/Subsurface/Screens/MainMenu.cs index 26fa90f87..54a58cb1a 100644 --- a/Subsurface/Screens/MainMenu.cs +++ b/Subsurface/Screens/MainMenu.cs @@ -56,23 +56,23 @@ namespace Subsurface new GUITextBlock(new Rectangle(0, 30, 0, 30), "Selected map:", Color.Transparent, Color.Black, Alignment.Left, menuTabs[(int)Tabs.NewGame]); mapList = new GUIListBox(new Rectangle(0, 60, 200, 400), Color.White, menuTabs[1]); - string[] mapFilePaths = Map.GetMapFilePaths(); - if (mapFilePaths!=null) - { - foreach (string s in mapFilePaths) + //string[] mapFilePaths = Map.GetMapFilePaths(); + //if (mapFilePaths!=null) + //{ + foreach (Map map in Map.SavedMaps) { GUITextBlock textBlock = new GUITextBlock( new Rectangle(0, 0, 0, 25), - Path.GetFileNameWithoutExtension(s), + map.Name, GUI.style, Alignment.Left, Alignment.Left, mapList); textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); - textBlock.UserData = s; + textBlock.UserData = map; } - if (mapFilePaths.Length > 0) mapList.Select(mapFilePaths[0]); - } + if (Map.SavedMaps.Count > 0) mapList.Select(Map.SavedMaps[0]); + //} button = new GUIButton(new Rectangle(0, 0, 100, 30), "Start", GUI.style, Alignment.Right | Alignment.Bottom, menuTabs[(int)Tabs.NewGame]); button.OnClicked = StartGame; @@ -146,9 +146,12 @@ namespace Subsurface private bool StartGame(GUIButton button, object obj) { - if (mapList.SelectedData == null) return false; - Game1.gameSession = new GameSession(mapList.SelectedData.ToString(), true, TimeSpan.Zero); + Map selectedMap = mapList.SelectedData as Map; + if (selectedMap == null) return false; + + + Game1.gameSession = new GameSession(selectedMap.FilePath, true, TimeSpan.Zero); Game1.lobbyScreen.Select(); diff --git a/Subsurface/Screens/NetLobbyScreen.cs b/Subsurface/Screens/NetLobbyScreen.cs index 3f3df070c..bdd1a4727 100644 --- a/Subsurface/Screens/NetLobbyScreen.cs +++ b/Subsurface/Screens/NetLobbyScreen.cs @@ -31,9 +31,9 @@ namespace Subsurface public bool isServer; - public string SelectedMap + public Map SelectedMap { - get { return mapList.SelectedData.ToString(); } + get { return mapList.SelectedData as Map; } } @@ -136,20 +136,19 @@ namespace Subsurface mapList.OnSelected = SelectMap; mapList.Enabled = (Game1.server!=null); - string[] mapFilePaths = Map.GetMapFilePaths(); - if (mapFilePaths != null) + if (Map.SavedMaps.Count>0) { - foreach (string s in mapFilePaths) + foreach (Map map in Map.SavedMaps) { GUITextBlock textBlock = new GUITextBlock( new Rectangle(0, 0, 0, 25), - Path.GetFileNameWithoutExtension(s), + map.Name, GUI.style, Alignment.Left, Alignment.Left, mapList); textBlock.Padding = new Vector4(10.0f, 0.0f, 0.0f, 0.0f); - textBlock.UserData = s; + textBlock.UserData = map; } } else @@ -194,7 +193,7 @@ namespace Subsurface modeList.OnSelected = Game1.server.UpdateNetLobby; durationBar.OnMoved = Game1.server.UpdateNetLobby; - if (mapFilePaths.Length > 0) mapList.Select(mapFilePaths[oldMapIndex]); + if (mapList.CountChildren > 0) mapList.Select(Map.SavedMaps[0]); if (GameMode.list.Count > 0) modeList.Select(GameMode.list[0]); } else @@ -245,8 +244,12 @@ namespace Subsurface { if (Game1.server != null) Game1.server.UpdateNetLobby(obj); - if ((string)obj == Map.FilePath) return true; - Map.Load((string)obj); + Map map = (Map)obj; + + //map already loaded + if (Map.Loaded!=null && map.FilePath == Map.Loaded.FilePath) return true; + + map.Load(); return true; } @@ -462,15 +465,60 @@ namespace Subsurface public void WriteData(NetOutgoingMessage msg) { - msg.Write(mapList.SelectedIndex); - msg.Write(modeList.SelectedIndex); + Map selectedMap = mapList.SelectedData as Map; + if (selectedMap==null) + { + msg.Write(" "); + msg.Write(" "); + } + else + { + msg.Write(selectedMap.Name); + msg.Write(selectedMap.MapHash.MD5Hash); + } + + msg.Write(modeList.SelectedIndex); msg.Write(durationBar.BarScroll); } + public bool TrySelectMap(string mapName, string md5Hash) + { + + Map map = Map.SavedMaps.Find(m => m.Name == mapName); + if (map==null) + { + DebugConsole.ThrowError("The map ''" + mapName + "'' has been selected by the server."); + DebugConsole.ThrowError("Matching map not found in your map folder."); + return false; + } + else + { + if (map.MapHash.MD5Hash!=md5Hash) + { + DebugConsole.ThrowError("Your version of the map file ''"+map.Name+"'' doesn't match the server's version!"); + DebugConsole.ThrowError("Your file: "+map.Name+"(MD5 hash : "+map.MapHash.MD5Hash+")"); + DebugConsole.ThrowError("Server's file: " + mapName + "(MD5 hash : " + md5Hash + ")"); + return false; + } + else + { + mapList.Select(map); + map.Load(); + return true; + } + } + } + public void ReadData(NetIncomingMessage msg) { - mapList.Select(msg.ReadInt32()); + string mapName = msg.ReadString(); + string md5Hash = msg.ReadString(); + + TrySelectMap(mapName, md5Hash); + + + //mapList.Select(msg.ReadInt32()); modeList.Select(msg.ReadInt32()); durationBar.BarScroll = msg.ReadFloat(); diff --git a/Subsurface/Sounds/AmbientSoundManager.cs b/Subsurface/Sounds/AmbientSoundManager.cs index 3bb42e95d..272686287 100644 --- a/Subsurface/Sounds/AmbientSoundManager.cs +++ b/Subsurface/Sounds/AmbientSoundManager.cs @@ -9,7 +9,11 @@ using Subsurface.Sounds; namespace Subsurface { - public enum DamageSoundType { None, StructureBlunt, StructureSlash, LimbBlunt, LimbSlash, Implode } + public enum DamageSoundType { + None, + StructureBlunt, StructureSlash, + LimbBlunt, LimbSlash, LimbArmor, + Implode } public struct DamageSound {