Merge branch 'ai-overhaul'
Conflicts: Barotrauma/Source/Characters/Attack.cs
@@ -387,6 +387,7 @@
|
||||
</Content>
|
||||
<Content Include="Content\Characters\Charybdis\charybdis.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Content\Characters\Coelanth\coelanth.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
@@ -868,9 +869,21 @@
|
||||
<Content Include="Content\Particles\shrapnel.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\Particles\Smoke.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\Particles\SmokeParticleSheet.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\Particles\Spatter1.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\Particles\Spatter2.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\Particles\Spatter3.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Content\Sounds\Damage\StructureBlunt10.ogg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<ErrorReportUrlHistory />
|
||||
<FallbackCulture>en-US</FallbackCulture>
|
||||
<VerifyUploadedFiles>false</VerifyUploadedFiles>
|
||||
<ProjectView>ProjectFiles</ProjectView>
|
||||
<ProjectView>ShowAllFiles</ProjectView>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ReferencePath>
|
||||
|
||||
@@ -8,6 +8,16 @@
|
||||
<sound file="Content/Characters/Carrier/carrier3.ogg" state="None" range="4000"/>
|
||||
|
||||
<sound file="Content/Characters/Carrier/ping.ogg" state="Die" range="3000"/>
|
||||
|
||||
<ai
|
||||
combatstrength="1000"
|
||||
attackpriorityhumans="100.0"
|
||||
attackpriorityrooms="50.0"
|
||||
attackpriorityweaker="0.0"
|
||||
attackprioritystronger="-80.0"
|
||||
attackcooldown="15.0"
|
||||
sight="0.5"
|
||||
hearing="1.0"/>
|
||||
|
||||
<ragdoll waveamplitude="0.0" swimspeed="4.0" mirror="true" rotatetowardsmovement="false" headangle="-90" canentersubmarine="false">
|
||||
|
||||
@@ -44,16 +54,12 @@
|
||||
</limb>
|
||||
|
||||
|
||||
<joint limb1="0" limb1anchor="92,-200" limb2="1" limb2anchor="0,-100" lowerlimit="180" upperlimit="210"/>
|
||||
<joint limb1="0" limb1anchor="64,-264" limb2="2" limb2anchor="0,-100" lowerlimit="180" upperlimit="210"/>
|
||||
<joint limb1="0" limb1anchor="92,-200" limb2="1" limb2anchor="0,-100" lowerlimit="180" upperlimit="210" canbesevered="true"/>
|
||||
<joint limb1="0" limb1anchor="64,-264" limb2="2" limb2anchor="0,-100" lowerlimit="180" upperlimit="210" canbesevered="true"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="-100,100" limb2="3" limb2anchor="38,0" lowerlimit="-50" upperlimit="5"/>
|
||||
<joint limb1="0" limb1anchor="-100,100" limb2="3" limb2anchor="38,0" lowerlimit="-50" upperlimit="5" canbesevered="true"/>
|
||||
<joint limb1="0" limb1anchor="140,268" limb2="4" limb2anchor="0,0" lowerlimit="87" upperlimit="93"/>
|
||||
|
||||
</ragdoll>
|
||||
|
||||
<ai attackhumans="100.0" attackrooms="50.0"
|
||||
attackweaker="50.0" attackstronger="-30.0"
|
||||
attackcooldown="15.0"
|
||||
sight="0.5" hearing="1.0"/>
|
||||
</Character>
|
||||
|
Before Width: | Height: | Size: 609 KiB After Width: | Height: | Size: 617 KiB |
@@ -2,20 +2,36 @@
|
||||
<Character name ="charybdis" humanoid="false" health="1000.0" bleedingdecreasespeed="0.2">
|
||||
|
||||
<sound file="Content/Characters/Charybdis/charybdisattack.ogg" state="Attack" range="8000" />
|
||||
|
||||
<ai
|
||||
combatstrength="1500"
|
||||
attackpriorityhumans="100.0"
|
||||
attackpriorityrooms="50.0"
|
||||
attackpriorityweaker="50"
|
||||
attackprioritystronger="-30"
|
||||
eatpriority="40"
|
||||
sight="0.5"
|
||||
hearing="1.0"/>
|
||||
|
||||
<ragdoll waveamplitude="150.0" wavelength="10000" swimspeed="4.0" scale="1.5" canentersubmarine="false">
|
||||
<ragdoll
|
||||
waveamplitude="150.0"
|
||||
wavelength="10000"
|
||||
steertorque="1000"
|
||||
swimspeed="4.0"
|
||||
scale="1.5"
|
||||
canentersubmarine="false">
|
||||
|
||||
<collider radius="80" height="440"/>
|
||||
|
||||
<!-- body -->
|
||||
<limb id = "0" radius="100" height="470" type="Torso" steerforce="1.0">
|
||||
<limb id = "0" radius="100" height="470" type="Torso" steerforce="1.0" mouthpos="0,260">
|
||||
<sprite texture="Content/Characters/Charybdis/charybdis.png" sourcerect="160,0,242,688" depth="0.015" origin="0.5,0.5"/>
|
||||
</limb>
|
||||
|
||||
<!-- lower yaw -->
|
||||
<limb id = "1" radius="70" height="100">
|
||||
<sprite texture="Content/Characters/Charybdis/charybdis.png" sourcerect="416,0,192,256" depth="0.025" origin="0.65,0.5"/>
|
||||
<attack range="500" duration="0.5" damage="5.00" bleedingdamage="50" structuredamage="500" damagetype="slash" torque="200" force="50" targetforce="-50"/>
|
||||
<attack range="500" duration="0.5" damage="5.00" bleedingdamage="50" structuredamage="500" damagetype="slash" torque="200" force="50" targetforce="-50" severlimbsprobability="1.0"/>
|
||||
</limb>
|
||||
|
||||
<!-- front fins -->
|
||||
@@ -24,18 +40,25 @@
|
||||
</limb>
|
||||
|
||||
<!-- tail -->
|
||||
<limb id = "3" radius="80" height="580" type="Tail">
|
||||
<sprite texture="Content/Characters/Charybdis/charybdis.png" sourcerect="0,0,160,752" depth="0.02" origin="0.5,0.5"/>
|
||||
<limb id = "3" radius="60" height="250" type="Tail">
|
||||
<sprite texture="Content/Characters/Charybdis/charybdis.png" sourcerect="0,0,160,379" depth="0.02" origin="0.5,0.5"/>
|
||||
</limb>
|
||||
<limb id = "4" radius="30" height="168" type="Tail">
|
||||
<sprite texture="Content/Characters/Charybdis/charybdis.png" sourcerect="24,402,83,228" depth="0.02" origin="0.5,0.5"/>
|
||||
</limb>
|
||||
<limb id = "5" radius="20" height="200" type="Tail">
|
||||
<sprite texture="Content/Characters/Charybdis/charybdis.png" sourcerect="33,645,77,244" depth="0.02" origin="0.5,0.5"/>
|
||||
</limb>
|
||||
|
||||
|
||||
<!-- body to lower yaw -->
|
||||
<joint limb1="0" limb1anchor="48,128" limb2="1" limb2anchor="-30,-90" lowerlimit="-10" upperlimit="30"/>
|
||||
<!-- body to front fin -->
|
||||
<joint limb1="0" limb1anchor="32,-32" limb2="2" limb2anchor="-32,260" lowerlimit="-50" upperlimit="0"/>
|
||||
<!-- body to tail -->
|
||||
<joint limb1="0" limb1anchor="0,-270" limb2="3" limb2anchor="0,280" lowerlimit="-20" upperlimit="20"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="0,-270" limb2="3" limb2anchor="2,134" lowerlimit="-30" upperlimit="30"/>
|
||||
<joint limb1="3" limb1anchor="-10,-153" limb2="4" limb2anchor="6,88" lowerlimit="-30" upperlimit="30"/>
|
||||
<joint limb1="4" limb1anchor="-14,-95" limb2="5" limb2anchor="-18,108" lowerlimit="-30" upperlimit="30"/>
|
||||
</ragdoll>
|
||||
|
||||
<ai attackhumans="100.0" attackrooms="50.0" attackweaker="50" attackstronger="-30" sight="0.5" hearing="1.0"/>
|
||||
</Character>
|
||||
@@ -5,19 +5,35 @@
|
||||
<sound file="Content/Characters/Coelanth/idle1.ogg" state="None" />
|
||||
<sound file="Content/Characters/Coelanth/idle2.ogg" state="None" />
|
||||
|
||||
<ragdoll waveamplitude="50.0" wavelength="2500" swimspeed="5.0" walkspeed="3.5" canentersubmarine="false">
|
||||
<ai
|
||||
combatstrength="400"
|
||||
attackpriorityhumans="90.0"
|
||||
attackpriorityrooms="50.0"
|
||||
attackpriorityweaker="50"
|
||||
attackprioritystronger="-100"
|
||||
eatpriority="40"
|
||||
sight="0.1"
|
||||
hearing="1.0"/>
|
||||
|
||||
<ragdoll
|
||||
waveamplitude="50.0"
|
||||
wavelength="2500"
|
||||
steertorque="500"
|
||||
swimspeed="5.0"
|
||||
walkspeed="3.5"
|
||||
canentersubmarine="false">
|
||||
|
||||
<collider radius="50" height="250"/>
|
||||
|
||||
<!-- head -->
|
||||
<limb id = "0" radius="50" height="270" type="Head" steerforce="1.0">
|
||||
<limb id = "0" radius="50" height="270" type="Head" steerforce="1.0" mouthpos="50,75">
|
||||
<sprite texture="Content/Characters/Coelanth/coelanth.png" sourcerect="267,171,162,392" depth="0.02" origin ="0.5,0.5"/>
|
||||
</limb>
|
||||
|
||||
<!-- lower yaw -->
|
||||
<limb id = "1" radius="20" height="240">
|
||||
<sprite texture="Content/Characters/Coelanth/coelanth.png" sourcerect="425,1,101,309" depth="0.025" origin="0.5,0.5"/>
|
||||
<attack range="300" duration="0.5" damage="200" bleedingdamage="50" structuredamage="150" damagetype="slash" torque="100" targetforce="-50"/>
|
||||
<attack range="300" duration="0.5" damage="200" bleedingdamage="50" structuredamage="150" damagetype="slash" torque="100" targetforce="-50" severlimbsprobability="0.8"/>
|
||||
</limb>
|
||||
|
||||
<!-- body -->
|
||||
@@ -51,10 +67,7 @@
|
||||
<joint limb1="2" limb1anchor="65,100" limb2="4" limb2anchor="0,160" lowerlimit="-50" upperlimit="0"/>
|
||||
|
||||
<!-- body to back fin -->
|
||||
<joint limb1="2" limb1anchor="46,-48" limb2="5" limb2anchor="0,55" lowerlimit="-50" upperlimit="0"/>
|
||||
|
||||
|
||||
<joint limb1="2" limb1anchor="46,-48" limb2="5" limb2anchor="0,55" lowerlimit="-50" upperlimit="0"/>
|
||||
</ragdoll>
|
||||
|
||||
<ai attackhumans="100.0" attackrooms="50.0" attackweaker="50" attackstronger="-30" sight="0.1" hearing="1.0"/>
|
||||
|
||||
</Character>
|
||||
@@ -1,14 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Character name ="crawler" humanoid="false">
|
||||
<Character name ="crawler" humanoid="false" health="100">
|
||||
<sound file="Content/Characters/Crawler/attack1.ogg" state="Attack" range="500"/>
|
||||
<sound file="Content/Characters/Crawler/attack2.ogg" state="Attack" range="500"/>
|
||||
|
||||
<sound file="Content/Characters/Crawler/idle1.ogg" state="None" range="500"/>
|
||||
<sound file="Content/Characters/Crawler/idle2.ogg" state="None" range="500"/>
|
||||
|
||||
<ai
|
||||
combatstrength="100"
|
||||
attackpriorityhumans="500"
|
||||
attackpriorityrooms="50.0"
|
||||
attackpriorityweaker="50"
|
||||
attackprioritystronger="-60"
|
||||
eatpriority="55"
|
||||
sight="0.5"
|
||||
hearing="1.0"
|
||||
fleehealththreshold="10"
|
||||
attachtowalls="true"
|
||||
attackcooldown="3.0"/>
|
||||
|
||||
<ragdoll headposition="50" headangle="-70"
|
||||
waveamplitude="2.0" wavelength="5000"
|
||||
swimspeed="3.0" walkspeed="2.0"
|
||||
waveamplitude="2.0" wavelength="3000"
|
||||
swimspeed="2.0" walkspeed="2.0"
|
||||
runspeedmultiplier="2" swimspeedmultiplier="2.0"
|
||||
stepsize ="15.0,20.0"
|
||||
legtorque="10"
|
||||
flip="true">
|
||||
@@ -16,7 +30,7 @@
|
||||
<collider width="45" radius="22"/>
|
||||
|
||||
<!-- head -->
|
||||
<limb id = "0" radius="22" height="45" type="Head" flip="true" steerforce="1.0" armorsector="0.0,180.0" armorvalue="30.0">
|
||||
<limb id = "0" radius="22" height="45" type="Head" flip="true" steerforce="1.0" armorsector="0.0,180.0" armorvalue="30.0" mouthpos="17,35">
|
||||
<sprite texture="Content/Characters/Crawler/crawler.png" sourcerect="0,0,51,121" depth="0.02" origin="0.45,0.63"/>
|
||||
</limb>
|
||||
|
||||
@@ -32,7 +46,9 @@
|
||||
|
||||
<limb id = "3" width="13" height="45" ignorecollisions="true" flip="true">
|
||||
<sprite texture="Content/Characters/Crawler/crawler.png" sourcerect="65,131,36,50" depth="0.15" origin="0.4,0.5"/>
|
||||
<attack range="120" duration="0.5" damage="30" stun="0.1" bleedingdamage="3" structuredamage="50" damagetype="slash" force="20" torque="-20" targetforce="-30"/>
|
||||
<attack range="120" duration="0.5" damage="30" stun="0.1" bleedingdamage="3" structuredamage="50"
|
||||
damagetype="slash" targetforce="-30" severlimbsprobability="0.5"
|
||||
force="5" applyforceonlimbs="0" torque="-20" />
|
||||
</limb>
|
||||
|
||||
<limb id = "4" width="11" height="34" type="RightLeg" flip="true">
|
||||
@@ -59,25 +75,21 @@
|
||||
<sound file ="Content/Sounds/stepMetal.ogg"/>
|
||||
</limb>
|
||||
|
||||
<joint limb1="0" limb1anchor="-5,-38" limb2="1" limb2anchor="-2,25" lowerlimit="-20" upperlimit="40"/>
|
||||
<joint limb1="0" limb1anchor="-5,-38" limb2="1" limb2anchor="-2,25" lowerlimit="-20" upperlimit="40" canbesevered="true"/>
|
||||
|
||||
<joint limb1="1" limb1anchor="0,-15" limb2="2" limb2anchor="-10,31" lowerlimit="-20" upperlimit="40"/>
|
||||
<joint limb1="1" limb1anchor="0,-15" limb2="2" limb2anchor="-10,31" lowerlimit="-20" upperlimit="40" canbesevered="true"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="7,30" limb2="3" limb2anchor="-2,-17" lowerlimit="-180" upperlimit="-90"/>
|
||||
<joint limb1="0" limb1anchor="7,30" limb2="3" limb2anchor="-2,-17" lowerlimit="-180" upperlimit="-90" canbesevered="true"/>
|
||||
|
||||
|
||||
<joint limb1="0" limb1anchor="13,6" limb2="4" limb2anchor="0,14" lowerlimit="-270" upperlimit="-180"/>
|
||||
<joint limb1="4" limb1anchor="0,-17" limb2="5" limb2anchor="0,-17" lowerlimit="-350" upperlimit="-190"/>
|
||||
<joint limb1="0" limb1anchor="13,6" limb2="4" limb2anchor="0,14" lowerlimit="-270" upperlimit="-180" canbesevered="true"/>
|
||||
<joint limb1="4" limb1anchor="0,-17" limb2="5" limb2anchor="0,-17" lowerlimit="-350" upperlimit="-190" canbesevered="true"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="13,-15" limb2="6" limb2anchor="0,14" lowerlimit="-270" upperlimit="-180"/>
|
||||
<joint limb1="6" limb1anchor="0,-17" limb2="7" limb2anchor="0,-17" lowerlimit="-350" upperlimit="-190"/>
|
||||
<joint limb1="0" limb1anchor="13,-15" limb2="6" limb2anchor="0,14" lowerlimit="-270" upperlimit="-180" canbesevered="true"/>
|
||||
<joint limb1="6" limb1anchor="0,-17" limb2="7" limb2anchor="0,-17" lowerlimit="-350" upperlimit="-190" canbesevered="true"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="13,-35" limb2="8" limb2anchor="0,14" lowerlimit="-270" upperlimit="-180"/>
|
||||
<joint limb1="8" limb1anchor="0,-17" limb2="9" limb2anchor="0,-17" lowerlimit="-350" upperlimit="-190"/>
|
||||
<joint limb1="0" limb1anchor="13,-35" limb2="8" limb2anchor="0,14" lowerlimit="-270" upperlimit="-180" canbesevered="true"/>
|
||||
<joint limb1="8" limb1anchor="0,-17" limb2="9" limb2anchor="0,-17" lowerlimit="-350" upperlimit="-190" canbesevered="true"/>
|
||||
</ragdoll>
|
||||
|
||||
<ai attackhumans="500" attackrooms="50.0" attackweaker="50" attackstronger="-30"
|
||||
sight="0.5" hearing="1.0"
|
||||
attackcooldown="3.0"/>
|
||||
</Character>
|
||||
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Character name ="endworm" humanoid="false" health="10000.0" doesbleed="false">
|
||||
|
||||
|
||||
<sound file="Content/Characters/Endworm/endwormidle.ogg" state="None" range="8000" />
|
||||
<sound file="Content/Characters/Endworm/endwormattack1.ogg" state="Attack" range="8000" />
|
||||
<sound file="Content/Characters/Endworm/endwormattack2.ogg" state="Attack" range="8000" />
|
||||
|
||||
<ai
|
||||
combatstrength="10000"
|
||||
attackpriorityrooms="100.0"
|
||||
attackpriorityweaker="0"
|
||||
attackstronger="-30"
|
||||
sight="0.1"
|
||||
hearing="2.0"/>
|
||||
|
||||
<ragdoll waveamplitude="100.0" wavelength="1000" speed="2.0" scale ="2.0" flip="false" canentersubmarine="false">
|
||||
|
||||
<collider radius="300"/>
|
||||
@@ -75,6 +83,5 @@
|
||||
<joint limb1="0" limb1anchor="160,50" limb2="9" limb2anchor="0,-200" lowerlimit="-50" upperlimit="20"/>
|
||||
</ragdoll>
|
||||
|
||||
<ai attackrooms="100.0" attackweaker="50" attackstronger="-30" sight="0.1" hearing="2.0"/>
|
||||
</Character>
|
||||
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
<sound file="Content/Characters/Fractalguardian/guardian2.ogg" state="Attack" range="3000" />
|
||||
<sound file="Content/Characters/Fractalguardian/Die1.ogg" state="Die" range="3000" />
|
||||
<sound file="Content/Characters/Fractalguardian/Die2.ogg" state="Die" range="3000" />
|
||||
|
||||
<ai
|
||||
combatstrength="500"
|
||||
attackpriorityrooms="0.0"
|
||||
attackpriorityhumans="100"
|
||||
sight="1.0"
|
||||
hearing="2.0"
|
||||
attackcooldown="1"/>
|
||||
|
||||
<ragdoll waveamplitude="50.0" wavelength="500" swimspeed="3.0" walkspeed="0.3" flip="false" canentersubmarine="false">
|
||||
|
||||
@@ -41,16 +49,15 @@
|
||||
|
||||
|
||||
<!-- head to body -->
|
||||
<joint limb1="0" limb1anchor="0,-60" limb2="1" limb2anchor="0,30" lowerlimit="-30" upperlimit="30"/>
|
||||
<joint limb1="0" limb1anchor="0,-60" limb2="1" limb2anchor="0,30" lowerlimit="-30" upperlimit="30" canbesevered="true"/>
|
||||
|
||||
<joint limb1="1" limb1anchor="0,-47" limb2="2" limb2anchor="0,56" lowerlimit="-30" upperlimit="30"/>
|
||||
<joint limb1="1" limb1anchor="0,-47" limb2="2" limb2anchor="0,56" lowerlimit="-30" upperlimit="30" canbesevered="true"/>
|
||||
|
||||
<joint limb1="2" limb1anchor="0,-60" limb2="3" limb2anchor="0,80" lowerlimit="-30" upperlimit="30"/>
|
||||
<joint limb1="2" limb1anchor="0,-60" limb2="3" limb2anchor="0,80" lowerlimit="-30" upperlimit="30" canbesevered="true"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="30,10" limb2="4" limb2anchor="0,-110" lowerlimit="-180" upperlimit="-90"/>
|
||||
<joint limb1="0" limb1anchor="-30,10" limb2="5" limb2anchor="0,-110" lowerlimit="90" upperlimit="180"/>
|
||||
<joint limb1="0" limb1anchor="30,10" limb2="4" limb2anchor="0,-110" lowerlimit="-180" upperlimit="-90" canbesevered="true"/>
|
||||
<joint limb1="0" limb1anchor="-30,10" limb2="5" limb2anchor="0,-110" lowerlimit="90" upperlimit="180" canbesevered="true"/>
|
||||
</ragdoll>
|
||||
|
||||
<ai attackrooms="0.0" attackhumans="100" sight="1.0" hearing="2.0" attackcooldown="1"/>
|
||||
</Character>
|
||||
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
<sound file="Content/Characters/Fractalguardian/guardian2.ogg" state="Attack" range="3000" />
|
||||
<sound file="Content/Characters/Fractalguardian/Die1.ogg" state="Die" range="3000" />
|
||||
<sound file="Content/Characters/Fractalguardian/Die2.ogg" state="Die" range="3000" />
|
||||
|
||||
<ai
|
||||
combatstrength="500"
|
||||
attackpriorityrooms="0.0"
|
||||
attackpriorityhumans="100"
|
||||
sight="1.0"
|
||||
hearing="2.0"
|
||||
attackcooldown="1"/>
|
||||
|
||||
<ragdoll waveamplitude="0.0" swimspeed="1.0" walkspeed="0.3" flip="false" canentersubmarine="false" rotatetowardsmovement="false">
|
||||
|
||||
@@ -32,19 +40,16 @@
|
||||
<limb id = "4" width="30" height="175">
|
||||
<sprite texture="Content/Characters/Fractalguardian/fractalguardian.png" sourcerect="131,0,36,175" depth="0.1" origin="0.5,0.5"/>
|
||||
<attack range="150" duration="0.5" damage="30" stun="1.0" torque="-150" damagetype="slash"/>
|
||||
</limb>
|
||||
|
||||
</limb>
|
||||
|
||||
<!-- head to body -->
|
||||
<joint limb1="0" limb1anchor="-37,-40" limb2="1" limb2anchor="0,80" lowerlimit="-60" upperlimit="0"/>
|
||||
<joint limb1="1" limb1anchor="0,-80" limb2="2" limb2anchor="0,80" lowerlimit="0" upperlimit="120"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="37,-40" limb2="3" limb2anchor="0,80" lowerlimit="0" upperlimit="60"/>
|
||||
<joint limb1="3" limb1anchor="0,-80" limb2="4" limb2anchor="0,80" lowerlimit="-120" upperlimit="0"/>
|
||||
<joint limb1="0" limb1anchor="-37,-40" limb2="1" limb2anchor="0,80" lowerlimit="-60" upperlimit="0" canbesevered="true"/>
|
||||
<joint limb1="1" limb1anchor="0,-80" limb2="2" limb2anchor="0,80" lowerlimit="0" upperlimit="120" canbesevered="true"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="37,-40" limb2="3" limb2anchor="0,80" lowerlimit="0" upperlimit="60" canbesevered="true"/>
|
||||
<joint limb1="3" limb1anchor="0,-80" limb2="4" limb2anchor="0,80" lowerlimit="-120" upperlimit="0" canbesevered="true"/>
|
||||
|
||||
</ragdoll>
|
||||
|
||||
<ai attackrooms="0.0" attackhumans="100" sight="1.0" hearing="2.0" attackcooldown="1"/>
|
||||
</Character>
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
movementlerp="0.4"
|
||||
legtorque="15.0"
|
||||
thightorque="-5.0"
|
||||
walkspeed="1.5"
|
||||
swimspeed="2.0"
|
||||
walkspeed="1.5" swimspeed="2.0"
|
||||
runspeedmultiplier="3.0" swimspeedmultiplier="1.5"
|
||||
colliderheightfromfloor="55"
|
||||
impacttolerance="7.5">
|
||||
|
||||
@@ -84,25 +84,25 @@
|
||||
</limb>
|
||||
|
||||
<!-- head to body -->
|
||||
<joint limb1="0" limb1anchor="0,-7" limb2="1" limb2anchor="-1,26" lowerlimit="-90" upperlimit="45"/>
|
||||
<joint limb1="0" limb1anchor="0,-7" limb2="1" limb2anchor="-1,26" lowerlimit="-90" upperlimit="45" canbesevered="true"/>
|
||||
<joint limb1="1" limb1anchor="0,-17" limb2="12" limb2anchor="0,7" lowerlimit="-10" upperlimit="10"/>
|
||||
|
||||
<!-- body to left arm -->
|
||||
<joint limb1="1" limb1anchor="-3,14" limb2="2" limb2anchor="0,12"/>
|
||||
<joint limb1="2" limb1anchor="0,-16" limb2="3" limb2anchor="-2,19" lowerlimit="5" upperlimit="170"/>
|
||||
<joint limb1="2" limb1anchor="0,-16" limb2="3" limb2anchor="-2,19" lowerlimit="5" upperlimit="170" canbesevered="true"/>
|
||||
<!-- body to right arm -->
|
||||
<joint limb1="1" limb1anchor="-3,14" limb2="4" limb2anchor="0,12"/>
|
||||
<joint limb1="4" limb1anchor="0,-16" limb2="5" limb2anchor="-2,19" lowerlimit="5" upperlimit="170"/>
|
||||
<joint limb1="4" limb1anchor="0,-16" limb2="5" limb2anchor="-2,19" lowerlimit="5" upperlimit="170" canbesevered="true"/>
|
||||
|
||||
<!-- body to left leg -->
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="6" limb2anchor="0,14" lowerlimit="-30" upperlimit="120"/>
|
||||
<joint limb1="6" limb1anchor="0,-15" limb2="7" limb2anchor="0,20" lowerlimit="-120" upperlimit="0"/>
|
||||
<joint limb1="7" limb1anchor="-3,-21" limb2="8" limb2anchor="5,7" lowerlimit="20" upperlimit="90"/>
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="6" limb2anchor="0,14" lowerlimit="-30" upperlimit="120" canbesevered="true"/>
|
||||
<joint limb1="6" limb1anchor="0,-15" limb2="7" limb2anchor="0,20" lowerlimit="-120" upperlimit="0" canbesevered="true"/>
|
||||
<joint limb1="7" limb1anchor="-3,-21" limb2="8" limb2anchor="5,7" lowerlimit="20" upperlimit="90" canbesevered="true"/>
|
||||
|
||||
<!-- body to right leg -->
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="9" limb2anchor="0,14" lowerlimit="-30" upperlimit="120"/>
|
||||
<joint limb1="9" limb1anchor="0,-15" limb2="10" limb2anchor="0,20" lowerlimit="-120" upperlimit="0"/>
|
||||
<joint limb1="10" limb1anchor="-3,-21" limb2="11" limb2anchor="5,7" lowerlimit="20" upperlimit="90"/>
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="9" limb2anchor="0,14" lowerlimit="-30" upperlimit="120" canbesevered="true"/>
|
||||
<joint limb1="9" limb1anchor="0,-15" limb2="10" limb2anchor="0,20" lowerlimit="-120" upperlimit="0" canbesevered="true"/>
|
||||
<joint limb1="10" limb1anchor="-3,-21" limb2="11" limb2anchor="5,7" lowerlimit="20" upperlimit="90" canbesevered="true"/>
|
||||
|
||||
</ragdoll>
|
||||
</Character>
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
movementlerp="0.4"
|
||||
legtorque="15.0"
|
||||
thightorque="-5.0"
|
||||
walkspeed="1.5"
|
||||
swimspeed="2.5"
|
||||
walkspeed="1.5" swimspeed="2.5"
|
||||
runspeedmultiplier="2.0" swimspeedmultiplier="1.5"
|
||||
impacttolerance="7.5">
|
||||
|
||||
<collider height="80" radius="15"/>
|
||||
<collider height="40" radius="15"/>
|
||||
<collider height="40" radius="15"/>
|
||||
|
||||
<!-- head -->
|
||||
<limb id = "0" radius="13" mass = "6" type="Head" attackpriority="2">
|
||||
@@ -84,34 +84,35 @@
|
||||
|
||||
<limb id = "13" width="10" height="30" mass = "6" attackpriority="2" flip="true" pullpos="0.0,25.0">
|
||||
<sprite texture="Content/Characters/Husk/DivingSuit.png" sourcerect="110,76,18,52" depth="0.5" origin="0.5,0.5"/>
|
||||
<attack range="70" duration="0.1" bleedingdamage="3" damage="10" stun="0.5" torque="-50" damagetype="slash" targetforce="10">
|
||||
<attack range="70" duration="0.1" bleedingdamage="3" damage="10" stun="0.5" damagetype="slash" targetforce="10"
|
||||
force="5" applyforceonlimbs="1" torque="-10">
|
||||
<StatusEffect type="OnUse" target="Character" HuskInfectionState="0.01" disabledeltatime="true"/>
|
||||
<StatusEffect type="OnUse" target="This" Health="20.0" disabledeltatime="true"/>
|
||||
</attack>
|
||||
</limb>
|
||||
|
||||
<!-- head to body -->
|
||||
<joint limb1="0" limb1anchor="0,-7" limb2="1" limb2anchor="-1,26" lowerlimit="-90" upperlimit="45"/>
|
||||
<joint limb1="0" limb1anchor="0,-7" limb2="1" limb2anchor="-1,26" lowerlimit="-90" upperlimit="45" canbesevered="true"/>
|
||||
<joint limb1="1" limb1anchor="0,-17" limb2="12" limb2anchor="0,7" lowerlimit="-10" upperlimit="10"/>
|
||||
|
||||
<!-- body to left arm -->
|
||||
<joint limb1="1" limb1anchor="-3,14" limb2="2" limb2anchor="0,12"/>
|
||||
<joint limb1="2" limb1anchor="0,-16" limb2="3" limb2anchor="-2,19" lowerlimit="5" upperlimit="170"/>
|
||||
<joint limb1="2" limb1anchor="0,-16" limb2="3" limb2anchor="-2,19" lowerlimit="5" upperlimit="170" canbesevered="true"/>
|
||||
<!-- body to right arm -->
|
||||
<joint limb1="1" limb1anchor="-3,14" limb2="4" limb2anchor="0,12"/>
|
||||
<joint limb1="4" limb1anchor="0,-16" limb2="5" limb2anchor="-2,19" lowerlimit="5" upperlimit="170"/>
|
||||
<joint limb1="4" limb1anchor="0,-16" limb2="5" limb2anchor="-2,19" lowerlimit="5" upperlimit="170" canbesevered="true"/>
|
||||
|
||||
<!-- body to left leg -->
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="6" limb2anchor="0,14" lowerlimit="-30" upperlimit="120"/>
|
||||
<joint limb1="6" limb1anchor="0,-15" limb2="7" limb2anchor="0,20" lowerlimit="-120" upperlimit="0"/>
|
||||
<joint limb1="7" limb1anchor="-3,-21" limb2="8" limb2anchor="5,7" lowerlimit="20" upperlimit="90"/>
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="6" limb2anchor="0,14" lowerlimit="-30" upperlimit="120" canbesevered="true"/>
|
||||
<joint limb1="6" limb1anchor="0,-15" limb2="7" limb2anchor="0,20" lowerlimit="-120" upperlimit="0" canbesevered="true"/>
|
||||
<joint limb1="7" limb1anchor="-3,-21" limb2="8" limb2anchor="5,7" lowerlimit="20" upperlimit="90" canbesevered="true"/>
|
||||
|
||||
<!-- body to right leg -->
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="9" limb2anchor="0,14" lowerlimit="-30" upperlimit="120"/>
|
||||
<joint limb1="9" limb1anchor="0,-15" limb2="10" limb2anchor="0,20" lowerlimit="-120" upperlimit="0"/>
|
||||
<joint limb1="10" limb1anchor="-3,-21" limb2="11" limb2anchor="5,7" lowerlimit="20" upperlimit="90"/>
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="9" limb2anchor="0,14" lowerlimit="-30" upperlimit="120" canbesevered="true"/>
|
||||
<joint limb1="9" limb1anchor="0,-15" limb2="10" limb2anchor="0,20" lowerlimit="-120" upperlimit="0" canbesevered="true"/>
|
||||
<joint limb1="10" limb1anchor="-3,-21" limb2="11" limb2anchor="5,7" lowerlimit="20" upperlimit="90" canbesevered="true"/>
|
||||
|
||||
<joint limb1="1" limb1anchor="25,10" limb2="13" limb2anchor="25,0" lowerlimit="-40" upperlimit="0"/>
|
||||
<joint limb1="1" limb1anchor="25,10" limb2="13" limb2anchor="25,0" lowerlimit="-40" upperlimit="0" canbesevered="true"/>
|
||||
|
||||
</ragdoll>
|
||||
|
||||
|
||||
@@ -5,28 +5,38 @@
|
||||
<sound file="Content/Characters/Husk/Husk2.ogg" state="Attack" range="1000"/>
|
||||
<sound file="Content/Characters/Husk/Husk3.ogg" state="Attack" range="1000"/>
|
||||
|
||||
<ai
|
||||
combatstrength="100"
|
||||
attackpriorityhumans="500"
|
||||
attackpriorityrooms="5.0"
|
||||
attackpriorityweaker="50"
|
||||
attackprioritystronger="-30"
|
||||
sight="0.5"
|
||||
hearing="1.0"
|
||||
attackcooldown="1.0"/>
|
||||
|
||||
<ragdoll headposition="134" torsoposition="108"
|
||||
stepsize="42.0, 12.0"
|
||||
walkanimspeed="4.58"
|
||||
movementlerp="0.4"
|
||||
legtorque="15.0"
|
||||
thightorque="-5.0"
|
||||
walkspeed="1.2"
|
||||
swimspeed="2.5">
|
||||
walkspeed="1.2" swimspeed="2.5"
|
||||
runspeedmultiplier="2.0" swimspeedmultiplier="1.5">
|
||||
|
||||
<collider height="80" radius="15"/>
|
||||
<collider height="40" radius="15"/>
|
||||
<collider height="40" radius="15"/>
|
||||
|
||||
<!-- head -->
|
||||
<limb id = "0" radius="13" mass = "6" type="Head" attackpriority="2">
|
||||
<sprite texture="Content/Characters/Husk/DivingSuit.png" sourcerect="95,0,33,25" depth="0.04" origin="0.5,0.5"/>
|
||||
</limb>
|
||||
|
||||
|
||||
<!-- spike/tentacle thingy -->
|
||||
<limb id = "13" width="10" height="30" mass = "6" attackpriority="2" flip="true" pullpos="0.0,25.0">
|
||||
<sprite texture="Content/Characters/Husk/DivingSuit.png" sourcerect="110,76,18,52" depth="0.05" origin="0.5,0.5"/>
|
||||
<attack range="70" duration="0.2" bleedingdamage="0.5" damage="10" stun="0.5" force="1" torque="-50" damagetype="slash" targetforce="10">
|
||||
<attack range="70" duration="0.2" bleedingdamage="0.5" damage="10" stun="0.5" damagetype="slash" targetforce="10"
|
||||
force="5" applyforceonlimbs="1" torque="-10">
|
||||
<StatusEffect type="OnUse" target="Character" HuskInfectionState="0.01" disabledeltatime="true"/>
|
||||
<StatusEffect type="OnUse" target="This" Health="1.0" disabledeltatime="true"/>
|
||||
</attack>
|
||||
@@ -82,7 +92,7 @@
|
||||
</limb>
|
||||
|
||||
<!-- head to body -->
|
||||
<joint limb1="0" limb1anchor="-10,-10" limb2="1" limb2anchor="-3,28" lowerlimit="0" upperlimit="10"/>
|
||||
<joint limb1="0" limb1anchor="-10,-10" limb2="1" limb2anchor="-3,28" lowerlimit="0" upperlimit="10" canbesevered="true"/>
|
||||
<!-- spike to head -->
|
||||
<joint limb1="0" limb1anchor="35,-8" limb2="13" limb2anchor="30,0" lowerlimit="-40" upperlimit="0"/>
|
||||
|
||||
@@ -90,26 +100,21 @@
|
||||
|
||||
<!-- body to left arm -->
|
||||
<joint limb1="1" limb1anchor="-3,14" limb2="2" limb2anchor="0,12"/>
|
||||
<joint limb1="2" limb1anchor="0,-16" limb2="3" limb2anchor="-2,19" lowerlimit="0" upperlimit="170"/>
|
||||
<joint limb1="2" limb1anchor="0,-16" limb2="3" limb2anchor="-2,19" lowerlimit="0" upperlimit="170" canbesevered="true"/>
|
||||
<!-- body to right arm -->
|
||||
<joint limb1="1" limb1anchor="-3,14" limb2="4" limb2anchor="0,12"/>
|
||||
<joint limb1="4" limb1anchor="0,-16" limb2="5" limb2anchor="-2,19" lowerlimit="0" upperlimit="170"/>
|
||||
<joint limb1="4" limb1anchor="0,-16" limb2="5" limb2anchor="-2,19" lowerlimit="0" upperlimit="170" canbesevered="true"/>
|
||||
|
||||
<!-- body to left leg -->
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="6" limb2anchor="0,14" lowerlimit="-30" upperlimit="120"/>
|
||||
<joint limb1="6" limb1anchor="0,-15" limb2="7" limb2anchor="0,20" lowerlimit="-150" upperlimit="-10"/>
|
||||
<joint limb1="7" limb1anchor="-3,-21" limb2="8" limb2anchor="5,7" lowerlimit="20" upperlimit="90"/>
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="6" limb2anchor="0,14" lowerlimit="-30" upperlimit="120" canbesevered="true"/>
|
||||
<joint limb1="6" limb1anchor="0,-15" limb2="7" limb2anchor="0,20" lowerlimit="-150" upperlimit="-10" canbesevered="true"/>
|
||||
<joint limb1="7" limb1anchor="-3,-21" limb2="8" limb2anchor="5,7" lowerlimit="20" upperlimit="90" canbesevered="true"/>
|
||||
|
||||
<!-- body to right leg -->
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="9" limb2anchor="0,14" lowerlimit="-30" upperlimit="120"/>
|
||||
<joint limb1="9" limb1anchor="0,-15" limb2="10" limb2anchor="0,20" lowerlimit="-150" upperlimit="-10"/>
|
||||
<joint limb1="10" limb1anchor="-3,-21" limb2="11" limb2anchor="5,7" lowerlimit="20" upperlimit="90"/>
|
||||
|
||||
<joint limb1="12" limb1anchor="0,-1" limb2="9" limb2anchor="0,14" lowerlimit="-30" upperlimit="120" canbesevered="true"/>
|
||||
<joint limb1="9" limb1anchor="0,-15" limb2="10" limb2anchor="0,20" lowerlimit="-150" upperlimit="-10" canbesevered="true"/>
|
||||
<joint limb1="10" limb1anchor="-3,-21" limb2="11" limb2anchor="5,7" lowerlimit="20" upperlimit="90" canbesevered="true"/>
|
||||
</ragdoll>
|
||||
|
||||
|
||||
<ai attackhumans="500" attackrooms="5.0" attackweaker="50" attackstronger="-30"
|
||||
sight="0.5" hearing="1.0"
|
||||
attackcooldown="1.0"/>
|
||||
</Character>
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 88 KiB |
@@ -7,10 +7,24 @@
|
||||
<sound file="Content/Characters/Mantis/idle1.ogg" state="None" range="500"/>
|
||||
<sound file="Content/Characters/Mantis/idle2.ogg" state="None" range="500"/>
|
||||
<sound file="Content/Characters/Mantis/idle3.ogg" state="None" range="500"/>
|
||||
|
||||
<ai
|
||||
combatstrength="250"
|
||||
attackpriorityhumans="500.0"
|
||||
attackpriorityrooms="50.0"
|
||||
attackpriorityweaker="60"
|
||||
attackprioritystronger="-70"
|
||||
eatpriority="65"
|
||||
attackcooldown="1.0"
|
||||
sight="0.5"
|
||||
hearing="1.0"
|
||||
attachtowalls="true"
|
||||
fleehealththreshold="20"/>
|
||||
|
||||
<ragdoll headposition="120" headangle="-90"
|
||||
waveamplitude="50.0" wavelength="2500"
|
||||
swimspeed="2.0" walkspeed="3.0"
|
||||
swimspeed="2.0" walkspeed="2.0"
|
||||
runspeedmultiplier="1.5" swimspeedmultiplier="1.5"
|
||||
stepsize ="20.0,20.0"
|
||||
legtorque="10"
|
||||
footrotation ="180.0"
|
||||
@@ -19,7 +33,7 @@
|
||||
<collider radius="60"/>
|
||||
|
||||
<!-- head -->
|
||||
<limb id = "0" radius="30" height="86" mass = "6" type="Head" flip="true" steerforce="1.0" armorsector="0.0,180.0" armor="10.0">
|
||||
<limb id = "0" radius="30" height="86" mass = "6" type="Head" flip="true" steerforce="1.0" armorsector="0.0,180.0" armor="10.0" mouthpos="30,65">
|
||||
<sprite texture="Content/Characters/Mantis/mantis.png" sourcerect="0,0,101,168" depth="0.02" origin="0.4,0.53"/>
|
||||
</limb>
|
||||
|
||||
@@ -35,7 +49,7 @@
|
||||
|
||||
<!-- tail -->
|
||||
<limb id = "3" radius="20" mass = "6" type="Tail" flip="true" armorsector="0.0,180.0" armor="10.0">
|
||||
<sprite texture="Content/Characters/Mantis/mantis.png" sourcerect="130,158,46,93" depth="0.023" origin="0.37,0.3"/>
|
||||
<sprite texture="Content/Characters/Mantis/mantis.png" sourcerect="133,158,46,93" depth="0.023" origin="0.37,0.3"/>
|
||||
</limb>
|
||||
|
||||
|
||||
@@ -49,7 +63,8 @@
|
||||
<!-- ""claw" -->
|
||||
<limb id = "6" width="15" height="63" mass = "4" flip="true" pullpos="0.0,30.0" refjoint="0">
|
||||
<sprite texture="Content/Characters/Mantis/mantis.png" sourcerect="228,1,28,76" depth="0.01" origin="0.5,0.5"/>
|
||||
<attack range="200" duration="0.5" damage="30" stun="0.1" bleedingdamage="5" structuredamage="50" torque="-20" damagetype="slash" force="10" targetforce="-30"/>
|
||||
<attack range="200" duration="0.25" damage="50" stun="0.1" bleedingdamage="5" structuredamage="50" damagetype="slash" targetforce="-100" severlimbsprobability="0.8"
|
||||
torque="-20" force="10" applyforceonlimbs="0,1,6"/>
|
||||
<sound file ="Content/Sounds/stepMetal.ogg"/>
|
||||
</limb>
|
||||
|
||||
@@ -69,27 +84,23 @@
|
||||
<sound file ="Content/Sounds/stepMetal.ogg"/>
|
||||
</limb>
|
||||
|
||||
<joint limb1="0" limb1anchor="-5,-53" limb2="1" limb2anchor="0,20" lowerlimit="-20" upperlimit="20"/>
|
||||
<joint limb1="0" limb1anchor="-5,-53" limb2="1" limb2anchor="0,20" lowerlimit="-20" upperlimit="20" canbesevered="true"/>
|
||||
|
||||
<joint limb1="1" limb1anchor="6,-18" limb2="2" limb2anchor="-2,36" lowerlimit="-20" upperlimit="30"/>
|
||||
<joint limb1="1" limb1anchor="6,-18" limb2="2" limb2anchor="-2,36" lowerlimit="-20" upperlimit="30" canbesevered="true"/>
|
||||
|
||||
<joint limb1="2" limb1anchor="1,7" limb2="3" limb2anchor="6,15" lowerlimit="-20" upperlimit="40"/>
|
||||
<joint limb1="2" limb1anchor="1,7" limb2="3" limb2anchor="0,20" lowerlimit="-20" upperlimit="40" canbesevered="true"/>
|
||||
|
||||
|
||||
<joint limb1="0" limb1anchor="16,2" limb2="4" limb2anchor="-5,-20" lowerlimit="-90" upperlimit="0"/>
|
||||
<joint limb1="4" limb1anchor="-2,21" limb2="5" limb2anchor="-5,-20" lowerlimit="-290" upperlimit="-190"/>
|
||||
<joint limb1="5" limb1anchor="-2,27" limb2="6" limb2anchor="0,-30" lowerlimit="-190" upperlimit="-30"/>
|
||||
<joint limb1="0" limb1anchor="16,2" limb2="4" limb2anchor="-5,-20" lowerlimit="-90" upperlimit="0" canbesevered="true"/>
|
||||
<joint limb1="4" limb1anchor="-2,21" limb2="5" limb2anchor="-5,-20" lowerlimit="-290" upperlimit="-190" canbesevered="true"/>
|
||||
<joint limb1="5" limb1anchor="-2,27" limb2="6" limb2anchor="0,-30" lowerlimit="-190" upperlimit="-30" canbesevered="true"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="52,-34" limb2="7" limb2anchor="-4,-19" lowerlimit="-90" upperlimit="0"/>
|
||||
<joint limb1="7" limb1anchor="-2,28" limb2="8" limb2anchor="2,-32" lowerlimit="-190" upperlimit="-30"/>
|
||||
<joint limb1="0" limb1anchor="52,-34" limb2="7" limb2anchor="-4,-19" lowerlimit="-90" upperlimit="0" canbesevered="true"/>
|
||||
<joint limb1="7" limb1anchor="-2,28" limb2="8" limb2anchor="2,-32" lowerlimit="-190" upperlimit="-30" canbesevered="true"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="43,-67" limb2="9" limb2anchor="0,21" lowerlimit="-180" upperlimit="-10"/>
|
||||
<joint limb1="9" limb1anchor="0,-28" limb2="10" limb2anchor="-11,-46" lowerlimit="-190" upperlimit="-50"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="43,-67" limb2="9" limb2anchor="0,21" lowerlimit="-180" upperlimit="-10" canbesevered="true"/>
|
||||
<joint limb1="9" limb1anchor="0,-28" limb2="10" limb2anchor="-11,-46" lowerlimit="-190" upperlimit="-50" canbesevered="true"/>
|
||||
</ragdoll>
|
||||
|
||||
<ai attackhumans="500" attackrooms="50.0" attackweaker="50" attackstronger="-30"
|
||||
sight="0.5" hearing="1.0"
|
||||
attackcooldown="1.0"/>
|
||||
</Character>
|
||||
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
<sound file="Content/Characters/Moloch/idle1.ogg" state="None" range="3000"/>
|
||||
<sound file="Content/Characters/Moloch/idle2.ogg" state="None" range="3000"/>
|
||||
|
||||
<ai
|
||||
combatstrength="1200"
|
||||
attackpriorityhumans="40.0"
|
||||
attackpriorityrooms="50.0"
|
||||
attackprioritystronger="-100.0"
|
||||
attackcooldown="15.0"
|
||||
sight="0.5" hearing="1.0"/>
|
||||
|
||||
<ragdoll waveamplitude="0.0" swimspeed="2.0" mirror="true" rotatetowardsmovement="false" headangle="-90" canentersubmarine="false">
|
||||
|
||||
<collider radius ="230"/>
|
||||
@@ -46,22 +54,18 @@
|
||||
<sprite texture="Content/Characters/Moloch/moloch.png" sourcerect="867,474,101,550" depth="0.025" origin="0.5,0.5"/>
|
||||
</limb>
|
||||
|
||||
<joint limb1="0" limb1anchor="112,77" limb2="1" limb2anchor="0,-190" lowerlimit="-180" upperlimit="-90"/>
|
||||
<joint limb1="1" limb1anchor="0,190" limb2="2" limb2anchor="0,-100" lowerlimit="-50" upperlimit="0"/>
|
||||
<joint limb1="2" limb1anchor="0,120" limb2="3" limb2anchor="15,-250" lowerlimit="-50" upperlimit="0"/>
|
||||
<joint limb1="0" limb1anchor="112,77" limb2="1" limb2anchor="0,-190" lowerlimit="-180" upperlimit="-90" canbesevered="true"/>
|
||||
<joint limb1="1" limb1anchor="0,190" limb2="2" limb2anchor="0,-100" lowerlimit="-50" upperlimit="0" canbesevered="true"/>
|
||||
<joint limb1="2" limb1anchor="0,120" limb2="3" limb2anchor="15,-250" lowerlimit="-50" upperlimit="0" canbesevered="true"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="0,0" limb2="4" limb2anchor="0,-190" lowerlimit="-180" upperlimit="-90"/>
|
||||
<joint limb1="4" limb1anchor="0,190" limb2="5" limb2anchor="0,-100" lowerlimit="-50" upperlimit="0"/>
|
||||
<joint limb1="5" limb1anchor="0,120" limb2="6" limb2anchor="15,-250" lowerlimit="-50" upperlimit="0"/>
|
||||
<joint limb1="0" limb1anchor="0,0" limb2="4" limb2anchor="0,-190" lowerlimit="-180" upperlimit="-90" canbesevered="true"/>
|
||||
<joint limb1="4" limb1anchor="0,190" limb2="5" limb2anchor="0,-100" lowerlimit="-50" upperlimit="0" canbesevered="true"/>
|
||||
<joint limb1="5" limb1anchor="0,120" limb2="6" limb2anchor="15,-250" lowerlimit="-50" upperlimit="0" canbesevered="true"/>
|
||||
|
||||
<joint limb1="0" limb1anchor="-53,-164" limb2="7" limb2anchor="0,-190" lowerlimit="-180" upperlimit="-90"/>
|
||||
<joint limb1="7" limb1anchor="0,190" limb2="8" limb2anchor="0,-100" lowerlimit="-50" upperlimit="0"/>
|
||||
<joint limb1="8" limb1anchor="0,120" limb2="9" limb2anchor="15,-250" lowerlimit="-50" upperlimit="0"/>
|
||||
<joint limb1="0" limb1anchor="-53,-164" limb2="7" limb2anchor="0,-190" lowerlimit="-180" upperlimit="-90" canbesevered="true"/>
|
||||
<joint limb1="7" limb1anchor="0,190" limb2="8" limb2anchor="0,-100" lowerlimit="-50" upperlimit="0" canbesevered="true"/>
|
||||
<joint limb1="8" limb1anchor="0,120" limb2="9" limb2anchor="15,-250" lowerlimit="-50" upperlimit="0" canbesevered="true"/>
|
||||
|
||||
</ragdoll>
|
||||
|
||||
<ai attackhumans="100.0" attackrooms="50.0"
|
||||
attackweaker="50.0" attackstronger="-30.0"
|
||||
attackcooldown="15.0"
|
||||
sight="0.5" hearing="1.0"/>
|
||||
</Character>
|
||||
@@ -5,12 +5,27 @@
|
||||
<sound file="Content/Characters/Scorpion/scorpionidle1.ogg" state="None" />
|
||||
<sound file="Content/Characters/Scorpion/scorpionidle2.ogg" state="None" />
|
||||
|
||||
<ragdoll waveamplitude="50.0" wavelength="2500" swimspeed="4.0" walkspeed="3.5" canentersubmarine="false">
|
||||
<ai
|
||||
combatstrength="400"
|
||||
attackpriorityhumans="100.0"
|
||||
attackpriorityrooms="50.0"
|
||||
attackpriorityweaker="50"
|
||||
attackprioritystronger="-30"
|
||||
eatpriority="55"
|
||||
sight="0.5"
|
||||
hearing="1.0"/>
|
||||
|
||||
<ragdoll waveamplitude="50.0"
|
||||
wavelength="2500"
|
||||
steertorque="100"
|
||||
swimspeed="4.0"
|
||||
swimspeedmultiplier="1.5"
|
||||
canentersubmarine="false">
|
||||
|
||||
<collider radius="50" height="320"/>
|
||||
|
||||
<!-- head -->
|
||||
<limb id = "0" radius="12" height="100" type="Head" steerforce="1.0">
|
||||
<limb id = "0" radius="12" height="100" type="Head" steerforce="1.0" mouthpos="20,0">
|
||||
<sprite texture="Content/Characters/Tigerthresher/tigerthresher.png" sourcerect="371,15,66,136" depth="0.02" origin ="0.5,0.5"/>
|
||||
<damagedsprite texture="Content/Characters/Tigerthresher/damagedtigerthresher.png" sourcerect="371,15,66,136" origin ="0.5,0.5"/>
|
||||
</limb>
|
||||
@@ -19,7 +34,7 @@
|
||||
<limb id = "1" width="16" height="103">
|
||||
<sprite texture="Content/Characters/Tigerthresher/tigerthresher.png" sourcerect="391,169,28,110" depth="0.025" origin="0.5,0.5"/>
|
||||
<damagedsprite texture="Content/Characters/Tigerthresher/damagedtigerthresher.png" sourcerect="391,169,28,110" origin="0.5,0.5"/>
|
||||
<attack range="300" duration="0.5" damage="150" bleedingdamage="10" structuredamage="200" damagetype="slash" force="10" torque="80" targetforce="-50"/>
|
||||
<attack range="300" duration="0.5" damage="150" bleedingdamage="10" structuredamage="200" damagetype="slash" force="80" torque="80" targetforce="-50" severlimbsprobability="0.8"/>
|
||||
</limb>
|
||||
|
||||
<!-- body -->
|
||||
@@ -67,10 +82,8 @@
|
||||
<joint limb1="2" limb1anchor="5,-30" limb2="5" limb2anchor="7,57" lowerlimit="-50" upperlimit="0"/>
|
||||
|
||||
<!-- body to long -->
|
||||
<joint limb1="2" limb1anchor="-5,-137" limb2="6" limb2anchor="-8,132" lowerlimit="-30" upperlimit="0"/>
|
||||
|
||||
<joint limb1="2" limb1anchor="-5,-137" limb2="6" limb2anchor="-8,132" lowerlimit="-30" upperlimit="0"/>
|
||||
|
||||
</ragdoll>
|
||||
|
||||
<ai attackhumans="100.0" attackrooms="50.0" attackweaker="50" attackstronger="-30" sight="0.5" hearing="1.0"/>
|
||||
</Character>
|
||||
@@ -12,6 +12,14 @@
|
||||
<sound file="Content/Characters/Watcher/watch5.ogg" state="None" range="500"/>
|
||||
<sound file="Content/Characters/Watcher/watch6.ogg" state="None" range="500"/>
|
||||
|
||||
<ai
|
||||
attackpriorityhumans="0.0"
|
||||
attackpriorityrooms="0.0"
|
||||
combatstrength="1000"
|
||||
attackwhenprovoked="true"
|
||||
sight="1.0"
|
||||
hearing="0.0" />
|
||||
|
||||
<ragdoll waveamplitude="0.0" swimspeed="0.5" walkspeed="0.3" mirror="true" rotatetowardsmovement="false" headangle="-90">
|
||||
|
||||
<collider radius="100"/>
|
||||
@@ -19,7 +27,7 @@
|
||||
<!-- head -->
|
||||
<limb id = "0" type="Head" width="350" height="320" steerforce="1.0" flip="true" armorsector="0.0,360.0" armorvalue="100.0">
|
||||
<sprite texture="Content/Characters/Watcher/watcher.png" sourcerect="0,0,369,348" depth="0.02" origin ="0.5,0.6"/>
|
||||
<attack range="150" duration="0.05" damage="200" stun="5" force="20" damagetype="blunt" targetforce="100"/>
|
||||
<attack range="250" duration="0.05" damage="200" stun="5" force="20" damagetype="blunt" targetforce="100"/>
|
||||
</limb>
|
||||
|
||||
<limb id = "1" radius="50" height="120" flip="true">
|
||||
@@ -36,6 +44,4 @@
|
||||
<joint limb1="0" limb1anchor="60,130" limb2="1" limb2anchor="-30,100" lowerlimit="70" upperlimit="80"/>
|
||||
<joint limb1="0" limb1anchor="72,110" limb2="2" limb2anchor="120,-20" lowerlimit="90" upperlimit="180"/>
|
||||
</ragdoll>
|
||||
|
||||
<ai attackhumans="0.0" attackrooms="0.0" sight="1.0" hearing="0.0" attackwhenprovoked="true"/>
|
||||
</Character>
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<Pickable slots="Any">
|
||||
<StatusEffect type="OnBroken" target="This" Condition="-100.0" sound="Content/Items/Reactor/explosion.ogg">
|
||||
<Explosion range="500.0" structuredamage="250" damage="200" stun="5" force="20.0"/>
|
||||
<Explosion range="500.0" structuredamage="250" damage="200" stun="5" force="20.0" severlimbsprobability="0.5"/>
|
||||
</StatusEffect>
|
||||
</Pickable>
|
||||
</Item>
|
||||
@@ -31,7 +31,7 @@
|
||||
<Pickable slots="Any">
|
||||
<StatusEffect type="OnFire" target="This" Condition="-50.0"/>
|
||||
<StatusEffect type="OnBroken" target="This" Condition="-100.0" sound="Content/Items/Reactor/explosion.ogg">
|
||||
<Explosion range="600.0" structuredamage="150" damage="300" stun="5" force="20.0"/>
|
||||
<Explosion range="600.0" structuredamage="150" damage="300" stun="5" force="20.0" severlimbsprobability="0.6"/>
|
||||
</StatusEffect>
|
||||
</Pickable>
|
||||
</Item>
|
||||
@@ -50,7 +50,7 @@
|
||||
<StatusEffect type="Always" target="This" Condition="-0.35"/>
|
||||
<StatusEffect type="OnFire" target="This" Condition="-50.0"/>
|
||||
<StatusEffect type="OnBroken" target="This" Condition="-100.0" sound="Content/Items/Reactor/explosion.ogg">
|
||||
<Explosion range="600.0" structuredamage="150" damage="300" stun="5" force="20.0"/>
|
||||
<Explosion range="600.0" structuredamage="150" damage="300" stun="5" force="20.0" severlimbsprobability="0.6"/>
|
||||
</StatusEffect>
|
||||
</Pickable>
|
||||
</Item>
|
||||
@@ -69,7 +69,7 @@
|
||||
<Pickable slots="Any">
|
||||
<StatusEffect type="OnFire" target="This" Condition="-50.0"/>
|
||||
<StatusEffect type="OnBroken" target="This" Condition="-100.0" sound="Content/Items/Reactor/explosion.ogg">
|
||||
<Explosion range="500.0" structuredamage="50" damage="300" stun="5" force="20.0"/>
|
||||
<Explosion range="500.0" structuredamage="50" damage="300" stun="5" force="20.0" severlimbsprobability="0.6"/>
|
||||
<Fire size="500"/>
|
||||
</StatusEffect>
|
||||
</Pickable>
|
||||
@@ -121,7 +121,7 @@
|
||||
<StatusEffect type="OnFire" target="This" Condition="-50.0"/>
|
||||
|
||||
<StatusEffect type="OnBroken" target="This" Condition="-100.0" sound="Content/Items/Reactor/explosion.ogg">
|
||||
<Explosion range="600.0" structuredamage="400" damage="300" stun="5" force="20.0"/>
|
||||
<Explosion range="600.0" structuredamage="400" damage="300" stun="5" force="20.0" severlimbsprobability="0.4"/>
|
||||
</StatusEffect>
|
||||
|
||||
<StatusEffect type="OnUse" target="This" Condition="-100.0">
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
<Holdable slots="RightHand+LeftHand" holdpos="0,-50" handle1="-10,0" handle2="10,0" aimable="false"/>
|
||||
|
||||
<Projectile launchimpulse="80.0">
|
||||
<Attack damage="100" bleedingdamage="10" structuredamage="200" damagetype="Blunt"/>
|
||||
<Attack damage="100" bleedingdamage="10" structuredamage="200" damagetype="Blunt" severlimbsprobability="1.0"/>
|
||||
|
||||
<StatusEffect type="OnActive" target="This">
|
||||
<ParticleEmitter particle="bubbles" anglemin="0" anglemax="360" particleamount="10" velocitymin="0" velocitymax="50" scalemin="2" scalemax="5"/>
|
||||
@@ -115,10 +115,10 @@
|
||||
<Holdable slots="RightHand+LeftHand" holdpos="0,-50" handle1="-10,0" handle2="10,0" aimable="false"/>
|
||||
|
||||
<Projectile launchimpulse="80.0">
|
||||
<Attack damage="1000" bleedingdamage="10" structuredamage="200" damagetype="Blunt"/>
|
||||
<Attack damage="1000" bleedingdamage="10" structuredamage="200" damagetype="Blunt" severlimbsprobability="1.0"/>
|
||||
|
||||
<StatusEffect type="OnUse" Condition="-100.0" stun="10.0" disabledeltatime="true" sound="Content/Items/Weapons/bigexplosion.ogg">
|
||||
<Explosion range="1000.0" structuredamage="1000" damage="1000" stun="10" force="50.0"/>
|
||||
<Explosion range="1000.0" structuredamage="1000" damage="1000" stun="10" force="50.0" severlimbsprobability="0.8"/>
|
||||
</StatusEffect>
|
||||
|
||||
<StatusEffect type="OnActive" target="This">
|
||||
|
||||
@@ -57,31 +57,29 @@
|
||||
</bubbles>
|
||||
|
||||
<blood
|
||||
startsizemin="0.05,0.05" startsizemax="0.6,0.6"
|
||||
sizechangemin="0.3,0.2" sizechangemax="0.4,0.2"
|
||||
startsizemin="0.5,0.5" startsizemax="1.0,1.0"
|
||||
startrotationmin ="0.0" startrotationmax="360"
|
||||
startcolor="0.5, 0.0, 0.0" startalpha="1.0"
|
||||
colorchange="0.0, 0.0, 0.0, -1.0"
|
||||
lifetime="2"
|
||||
lifetime="1"
|
||||
growtime ="0.1"
|
||||
deleteoncollision="true"
|
||||
rotatetodirection="true"
|
||||
velocitychange="0.0, -9.8">
|
||||
<sprite texture="Content/Particles/spatter.png" sourcerect="0,0,128,128"/>
|
||||
<sprite texture="Content/Particles/spatter.png" sourcerect="128,0,128,128"/>
|
||||
<sprite texture="Content/Particles/spatter.png" sourcerect="0,128,128,128"/>
|
||||
velocitychange="0.0, -0.1">
|
||||
<animatedsprite texture="Content/Particles/Spatter1.png" sourcerect="0,0,1024,1024" columns="4" rows="8" origin="0.2,0.5"/>
|
||||
<animatedsprite texture="Content/Particles/Spatter2.png" sourcerect="0,0,1024,1024" columns="4" rows="8" origin="0.5,0.5"/>
|
||||
<animatedsprite texture="Content/Particles/Spatter3.png" sourcerect="0,0,1024,1024" columns="4" rows="8" origin="0.3,0.5"/>
|
||||
</blood>
|
||||
|
||||
<waterblood
|
||||
startsize="0.05,0.05"
|
||||
sizechangemin="0.1,0.1" sizechangemax="0.15,0.15"
|
||||
startsizemin="0.1,0.1" startsizemax="0.3,0.3"
|
||||
sizechangemin="0.1,0.1" sizechangemax="0.2,0.2"
|
||||
startrotationmin ="0.0" startrotationmax="360"
|
||||
startcolor="0.5, 0.0, 0.0" startalpha="1.0"
|
||||
colorchange="0.0, 0.0, 0.0, -0.25"
|
||||
startcolor="0.3, 0.0, 0.0" startalpha="1.0"
|
||||
animduration="5"
|
||||
colorchange="0.0, 0.0, 0.0, -0.2"
|
||||
growtime ="0.1"
|
||||
lifetime="5.0"
|
||||
drawtarget="water"
|
||||
velocitychange="0.0, 0.0">
|
||||
<sprite texture="Content/Particles/spatter.png" sourcerect="128,128,128,128"/>
|
||||
<animatedsprite texture="Content/Particles/Smoke.png" sourcerect="0,0,4096,4096" columns="8" rows="8" origin="0.5,0.5"/>
|
||||
</waterblood>
|
||||
|
||||
<spark
|
||||
|
||||
BIN
Barotrauma/Content/Particles/Smoke.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
Barotrauma/Content/Particles/Spatter1.png
Normal file
|
After Width: | Height: | Size: 750 KiB |
BIN
Barotrauma/Content/Particles/Spatter2.png
Normal file
|
After Width: | Height: | Size: 279 KiB |
BIN
Barotrauma/Content/Particles/Spatter3.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
@@ -2,9 +2,10 @@
|
||||
<Randomevents>
|
||||
<MonsterEvent name="Under attack" description=""
|
||||
characterfile="Content/Characters/Crawler/crawler.xml"
|
||||
commonness="10"
|
||||
commonness="15"
|
||||
difficulty="10"
|
||||
minamount="2" maxamount="3"
|
||||
repeat="true"
|
||||
spawntype="mainpath,cave,ruin"
|
||||
musictype="monster"/>
|
||||
|
||||
@@ -20,13 +21,14 @@
|
||||
characterfile="Content/Characters/Moloch/moloch.xml"
|
||||
commonness="10"
|
||||
difficulty="30"
|
||||
spawntype="mainpath"
|
||||
spawntype="mainpath"
|
||||
musictype="monster"/>
|
||||
|
||||
<MonsterEvent name="Under attack" description=""
|
||||
characterfile="Content/Characters/Mantis/mantis.xml"
|
||||
commonness="10"
|
||||
difficulty="15"
|
||||
repeat="true"
|
||||
minamount="1" maxamount="2"
|
||||
spawntype="mainpath,cave,ruin"
|
||||
musictype="monster"/>
|
||||
@@ -70,7 +72,7 @@
|
||||
commonness="5"
|
||||
difficulty="10"
|
||||
minamount="2" maxamount="3"
|
||||
|
||||
repeat="true"
|
||||
spawntype="mainpath,cave,ruin"
|
||||
musictype="monster"/>
|
||||
|
||||
|
||||
@@ -6,15 +6,13 @@ namespace Barotrauma
|
||||
{
|
||||
class AIController : ISteerable
|
||||
{
|
||||
|
||||
public enum AiState { None, Attack, GoTo, Escape }
|
||||
public enum SteeringState { Wander, Seek, Escape }
|
||||
public enum AIState { None, Attack, GoTo, Escape, Eat }
|
||||
|
||||
public bool Enabled;
|
||||
|
||||
public readonly Character Character;
|
||||
|
||||
protected AiState state;
|
||||
protected AIState state;
|
||||
|
||||
protected SteeringManager steeringManager;
|
||||
|
||||
@@ -44,7 +42,7 @@ namespace Barotrauma
|
||||
get { return Character.AnimController.Collider.LinearVelocity; }
|
||||
}
|
||||
|
||||
public AiState State
|
||||
public AIState State
|
||||
{
|
||||
get { return state; }
|
||||
set { state = value; }
|
||||
|
||||
@@ -11,7 +11,11 @@ namespace Barotrauma
|
||||
|
||||
public static List<AITarget> List = new List<AITarget>();
|
||||
|
||||
public readonly Entity Entity;
|
||||
public Entity Entity
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private float soundRange;
|
||||
private float sightRange;
|
||||
@@ -47,6 +51,7 @@ namespace Barotrauma
|
||||
public void Remove()
|
||||
{
|
||||
List.Remove(this);
|
||||
Entity = null;
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Xml.Linq;
|
||||
using FarseerPhysics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
@@ -23,21 +21,22 @@ namespace Barotrauma
|
||||
//0.0 = doesn't attack targets of the type
|
||||
//positive values = attacks targets of this type
|
||||
//negative values = escapes targets of this type
|
||||
private float attackRooms, attackHumans, attackWeaker, attackStronger;
|
||||
private float attackRooms, attackHumans, attackWeaker, attackStronger, eatDeadPriority;
|
||||
|
||||
//determines which characters are considered weaker/stronger
|
||||
private float combatStrength;
|
||||
|
||||
private SteeringManager outsideSteering, insideSteering;
|
||||
|
||||
private float updateTargetsTimer;
|
||||
|
||||
private float raycastTimer;
|
||||
|
||||
//a timer for attacks such as biting that last for a specific amount of time
|
||||
//the duration is determined by the attackDuration of the attacking limb
|
||||
private float attackTimer;
|
||||
|
||||
|
||||
//a "cooldown time" after an attack during which the Character doesn't try to attack again
|
||||
private float attackCoolDown;
|
||||
private float coolDownTimer;
|
||||
|
||||
private bool attachToWalls;
|
||||
|
||||
//a point in a wall which the Character is currently targeting
|
||||
private Vector2 wallAttackPos;
|
||||
@@ -46,10 +45,15 @@ namespace Barotrauma
|
||||
|
||||
//the limb selected for the current attack
|
||||
private Limb attackingLimb;
|
||||
|
||||
//flee when the health is below this value
|
||||
private float fleeHealthThreshold;
|
||||
|
||||
private AITarget selectedAiTarget;
|
||||
private AITargetMemory selectedTargetMemory;
|
||||
private float targetValue;
|
||||
|
||||
private float eatTimer;
|
||||
|
||||
private Dictionary<AITarget, AITargetMemory> targetMemories;
|
||||
|
||||
@@ -73,10 +77,13 @@ namespace Barotrauma
|
||||
XElement aiElement = doc.Root.Element("ai");
|
||||
if (aiElement == null) return;
|
||||
|
||||
attackRooms = ToolBox.GetAttributeFloat(aiElement, "attackrooms", 0.0f) / 100.0f;
|
||||
attackHumans = ToolBox.GetAttributeFloat(aiElement, "attackhumans", 0.0f) / 100.0f;
|
||||
attackWeaker = ToolBox.GetAttributeFloat(aiElement, "attackweaker", 0.0f) / 100.0f;
|
||||
attackStronger = ToolBox.GetAttributeFloat(aiElement, "attackstronger", 0.0f) / 100.0f;
|
||||
attackRooms = ToolBox.GetAttributeFloat(aiElement, 0.0f, "attackrooms", "attackpriorityrooms") / 100.0f;
|
||||
attackHumans = ToolBox.GetAttributeFloat(aiElement, 0.0f, "attackhumans", "attackpriorityhumans") / 100.0f;
|
||||
attackWeaker = ToolBox.GetAttributeFloat(aiElement, 0.0f, "attackweaker", "attackpriorityweaker") / 100.0f;
|
||||
attackStronger = ToolBox.GetAttributeFloat(aiElement, 0.0f, "attackstronger", "attackprioritystronger") / 100.0f;
|
||||
eatDeadPriority = ToolBox.GetAttributeFloat(aiElement, "eatpriority", 0.0f) / 100.0f;
|
||||
|
||||
combatStrength = ToolBox.GetAttributeFloat(aiElement, "combatstrength", 1.0f);
|
||||
|
||||
attackCoolDown = ToolBox.GetAttributeFloat(aiElement, "attackcooldown", 5.0f);
|
||||
|
||||
@@ -85,12 +92,16 @@ namespace Barotrauma
|
||||
|
||||
attackWhenProvoked = ToolBox.GetAttributeBool(aiElement, "attackwhenprovoked", false);
|
||||
|
||||
fleeHealthThreshold = ToolBox.GetAttributeFloat(aiElement, "fleehealththreshold", 0.0f);
|
||||
|
||||
attachToWalls = ToolBox.GetAttributeBool(aiElement, "attachtowalls", false);
|
||||
|
||||
outsideSteering = new SteeringManager(this);
|
||||
insideSteering = new IndoorsSteeringManager(this, false);
|
||||
|
||||
steeringManager = outsideSteering;
|
||||
|
||||
state = AiState.None;
|
||||
state = AIState.None;
|
||||
}
|
||||
|
||||
public override void SelectTarget(AITarget target)
|
||||
@@ -138,54 +149,140 @@ namespace Barotrauma
|
||||
|
||||
if (selectedAiTarget == null)
|
||||
{
|
||||
state = AiState.None;
|
||||
state = AIState.None;
|
||||
}
|
||||
else if ((selectedAiTarget.Entity is Character) && ((Character)selectedAiTarget.Entity).IsDead)
|
||||
{
|
||||
if (state != AIState.Eat)
|
||||
{
|
||||
eatTimer = 0.0f;
|
||||
state = AIState.Eat;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state = (targetValue > 0.0f) ? AiState.Attack : AiState.Escape;
|
||||
state = (targetValue < 0.0f || Character.Health < fleeHealthThreshold) ? AIState.Escape : AIState.Attack;
|
||||
}
|
||||
//if (coolDownTimer >= 0.0f) return;
|
||||
}
|
||||
|
||||
steeringManager = Character.Submarine == null ? outsideSteering : insideSteering;
|
||||
|
||||
bool run = false;
|
||||
switch (state)
|
||||
{
|
||||
case AiState.None:
|
||||
case AIState.None:
|
||||
UpdateNone(deltaTime);
|
||||
break;
|
||||
case AiState.Attack:
|
||||
case AIState.Attack:
|
||||
run = coolDownTimer <= 0.0f;
|
||||
UpdateAttack(deltaTime);
|
||||
break;
|
||||
case AIState.Eat:
|
||||
UpdateEating(deltaTime);
|
||||
break;
|
||||
case AIState.Escape:
|
||||
run = true;
|
||||
UpdateEscape(deltaTime);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
steeringManager.Update();
|
||||
}
|
||||
|
||||
private void UpdateNone(float deltaTime)
|
||||
{
|
||||
//wander around randomly
|
||||
if (Character.Submarine==null && SimPosition.Y < ConvertUnits.ToSimUnits(SubmarineBody.DamageDepth*0.5f))
|
||||
if (run)
|
||||
{
|
||||
steeringManager.SteeringManual(deltaTime, Vector2.UnitY);
|
||||
steeringManager.Update(Character.AnimController.InWater ?
|
||||
Character.AnimController.SwimSpeedMultiplier : Character.AnimController.RunSpeedMultiplier);
|
||||
}
|
||||
else
|
||||
{
|
||||
steeringManager.SteeringAvoid(deltaTime, 0.1f);
|
||||
steeringManager.SteeringWander(0.5f);
|
||||
steeringManager.Update();
|
||||
}
|
||||
}
|
||||
|
||||
#region Idle
|
||||
|
||||
private void UpdateNone(float deltaTime)
|
||||
{
|
||||
attackingLimb = null;
|
||||
coolDownTimer -= deltaTime;
|
||||
|
||||
if (Character.Submarine == null && SimPosition.Y < ConvertUnits.ToSimUnits(SubmarineBody.DamageDepth * 0.5f))
|
||||
{
|
||||
//steer straight up if very deep
|
||||
steeringManager.SteeringManual(deltaTime, Vector2.UnitY);
|
||||
return;
|
||||
}
|
||||
|
||||
attackingLimb = null;
|
||||
attackTimer = 0.0f;
|
||||
if (attachToWalls && Character.Submarine == null)
|
||||
{
|
||||
raycastTimer -= deltaTime;
|
||||
//check if there are any walls nearby the character could attach to
|
||||
if (raycastTimer < 1.0f)
|
||||
{
|
||||
wallAttackPos = Vector2.Zero;
|
||||
|
||||
coolDownTimer -= deltaTime;
|
||||
var cells = Level.Loaded.GetCells(WorldPosition, 1);
|
||||
if (cells.Count > 0)
|
||||
{
|
||||
Body closestBody = Submarine.CheckVisibility(Character.SimPosition, ConvertUnits.ToSimUnits(cells[0].Center));
|
||||
if (closestBody != null && closestBody.UserData is Voronoi2.VoronoiCell)
|
||||
{
|
||||
wallAttackPos = Submarine.LastPickedPosition;
|
||||
}
|
||||
}
|
||||
raycastTimer = RaycastInterval;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wallAttackPos = Vector2.Zero;
|
||||
}
|
||||
|
||||
if (wallAttackPos == Vector2.Zero)
|
||||
{
|
||||
//wander around randomly
|
||||
steeringManager.SteeringAvoid(deltaTime, 0.1f);
|
||||
steeringManager.SteeringWander(0.5f);
|
||||
return;
|
||||
}
|
||||
|
||||
float dist = Vector2.Distance(SimPosition, wallAttackPos);
|
||||
if (dist < Math.Max(Math.Max(Character.AnimController.Collider.radius, Character.AnimController.Collider.width), Character.AnimController.Collider.height) * 1.2f)
|
||||
{
|
||||
//close enough to a wall -> attach
|
||||
Character.AnimController.Collider.MoveToPos(wallAttackPos, 1.0f);
|
||||
steeringManager.Reset();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//move closer to the wall
|
||||
steeringManager.SteeringAvoid(deltaTime, 0.1f);
|
||||
steeringManager.SteeringSeek(wallAttackPos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Escape
|
||||
|
||||
private void UpdateEscape(float deltaTime)
|
||||
{
|
||||
SteeringManager.SteeringManual(deltaTime, Vector2.Normalize(SimPosition - selectedAiTarget.SimPosition) * 5);
|
||||
SteeringManager.SteeringWander(1.0f);
|
||||
SteeringManager.SteeringAvoid(deltaTime, 2f);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Attack
|
||||
|
||||
private void UpdateAttack(float deltaTime)
|
||||
{
|
||||
if (selectedAiTarget == null || selectedAiTarget.Entity == null || selectedAiTarget.Entity.Removed)
|
||||
{
|
||||
state = AiState.None;
|
||||
state = AIState.None;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -198,7 +295,22 @@ namespace Barotrauma
|
||||
|
||||
if (selectedAiTarget.Entity != null && Character.Submarine == null && selectedAiTarget.Entity.Submarine != null) attackSimPosition += ConvertUnits.ToSimUnits(selectedAiTarget.Entity.Submarine.Position);
|
||||
}
|
||||
|
||||
else if (selectedAiTarget.Entity is Character)
|
||||
{
|
||||
//target the closest limb if the target is a character
|
||||
float closestDist = Vector2.DistanceSquared(selectedAiTarget.SimPosition, SimPosition);
|
||||
foreach (Limb limb in ((Character)selectedAiTarget.Entity).AnimController.Limbs)
|
||||
{
|
||||
if (limb == null) continue;
|
||||
float dist = Vector2.DistanceSquared(limb.SimPosition, SimPosition);
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestDist = dist;
|
||||
attackSimPosition = limb.SimPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.Abs(Character.AnimController.movement.X) > 0.1f && !Character.AnimController.InWater)
|
||||
{
|
||||
Character.AnimController.TargetDir = Character.SimPosition.X < attackSimPosition.X ? Direction.Right : Direction.Left;
|
||||
@@ -229,13 +341,13 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Limb limb in Character.AnimController.Limbs)
|
||||
{
|
||||
if (limb.attack==null) continue;
|
||||
if (limb.attack == null) continue;
|
||||
attackLimb = limb;
|
||||
|
||||
if (ConvertUnits.ToDisplayUnits(Vector2.Distance(limb.SimPosition, attackSimPosition)) > limb.attack.Range) continue;
|
||||
|
||||
|
||||
attackingLimb = limb;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Character.IsRemotePlayer)
|
||||
@@ -245,36 +357,18 @@ namespace Barotrauma
|
||||
}
|
||||
if (attackLimb != null)
|
||||
{
|
||||
steeringManager.SteeringSeek(attackSimPosition - (attackLimb.SimPosition - SimPosition));
|
||||
steeringManager.SteeringSeek(attackSimPosition - (attackLimb.SimPosition - SimPosition), 3);
|
||||
|
||||
if (steeringManager is IndoorsSteeringManager)
|
||||
{
|
||||
var indoorsSteering = (IndoorsSteeringManager)steeringManager;
|
||||
if (indoorsSteering.CurrentPath!=null && (indoorsSteering.CurrentPath.Finished || indoorsSteering.CurrentPath.Unreachable))
|
||||
if (indoorsSteering.CurrentPath != null && (indoorsSteering.CurrentPath.Finished || indoorsSteering.CurrentPath.Unreachable))
|
||||
{
|
||||
steeringManager.SteeringManual(deltaTime, attackSimPosition - attackLimb.SimPosition);
|
||||
}
|
||||
}
|
||||
|
||||
if (attackingLimb != null) UpdateLimbAttack(deltaTime, attackingLimb, attackSimPosition);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCoolDown(Vector2 attackPosition, float deltaTime)
|
||||
{
|
||||
coolDownTimer -= deltaTime;
|
||||
attackingLimb = null;
|
||||
|
||||
if (selectedAiTarget.Entity is Hull ||
|
||||
Vector2.Distance(attackPosition, Character.AnimController.Limbs[0].SimPosition) < ConvertUnits.ToSimUnits(500.0f))
|
||||
{
|
||||
steeringManager.SteeringSeek(attackPosition, -0.8f);
|
||||
steeringManager.SteeringAvoid(deltaTime, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
steeringManager.SteeringSeek(attackPosition, -0.5f);
|
||||
steeringManager.SteeringAvoid(deltaTime, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,13 +433,16 @@ namespace Barotrauma
|
||||
updateTargetsTimer = Math.Min(updateTargetsTimer, 0.1f);
|
||||
coolDownTimer *= 0.1f;
|
||||
|
||||
if (amount > 0.1f && attackWhenProvoked)
|
||||
if (amount > 0.0f && attackWhenProvoked)
|
||||
{
|
||||
attackHumans = 100.0f;
|
||||
attackRooms = 100.0f;
|
||||
if (!(attacker is AICharacter) || (((AICharacter)attacker).AIController is HumanAIController))
|
||||
{
|
||||
attackHumans = 100.0f;
|
||||
attackRooms = 100.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (attacker==null || attacker.AiTarget==null) return;
|
||||
if (attacker == null || attacker.AiTarget == null) return;
|
||||
AITargetMemory targetMemory = FindTargetMemory(attacker.AiTarget);
|
||||
targetMemory.Priority += amount;
|
||||
}
|
||||
@@ -363,7 +460,112 @@ namespace Barotrauma
|
||||
coolDownTimer = attackCoolDown;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCoolDown(Vector2 attackPosition, float deltaTime)
|
||||
{
|
||||
coolDownTimer -= deltaTime;
|
||||
attackingLimb = null;
|
||||
|
||||
float dist = Vector2.Distance(attackPosition, Character.SimPosition);
|
||||
|
||||
if (dist < ConvertUnits.ToSimUnits(500.0f))
|
||||
{
|
||||
steeringManager.SteeringSeek(attackPosition, -0.8f);
|
||||
steeringManager.SteeringManual(deltaTime, Vector2.Normalize(Character.SimPosition - attackPosition) * (1.0f - (dist / 500.0f)));
|
||||
}
|
||||
|
||||
steeringManager.SteeringAvoid(deltaTime, 1.0f);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Eat
|
||||
|
||||
private void UpdateEating(float deltaTime)
|
||||
{
|
||||
if (selectedAiTarget == null || selectedAiTarget.Entity == null || selectedAiTarget.Entity.Removed)
|
||||
{
|
||||
state = AIState.None;
|
||||
return;
|
||||
}
|
||||
|
||||
Limb mouthLimb = Array.Find(Character.AnimController.Limbs, l => l != null && l.MouthPos.HasValue);
|
||||
if (mouthLimb == null) mouthLimb = Character.AnimController.GetLimb(LimbType.Head);
|
||||
|
||||
if (mouthLimb == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Character \"" + Character.SpeciesName + "\" failed to eat a target (a head or a limb with a mouthpos required)");
|
||||
state = AIState.None;
|
||||
return;
|
||||
}
|
||||
|
||||
Character targetCharacter = selectedAiTarget.Entity as Character;
|
||||
float eatSpeed = Character.Mass / targetCharacter.Mass * 0.1f;
|
||||
|
||||
eatTimer += deltaTime * eatSpeed;
|
||||
|
||||
Vector2 mouthPos = mouthLimb.SimPosition;
|
||||
if (mouthLimb.MouthPos.HasValue)
|
||||
{
|
||||
float cos = (float)Math.Cos(mouthLimb.Rotation);
|
||||
float sin = (float)Math.Sin(mouthLimb.Rotation);
|
||||
|
||||
mouthPos += new Vector2(
|
||||
mouthLimb.MouthPos.Value.X * cos - mouthLimb.MouthPos.Value.Y * sin,
|
||||
mouthLimb.MouthPos.Value.X * sin + mouthLimb.MouthPos.Value.Y * cos);
|
||||
}
|
||||
|
||||
Vector2 attackSimPosition = Character.Submarine == null ? ConvertUnits.ToSimUnits(selectedAiTarget.WorldPosition) : selectedAiTarget.SimPosition;
|
||||
|
||||
|
||||
Vector2 limbDiff = attackSimPosition - mouthPos;
|
||||
float limbDist = limbDiff.Length();
|
||||
if (limbDist < 1.0f)
|
||||
{
|
||||
//pull the target character to the position of the mouth
|
||||
//(+ make the force fluctuate to waggle the character a bit)
|
||||
targetCharacter.AnimController.MainLimb.MoveToPos(mouthPos, (float)(Math.Sin(eatTimer) + 10.0f));
|
||||
|
||||
//pull the character's mouth to the target character (again with a fluctuating force)
|
||||
float pullStrength = (float)(Math.Sin(eatTimer) * Math.Max(Math.Sin(eatTimer * 0.5f), 0.0f));
|
||||
steeringManager.SteeringManual(deltaTime, limbDiff * pullStrength);
|
||||
mouthLimb.body.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f * pullStrength);
|
||||
|
||||
if (eatTimer % 1.0f < 0.5f && (eatTimer - deltaTime * eatSpeed) % 1.0f > 0.5f)
|
||||
{
|
||||
//apply damage to the target character to get some blood particles flying
|
||||
targetCharacter.AnimController.MainLimb.AddDamage(targetCharacter.SimPosition, DamageType.None, Rand.Range(10.0f, 25.0f), 10.0f, false);
|
||||
|
||||
//keep severing joints until there is only one limb left
|
||||
LimbJoint[] nonSeveredJoints = Array.FindAll(targetCharacter.AnimController.LimbJoints, l => !l.IsSevered);
|
||||
if (nonSeveredJoints.Length == 0)
|
||||
{
|
||||
//only one limb left, the character is now full eaten
|
||||
Entity.Spawner.AddToRemoveQueue(targetCharacter);
|
||||
selectedAiTarget = null;
|
||||
state = AIState.None;
|
||||
}
|
||||
else //sever a random joint
|
||||
{
|
||||
targetCharacter.AnimController.SeverLimbJoint(nonSeveredJoints[Rand.Int(nonSeveredJoints.Length)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (limbDist < 2.0f)
|
||||
{
|
||||
steeringManager.SteeringManual(deltaTime, limbDiff);
|
||||
Character.AnimController.Collider.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f, mouthPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
steeringManager.SteeringSeek(attackSimPosition + (mouthPos - SimPosition), 3);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Targeting
|
||||
|
||||
//goes through all the AItargets, evaluates how preferable it is to attack the target,
|
||||
//whether the Character can see/hear the target and chooses the most preferable target within
|
||||
//sight/hearing range
|
||||
@@ -387,33 +589,62 @@ namespace Barotrauma
|
||||
float valueModifier = 0.0f;
|
||||
float dist = 0.0f;
|
||||
|
||||
IDamageable targetDamageable = target.Entity as IDamageable;
|
||||
if (targetDamageable!=null && targetDamageable.Health <= 0.0f) continue;
|
||||
|
||||
Character targetCharacter = target.Entity as Character;
|
||||
|
||||
//ignore the aitarget if it is the Character itself
|
||||
if (targetCharacter == character) continue;
|
||||
|
||||
if (targetCharacter!=null)
|
||||
|
||||
if (targetCharacter != null)
|
||||
{
|
||||
if (attackHumans == 0.0f || targetCharacter.SpeciesName != "human") continue;
|
||||
|
||||
valueModifier = attackHumans;
|
||||
if (targetCharacter.IsDead)
|
||||
{
|
||||
if (eatDeadPriority == 0.0f) continue;
|
||||
valueModifier = eatDeadPriority;
|
||||
}
|
||||
else if (targetCharacter.SpeciesName == "human")
|
||||
{
|
||||
if (attackHumans == 0.0f) continue;
|
||||
valueModifier = attackHumans;
|
||||
}
|
||||
else
|
||||
{
|
||||
EnemyAIController enemy = targetCharacter.AIController as EnemyAIController;
|
||||
if (enemy != null)
|
||||
{
|
||||
if (enemy.combatStrength > combatStrength)
|
||||
{
|
||||
valueModifier = attackStronger;
|
||||
}
|
||||
else if (enemy.combatStrength < combatStrength)
|
||||
{
|
||||
valueModifier = attackWeaker;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (target.Entity!=null && attackRooms != 0.0f)
|
||||
{
|
||||
IDamageable targetDamageable = target.Entity as IDamageable;
|
||||
if (targetDamageable != null && targetDamageable.Health <= 0.0f) continue;
|
||||
|
||||
//skip the target if it's the room the Character is inside of
|
||||
if (character.AnimController.CurrentHull != null && character.AnimController.CurrentHull == target.Entity as Hull) continue;
|
||||
|
||||
valueModifier = attackRooms;
|
||||
}
|
||||
|
||||
if (valueModifier == 0.0f) continue;
|
||||
|
||||
dist = Vector2.Distance(character.WorldPosition, target.WorldPosition);
|
||||
|
||||
//if the target has been within range earlier, the character will notice it more easily
|
||||
//(i.e. remember where the target was)
|
||||
if (targetMemories.ContainsKey(target)) dist *= 0.1f;
|
||||
if (targetMemories.ContainsKey(target)) dist *= 0.5f;
|
||||
|
||||
//ignore target if it's too far to see or hear
|
||||
if (dist > target.SightRange * sight && dist > target.SoundRange * hearing) continue;
|
||||
@@ -433,20 +664,7 @@ namespace Barotrauma
|
||||
|
||||
Body closestBody = Submarine.CheckVisibility(rayStart, rayEnd);
|
||||
Structure closestStructure = (closestBody == null) ? null : closestBody.UserData as Structure;
|
||||
|
||||
if (targetDamageable != null)
|
||||
{
|
||||
valueModifier = valueModifier / targetDamageable.Health;
|
||||
}
|
||||
else if (closestStructure!=null)
|
||||
{
|
||||
valueModifier = valueModifier / ((IDamageable)closestStructure).Health;
|
||||
}
|
||||
else
|
||||
{
|
||||
valueModifier = valueModifier / 1000.0f;
|
||||
}
|
||||
|
||||
|
||||
if (selectedAiTarget == null || Math.Abs(valueModifier) > Math.Abs(targetValue))
|
||||
{
|
||||
selectedAiTarget = target;
|
||||
@@ -497,6 +715,8 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override void DebugDraw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (Character.IsDead) return;
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Barotrauma
|
||||
{
|
||||
switch (aiController.State)
|
||||
{
|
||||
case AIController.AiState.Attack:
|
||||
case AIController.AIState.Attack:
|
||||
PlaySound(CharacterSound.SoundType.Attack);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -12,13 +12,25 @@ namespace Barotrauma
|
||||
|
||||
protected Character character;
|
||||
|
||||
protected float walkSpeed, swimSpeed;
|
||||
|
||||
protected float walkSpeed, swimSpeed;
|
||||
|
||||
protected float walkPos;
|
||||
|
||||
protected readonly Vector2 stepSize;
|
||||
protected readonly float legTorque;
|
||||
|
||||
|
||||
public float RunSpeedMultiplier
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public float SwimSpeedMultiplier
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public AnimController(Character character, XElement element)
|
||||
: base(character, element)
|
||||
{
|
||||
@@ -30,6 +42,9 @@ namespace Barotrauma
|
||||
walkSpeed = ToolBox.GetAttributeFloat(element, "walkspeed", 1.0f);
|
||||
swimSpeed = ToolBox.GetAttributeFloat(element, "swimspeed", 1.0f);
|
||||
|
||||
RunSpeedMultiplier = ToolBox.GetAttributeFloat(element, "runspeedmultiplier", 2f);
|
||||
SwimSpeedMultiplier = ToolBox.GetAttributeFloat(element, "swimspeedmultiplier", 1.5f);
|
||||
|
||||
legTorque = ToolBox.GetAttributeFloat(element, "legtorque", 0.0f);
|
||||
}
|
||||
|
||||
@@ -37,7 +52,7 @@ namespace Barotrauma
|
||||
|
||||
public virtual void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle) { }
|
||||
|
||||
public virtual void DragCharacter(Character target, LimbType rightHandTarget = LimbType.RightHand, LimbType leftHandTarget = LimbType.LeftHand) { }
|
||||
public virtual void DragCharacter(Character target) { }
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace Barotrauma
|
||||
private float waveAmplitude;
|
||||
private float waveLength;
|
||||
|
||||
private float steerTorque;
|
||||
|
||||
private bool rotateTowardsMovement;
|
||||
|
||||
private bool mirror, flip;
|
||||
@@ -23,16 +25,20 @@ namespace Barotrauma
|
||||
|
||||
private float? footRotation;
|
||||
|
||||
private float deathAnimTimer, deathAnimDuration = 5.0f;
|
||||
|
||||
public FishAnimController(Character character, XElement element)
|
||||
: base(character, element)
|
||||
{
|
||||
waveAmplitude = ConvertUnits.ToSimUnits(ToolBox.GetAttributeFloat(element, "waveamplitude", 0.0f));
|
||||
waveLength = ConvertUnits.ToSimUnits(ToolBox.GetAttributeFloat(element, "wavelength", 0.0f));
|
||||
waveAmplitude = ConvertUnits.ToSimUnits(ToolBox.GetAttributeFloat(element, "waveamplitude", 0.0f));
|
||||
waveLength = ConvertUnits.ToSimUnits(ToolBox.GetAttributeFloat(element, "wavelength", 0.0f));
|
||||
|
||||
steerTorque = ToolBox.GetAttributeFloat(element, "steertorque", 25.0f);
|
||||
|
||||
flip = ToolBox.GetAttributeBool(element, "flip", true);
|
||||
mirror = ToolBox.GetAttributeBool(element, "mirror", false);
|
||||
flip = ToolBox.GetAttributeBool(element, "flip", true);
|
||||
mirror = ToolBox.GetAttributeBool(element, "mirror", false);
|
||||
|
||||
float footRot = ToolBox.GetAttributeFloat(element,"footrotation", float.NaN);
|
||||
float footRot = ToolBox.GetAttributeFloat(element, "footrotation", float.NaN);
|
||||
if (float.IsNaN(footRot))
|
||||
{
|
||||
footRotation = null;
|
||||
@@ -63,6 +69,12 @@ namespace Barotrauma
|
||||
Collider.LinearVelocity = (MainLimb.SimPosition - Collider.SimPosition) * 60.0f;
|
||||
Collider.SmoothRotate(MainLimb.Rotation);
|
||||
}
|
||||
|
||||
if (character.IsDead && deathAnimTimer < deathAnimDuration)
|
||||
{
|
||||
deathAnimTimer += deltaTime;
|
||||
UpdateDying(deltaTime);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -176,12 +188,12 @@ namespace Barotrauma
|
||||
if (rotateTowardsMovement)
|
||||
{
|
||||
Collider.SmoothRotate(movementAngle, 25.0f);
|
||||
MainLimb.body.SmoothRotate(movementAngle, 25.0f);
|
||||
MainLimb.body.SmoothRotate(movementAngle, steerTorque);
|
||||
}
|
||||
else
|
||||
{
|
||||
Collider.SmoothRotate(HeadAngle * Dir, 25.0f);
|
||||
MainLimb.body.SmoothRotate(HeadAngle * Dir, 25.0f);
|
||||
MainLimb.body.SmoothRotate(HeadAngle * Dir, steerTorque);
|
||||
}
|
||||
|
||||
Limb tail = GetLimb(LimbType.Tail);
|
||||
@@ -260,7 +272,7 @@ namespace Barotrauma
|
||||
|
||||
if (limb.RefJointIndex>-1)
|
||||
{
|
||||
RevoluteJoint refJoint = limbJoints[limb.RefJointIndex];
|
||||
RevoluteJoint refJoint = LimbJoints[limb.RefJointIndex];
|
||||
footPos.X = refJoint.WorldAnchorA.X;
|
||||
}
|
||||
footPos.X += limb.StepOffset.X * Dir;
|
||||
@@ -297,8 +309,8 @@ namespace Barotrauma
|
||||
Limb head = GetLimb(LimbType.Head);
|
||||
Limb tail = GetLimb(LimbType.Tail);
|
||||
|
||||
if (head != null) head.body.ApplyTorque(head.Mass * Dir * (float)Math.Sin(walkPos) * 5.0f);
|
||||
if (tail != null) tail.body.ApplyTorque(tail.Mass * -Dir * (float)Math.Sin(walkPos) * 5.0f);
|
||||
if (head != null && !head.IsSevered) head.body.ApplyTorque((float)(Math.Sqrt(head.Mass) * Dir * Math.Sin(walkPos)) * 10.0f);
|
||||
if (tail != null && !tail.IsSevered) tail.body.ApplyTorque((float)(Math.Sqrt(tail.Mass) * -Dir * (float)Math.Sin(walkPos)) * 10.0f);
|
||||
|
||||
walkPos += deltaTime * 5.0f;
|
||||
|
||||
@@ -306,9 +318,9 @@ namespace Barotrauma
|
||||
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.type == LimbType.Head || limb.type == LimbType.Tail) continue;
|
||||
if (limb.type == LimbType.Head || limb.type == LimbType.Tail || limb.IsSevered) continue;
|
||||
|
||||
limb.body.ApplyForce((centerOfMass - limb.SimPosition) * (float)Math.Sin(walkPos) * limb.Mass * 10.0f);
|
||||
limb.body.ApplyForce((centerOfMass - limb.SimPosition) * (float)(Math.Sin(walkPos) * Math.Sqrt(limb.Mass)) * 10.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -571,7 +571,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
float targetSpeed = TargetMovement.Length();
|
||||
if (targetSpeed > 0.0f) TargetMovement /= targetSpeed;
|
||||
|
||||
if (targetSpeed > 0.1f)
|
||||
{
|
||||
@@ -633,7 +632,7 @@ namespace Barotrauma
|
||||
Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement * swimSpeed, movementLerp);
|
||||
}
|
||||
|
||||
walkPos += movement.Length() * 0.15f;
|
||||
walkPos += movement.Length() * 0.2f;
|
||||
footPos = Collider.SimPosition - new Vector2((float)Math.Sin(-Collider.Rotation), (float)Math.Cos(-Collider.Rotation)) * 0.4f;
|
||||
|
||||
for (int i = -1; i<2; i+=2)
|
||||
@@ -691,7 +690,7 @@ namespace Barotrauma
|
||||
|
||||
handPos += head.LinearVelocity * 0.1f;
|
||||
|
||||
float handCyclePos = walkPos / 3.0f * -Dir;
|
||||
float handCyclePos = walkPos / 2.0f * -Dir;
|
||||
float handPosX = (float)Math.Cos(handCyclePos) * 0.4f;
|
||||
float handPosY = (float)Math.Sin(handCyclePos) * 1.0f;
|
||||
handPosY = MathHelper.Clamp(handPosY, -0.8f, 0.8f);
|
||||
@@ -883,23 +882,48 @@ namespace Barotrauma
|
||||
head.pullJoint.WorldAnchorB = new Vector2(targetHead.SimPosition.X, targetHead.SimPosition.Y + 0.6f + yPos);
|
||||
head.pullJoint.Enabled = true;
|
||||
}
|
||||
public override void DragCharacter(Character target, LimbType rightHandTarget = LimbType.RightHand, LimbType leftHandTarget = LimbType.LeftHand)
|
||||
public override void DragCharacter(Character target)
|
||||
{
|
||||
if (target == null) return;
|
||||
|
||||
Limb leftHand = GetLimb(LimbType.LeftHand);
|
||||
Limb rightHand = GetLimb(LimbType.RightHand);
|
||||
|
||||
Limb targetLeftHand = target.AnimController.GetLimb(LimbType.LeftHand);
|
||||
Limb targetRightHand = target.AnimController.GetLimb(LimbType.RightHand);
|
||||
|
||||
//only grab with one hand when swimming
|
||||
leftHand.Disabled = true;
|
||||
if (!inWater) rightHand.Disabled = true;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
LimbType type = i == 0 ? leftHandTarget : rightHandTarget;
|
||||
Limb targetLimb = target.AnimController.GetLimb(type);
|
||||
Limb targetLimb = target.AnimController.GetLimb(LimbType.Torso);
|
||||
|
||||
Limb pullLimb = GetLimb(i == 0 ? LimbType.LeftHand : LimbType.RightHand);
|
||||
if (i == 0)
|
||||
{
|
||||
if (!targetLeftHand.IsSevered)
|
||||
{
|
||||
targetLimb = targetLeftHand;
|
||||
}
|
||||
else if (!targetRightHand.IsSevered)
|
||||
{
|
||||
targetLimb = targetRightHand;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!targetRightHand.IsSevered)
|
||||
{
|
||||
targetLimb = targetRightHand;
|
||||
}
|
||||
else if (!targetLeftHand.IsSevered)
|
||||
{
|
||||
targetLimb = targetLeftHand;
|
||||
}
|
||||
}
|
||||
|
||||
Limb pullLimb = i == 0 ? leftHand : rightHand;
|
||||
|
||||
if (i == 1 && inWater)
|
||||
{
|
||||
@@ -1013,7 +1037,7 @@ namespace Barotrauma
|
||||
itemAngle = (torso.body.Rotation + holdAngle * Dir);
|
||||
}
|
||||
|
||||
Vector2 shoulderPos = limbJoints[2].WorldAnchorA;
|
||||
Vector2 shoulderPos = LimbJoints[2].WorldAnchorA;
|
||||
Vector2 transformedHoldPos = shoulderPos;
|
||||
|
||||
if (itemPos == Vector2.Zero || Anim == Animation.Climbing || usingController)
|
||||
@@ -1072,7 +1096,7 @@ namespace Barotrauma
|
||||
|
||||
private void HandIK(Limb hand, Vector2 pos, float force = 1.0f)
|
||||
{
|
||||
Vector2 shoulderPos = limbJoints[2].WorldAnchorA;
|
||||
Vector2 shoulderPos = LimbJoints[2].WorldAnchorA;
|
||||
|
||||
Limb arm = (hand.type == LimbType.LeftHand) ? GetLimb(LimbType.LeftArm) : GetLimb(LimbType.RightArm);
|
||||
|
||||
|
||||
@@ -28,17 +28,13 @@ namespace Barotrauma
|
||||
if (frozen == value) return;
|
||||
|
||||
frozen = value;
|
||||
|
||||
/*foreach (Limb l in Limbs)
|
||||
{
|
||||
l.body.PhysEnabled = !frozen;
|
||||
}*/
|
||||
|
||||
Collider.PhysEnabled = !frozen;
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<LimbType, Limb> limbDictionary;
|
||||
public RevoluteJoint[] limbJoints;
|
||||
public LimbJoint[] LimbJoints;
|
||||
|
||||
private bool simplePhysicsEnabled;
|
||||
|
||||
@@ -163,18 +159,20 @@ namespace Barotrauma
|
||||
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) continue;
|
||||
limb.body.Enabled = !simplePhysicsEnabled;
|
||||
}
|
||||
|
||||
foreach (RevoluteJoint joint in limbJoints)
|
||||
foreach (LimbJoint joint in LimbJoints)
|
||||
{
|
||||
joint.Enabled = !simplePhysicsEnabled;
|
||||
joint.Enabled = !joint.IsSevered && !simplePhysicsEnabled;
|
||||
}
|
||||
|
||||
if (!simplePhysicsEnabled)
|
||||
{
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) continue;
|
||||
limb.body.SetTransform(Collider.SimPosition, Collider.Rotation);
|
||||
}
|
||||
}
|
||||
@@ -278,9 +276,9 @@ namespace Barotrauma
|
||||
|
||||
float scale = ToolBox.GetAttributeFloat(element, "scale", 1.0f);
|
||||
|
||||
Limbs = new Limb[element.Elements("limb").Count()];
|
||||
limbJoints = new RevoluteJoint[element.Elements("joint").Count()];
|
||||
limbDictionary = new Dictionary<LimbType, Limb>();
|
||||
Limbs = new Limb[element.Elements("limb").Count()];
|
||||
LimbJoints = new LimbJoint[element.Elements("joint").Count()];
|
||||
limbDictionary = new Dictionary<LimbType, Limb>();
|
||||
|
||||
headPosition = ToolBox.GetAttributeFloat(element, "headposition", 50.0f);
|
||||
headPosition = ConvertUnits.ToSimUnits(headPosition);
|
||||
@@ -346,7 +344,7 @@ namespace Barotrauma
|
||||
|
||||
UpdateCollisionCategories();
|
||||
|
||||
foreach (var joint in limbJoints)
|
||||
foreach (var joint in LimbJoints)
|
||||
{
|
||||
joint.BodyB.SetTransform(
|
||||
joint.BodyA.Position + (joint.LocalAnchorA - joint.LocalAnchorB)*0.1f,
|
||||
@@ -385,9 +383,8 @@ namespace Barotrauma
|
||||
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;
|
||||
LimbJoint joint = new LimbJoint(Limbs[limb1ID], Limbs[limb2ID], limb1Pos, limb2Pos);
|
||||
joint.CanBeSevered = ToolBox.GetAttributeBool(subElement, "canbesevered", false);
|
||||
|
||||
if (subElement.Attribute("lowerlimit") != null)
|
||||
{
|
||||
@@ -396,22 +393,18 @@ namespace Barotrauma
|
||||
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++)
|
||||
for (int i = 0; i < LimbJoints.Length; i++)
|
||||
{
|
||||
if (limbJoints[i] != null) continue;
|
||||
if (LimbJoints[i] != null) continue;
|
||||
|
||||
limbJoints[i] = joint;
|
||||
LimbJoints[i] = joint;
|
||||
return;
|
||||
}
|
||||
|
||||
Array.Resize(ref limbJoints, limbJoints.Length + 1);
|
||||
limbJoints[limbJoints.Length - 1] = joint;
|
||||
|
||||
Array.Resize(ref LimbJoints, LimbJoints.Length + 1);
|
||||
LimbJoints[LimbJoints.Length - 1] = joint;
|
||||
}
|
||||
|
||||
public void AddLimb(Limb limb)
|
||||
@@ -509,9 +502,9 @@ namespace Barotrauma
|
||||
{
|
||||
Limb limb = (Limb)f1.Body.UserData;
|
||||
|
||||
if (impact > 3.0f && limb.HitSound != null && limb.soundTimer <= 0.0f)
|
||||
if (impact > 3.0f && limb.HitSound != null && limb.SoundTimer <= 0.0f)
|
||||
{
|
||||
limb.soundTimer = Limb.SoundInterval;
|
||||
limb.SoundTimer = Limb.SoundInterval;
|
||||
limb.HitSound.Play(volume, impact * 100.0f, limb.WorldPosition);
|
||||
}
|
||||
}
|
||||
@@ -531,6 +524,51 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SeverLimbJoint(LimbJoint limbJoint)
|
||||
{
|
||||
limbJoint.IsSevered = true;
|
||||
limbJoint.Enabled = false;
|
||||
|
||||
List<Limb> connectedLimbs = new List<Limb>();
|
||||
List<LimbJoint> checkedJoints = new List<LimbJoint>();
|
||||
|
||||
GetConnectedLimbs(connectedLimbs, checkedJoints, MainLimb);
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (!connectedLimbs.Contains(limb))
|
||||
{
|
||||
limb.IsSevered = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void GetConnectedLimbs(List<Limb> connectedLimbs, List<LimbJoint> checkedJoints, Limb limb)
|
||||
{
|
||||
connectedLimbs.Add(limb);
|
||||
|
||||
foreach (LimbJoint joint in LimbJoints)
|
||||
{
|
||||
if (joint.IsSevered || checkedJoints.Contains(joint)) continue;
|
||||
if (joint.LimbA == limb)
|
||||
{
|
||||
if (!connectedLimbs.Contains(joint.LimbB))
|
||||
{
|
||||
checkedJoints.Add(joint);
|
||||
GetConnectedLimbs(connectedLimbs, checkedJoints, joint.LimbB);
|
||||
}
|
||||
}
|
||||
else if (joint.LimbB == limb)
|
||||
{
|
||||
if (!connectedLimbs.Contains(joint.LimbA))
|
||||
{
|
||||
checkedJoints.Add(joint);
|
||||
GetConnectedLimbs(connectedLimbs, checkedJoints, joint.LimbA);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (simplePhysicsEnabled) return;
|
||||
@@ -559,13 +597,15 @@ namespace Barotrauma
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)pos.Y, 5, 5), Color.Red, true, 0.01f);
|
||||
}
|
||||
|
||||
limb.body.DebugDraw(spriteBatch, inWater ? Color.Cyan : Color.White);
|
||||
Color limbColor = inWater ? Color.Cyan : Color.White;
|
||||
if (limb.IsSevered) limbColor = Color.Red;
|
||||
limb.body.DebugDraw(spriteBatch, limbColor);
|
||||
}
|
||||
|
||||
Collider.DebugDraw(spriteBatch, frozen ? Color.Red : (inWater ? Color.SkyBlue : Color.Gray));
|
||||
GUI.Font.DrawString(spriteBatch, Collider.LinearVelocity.X.ToString(), new Vector2(Collider.DrawPosition.X, -Collider.DrawPosition.Y), Color.Orange);
|
||||
|
||||
foreach (RevoluteJoint joint in limbJoints)
|
||||
foreach (RevoluteJoint joint in LimbJoints)
|
||||
{
|
||||
Vector2 pos = ConvertUnits.ToDisplayUnits(joint.WorldAnchorA);
|
||||
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 5, 5), Color.White, true);
|
||||
@@ -619,22 +659,24 @@ namespace Barotrauma
|
||||
{
|
||||
dir = (dir == Direction.Left) ? Direction.Right : Direction.Left;
|
||||
|
||||
for (int i = 0; i < limbJoints.Length; i++)
|
||||
for (int i = 0; i < LimbJoints.Length; i++)
|
||||
{
|
||||
float lowerLimit = -limbJoints[i].UpperLimit;
|
||||
float upperLimit = -limbJoints[i].LowerLimit;
|
||||
float lowerLimit = -LimbJoints[i].UpperLimit;
|
||||
float upperLimit = -LimbJoints[i].LowerLimit;
|
||||
|
||||
limbJoints[i].LowerLimit = lowerLimit;
|
||||
limbJoints[i].UpperLimit = upperLimit;
|
||||
LimbJoints[i].LowerLimit = lowerLimit;
|
||||
LimbJoints[i].UpperLimit = upperLimit;
|
||||
|
||||
limbJoints[i].LocalAnchorA = new Vector2(-limbJoints[i].LocalAnchorA.X, limbJoints[i].LocalAnchorA.Y);
|
||||
limbJoints[i].LocalAnchorB = new Vector2(-limbJoints[i].LocalAnchorB.X, limbJoints[i].LocalAnchorB.Y);
|
||||
LimbJoints[i].LocalAnchorA = new Vector2(-LimbJoints[i].LocalAnchorA.X, LimbJoints[i].LocalAnchorA.Y);
|
||||
LimbJoints[i].LocalAnchorB = new Vector2(-LimbJoints[i].LocalAnchorB.X, LimbJoints[i].LocalAnchorB.Y);
|
||||
}
|
||||
|
||||
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb == null) continue;
|
||||
if (limb == null || limb.IsSevered) continue;
|
||||
|
||||
limb.Dir = Dir;
|
||||
|
||||
if (limb.sprite != null)
|
||||
{
|
||||
@@ -643,12 +685,13 @@ namespace Barotrauma
|
||||
limb.sprite.Origin = spriteOrigin;
|
||||
}
|
||||
|
||||
limb.Dir = Dir;
|
||||
|
||||
/*if (limb.LightSource != null)
|
||||
|
||||
if (limb.MouthPos.HasValue)
|
||||
{
|
||||
limb.LightSource.FlipX();
|
||||
}*/
|
||||
limb.MouthPos = new Vector2(
|
||||
-limb.MouthPos.Value.X,
|
||||
limb.MouthPos.Value.Y);
|
||||
}
|
||||
|
||||
if (limb.pullJoint != null)
|
||||
{
|
||||
@@ -663,12 +706,15 @@ namespace Barotrauma
|
||||
public Vector2 GetCenterOfMass()
|
||||
{
|
||||
Vector2 centerOfMass = Vector2.Zero;
|
||||
float totalMass = 0.0f;
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) continue;
|
||||
centerOfMass += limb.Mass * limb.SimPosition;
|
||||
totalMass += limb.Mass;
|
||||
}
|
||||
|
||||
centerOfMass /= Mass;
|
||||
centerOfMass /= totalMass;
|
||||
|
||||
return centerOfMass;
|
||||
}
|
||||
@@ -769,6 +815,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) continue;
|
||||
if (limb.body.FarseerBody.ContactList == null) continue;
|
||||
|
||||
ContactEdge ce = limb.body.FarseerBody.ContactList;
|
||||
@@ -781,6 +828,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) continue;
|
||||
limb.body.LinearVelocity += velocityChange;
|
||||
}
|
||||
|
||||
@@ -805,7 +853,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.ignoreCollisions) continue;
|
||||
if (limb.ignoreCollisions || limb.IsSevered) continue;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -1145,6 +1193,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) continue;
|
||||
//check visibility from the new position of the collider to the new position of this limb
|
||||
Vector2 movePos = limb.SimPosition + limbMoveAmount;
|
||||
|
||||
@@ -1208,6 +1257,7 @@ namespace Barotrauma
|
||||
//(in case the ragdoll has gotten stuck somewhere)
|
||||
foreach (Limb limb in Limbs)
|
||||
{
|
||||
if (limb.IsSevered) continue;
|
||||
limb.body.CollidesWith = Physics.CollisionNone;
|
||||
}
|
||||
|
||||
@@ -1463,22 +1513,28 @@ namespace Barotrauma
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
foreach (Limb l in Limbs)
|
||||
if (Limbs != null)
|
||||
{
|
||||
l.Remove();
|
||||
foreach (Limb l in Limbs)
|
||||
{
|
||||
l.Remove();
|
||||
}
|
||||
Limbs = null;
|
||||
}
|
||||
Limbs = null;
|
||||
|
||||
foreach (PhysicsBody b in collider)
|
||||
{
|
||||
b.Remove();
|
||||
}
|
||||
|
||||
foreach (RevoluteJoint joint in limbJoints)
|
||||
if (LimbJoints != null)
|
||||
{
|
||||
GameMain.World.RemoveJoint(joint);
|
||||
foreach (RevoluteJoint joint in LimbJoints)
|
||||
{
|
||||
GameMain.World.RemoveJoint(joint);
|
||||
}
|
||||
LimbJoints = null;
|
||||
}
|
||||
limbJoints = null;
|
||||
|
||||
list.Remove(this);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Barotrauma
|
||||
{
|
||||
public readonly float Damage;
|
||||
public readonly float Bleeding;
|
||||
|
||||
|
||||
public readonly bool HitArmor;
|
||||
|
||||
public AttackResult(float damage, float bleeding, bool hitArmor=false)
|
||||
@@ -49,6 +49,12 @@ namespace Barotrauma
|
||||
|
||||
public readonly float TargetForce;
|
||||
|
||||
public readonly float SeverLimbsProbability;
|
||||
|
||||
//the indices of the limbs Force is applied on
|
||||
//(if none, force is applied only to the limb the attack is attached to)
|
||||
public readonly List<int> ApplyForceOnLimbs;
|
||||
|
||||
private Sound sound;
|
||||
|
||||
private ParticleEmitterPrefab particleEmitterPrefab;
|
||||
@@ -91,29 +97,41 @@ namespace Barotrauma
|
||||
DamageType = DamageType.None;
|
||||
}
|
||||
|
||||
|
||||
damage = ToolBox.GetAttributeFloat(element, "damage", 0.0f);
|
||||
damage = ToolBox.GetAttributeFloat(element, "damage", 0.0f);
|
||||
structureDamage = ToolBox.GetAttributeFloat(element, "structuredamage", 0.0f);
|
||||
bleedingDamage = ToolBox.GetAttributeFloat(element, "bleedingdamage", 0.0f);
|
||||
bleedingDamage = ToolBox.GetAttributeFloat(element, "bleedingdamage", 0.0f);
|
||||
Stun = ToolBox.GetAttributeFloat(element, "stun", 0.0f);
|
||||
|
||||
Force = ToolBox.GetAttributeFloat(element,"force", 0.0f);
|
||||
TargetForce = ToolBox.GetAttributeFloat(element, "targetforce", 0.0f);
|
||||
|
||||
Torque = ToolBox.GetAttributeFloat(element, "torque", 0.0f);
|
||||
|
||||
Stun = ToolBox.GetAttributeFloat(element, "stun", 0.0f);
|
||||
SeverLimbsProbability = ToolBox.GetAttributeFloat(element, "severlimbsprobability", 0.0f);
|
||||
|
||||
Force = ToolBox.GetAttributeFloat(element, "force", 0.0f);
|
||||
TargetForce = ToolBox.GetAttributeFloat(element, "targetforce", 0.0f);
|
||||
Torque = ToolBox.GetAttributeFloat(element, "torque", 0.0f);
|
||||
|
||||
string soundPath = ToolBox.GetAttributeString(element, "sound", "");
|
||||
if (!string.IsNullOrWhiteSpace(soundPath))
|
||||
{
|
||||
sound = Sound.Load(soundPath);
|
||||
}
|
||||
|
||||
Range = ToolBox.GetAttributeFloat(element, "range", 0.0f);
|
||||
Range = ToolBox.GetAttributeFloat(element, "range", 0.0f);
|
||||
Duration = ToolBox.GetAttributeFloat(element, "duration", 0.0f);
|
||||
|
||||
Duration = ToolBox.GetAttributeFloat(element, "duration", 0.0f);
|
||||
|
||||
priority = ToolBox.GetAttributeFloat(element, "priority", 1.0f);
|
||||
priority = ToolBox.GetAttributeFloat(element, "priority", 1.0f);
|
||||
|
||||
string limbIndicesStr = ToolBox.GetAttributeString(element, "applyforceonlimbs", "");
|
||||
if (!string.IsNullOrWhiteSpace(limbIndicesStr))
|
||||
{
|
||||
ApplyForceOnLimbs = new List<int>();
|
||||
foreach (string limbIndexStr in limbIndicesStr.Split(','))
|
||||
{
|
||||
int limbIndex;
|
||||
if (int.TryParse(limbIndexStr, out limbIndex))
|
||||
{
|
||||
ApplyForceOnLimbs.Add(limbIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
|
||||
@@ -785,16 +785,14 @@ namespace Barotrauma
|
||||
if (IsKeyDown(InputType.Run))
|
||||
{
|
||||
//can't run if
|
||||
// - not a humanoid
|
||||
// - dragging someone
|
||||
// - crouching
|
||||
// - moving backwards
|
||||
if (AnimController is HumanoidAnimController &&
|
||||
selectedCharacter == null &&
|
||||
!((HumanoidAnimController)AnimController).Crouching &&
|
||||
if (selectedCharacter == null &&
|
||||
(!(AnimController is HumanoidAnimController) || !((HumanoidAnimController)AnimController).Crouching) &&
|
||||
Math.Sign(targetMovement.X) != -Math.Sign(AnimController.Dir))
|
||||
{
|
||||
targetMovement *= 3.0f;
|
||||
targetMovement *= AnimController.InWater ? AnimController.SwimSpeedMultiplier : AnimController.RunSpeedMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1161,9 +1159,10 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (moveCam && needsAir)
|
||||
if (moveCam)
|
||||
{
|
||||
if (pressureProtection < 80.0f &&
|
||||
if (needsAir &&
|
||||
pressureProtection < 80.0f &&
|
||||
(AnimController.CurrentHull == null || AnimController.CurrentHull.LethalPressure > 50.0f))
|
||||
{
|
||||
float pressure = AnimController.CurrentHull == null ? 100.0f : AnimController.CurrentHull.LethalPressure;
|
||||
@@ -1172,7 +1171,16 @@ namespace Barotrauma
|
||||
(pressure / 50.0f) * Rand.Range(1.0f, 1.05f),
|
||||
(pressure - 50.0f) / 50.0f);
|
||||
}
|
||||
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 250.0f, 0.05f);
|
||||
|
||||
if (IsHumanoid)
|
||||
{
|
||||
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, 250.0f, deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
//increased visibility range when controlling large a non-humanoid
|
||||
cam.OffsetAmount = MathHelper.Lerp(cam.OffsetAmount, MathHelper.Clamp(Mass, 250.0f, 800.0f), deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
cursorPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
@@ -1721,46 +1729,77 @@ namespace Barotrauma
|
||||
|
||||
public virtual AttackResult AddDamage(IDamageable attacker, Vector2 worldPosition, Attack attack, float deltaTime, bool playSound = false)
|
||||
{
|
||||
var attackResult = AddDamage(worldPosition, attack.DamageType, attack.GetDamage(deltaTime), attack.GetBleedingDamage(deltaTime), attack.Stun, playSound, attack.TargetForce);
|
||||
Limb limbHit = null;
|
||||
var attackResult = AddDamage(worldPosition, attack.DamageType, attack.GetDamage(deltaTime), attack.GetBleedingDamage(deltaTime), attack.Stun, playSound, attack.TargetForce, out limbHit);
|
||||
if (limbHit == null) return new AttackResult();
|
||||
|
||||
var attackingCharacter = attacker as Character;
|
||||
if (attackingCharacter != null && attackingCharacter.AIController == null)
|
||||
{
|
||||
GameServer.Log(Name + " attacked by " + attackingCharacter.Name+". Damage: "+attackResult.Damage+" Bleeding damage: "+attackResult.Bleeding, ServerLog.MessageType.Attack);
|
||||
}
|
||||
|
||||
if (GameMain.Client == null &&
|
||||
isDead &&
|
||||
health - attackResult.Damage <= minHealth && Rand.Range(0.0f, 1.0f) < attack.SeverLimbsProbability)
|
||||
{
|
||||
foreach (LimbJoint joint in AnimController.LimbJoints)
|
||||
{
|
||||
if (joint.CanBeSevered && (joint.LimbA == limbHit || joint.LimbB == limbHit))
|
||||
{
|
||||
AnimController.SeverLimbJoint(joint);
|
||||
|
||||
if (joint.LimbA == limbHit)
|
||||
{
|
||||
joint.LimbB.body.LinearVelocity += limbHit.LinearVelocity * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
joint.LimbA.body.LinearVelocity += limbHit.LinearVelocity * 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attackResult;
|
||||
}
|
||||
|
||||
public AttackResult AddDamage(Vector2 worldPosition, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound, float attackForce = 0.0f)
|
||||
{
|
||||
Limb temp = null;
|
||||
return AddDamage(worldPosition, damageType, amount, bleedingAmount, stun, playSound, attackForce, out temp);
|
||||
}
|
||||
|
||||
public AttackResult AddDamage(Vector2 worldPosition, DamageType damageType, float amount, float bleedingAmount, float stun, bool playSound, float attackForce, out Limb hitLimb)
|
||||
{
|
||||
hitLimb = null;
|
||||
|
||||
if (Removed) return new AttackResult();
|
||||
|
||||
SetStun(stun);
|
||||
|
||||
Limb closestLimb = null;
|
||||
|
||||
float closestDistance = 0.0f;
|
||||
foreach (Limb limb in AnimController.Limbs)
|
||||
{
|
||||
float distance = Vector2.Distance(worldPosition, limb.WorldPosition);
|
||||
if (closestLimb == null || distance < closestDistance)
|
||||
if (hitLimb == null || distance < closestDistance)
|
||||
{
|
||||
closestLimb = limb;
|
||||
hitLimb = limb;
|
||||
closestDistance = distance;
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.Abs(attackForce) > 0.0f)
|
||||
{
|
||||
closestLimb.body.ApplyForce((closestLimb.WorldPosition - worldPosition) * attackForce);
|
||||
Vector2 diff = hitLimb.WorldPosition - worldPosition;
|
||||
if (diff == Vector2.Zero) diff = Rand.Vector(1.0f);
|
||||
hitLimb.body.ApplyForce(Vector2.Normalize(diff) * attackForce, hitLimb.SimPosition + ConvertUnits.ToSimUnits(diff));
|
||||
}
|
||||
|
||||
AttackResult attackResult = closestLimb.AddDamage(worldPosition, damageType, amount, bleedingAmount, playSound);
|
||||
AttackResult attackResult = hitLimb.AddDamage(worldPosition, damageType, amount, bleedingAmount, playSound);
|
||||
|
||||
AddDamage(damageType == DamageType.Burn ? CauseOfDeath.Burn : causeOfDeath, attackResult.Damage, null);
|
||||
|
||||
//health -= attackResult.Damage;
|
||||
//if (health <= 0.0f && damageType == DamageType.Burn) Kill(CauseOfDeath.Burn);
|
||||
|
||||
if (DoesBleed)
|
||||
{
|
||||
Bleeding += attackResult.Bleeding;
|
||||
@@ -1834,7 +1873,7 @@ namespace Barotrauma
|
||||
new Vector2(Rand.Range(-50f, 50f), Rand.Range(-100f, 50f)));
|
||||
}
|
||||
|
||||
foreach (var joint in AnimController.limbJoints)
|
||||
foreach (var joint in AnimController.LimbJoints)
|
||||
{
|
||||
joint.LimitEnabled = false;
|
||||
}
|
||||
@@ -1884,20 +1923,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (selectedItems[i] != null) selectedItems[i].Drop(this);
|
||||
}
|
||||
|
||||
if (aiTarget != null)
|
||||
{
|
||||
aiTarget.Remove();
|
||||
aiTarget = null;
|
||||
}
|
||||
|
||||
|
||||
foreach (Limb limb in AnimController.Limbs)
|
||||
{
|
||||
if (limb.pullJoint == null) continue;
|
||||
limb.pullJoint.Enabled = false;
|
||||
}
|
||||
|
||||
foreach (RevoluteJoint joint in AnimController.limbJoints)
|
||||
foreach (RevoluteJoint joint in AnimController.LimbJoints)
|
||||
{
|
||||
joint.MotorEnabled = false;
|
||||
}
|
||||
@@ -1916,9 +1949,16 @@ namespace Barotrauma
|
||||
|
||||
Health = Math.Max(maxHealth * 0.1f, health);
|
||||
|
||||
foreach (RevoluteJoint joint in AnimController.limbJoints)
|
||||
foreach (LimbJoint joint in AnimController.LimbJoints)
|
||||
{
|
||||
joint.MotorEnabled = true;
|
||||
joint.Enabled = true;
|
||||
joint.IsSevered = false;
|
||||
}
|
||||
|
||||
foreach (Limb limb in AnimController.Limbs)
|
||||
{
|
||||
limb.IsSevered = false;
|
||||
}
|
||||
|
||||
if (GameMain.GameSession != null)
|
||||
@@ -1929,6 +1969,13 @@ namespace Barotrauma
|
||||
|
||||
public override void Remove()
|
||||
{
|
||||
#if DEBUG
|
||||
if (Removed)
|
||||
{
|
||||
DebugConsole.ThrowError("Attempting to remove an already removed character\n" + Environment.StackTrace);
|
||||
}
|
||||
#endif
|
||||
|
||||
base.Remove();
|
||||
|
||||
if (info != null) info.Remove();
|
||||
@@ -1939,7 +1986,7 @@ namespace Barotrauma
|
||||
|
||||
if (GameMain.Client != null && GameMain.Client.Character == this) GameMain.Client.Character = null;
|
||||
|
||||
if (aiTarget != null) aiTarget.Remove();
|
||||
if (aiTarget != null) aiTarget.Remove();
|
||||
|
||||
if (AnimController != null) AnimController.Remove();
|
||||
|
||||
|
||||
@@ -638,6 +638,19 @@ namespace Barotrauma
|
||||
if (isDead)
|
||||
{
|
||||
msg.Write((byte)causeOfDeath);
|
||||
List<int> severedJointIndices = new List<int>();
|
||||
for (int i = 0; i < AnimController.LimbJoints.Length; i++)
|
||||
{
|
||||
if (AnimController.LimbJoints[i] != null && AnimController.LimbJoints[i].IsSevered)
|
||||
{
|
||||
severedJointIndices.Add(i);
|
||||
}
|
||||
}
|
||||
msg.Write((byte)severedJointIndices.Count);
|
||||
foreach (int jointIndex in severedJointIndices)
|
||||
{
|
||||
msg.Write((byte)jointIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -677,6 +690,7 @@ namespace Barotrauma
|
||||
if (isDead)
|
||||
{
|
||||
causeOfDeath = (CauseOfDeath)msg.ReadByte();
|
||||
byte severedLimbCount = msg.ReadByte();
|
||||
if (causeOfDeath == CauseOfDeath.Pressure)
|
||||
{
|
||||
Implode(true);
|
||||
@@ -685,6 +699,11 @@ namespace Barotrauma
|
||||
{
|
||||
Kill(causeOfDeath, true);
|
||||
}
|
||||
for (int i = 0; i < severedLimbCount; i++)
|
||||
{
|
||||
int severedJointIndex = msg.ReadByte();
|
||||
AnimController.SeverLimbJoint(AnimController.LimbJoints[severedJointIndex]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -19,11 +19,33 @@ namespace Barotrauma
|
||||
LeftLeg, RightLeg, LeftFoot, RightFoot, Head, Torso, Tail, Legs, RightThigh, LeftThigh, Waist
|
||||
};
|
||||
|
||||
class LimbJoint : RevoluteJoint
|
||||
{
|
||||
public bool IsSevered;
|
||||
public bool CanBeSevered;
|
||||
|
||||
public readonly Limb LimbA, LimbB;
|
||||
|
||||
public LimbJoint(Limb limbA, Limb limbB, Vector2 anchor1, Vector2 anchor2)
|
||||
: base(limbA.body.FarseerBody, limbB.body.FarseerBody, anchor1, anchor2)
|
||||
{
|
||||
CollideConnected = false;
|
||||
MotorEnabled = true;
|
||||
MaxMotorTorque = 0.25f;
|
||||
|
||||
LimbA = limbA;
|
||||
LimbB = limbB;
|
||||
}
|
||||
}
|
||||
|
||||
class Limb
|
||||
{
|
||||
private const float LimbDensity = 15;
|
||||
private const float LimbAngularDamping = 7;
|
||||
|
||||
//how long it takes for severed limbs to fade out
|
||||
private const float SeveredFadeOutTime = 10.0f;
|
||||
|
||||
public readonly Character character;
|
||||
|
||||
//the physics body of the limb
|
||||
@@ -51,12 +73,17 @@ namespace Barotrauma
|
||||
|
||||
private float damage, burnt;
|
||||
|
||||
private bool isSevered;
|
||||
private float severedFadeOutTimer;
|
||||
|
||||
private readonly Vector2 armorSector;
|
||||
private readonly float armorValue;
|
||||
|
||||
Sound hitSound;
|
||||
public Vector2? MouthPos;
|
||||
|
||||
private Sound hitSound;
|
||||
//a timer for delaying when a hitsound/attacksound can be played again
|
||||
public float soundTimer;
|
||||
public float SoundTimer;
|
||||
public const float SoundInterval = 0.4f;
|
||||
|
||||
public readonly Attack attack;
|
||||
@@ -66,7 +93,24 @@ namespace Barotrauma
|
||||
private List<WearableSprite> wearingItems;
|
||||
|
||||
private Vector2 animTargetPos;
|
||||
|
||||
private float scale;
|
||||
|
||||
public float AttackTimer;
|
||||
|
||||
public bool IsSevered
|
||||
{
|
||||
get { return isSevered; }
|
||||
set
|
||||
{
|
||||
isSevered = value;
|
||||
if (isSevered)
|
||||
{
|
||||
damage = 100.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool DoesFlip
|
||||
{
|
||||
get { return doesFlip; }
|
||||
@@ -92,6 +136,11 @@ namespace Barotrauma
|
||||
get { return body.Rotation; }
|
||||
}
|
||||
|
||||
public float Scale
|
||||
{
|
||||
get { return scale; }
|
||||
}
|
||||
|
||||
//where an animcontroller is trying to pull the limb, only used for debug visualization
|
||||
public Vector2 AnimTargetPos
|
||||
{
|
||||
@@ -135,55 +184,23 @@ namespace Barotrauma
|
||||
{
|
||||
get { return stepOffset; }
|
||||
}
|
||||
|
||||
|
||||
public float Burnt
|
||||
{
|
||||
get { return burnt; }
|
||||
set { burnt = MathHelper.Clamp(value,0.0f,100.0f); }
|
||||
}
|
||||
|
||||
private float scale;
|
||||
|
||||
public float AttackTimer;
|
||||
|
||||
//public float Damage
|
||||
//{
|
||||
// get { return damage; }
|
||||
// set
|
||||
// {
|
||||
// damage = Math.Max(value, 0.0f);
|
||||
// if (damage >=maxHealth) Character.Kill();
|
||||
// }
|
||||
//}
|
||||
|
||||
//public float MaxHealth
|
||||
//{
|
||||
// get { return maxHealth; }
|
||||
//}
|
||||
|
||||
//public float Bleeding
|
||||
//{
|
||||
// get { return bleeding; }
|
||||
// set { bleeding = MathHelper.Clamp(value, 0.0f, 100.0f); }
|
||||
//}
|
||||
|
||||
|
||||
public List<WearableSprite> WearingItems
|
||||
{
|
||||
get { return wearingItems; }
|
||||
set { wearingItems = value; }
|
||||
}
|
||||
|
||||
//public WearableSprite WearingItemSprite
|
||||
//{
|
||||
// get { return wearingItemSprite; }
|
||||
// set { wearingItemSprite = value; }
|
||||
//}
|
||||
|
||||
|
||||
public Limb (Character character, XElement element, float scale = 1.0f)
|
||||
{
|
||||
this.character = character;
|
||||
|
||||
WearingItems = new List<WearableSprite>();
|
||||
wearingItems = new List<WearableSprite>();
|
||||
|
||||
dir = Direction.Right;
|
||||
|
||||
@@ -255,7 +272,12 @@ namespace Barotrauma
|
||||
armorSector.Y = MathHelper.ToRadians(armorSector.Y);
|
||||
|
||||
armorValue = Math.Max(ToolBox.GetAttributeFloat(element, "armor", 0.0f), 0.0f);
|
||||
|
||||
|
||||
if (element.Attribute("mouthpos") != null)
|
||||
{
|
||||
MouthPos = ConvertUnits.ToSimUnits(ToolBox.GetAttributeVector2(element, "mouthpos", Vector2.Zero));
|
||||
}
|
||||
|
||||
body.BodyType = BodyType.Dynamic;
|
||||
body.FarseerBody.AngularDamping = LimbAngularDamping;
|
||||
|
||||
@@ -340,7 +362,7 @@ namespace Barotrauma
|
||||
bool hitArmor = false;
|
||||
float totalArmorValue = 0.0f;
|
||||
|
||||
if (armorValue>0.0f && SectorHit(armorSector, position))
|
||||
if (armorValue > 0.0f && SectorHit(armorSector, position))
|
||||
{
|
||||
hitArmor = true;
|
||||
totalArmorValue += armorValue;
|
||||
@@ -354,8 +376,7 @@ namespace Barotrauma
|
||||
hitArmor = true;
|
||||
totalArmorValue += wearable.WearableComponent.ArmorValue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (hitArmor)
|
||||
{
|
||||
@@ -371,28 +392,19 @@ namespace Barotrauma
|
||||
SoundPlayer.PlayDamageSound(damageSoundType, amount, position);
|
||||
}
|
||||
|
||||
//Bleeding += bleedingAmount;
|
||||
//Damage += amount;
|
||||
float bloodParticleAmount = hitArmor || bleedingAmount <= 0.0f ? 0 : (int)Math.Min(amount / 5, 10);
|
||||
float bloodParticleSize = MathHelper.Clamp(amount / 50.0f, 0.1f, 1.0f);
|
||||
|
||||
float bloodAmount = hitArmor || bleedingAmount<=0.0f ? 0 : (int)Math.Min((int)(amount * 2.0f), 20);
|
||||
for (int i = 0; i < bloodParticleAmount; i++)
|
||||
{
|
||||
var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", WorldPosition, Vector2.Zero, 0.0f, character.AnimController.CurrentHull);
|
||||
if (blood != null)
|
||||
{
|
||||
blood.Size *= bloodParticleSize;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < bloodAmount; i++)
|
||||
{
|
||||
Vector2 particleVel = SimPosition - position;
|
||||
if (particleVel != Vector2.Zero) particleVel = Vector2.Normalize(particleVel);
|
||||
|
||||
GameMain.ParticleManager.CreateParticle("blood",
|
||||
WorldPosition,
|
||||
particleVel * Rand.Range(100.0f, 300.0f), 0.0f, character.AnimController.CurrentHull);
|
||||
}
|
||||
|
||||
for (int i = 0; i < bloodAmount / 2; i++)
|
||||
{
|
||||
GameMain.ParticleManager.CreateParticle("waterblood", WorldPosition, Vector2.Zero, 0.0f, character.AnimController.CurrentHull);
|
||||
}
|
||||
|
||||
damage += Math.Max(amount,bleedingAmount) / character.MaxHealth * 100.0f;
|
||||
|
||||
damage += Math.Max(amount, bleedingAmount) / character.MaxHealth * 100.0f;
|
||||
|
||||
return new AttackResult(amount, bleedingAmount, hitArmor);
|
||||
}
|
||||
@@ -418,9 +430,7 @@ namespace Barotrauma
|
||||
{
|
||||
LightSource.ParentSub = body.Submarine;
|
||||
}
|
||||
|
||||
if (!character.IsDead) damage = Math.Max(0.0f, damage-deltaTime*0.1f);
|
||||
|
||||
|
||||
if (burnt > 0.0f) Burnt -= deltaTime;
|
||||
|
||||
if (LinearVelocity.X > 500.0f)
|
||||
@@ -435,9 +445,19 @@ namespace Barotrauma
|
||||
body.ApplyWaterForces();
|
||||
}
|
||||
|
||||
if (isSevered)
|
||||
{
|
||||
severedFadeOutTimer += deltaTime;
|
||||
if (severedFadeOutTimer > SeveredFadeOutTime)
|
||||
{
|
||||
body.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (character.IsDead) return;
|
||||
|
||||
soundTimer -= deltaTime;
|
||||
damage = Math.Max(0.0f, damage - deltaTime * 0.1f);
|
||||
SoundTimer -= deltaTime;
|
||||
|
||||
//if (MathUtils.RandomFloat(0.0f, 1000.0f) < Bleeding)
|
||||
//{
|
||||
@@ -446,12 +466,7 @@ namespace Barotrauma
|
||||
// SimPosition, Vector2.Zero);
|
||||
//}
|
||||
}
|
||||
|
||||
public void ActivateDamagedSprite()
|
||||
{
|
||||
damage = 100.0f;
|
||||
}
|
||||
|
||||
|
||||
public void UpdateAttack(float deltaTime, Vector2 attackPosition, IDamageable damageTarget)
|
||||
{
|
||||
float dist = ConvertUnits.ToDisplayUnits(Vector2.Distance(SimPosition, attackPosition));
|
||||
@@ -464,19 +479,34 @@ namespace Barotrauma
|
||||
{
|
||||
if (AttackTimer >= attack.Duration && damageTarget != null)
|
||||
{
|
||||
attack.DoDamage(character, damageTarget, WorldPosition, 1.0f, (soundTimer <= 0.0f));
|
||||
attack.DoDamage(character, damageTarget, WorldPosition, 1.0f, (SoundTimer <= 0.0f));
|
||||
|
||||
soundTimer = Limb.SoundInterval;
|
||||
SoundTimer = SoundInterval;
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 diff = attackPosition - SimPosition;
|
||||
if (diff.LengthSquared() > 0.00001f)
|
||||
if (diff.LengthSquared() < 0.00001f) return;
|
||||
|
||||
if (attack.ApplyForceOnLimbs != null)
|
||||
{
|
||||
Vector2 pos = pullJoint == null ? body.SimPosition : pullJoint.WorldAnchorA;
|
||||
body.ApplyLinearImpulse(Mass * attack.Force *
|
||||
Vector2.Normalize(attackPosition - SimPosition), pos);
|
||||
foreach (int limbIndex in attack.ApplyForceOnLimbs)
|
||||
{
|
||||
if (limbIndex < 0 || limbIndex >= character.AnimController.Limbs.Length) continue;
|
||||
|
||||
Limb limb = character.AnimController.Limbs[limbIndex];
|
||||
Vector2 forcePos = limb.pullJoint == null ? limb.body.SimPosition : limb.pullJoint.WorldAnchorA;
|
||||
limb.body.ApplyLinearImpulse(
|
||||
limb.Mass * attack.Force * Vector2.Normalize(attackPosition - SimPosition), forcePos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 forcePos = pullJoint == null ? body.SimPosition : pullJoint.WorldAnchorA;
|
||||
body.ApplyLinearImpulse(Mass * attack.Force *
|
||||
Vector2.Normalize(attackPosition - SimPosition), forcePos);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
@@ -484,10 +514,21 @@ namespace Barotrauma
|
||||
float brightness = 1.0f - (burnt / 100.0f) * 0.5f;
|
||||
Color color = new Color(brightness, brightness, brightness);
|
||||
|
||||
if (isSevered)
|
||||
{
|
||||
if (severedFadeOutTimer > SeveredFadeOutTime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (severedFadeOutTimer > SeveredFadeOutTime - 1.0f)
|
||||
{
|
||||
color *= SeveredFadeOutTime - severedFadeOutTimer;
|
||||
}
|
||||
}
|
||||
|
||||
body.Dir = Dir;
|
||||
|
||||
bool hideLimb = wearingItems.Any(w => w != null && w.HideLimb);
|
||||
|
||||
if (!hideLimb)
|
||||
{
|
||||
body.Draw(spriteBatch, sprite, color, null, scale);
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace Barotrauma
|
||||
private bool spawnDeep;
|
||||
|
||||
private bool disallowed;
|
||||
|
||||
private bool repeat;
|
||||
|
||||
private Level.PositionType spawnPosType;
|
||||
|
||||
@@ -39,7 +41,9 @@ namespace Barotrauma
|
||||
{
|
||||
characterFile = ToolBox.GetAttributeString(element, "characterfile", "");
|
||||
|
||||
minAmount = ToolBox.GetAttributeInt(element, "minamount", 1);
|
||||
int defaultAmount = ToolBox.GetAttributeInt(element, "amount", 1);
|
||||
|
||||
minAmount = ToolBox.GetAttributeInt(element, "minamount", defaultAmount);
|
||||
maxAmount = Math.Max(ToolBox.GetAttributeInt(element, "maxamount", 1), minAmount);
|
||||
|
||||
var spawnPosTypeStr = ToolBox.GetAttributeString(element, "spawntype", "");
|
||||
@@ -52,6 +56,8 @@ namespace Barotrauma
|
||||
|
||||
spawnDeep = ToolBox.GetAttributeBool(element, "spawndeep", false);
|
||||
|
||||
repeat = ToolBox.GetAttributeBool(element, "repeat", repeat);
|
||||
|
||||
if (GameMain.NetworkMember != null)
|
||||
{
|
||||
List<string> monsterNames = GameMain.NetworkMember.monsterEnabled.Keys.ToList();
|
||||
@@ -67,18 +73,17 @@ namespace Barotrauma
|
||||
{
|
||||
base.Init();
|
||||
|
||||
SpawnMonsters();
|
||||
SpawnMonsters(Rand.Range(minAmount, maxAmount, false));
|
||||
}
|
||||
|
||||
private void SpawnMonsters()
|
||||
private Character[] SpawnMonsters(int amount)
|
||||
{
|
||||
if (disallowed) return;
|
||||
if (disallowed) return null;
|
||||
|
||||
Vector2 spawnPos = Level.Loaded.GetRandomInterestingPosition(true, spawnPosType, true);
|
||||
|
||||
int amount = Rand.Range(minAmount, maxAmount, false);
|
||||
|
||||
monsters = new Character[amount];
|
||||
var monsters = new Character[amount];
|
||||
|
||||
if (spawnDeep) spawnPos.Y -= Level.Loaded.Size.Y;
|
||||
|
||||
@@ -88,6 +93,8 @@ namespace Barotrauma
|
||||
spawnPos.Y += Rand.Range(-0.5f, 0.5f, false);
|
||||
monsters[i] = Character.Create(characterFile, spawnPos, null, GameMain.Client != null);
|
||||
}
|
||||
|
||||
return monsters;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
@@ -97,7 +104,29 @@ namespace Barotrauma
|
||||
Finished();
|
||||
return;
|
||||
}
|
||||
if (monsters == null) SpawnMonsters();
|
||||
|
||||
if (monsters == null)
|
||||
{
|
||||
monsters = SpawnMonsters(Rand.Range(minAmount, maxAmount, false));
|
||||
return;
|
||||
}
|
||||
|
||||
if (repeat)
|
||||
{
|
||||
//clients aren't allowed to spawn more monsters mid-round
|
||||
if (GameMain.Client != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < monsters.Length; i++)
|
||||
{
|
||||
if (monsters[i] == null || monsters[i].Removed || monsters[i].IsDead)
|
||||
{
|
||||
monsters[i] = SpawnMonsters(1)[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isFinished) return;
|
||||
|
||||
@@ -128,7 +157,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (monstersDead) Finished();
|
||||
if (monstersDead && !repeat) Finished();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +655,7 @@ namespace Barotrauma.Tutorials
|
||||
|
||||
enemy.Health = 50.0f;
|
||||
|
||||
enemy.AIController.State = AIController.AiState.None;
|
||||
enemy.AIController.State = AIController.AIState.None;
|
||||
|
||||
Vector2 targetPos = Character.Controlled.WorldPosition + new Vector2(0.0f, 3000.0f);
|
||||
|
||||
|
||||
@@ -60,6 +60,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (character != null && !characterUsable) return false;
|
||||
|
||||
User = character;
|
||||
|
||||
Launch(new Vector2(
|
||||
(float)Math.Cos(item.body.Rotation),
|
||||
(float)Math.Sin(item.body.Rotation)) * launchImpulse * item.body.Mass);
|
||||
@@ -147,7 +149,7 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
|
||||
AttackResult attackResult = new AttackResult(0.0f, 0.0f);
|
||||
AttackResult attackResult = new AttackResult();
|
||||
if (attack != null)
|
||||
{
|
||||
var submarine = f2.Body.UserData as Submarine;
|
||||
|
||||
@@ -190,7 +190,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
Launch(projectiles[0].Item);
|
||||
Launch(projectiles[0].Item, character);
|
||||
|
||||
if (character != null)
|
||||
{
|
||||
@@ -200,7 +200,7 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Launch(Item projectile)
|
||||
private void Launch(Item projectile, Character user = null)
|
||||
{
|
||||
reload = reloadTime;
|
||||
|
||||
@@ -217,6 +217,7 @@ namespace Barotrauma.Items.Components
|
||||
if (projectileComponent != null)
|
||||
{
|
||||
projectileComponent.Use((float)Timing.Step);
|
||||
projectileComponent.User = user;
|
||||
}
|
||||
|
||||
if (projectile.Container != null) projectile.Container.RemoveContained(projectile);
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace Barotrauma
|
||||
|
||||
if (force == 0.0f && attack.Stun == 0.0f && attack.GetDamage(1.0f) == 0.0f) return;
|
||||
|
||||
ApplyExplosionForces(worldPosition, attack.Range, force, attack.GetDamage(1.0f), attack.Stun);
|
||||
ApplyExplosionForces(worldPosition, attack, force);
|
||||
|
||||
if (flames && GameMain.Client == null)
|
||||
{
|
||||
@@ -141,9 +141,9 @@ namespace Barotrauma
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public static void ApplyExplosionForces(Vector2 worldPosition, float range, float force, float damage = 0.0f, float stun = 0.0f)
|
||||
public static void ApplyExplosionForces(Vector2 worldPosition, Attack attack, float force)
|
||||
{
|
||||
if (range <= 0.0f) return;
|
||||
if (attack.Range <= 0.0f) return;
|
||||
|
||||
foreach (Character c in Character.CharacterList)
|
||||
{
|
||||
@@ -152,6 +152,7 @@ namespace Barotrauma
|
||||
|
||||
explosionPos = ConvertUnits.ToSimUnits(explosionPos);
|
||||
|
||||
bool wasDead = c.IsDead;
|
||||
foreach (Limb limb in c.AnimController.Limbs)
|
||||
{
|
||||
float dist = Vector2.Distance(limb.WorldPosition, worldPosition);
|
||||
@@ -160,24 +161,36 @@ namespace Barotrauma
|
||||
//doesn't take the rotation of the limb into account, but should be accurate enough for this purpose
|
||||
float limbRadius = Math.Max(Math.Max(limb.body.width * 0.5f, limb.body.height * 0.5f), limb.body.radius);
|
||||
dist = Math.Max(0.0f, dist - FarseerPhysics.ConvertUnits.ToDisplayUnits(limbRadius));
|
||||
|
||||
if (dist > attack.Range) continue;
|
||||
|
||||
if (dist > range) continue;
|
||||
|
||||
float distFactor = 1.0f - dist / range;
|
||||
float distFactor = 1.0f - dist / attack.Range;
|
||||
|
||||
//solid obstacles between the explosion and the limb reduce the effect of the explosion by 90%
|
||||
if (Submarine.CheckVisibility(limb.SimPosition, explosionPos) != null) distFactor *= 0.1f;
|
||||
|
||||
c.AddDamage(limb.WorldPosition, DamageType.None,
|
||||
damage / c.AnimController.Limbs.Length * distFactor, 0.0f, stun * distFactor, false);
|
||||
attack.GetDamage(1.0f) / c.AnimController.Limbs.Length * distFactor,
|
||||
attack.GetBleedingDamage(1.0f) / c.AnimController.Limbs.Length * distFactor,
|
||||
attack.Stun * distFactor,
|
||||
false);
|
||||
|
||||
if (limb.WorldPosition == worldPosition) continue;
|
||||
|
||||
if (force > 0.0f)
|
||||
if (limb.WorldPosition != worldPosition && force > 0.0f)
|
||||
{
|
||||
limb.body.ApplyLinearImpulse(Vector2.Normalize(limb.WorldPosition - worldPosition) * distFactor * force);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!wasDead && c.IsDead)
|
||||
{
|
||||
foreach (LimbJoint joint in c.AnimController.LimbJoints)
|
||||
{
|
||||
if (Rand.Range(0.0f, 1.0f) < attack.SeverLimbsProbability)
|
||||
{
|
||||
c.AnimController.SeverLimbJoint(joint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +109,7 @@ namespace Barotrauma
|
||||
public void AddToRemoveQueue(Entity entity)
|
||||
{
|
||||
if (GameMain.Client != null) return;
|
||||
if (removeQueue.Contains(entity) || entity.Removed) return;
|
||||
|
||||
removeQueue.Enqueue(entity);
|
||||
}
|
||||
@@ -116,6 +117,7 @@ namespace Barotrauma
|
||||
public void AddToRemoveQueue(Item item)
|
||||
{
|
||||
if (GameMain.Client != null) return;
|
||||
if (removeQueue.Contains(item) || item.Removed) return;
|
||||
|
||||
removeQueue.Enqueue(item);
|
||||
if (item.ContainedItems == null) return;
|
||||
|
||||
@@ -217,7 +217,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
jointList.ClearChildren();
|
||||
foreach (RevoluteJoint joint in character.AnimController.limbJoints)
|
||||
foreach (RevoluteJoint joint in character.AnimController.LimbJoints)
|
||||
{
|
||||
Limb limb1 = (Limb)(joint.BodyA.UserData);
|
||||
Limb limb2 = (Limb)(joint.BodyB.UserData);
|
||||
@@ -236,7 +236,7 @@ namespace Barotrauma
|
||||
|
||||
private void DrawJoints(SpriteBatch spriteBatch, Limb limb, Vector2 limbBodyPos)
|
||||
{
|
||||
foreach (var joint in editingCharacter.AnimController.limbJoints)
|
||||
foreach (var joint in editingCharacter.AnimController.LimbJoints)
|
||||
{
|
||||
Vector2 jointPos = Vector2.Zero;
|
||||
|
||||
@@ -253,24 +253,27 @@ namespace Barotrauma
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
jointPos.Y = -jointPos.Y;
|
||||
jointPos += limbBodyPos;
|
||||
|
||||
Vector2 tformedJointPos = jointPos /= limb.Scale;
|
||||
tformedJointPos.Y = -tformedJointPos.Y;
|
||||
tformedJointPos += limbBodyPos;
|
||||
|
||||
if (joint.BodyA == limb.body.FarseerBody)
|
||||
{
|
||||
float a1 = joint.UpperLimit - MathHelper.PiOver2;
|
||||
float a2 = joint.LowerLimit - MathHelper.PiOver2;
|
||||
float a3 =( a1+a2)/2.0f;
|
||||
GUI.DrawLine(spriteBatch, jointPos, jointPos + new Vector2((float)Math.Cos(a1), -(float)Math.Sin(a1)) * 30.0f, Color.Green);
|
||||
GUI.DrawLine(spriteBatch, jointPos, jointPos + new Vector2((float)Math.Cos(a2), -(float)Math.Sin(a2)) * 30.0f, Color.DarkGreen);
|
||||
float a3 = (a1 + a2) / 2.0f;
|
||||
GUI.DrawLine(spriteBatch, tformedJointPos, tformedJointPos + new Vector2((float)Math.Cos(a1), -(float)Math.Sin(a1)) * 30.0f, Color.Green);
|
||||
GUI.DrawLine(spriteBatch, tformedJointPos, tformedJointPos + new Vector2((float)Math.Cos(a2), -(float)Math.Sin(a2)) * 30.0f, Color.DarkGreen);
|
||||
|
||||
GUI.DrawLine(spriteBatch, jointPos, jointPos + new Vector2((float)Math.Cos(a3), -(float)Math.Sin(a3)) * 30.0f, Color.LightGray);
|
||||
GUI.DrawLine(spriteBatch, tformedJointPos, tformedJointPos + new Vector2((float)Math.Cos(a3), -(float)Math.Sin(a3)) * 30.0f, Color.LightGray);
|
||||
}
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, jointPos, new Vector2(5.0f, 5.0f), Color.Red, true);
|
||||
if (Vector2.Distance(PlayerInput.MousePosition, jointPos) < 6.0f)
|
||||
GUI.DrawRectangle(spriteBatch, tformedJointPos, new Vector2(5.0f, 5.0f), Color.Red, true);
|
||||
if (Vector2.Distance(PlayerInput.MousePosition, tformedJointPos) < 10.0f)
|
||||
{
|
||||
GUI.DrawRectangle(spriteBatch, jointPos - new Vector2(3.0f, 3.0f), new Vector2(11.0f, 11.0f), Color.Red, false);
|
||||
GUI.DrawString(spriteBatch, tformedJointPos + Vector2.One*10.0f, jointPos.ToString(), Color.White, Color.Black * 0.5f);
|
||||
GUI.DrawRectangle(spriteBatch, tformedJointPos - new Vector2(3.0f, 3.0f), new Vector2(11.0f, 11.0f), Color.Red, false);
|
||||
if (PlayerInput.LeftButtonHeld())
|
||||
{
|
||||
Vector2 speed = ConvertUnits.ToSimUnits(PlayerInput.MouseSpeed);
|
||||
|
||||
@@ -162,6 +162,35 @@ namespace Barotrauma
|
||||
return value;
|
||||
}
|
||||
|
||||
public static float GetAttributeFloat(XElement element, float defaultValue, params string[] matchingAttributeName)
|
||||
{
|
||||
if (element == null) return defaultValue;
|
||||
|
||||
foreach (string name in matchingAttributeName)
|
||||
{
|
||||
if (element.Attribute(name) == null) continue;
|
||||
|
||||
float val = defaultValue;
|
||||
|
||||
try
|
||||
{
|
||||
if (!float.TryParse(element.Attribute(name).Value, NumberStyles.Float, CultureInfo.InvariantCulture, out val))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in "+element+"!", e);
|
||||
continue;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public static float GetAttributeFloat(XElement element, string name, float defaultValue)
|
||||
{
|
||||
if (element == null || element.Attribute(name) == null) return defaultValue;
|
||||
|
||||