Merge branch 'ai-overhaul'

Conflicts:
	Barotrauma/Source/Characters/Attack.cs
This commit is contained in:
Joonas Rikkonen
2017-06-29 17:02:37 +03:00
46 changed files with 1148 additions and 488 deletions

View File

@@ -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>

View File

@@ -9,7 +9,7 @@
<ErrorReportUrlHistory />
<FallbackCulture>en-US</FallbackCulture>
<VerifyUploadedFiles>false</VerifyUploadedFiles>
<ProjectView>ProjectFiles</ProjectView>
<ProjectView>ShowAllFiles</ProjectView>
</PropertyGroup>
<PropertyGroup>
<ReferencePath>

View File

@@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 609 KiB

After

Width:  |  Height:  |  Size: 617 KiB

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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">

View File

@@ -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">

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View File

@@ -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"/>

View File

@@ -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; }

View File

@@ -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)

View File

@@ -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;

View File

@@ -51,7 +51,7 @@ namespace Barotrauma
{
switch (aiController.State)
{
case AIController.AiState.Attack:
case AIController.AIState.Attack:
PlaySound(CharacterSound.SoundType.Attack);
break;
default:

View File

@@ -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) { }
}

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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())
{

View File

@@ -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();

View File

@@ -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
{

View File

@@ -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);

View File

@@ -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();
}
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}
}
}
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;