Alien ruins, some new alien items and a new monster
This commit is contained in:
@@ -134,6 +134,10 @@
|
|||||||
<Compile Include="Source\Map\FireSource.cs" />
|
<Compile Include="Source\Map\FireSource.cs" />
|
||||||
<Compile Include="Source\Map\Levels\CaveGenerator.cs" />
|
<Compile Include="Source\Map\Levels\CaveGenerator.cs" />
|
||||||
<Compile Include="Source\Map\Levels\LevelRenderer.cs" />
|
<Compile Include="Source\Map\Levels\LevelRenderer.cs" />
|
||||||
|
<Compile Include="Source\Map\Levels\Ruins\BTRoom.cs" />
|
||||||
|
<Compile Include="Source\Map\Levels\Ruins\Corridor.cs" />
|
||||||
|
<Compile Include="Source\Map\Levels\Ruins\RuinGenerator.cs" />
|
||||||
|
<Compile Include="Source\Map\Levels\Ruins\RuinStructure.cs" />
|
||||||
<Compile Include="Source\Map\Levels\WrappingWall.cs" />
|
<Compile Include="Source\Map\Levels\WrappingWall.cs" />
|
||||||
<Compile Include="Source\Map\Lights\LightSource.cs" />
|
<Compile Include="Source\Map\Lights\LightSource.cs" />
|
||||||
<Compile Include="Source\Map\Map\LocationType.cs" />
|
<Compile Include="Source\Map\Map\LocationType.cs" />
|
||||||
@@ -357,6 +361,13 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="Content\Characters\Fractalguardian\fractalguardian.xml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Content\Characters\Fractalguardian\fractalguardian.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="Content\Characters\Husk\DivingSuit.png">
|
<Content Include="Content\Characters\Husk\DivingSuit.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@@ -446,11 +457,15 @@
|
|||||||
<Content Include="Content\InfoTexts.xml">
|
<Content Include="Content\InfoTexts.xml">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="Content\Items\Artifacts\alientools.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="Content\Items\Artifacts\artifact.png">
|
<Content Include="Content\Items\Artifacts\artifact.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="Content\Items\Artifacts\artifacts.xml">
|
<Content Include="Content\Items\Artifacts\artifacts.xml">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
</Content>
|
</Content>
|
||||||
<Content Include="Content\Items\blank.png">
|
<Content Include="Content\Items\blank.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
@@ -706,6 +721,16 @@
|
|||||||
<Content Include="Content\Map\researchSymbol.png">
|
<Content Include="Content\Map\researchSymbol.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Include="Content\Map\RuinConfig.xml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Content\Map\ruins.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Content\Map\ruins2.png">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
<Content Include="Content\Map\shaft.png">
|
<Content Include="Content\Map\shaft.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
@@ -974,6 +999,12 @@
|
|||||||
<None Include="Content\Characters\Endworm\endwormidle.ogg">
|
<None Include="Content\Characters\Endworm\endwormidle.ogg">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="Content\Characters\Fractalguardian\guardian1.ogg">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="Content\Characters\Fractalguardian\guardian2.ogg">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Include="Content\Characters\Husk\Husk1.ogg">
|
<None Include="Content\Characters\Husk\Husk1.ogg">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
@@ -1166,6 +1197,9 @@
|
|||||||
<None Include="Content\Sounds\Music\amb_JD_drone_clattering_machine.ogg">
|
<None Include="Content\Sounds\Music\amb_JD_drone_clattering_machine.ogg">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="Content\Sounds\Music\Controlled Chaos.ogg">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Include="Content\Sounds\Music\Enter the Maze.ogg">
|
<None Include="Content\Sounds\Music\Enter the Maze.ogg">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 120 KiB |
@@ -0,0 +1,52 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Character name="fractalguardian" humanoid="false" health="500.0" doesbleed="false">
|
||||||
|
|
||||||
|
<sound file="Content/Characters/Fractalguardian/guardian1.ogg" state="Attack" range="3000" />
|
||||||
|
<sound file="Content/Characters/Fractalguardian/guardian2.ogg" state="Attack" range="3000" />
|
||||||
|
|
||||||
|
<ragdoll waveamplitude="100.0" wavelength="1000" speed="2.5" flip="false" canentersubmarine="false">
|
||||||
|
|
||||||
|
<!-- head -->
|
||||||
|
<limb id = "0" radius="65" type="Head" steerforce="3.0">
|
||||||
|
<sprite texture="Content/Characters/Fractalguardian/fractalguardian.png" sourcerect="0,0,129,128" depth="0.05"/>
|
||||||
|
</limb>
|
||||||
|
|
||||||
|
<!-- body -->
|
||||||
|
<limb id = "1" radius="50" type="Torso">
|
||||||
|
<sprite texture="Content/Characters/Fractalguardian/fractalguardian.png" sourcerect="0,125,108,105" depth="0.01" origin="0.5,0.5"/>
|
||||||
|
</limb>
|
||||||
|
|
||||||
|
<!-- body -->
|
||||||
|
<limb id = "2" radius="45" height="75" type="Torso">
|
||||||
|
<sprite texture="Content/Characters/Fractalguardian/fractalguardian.png" sourcerect="0,239,90,136" depth="0.02" origin="0.5,0.5"/>
|
||||||
|
</limb>
|
||||||
|
|
||||||
|
<limb id = "3" width="30" height="175" type="Tail">
|
||||||
|
<sprite texture="Content/Characters/Fractalguardian/fractalguardian.png" sourcerect="131,0,36,175" depth="0.04" origin="0.5,0.5"/>
|
||||||
|
</limb>
|
||||||
|
|
||||||
|
<limb id = "4" width="30" height="239" impacttolerance="100.0">
|
||||||
|
<sprite texture="Content/Characters/Fractalguardian/fractalguardian.png" sourcerect="183,0,53,238" depth="0.08" origin="0.5,0.5"/>
|
||||||
|
<attack type="PinchCCW" range="150" duration="0.5" damage="30" stun="5.0" damagetype="slash"/>
|
||||||
|
</limb>
|
||||||
|
|
||||||
|
<limb id = "5" width="30" height="239" impacttolerance="100.0">
|
||||||
|
<sprite texture="Content/Characters/Fractalguardian/fractalguardian.png" sourcerect="236,0,53,238" size="-1,1" depth="0.08" origin="0.5,0.5"/>
|
||||||
|
<attack type="PinchCW" range="150" duration="0.5" damage="30" stun="5.0" damagetype="slash"/>
|
||||||
|
</limb>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- head to body -->
|
||||||
|
<joint limb1="0" limb1anchor="0,-60" limb2="1" limb2anchor="0,30" lowerlimit="-30" upperlimit="30"/>
|
||||||
|
|
||||||
|
<joint limb1="1" limb1anchor="0,-47" limb2="2" limb2anchor="0,56" lowerlimit="-30" upperlimit="30"/>
|
||||||
|
|
||||||
|
<joint limb1="2" limb1anchor="0,-60" limb2="3" limb2anchor="0,80" lowerlimit="-30" upperlimit="30"/>
|
||||||
|
|
||||||
|
<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"/>
|
||||||
|
</ragdoll>
|
||||||
|
|
||||||
|
<ai attackrooms="0.0" attackhumans="100" sight="1.0" hearing="2.0"/>
|
||||||
|
</Character>
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 23 KiB |
@@ -4,7 +4,7 @@
|
|||||||
name="Skyholder Artifact"
|
name="Skyholder Artifact"
|
||||||
pickdistance="150">
|
pickdistance="150">
|
||||||
|
|
||||||
<Sprite texture="artifact.png" depth="0.7" sourcerect="0,0,38,60"/>
|
<Sprite texture="artifact.png" depth="0.7" sourcerect="59,0,60,61"/>
|
||||||
|
|
||||||
<Deconstruct time="30">
|
<Deconstruct time="30">
|
||||||
<Item name="Steel Bar"/>
|
<Item name="Steel Bar"/>
|
||||||
@@ -13,8 +13,7 @@
|
|||||||
<Item name="Uranium Bar"/>
|
<Item name="Uranium Bar"/>
|
||||||
</Deconstruct>
|
</Deconstruct>
|
||||||
|
|
||||||
|
<Body width="60" height="61" density="50"/>
|
||||||
<Body width="36" height="60" density="50"/>
|
|
||||||
|
|
||||||
<Holdable slots="RightHand+LeftHand" holdpos="30,-15" handle1="0,10" handle2="0,-10">
|
<Holdable slots="RightHand+LeftHand" holdpos="30,-15" handle1="0,10" handle2="0,-10">
|
||||||
<StatusEffect type="Always" target="Hull" oxygen="-50000.0"/>
|
<StatusEffect type="Always" target="Hull" oxygen="-50000.0"/>
|
||||||
@@ -25,7 +24,7 @@
|
|||||||
name="Thermal Artifact"
|
name="Thermal Artifact"
|
||||||
pickdistance="150">
|
pickdistance="150">
|
||||||
|
|
||||||
<Sprite texture="artifact.png" depth="0.7" sourcerect="75,0,50,62"/>
|
<Sprite texture="artifact.png" depth="0.7" sourcerect="0,0,58,56"/>
|
||||||
|
|
||||||
<Deconstruct time="30">
|
<Deconstruct time="30">
|
||||||
<Item name="Steel Bar"/>
|
<Item name="Steel Bar"/>
|
||||||
@@ -34,7 +33,7 @@
|
|||||||
<Item name="Incendium Bar"/>
|
<Item name="Incendium Bar"/>
|
||||||
</Deconstruct>
|
</Deconstruct>
|
||||||
|
|
||||||
<Body radius="20" height="20" density="50"/>
|
<Body radius="28" density="50"/>
|
||||||
|
|
||||||
<Holdable slots="RightHand+LeftHand" holdpos="30,-15" handle1="0,10" handle2="0,-10">
|
<Holdable slots="RightHand+LeftHand" holdpos="30,-15" handle1="0,10" handle2="0,-10">
|
||||||
<StatusEffect type="Always">
|
<StatusEffect type="Always">
|
||||||
@@ -47,7 +46,7 @@
|
|||||||
name="Faraday Artifact"
|
name="Faraday Artifact"
|
||||||
pickdistance="150">
|
pickdistance="150">
|
||||||
|
|
||||||
<Sprite texture="artifact.png" depth="0.7" sourcerect="40,0,33,61"/>
|
<Sprite texture="artifact.png" depth="0.7" sourcerect="0,56,60,49"/>
|
||||||
|
|
||||||
<Deconstruct time="30">
|
<Deconstruct time="30">
|
||||||
<Item name="Steel Bar"/>
|
<Item name="Steel Bar"/>
|
||||||
@@ -56,8 +55,87 @@
|
|||||||
<Item name="Fulgurium Bar"/>
|
<Item name="Fulgurium Bar"/>
|
||||||
</Deconstruct>
|
</Deconstruct>
|
||||||
|
|
||||||
<Body radius="20" height="20" density="50"/>
|
<Body radius="25" density="50"/>
|
||||||
|
|
||||||
<Holdable slots="RightHand+LeftHand" holdpos="30,-15" handle1="0,10" handle2="0,-10"/>
|
<Holdable slots="RightHand+LeftHand" holdpos="30,-15" handle1="0,10" handle2="0,-10"/>
|
||||||
</Item>
|
</Item>
|
||||||
|
|
||||||
|
<Item
|
||||||
|
name="Oxygenite Shard"
|
||||||
|
pickdistance="150"
|
||||||
|
tags="smallitem"
|
||||||
|
impacttolerance="8">
|
||||||
|
|
||||||
|
<Sprite texture="artifact.png" depth="0.7" sourcerect="119,96,9,32"/>
|
||||||
|
|
||||||
|
<Body width="9" height="32" density="15"/>
|
||||||
|
|
||||||
|
<Holdable slots="Any,RightHand,LeftHand" handle1="0,-5">
|
||||||
|
<StatusEffect type="Always" target="Hull" oxygen="5000.0"/>
|
||||||
|
|
||||||
|
<StatusEffect type="OnImpact" target="This" Condition="0.0" setvalue="true" sound="Content/Items/Reactor/explosion.ogg">
|
||||||
|
<Explosion range="600.0" structuredamage="400" damage="300" stun="5" force="20.0"/>
|
||||||
|
</StatusEffect>
|
||||||
|
</Holdable>
|
||||||
|
</Item>
|
||||||
|
|
||||||
|
<Item
|
||||||
|
name="Sulphurite Shard"
|
||||||
|
pickdistance="150"
|
||||||
|
tags="smallitem"
|
||||||
|
impacttolerance="8"
|
||||||
|
spritecolor="1.0,0.0,0.0,1.0">
|
||||||
|
|
||||||
|
<Deconstruct time="20">
|
||||||
|
<Item name="Steel Bar"/>
|
||||||
|
<Item name="Sulphuric Acid"/>
|
||||||
|
<Item name="Sulphuric Acid"/>
|
||||||
|
<Item name="Sulphuric Acid"/>
|
||||||
|
</Deconstruct>
|
||||||
|
|
||||||
|
<Sprite texture="artifact.png" depth="0.7" sourcerect="119,96,9,32"/>
|
||||||
|
|
||||||
|
<Body width="9" height="32" density="15"/>
|
||||||
|
|
||||||
|
<Body width="8" height="32" density="15"/>
|
||||||
|
|
||||||
|
<Holdable slots="Any,RightHand,LeftHand" handle1="0,-5"/>
|
||||||
|
</Item>
|
||||||
|
|
||||||
|
<Item
|
||||||
|
name="Ancient Weapon"
|
||||||
|
category="Equipment"
|
||||||
|
Tags="smallitem"
|
||||||
|
pickdistance="200">
|
||||||
|
|
||||||
|
<Deconstruct time="20">
|
||||||
|
<Item name="Steel Bar"/>
|
||||||
|
<Item name="Steel Bar"/>
|
||||||
|
<Item name="Fulgurium Bar"/>
|
||||||
|
</Deconstruct>
|
||||||
|
|
||||||
|
<Sprite texture ="alientools.png" depth="0.5" sourcerect="0,0,95,50" origin="0.5,0.4"/>
|
||||||
|
|
||||||
|
<Body width="85" height="40" density="15"/>
|
||||||
|
|
||||||
|
<Holdable slots="Any,RightHand+LeftHand" aimpos="100,50" handle1="0,11" handle2="2,11"/>
|
||||||
|
|
||||||
|
<RepairTool structurefixamount="-5.0" limbfixamount="-3.0" range="600" barrelpos="30,15" particles="largeplasma">
|
||||||
|
<Fixable name="structure"/>
|
||||||
|
|
||||||
|
<StatusEffect type="OnUse" target="This" Condition="-0.5"/>
|
||||||
|
|
||||||
|
<LightComponent LightColor="0.8,0.7,1.0,1.0" Flicker="0.5" range="500">
|
||||||
|
<sprite texture="Content/Items/Electricity/lightsprite.png" origin="0.5,0.5"/>
|
||||||
|
</LightComponent>
|
||||||
|
</RepairTool>
|
||||||
|
|
||||||
|
<Propulsion force="-40" usablein="both"/>
|
||||||
|
|
||||||
|
<ItemContainer capacity="1" hideitems="false" itempos="9,-15">
|
||||||
|
<Containable name="Welding Fuel Tank"/>
|
||||||
|
<Containable name="Oxygen Tank"/>
|
||||||
|
</ItemContainer>
|
||||||
|
</Item>
|
||||||
|
|
||||||
</Items>
|
</Items>
|
||||||
@@ -47,11 +47,15 @@
|
|||||||
<StatusEffect type="OnWearing" target="Contained,Character" OxygenAvailable="-100.0" Oxygen="-20.0" Condition="-0.5">
|
<StatusEffect type="OnWearing" target="Contained,Character" OxygenAvailable="-100.0" Oxygen="-20.0" Condition="-0.5">
|
||||||
<RequiredItem type="Contained" name="Welding Fuel Tank"/>
|
<RequiredItem type="Contained" name="Welding Fuel Tank"/>
|
||||||
</StatusEffect>
|
</StatusEffect>
|
||||||
|
<StatusEffect type="OnWearing" target="Contained,Character" OxygenAvailable="1500.0" SpeedMultiplier="1.3" Condition="-0.1">
|
||||||
|
<RequiredItem type="Contained" name="Oxygenite Shard"/>
|
||||||
|
</StatusEffect>
|
||||||
</Wearable>
|
</Wearable>
|
||||||
|
|
||||||
<ItemContainer capacity="1" hideitems="true">
|
<ItemContainer capacity="1" hideitems="true">
|
||||||
<Containable name="Oxygen Tank"/>
|
<Containable name="Oxygen Tank"/>
|
||||||
<Containable name="Welding Fuel Tank"/>
|
<Containable name="Welding Fuel Tank"/>
|
||||||
|
<Containable name="Oxygenite Shard"/>
|
||||||
</ItemContainer>
|
</ItemContainer>
|
||||||
</Item>
|
</Item>
|
||||||
|
|
||||||
@@ -92,12 +96,16 @@
|
|||||||
<StatusEffect type="OnWearing" target="Contained,Character" Oxygen="-20.0" Condition="-0.5">
|
<StatusEffect type="OnWearing" target="Contained,Character" Oxygen="-20.0" Condition="-0.5">
|
||||||
<RequiredItem type="Contained" name="Welding Fuel Tank"/>
|
<RequiredItem type="Contained" name="Welding Fuel Tank"/>
|
||||||
</StatusEffect>
|
</StatusEffect>
|
||||||
|
<StatusEffect type="OnWearing" target="Contained,Character" OxygenAvailable="1500.0" SpeedMultiplier="1.3" Condition="-0.1">
|
||||||
|
<RequiredItem type="Contained" name="Oxygenite Shard"/>
|
||||||
|
</StatusEffect>
|
||||||
<StatusEffect type="OnWearing" target="Character" OxygenAvailable="-100.0"/>
|
<StatusEffect type="OnWearing" target="Character" OxygenAvailable="-100.0"/>
|
||||||
</Wearable>
|
</Wearable>
|
||||||
|
|
||||||
<ItemContainer capacity="1" hideitems="true">
|
<ItemContainer capacity="1" hideitems="true">
|
||||||
<Containable name="Oxygen Tank"/>
|
<Containable name="Oxygen Tank"/>
|
||||||
<Containable name="Welding Fuel Tank"/>
|
<Containable name="Welding Fuel Tank"/>
|
||||||
|
<Containable name="Oxygenite Shard"/>
|
||||||
</ItemContainer>
|
</ItemContainer>
|
||||||
</Item>
|
</Item>
|
||||||
|
|
||||||
|
|||||||
@@ -27,33 +27,6 @@
|
|||||||
</ItemContainer>
|
</ItemContainer>
|
||||||
</Item>
|
</Item>
|
||||||
|
|
||||||
<Item
|
|
||||||
name="Defibrillator"
|
|
||||||
category="Equipment"
|
|
||||||
Tags="smallitem,medical"
|
|
||||||
pickdistance="150"
|
|
||||||
price="50"
|
|
||||||
canuseonself="true"
|
|
||||||
description="A syringe filled with a potent general-purpose medical compound.">
|
|
||||||
|
|
||||||
<Sprite texture ="med.png" sourcerect="0,0,24,5" depth="0.6"/>
|
|
||||||
|
|
||||||
<Body width="24" height="5" density="20"/>
|
|
||||||
|
|
||||||
<MeleeWeapon slots="Any,RightHand,LeftHand"
|
|
||||||
aimpos="50,0" handle1="-5,0" holdangle="10" reload="1.0">
|
|
||||||
<StatusEffect type="OnUse" target="Contained" Condition="-25.0" disabledeltatime="true"/>
|
|
||||||
<StatusEffect type="OnUse" target="Character" oxygen="1" setvalue="true" sound="Content/Items/Weapons/stunbaton.ogg">
|
|
||||||
<RequiredItem name="Battery Cell" type="Contained" msg="Loaded Battery Cell required"/>
|
|
||||||
<Explosion range="10.0" force="1.0" shockwave="false" flames="false" camerashake="1.0"/>
|
|
||||||
</StatusEffect>
|
|
||||||
</MeleeWeapon>
|
|
||||||
|
|
||||||
<ItemContainer capacity="1" hideitems="true">
|
|
||||||
<Containable name="Battery Cell"/>
|
|
||||||
</ItemContainer>
|
|
||||||
</Item>
|
|
||||||
|
|
||||||
<Item
|
<Item
|
||||||
name="Bandage"
|
name="Bandage"
|
||||||
category="Equipment"
|
category="Equipment"
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Structures>
|
||||||
|
<structure prefab="RuinWallHorizontal" alignment="Top, Bottom" type="Wall"/>
|
||||||
|
<structure prefab="RuinWallHorizontalSmall" alignment="Top, Bottom" type="CorridorWall"/>
|
||||||
|
|
||||||
|
<structure prefab="RuinWallVertical" alignment="Left,Right" type="Wall"/>
|
||||||
|
<structure prefab="RuinWallVerticalSmall" alignment="Left,Right" type="CorridorWall"/>
|
||||||
|
|
||||||
|
<structure prefab="RuinBack" alignment="Center" type="Back" commonness="3"/>
|
||||||
|
<structure prefab="RuinBackCarvings" alignment="Center" type="Back" commonness="1"/>
|
||||||
|
|
||||||
|
<item prefab="RuinBlock" alignment="Right,Top,Bottom,Left" type="Prop" commonness="5"/>
|
||||||
|
|
||||||
|
<item prefab="RuinFractalBall" alignment="Center,Right,Top,Bottom,Left" type="Prop" commonness="5"/>
|
||||||
|
|
||||||
|
<item prefab="RuinClaw" alignment="Bottom" type="Prop" commonness="5"/>
|
||||||
|
|
||||||
|
|
||||||
|
<item prefab="Oxygenite Shard" alignment="Center,Right,Top,Bottom,Left" type="Prop" commonness="5"/>
|
||||||
|
<item prefab="Sulphurite Shard" alignment="Center,Right,Top,Bottom,Left" type="Prop" commonness="5"/>
|
||||||
|
|
||||||
|
<item prefab="Ancient Weapon" alignment="Center,Right,Top,Bottom,Left" type="Prop" commonness="1"/>
|
||||||
|
|
||||||
|
</Structures>
|
||||||
@@ -109,4 +109,32 @@
|
|||||||
<bunk sprite="Content/Map/testroom.png" fliphorizontal="true" sourcerect="0,546,173,129"
|
<bunk sprite="Content/Map/testroom.png" fliphorizontal="true" sourcerect="0,546,173,129"
|
||||||
width="173" height="129" depth = "0.9"/>
|
width="173" height="129" depth = "0.9"/>
|
||||||
|
|
||||||
|
<RuinWallHorizontal sprite="Content/Map/ruins.png" sourcerect="0,896,832,128" depth ="0.95" castshadow="true"
|
||||||
|
width = "128" height ="128" resizehorizontal="true" body="true" health="500"/>
|
||||||
|
|
||||||
|
<RuinWallVertical sprite="Content/Map/ruins.png" sourcerect="896,0,128,832" depth ="0.94" castshadow="true"
|
||||||
|
width = "128" height ="128" resizevertical="true" body="true" health="500"/>
|
||||||
|
|
||||||
|
<RuinWallHorizontalSmall sprite="Content/Map/ruins.png" sourcerect="0,842,832,54" depth ="0.95" castshadow="true"
|
||||||
|
width = "128" height ="54" resizehorizontal="true" body="true" health="500"/>
|
||||||
|
|
||||||
|
<RuinWallVerticalSmall sprite="Content/Map/ruins.png" sourcerect="842,0,54,832" depth ="0.96" castshadow="true"
|
||||||
|
width = "54" height ="128" resizevertical="true" body="true" health="500"/>
|
||||||
|
|
||||||
|
|
||||||
|
<RuinBack sprite="Content/Map/ruins.png" sourcerect="0,0,512,512" depth ="0.98"
|
||||||
|
width="64" height="64" resizehorizontal="true" resizevertical="true"/>
|
||||||
|
|
||||||
|
<RuinBackCarvings sprite="Content/Map/ruins.png" sourcerect="512,0,233,512" depth ="0.98"
|
||||||
|
width="64" height="64" resizehorizontal="true" resizevertical="true"/>
|
||||||
|
|
||||||
|
<RuinBlock sprite="Content/Map/ruins.png" sourcerect="0,513,514,296" depth ="0.99"
|
||||||
|
width="514" height="296"/>
|
||||||
|
|
||||||
|
<RuinFractalBall sprite="Content/Map/ruins2.png" sourcerect="0,0,512,512" depth ="0.97"
|
||||||
|
width="512" height="512"/>
|
||||||
|
|
||||||
|
<RuinClaw sprite="Content/Map/ruins2.png" sourcerect="512,517,126,270" depth ="0.97"
|
||||||
|
width="126" height="270"/>
|
||||||
|
|
||||||
</prefabs>
|
</prefabs>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 401 KiB |
@@ -8,6 +8,7 @@
|
|||||||
radarlabel="Infrasonic signal"
|
radarlabel="Infrasonic signal"
|
||||||
failuremessage="Retrieving the artifact failed"
|
failuremessage="Retrieving the artifact failed"
|
||||||
successmessage="The artifact has been succesfully retrieved"
|
successmessage="The artifact has been succesfully retrieved"
|
||||||
|
spawntype="ruin"
|
||||||
itemname="Skyholder Artifact">
|
itemname="Skyholder Artifact">
|
||||||
<message header="Artifact collected" text="The artifact is now on board. Navigate the submarine out of the cavern to claim the reward."/>
|
<message header="Artifact collected" text="The artifact is now on board. Navigate the submarine out of the cavern to claim the reward."/>
|
||||||
</SalvageMission>
|
</SalvageMission>
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
radarlabel="Infrasonic signal"
|
radarlabel="Infrasonic signal"
|
||||||
failuremessage="Retrieving the artifact failed"
|
failuremessage="Retrieving the artifact failed"
|
||||||
successmessage="The artifact has been succesfully retrieved"
|
successmessage="The artifact has been succesfully retrieved"
|
||||||
|
spawntype="ruin"
|
||||||
itemname="Thermal Artifact">
|
itemname="Thermal Artifact">
|
||||||
<message header="Artifact collected" text="The artifact is now on board. Navigate the submarine out of the cavern to claim the reward."/>
|
<message header="Artifact collected" text="The artifact is now on board. Navigate the submarine out of the cavern to claim the reward."/>
|
||||||
</SalvageMission>
|
</SalvageMission>
|
||||||
|
|||||||
@@ -193,6 +193,18 @@
|
|||||||
<sprite texture="Content/Particles/flames.png" sourcerect="0,64,128,64" origin="0.15,0.5"/>
|
<sprite texture="Content/Particles/flames.png" sourcerect="0,64,128,64" origin="0.15,0.5"/>
|
||||||
</plasma>
|
</plasma>
|
||||||
|
|
||||||
|
<largeplasma
|
||||||
|
startsizemin="0.9,3.0" startsizemax="5.0,5.0"
|
||||||
|
sizechange="20.0,-0.5"
|
||||||
|
startcolor="1.0, 1.0, 1.0" startalpha="1.0"
|
||||||
|
colorchange="0.0, 0.0, 0.0, -4.0"
|
||||||
|
lifetime="0.25"
|
||||||
|
drawtarget="both"
|
||||||
|
blendstate="additive"
|
||||||
|
velocitychange="0.0, 0.0">
|
||||||
|
<sprite texture="Content/Particles/flames.png" sourcerect="0,64,128,64" origin="0.0,0.5"/>
|
||||||
|
</largeplasma>
|
||||||
|
|
||||||
<extinguisher
|
<extinguisher
|
||||||
startsizemin="1.2,1.2" startsizemax="1.5,1.5"
|
startsizemin="1.2,1.2" startsizemax="1.5,1.5"
|
||||||
sizechangemin="1.5,1.5" sizechangemax="2.0,2.0"
|
sizechangemin="1.5,1.5" sizechangemax="2.0,2.0"
|
||||||
|
|||||||
Binary file not shown.
@@ -44,5 +44,7 @@
|
|||||||
<music file="Content/Sounds/Music/Enter the Maze.ogg" type="repair" priorityrange="30,60"/>
|
<music file="Content/Sounds/Music/Enter the Maze.ogg" type="repair" priorityrange="30,60"/>
|
||||||
<music file="Content/Sounds/Music/Static Motion.ogg" type="repair" priorityrange="50,80"/>
|
<music file="Content/Sounds/Music/Static Motion.ogg" type="repair" priorityrange="50,80"/>
|
||||||
<music file="Content/Sounds/Music/Unseen Horrors.ogg" type="monster" priorityrange="40,100"/>
|
<music file="Content/Sounds/Music/Unseen Horrors.ogg" type="monster" priorityrange="40,100"/>
|
||||||
|
|
||||||
<music file="Content/Sounds/Music/amb_JD_drone_clattering_machine.ogg" type="deep"/>
|
<music file="Content/Sounds/Music/amb_JD_drone_clattering_machine.ogg" type="deep"/>
|
||||||
|
<music file="Content/Sounds/Music/Controlled Chaos.ogg" type="ruins"/>
|
||||||
</sounds>
|
</sounds>
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
commonness="10"
|
commonness="10"
|
||||||
difficulty="10"
|
difficulty="10"
|
||||||
minamount="2" maxamount="3"
|
minamount="2" maxamount="3"
|
||||||
|
spawntype="mainpath,cave,ruin"
|
||||||
musictype="monster"/>
|
musictype="monster"/>
|
||||||
|
|
||||||
<MonsterEvent name="Under attack" description=""
|
<MonsterEvent name="Under attack" description=""
|
||||||
@@ -12,12 +13,14 @@
|
|||||||
commonness="10"
|
commonness="10"
|
||||||
difficulty="20"
|
difficulty="20"
|
||||||
minamount="1" maxamount="3"
|
minamount="1" maxamount="3"
|
||||||
|
spawntype="mainpath"
|
||||||
musictype="monster"/>
|
musictype="monster"/>
|
||||||
|
|
||||||
<MonsterEvent name="Under attack" description=""
|
<MonsterEvent name="Under attack" description=""
|
||||||
characterfile="Content/Characters/Moloch/moloch.xml"
|
characterfile="Content/Characters/Moloch/moloch.xml"
|
||||||
commonness="10"
|
commonness="10"
|
||||||
difficulty="30"
|
difficulty="30"
|
||||||
|
spawntype="mainpath"
|
||||||
musictype="monster"/>
|
musictype="monster"/>
|
||||||
|
|
||||||
<MonsterEvent name="Under attack" description=""
|
<MonsterEvent name="Under attack" description=""
|
||||||
@@ -25,6 +28,7 @@
|
|||||||
commonness="10"
|
commonness="10"
|
||||||
difficulty="15"
|
difficulty="15"
|
||||||
minamount="1" maxamount="2"
|
minamount="1" maxamount="2"
|
||||||
|
spawntype="mainpath,cave,ruin"
|
||||||
musictype="monster"/>
|
musictype="monster"/>
|
||||||
|
|
||||||
<MonsterEvent name="Under attack" description=""
|
<MonsterEvent name="Under attack" description=""
|
||||||
@@ -33,6 +37,7 @@
|
|||||||
commonness="10"
|
commonness="10"
|
||||||
difficulty="5"
|
difficulty="5"
|
||||||
minamount="1" maxamount="1"
|
minamount="1" maxamount="1"
|
||||||
|
spawntype="mainpath"
|
||||||
musictype="monster"/>
|
musictype="monster"/>
|
||||||
|
|
||||||
<MonsterEvent name="Under attack" description=""
|
<MonsterEvent name="Under attack" description=""
|
||||||
@@ -41,12 +46,14 @@
|
|||||||
commonness="1"
|
commonness="1"
|
||||||
difficulty="20"
|
difficulty="20"
|
||||||
minamount="1" maxamount="1"
|
minamount="1" maxamount="1"
|
||||||
|
spawntype="mainpath"
|
||||||
musictype="deep"/>
|
musictype="deep"/>
|
||||||
|
|
||||||
<MonsterEvent name="Under attack" description=""
|
<MonsterEvent name="Under attack" description=""
|
||||||
characterfile="Content/Characters/Watcher/watcher.xml"
|
characterfile="Content/Characters/Watcher/watcher.xml"
|
||||||
commonness="3"
|
commonness="3"
|
||||||
difficulty="5"
|
difficulty="5"
|
||||||
|
spawntype="mainpath,cave"
|
||||||
minamount="1" maxamount="1"/>
|
minamount="1" maxamount="1"/>
|
||||||
|
|
||||||
<MonsterEvent name="Under attack" description=""
|
<MonsterEvent name="Under attack" description=""
|
||||||
@@ -54,6 +61,16 @@
|
|||||||
commonness="5"
|
commonness="5"
|
||||||
difficulty="10"
|
difficulty="10"
|
||||||
minamount="2" maxamount="3"
|
minamount="2" maxamount="3"
|
||||||
|
|
||||||
|
spawntype="mainpath,cave,ruin"
|
||||||
|
musictype="monster"/>
|
||||||
|
|
||||||
|
<MonsterEvent name="Under attack" description=""
|
||||||
|
characterfile="Content/Characters/Fractalguardian/fractalguardian.xml"
|
||||||
|
commonness="5"
|
||||||
|
difficulty="10"
|
||||||
|
minamount="1" maxamount="1"
|
||||||
|
spawntype="ruin"
|
||||||
musictype="monster"/>
|
musictype="monster"/>
|
||||||
|
|
||||||
<ArtifactEvent name="Artifact" description=""
|
<ArtifactEvent name="Artifact" description=""
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
protected override void Start()
|
protected override void Start()
|
||||||
{
|
{
|
||||||
Vector2 position = Level.Loaded.GetRandomItemPos(30.0f);
|
Vector2 position = Level.Loaded.GetRandomItemPos(Level.PositionType.Cave, 30.0f);
|
||||||
|
|
||||||
item = new Item(itemPrefab, position, null);
|
item = new Item(itemPrefab, position, null);
|
||||||
item.MoveWithLevel = true;
|
item.MoveWithLevel = true;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public override void Start(Level level)
|
public override void Start(Level level)
|
||||||
{
|
{
|
||||||
Vector2 position = level.GetRandomInterestingPosition(true, true);
|
Vector2 position = level.GetRandomInterestingPosition(true, Level.PositionType.MainPath);
|
||||||
|
|
||||||
monster = Character.Create(monsterFile, position, null, GameMain.Client != null);
|
monster = Character.Create(monsterFile, position, null, GameMain.Client != null);
|
||||||
monster.Enabled = false;
|
monster.Enabled = false;
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private Item item;
|
private Item item;
|
||||||
|
|
||||||
|
private Level.PositionType spawnPositionType;
|
||||||
|
|
||||||
private int state;
|
private int state;
|
||||||
|
|
||||||
public override Vector2 RadarPosition
|
public override Vector2 RadarPosition
|
||||||
@@ -31,6 +33,14 @@ namespace Barotrauma
|
|||||||
|
|
||||||
itemPrefab = ItemPrefab.list.Find(ip => ip.Name == itemName) as ItemPrefab;
|
itemPrefab = ItemPrefab.list.Find(ip => ip.Name == itemName) as ItemPrefab;
|
||||||
|
|
||||||
|
string spawnPositionTypeStr = ToolBox.GetAttributeString(element, "spawntype", "");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(spawnPositionTypeStr) ||
|
||||||
|
!Enum.TryParse<Level.PositionType>(spawnPositionTypeStr, true, out spawnPositionType))
|
||||||
|
{
|
||||||
|
spawnPositionType = Level.PositionType.Cave | Level.PositionType.Ruin;
|
||||||
|
}
|
||||||
|
|
||||||
if (itemPrefab == null)
|
if (itemPrefab == null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Error in SalvageMission: couldn't find an item prefab with the name "+itemName);
|
DebugConsole.ThrowError("Error in SalvageMission: couldn't find an item prefab with the name "+itemName);
|
||||||
@@ -39,7 +49,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public override void Start(Level level)
|
public override void Start(Level level)
|
||||||
{
|
{
|
||||||
Vector2 position = Level.Loaded.GetRandomItemPos(30.0f);
|
Vector2 position = Level.Loaded.GetRandomItemPos(spawnPositionType, 30.0f);
|
||||||
|
|
||||||
item = new Item(itemPrefab, position, null);
|
item = new Item(itemPrefab, position, null);
|
||||||
item.MoveWithLevel = true;
|
item.MoveWithLevel = true;
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private bool spawnDeep;
|
private bool spawnDeep;
|
||||||
|
|
||||||
|
private Level.PositionType spawnPosType;
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return "ScriptedEvent (" + characterFile + ")";
|
return "ScriptedEvent (" + characterFile + ")";
|
||||||
@@ -27,6 +29,14 @@ namespace Barotrauma
|
|||||||
minAmount = ToolBox.GetAttributeInt(element, "minamount", 1);
|
minAmount = ToolBox.GetAttributeInt(element, "minamount", 1);
|
||||||
maxAmount = Math.Max(ToolBox.GetAttributeInt(element, "maxamount", 1), minAmount);
|
maxAmount = Math.Max(ToolBox.GetAttributeInt(element, "maxamount", 1), minAmount);
|
||||||
|
|
||||||
|
var spawnPosTypeStr = ToolBox.GetAttributeString(element, "spawntype", "");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(spawnPosTypeStr) ||
|
||||||
|
!Enum.TryParse<Level.PositionType>(spawnPosTypeStr, true, out spawnPosType))
|
||||||
|
{
|
||||||
|
spawnPosType = Level.PositionType.MainPath;
|
||||||
|
}
|
||||||
|
|
||||||
spawnDeep = ToolBox.GetAttributeBool(element, "spawndeep", false);
|
spawnDeep = ToolBox.GetAttributeBool(element, "spawndeep", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +47,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void SpawnMonsters()
|
private void SpawnMonsters()
|
||||||
{
|
{
|
||||||
WayPoint randomWayPoint = WayPoint.GetRandom(SpawnType.Enemy);
|
//WayPoint randomWayPoint = WayPoint.GetRandom(SpawnType.Enemy);
|
||||||
|
|
||||||
|
Vector2 spawnPos = Level.Loaded.GetRandomInterestingPosition(true, spawnPosType);
|
||||||
|
|
||||||
int amount = Rand.Range(minAmount, maxAmount, false);
|
int amount = Rand.Range(minAmount, maxAmount, false);
|
||||||
|
|
||||||
@@ -45,16 +57,14 @@ namespace Barotrauma
|
|||||||
|
|
||||||
for (int i = 0; i < amount; i++)
|
for (int i = 0; i < amount; i++)
|
||||||
{
|
{
|
||||||
Vector2 position = (randomWayPoint == null) ? Vector2.Zero : randomWayPoint.Position;
|
|
||||||
|
|
||||||
if (spawnDeep)
|
if (spawnDeep)
|
||||||
{
|
{
|
||||||
position.Y -= Level.Loaded.Size.Y;
|
spawnPos.Y -= Level.Loaded.Size.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
position.X += Rand.Range(-0.5f, 0.5f, false);
|
spawnPos.X += Rand.Range(-0.5f, 0.5f, false);
|
||||||
position.Y += Rand.Range(-0.5f, 0.5f, false);
|
spawnPos.Y += Rand.Range(-0.5f, 0.5f, false);
|
||||||
monsters[i] = Character.Create(characterFile, position, null, GameMain.Client != null);
|
monsters[i] = Character.Create(characterFile, spawnPos, null, GameMain.Client != null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace Barotrauma.Items.Components
|
|||||||
public Propulsion(Item item, XElement element)
|
public Propulsion(Item item, XElement element)
|
||||||
: base(item,element)
|
: base(item,element)
|
||||||
{
|
{
|
||||||
switch (ToolBox.GetAttributeString(element, "usablein", "air").ToLowerInvariant())
|
switch (ToolBox.GetAttributeString(element, "usablein", "both").ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case "air":
|
case "air":
|
||||||
usableIn = ParticlePrefab.DrawTargetType.Air;
|
usableIn = ParticlePrefab.DrawTargetType.Air;
|
||||||
@@ -38,6 +38,7 @@ namespace Barotrauma.Items.Components
|
|||||||
case "water":
|
case "water":
|
||||||
usableIn = ParticlePrefab.DrawTargetType.Water;
|
usableIn = ParticlePrefab.DrawTargetType.Water;
|
||||||
break;
|
break;
|
||||||
|
case "both":
|
||||||
default:
|
default:
|
||||||
usableIn = ParticlePrefab.DrawTargetType.Both;
|
usableIn = ParticlePrefab.DrawTargetType.Both;
|
||||||
break;
|
break;
|
||||||
@@ -49,7 +50,7 @@ namespace Barotrauma.Items.Components
|
|||||||
if (character == null) return false;
|
if (character == null) return false;
|
||||||
if (!character.IsKeyDown(InputType.Aim) || character.Stun>0.0f) return false;
|
if (!character.IsKeyDown(InputType.Aim) || character.Stun>0.0f) return false;
|
||||||
|
|
||||||
if (item.InWater)
|
if (character.AnimController.InWater)
|
||||||
{
|
{
|
||||||
if (usableIn == ParticlePrefab.DrawTargetType.Air) return true;
|
if (usableIn == ParticlePrefab.DrawTargetType.Air) return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,21 @@ namespace Barotrauma
|
|||||||
allowedNextCells.Add(adjacent);
|
allowedNextCells.Add(adjacent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowedNextCells.Count == 0) break;
|
if (allowedNextCells.Count == 0)
|
||||||
|
{
|
||||||
|
if (i>5) break;
|
||||||
|
|
||||||
|
foreach (GraphEdge edge in pathCell.edges)
|
||||||
|
{
|
||||||
|
var adjacent = edge.AdjacentCell(pathCell);
|
||||||
|
if (adjacent == null ||
|
||||||
|
adjacent.CellType == CellType.Removed) continue;
|
||||||
|
|
||||||
|
allowedNextCells.Add(adjacent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allowedNextCells.Count == 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
//randomly pick one of the adjacent cells as the next cell
|
//randomly pick one of the adjacent cells as the next cell
|
||||||
pathCell = allowedNextCells[Rand.Int(allowedNextCells.Count, false)];
|
pathCell = allowedNextCells[Rand.Int(allowedNextCells.Count, false)];
|
||||||
@@ -388,6 +402,8 @@ namespace Barotrauma
|
|||||||
bodyPoints[i] = ConvertUnits.ToSimUnits(bodyPoints[i]);
|
bodyPoints[i] = ConvertUnits.ToSimUnits(bodyPoints[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cell.CellType == CellType.Empty) continue;
|
||||||
|
|
||||||
triangles = MathUtils.TriangulateConvexHull(bodyPoints, cell.Center);
|
triangles = MathUtils.TriangulateConvexHull(bodyPoints, cell.Center);
|
||||||
|
|
||||||
Body edgeBody = new Body(GameMain.World);
|
Body edgeBody = new Body(GameMain.World);
|
||||||
@@ -442,7 +458,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
foreach (VoronoiCell cell in cells)
|
foreach (VoronoiCell cell in cells)
|
||||||
{
|
{
|
||||||
if (cell.body == null) continue;
|
//if (cell.body == null) continue;
|
||||||
foreach (GraphEdge edge in cell.edges)
|
foreach (GraphEdge edge in cell.edges)
|
||||||
{
|
{
|
||||||
if (!edge.isSolid) continue;
|
if (!edge.isSolid) continue;
|
||||||
@@ -482,7 +498,7 @@ namespace Barotrauma
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
DebugConsole.ThrowError("Invalid right normal");
|
DebugConsole.ThrowError("Invalid right normal");
|
||||||
#endif
|
#endif
|
||||||
GameMain.World.RemoveBody(cell.body);
|
if (cell.body != null) GameMain.World.RemoveBody(cell.body);
|
||||||
cell.body = null;
|
cell.body = null;
|
||||||
leftNormal = Vector2.UnitX;
|
leftNormal = Vector2.UnitX;
|
||||||
break;
|
break;
|
||||||
@@ -505,7 +521,7 @@ namespace Barotrauma
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
DebugConsole.ThrowError("Invalid right normal");
|
DebugConsole.ThrowError("Invalid right normal");
|
||||||
#endif
|
#endif
|
||||||
GameMain.World.RemoveBody(cell.body);
|
if (cell.body != null) GameMain.World.RemoveBody(cell.body);
|
||||||
cell.body = null;
|
cell.body = null;
|
||||||
rightNormal = Vector2.UnitX;
|
rightNormal = Vector2.UnitX;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using System.Linq;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Voronoi2;
|
using Voronoi2;
|
||||||
|
using Barotrauma.RuinGeneration;
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -21,15 +22,21 @@ namespace Barotrauma
|
|||||||
get { return loaded; }
|
get { return loaded; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum PositionType
|
||||||
|
{
|
||||||
|
MainPath=1, Cave=2, Ruin=4
|
||||||
|
}
|
||||||
|
|
||||||
struct InterestingPosition
|
struct InterestingPosition
|
||||||
{
|
{
|
||||||
public readonly Vector2 Position;
|
public readonly Vector2 Position;
|
||||||
public readonly bool IsLarge;
|
public readonly PositionType PositionType;
|
||||||
|
|
||||||
public InterestingPosition(Vector2 position, bool isLarge)
|
public InterestingPosition(Vector2 position, PositionType positionType)
|
||||||
{
|
{
|
||||||
Position = position;
|
Position = position;
|
||||||
IsLarge = isLarge;
|
PositionType = positionType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,6 +71,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private List<InterestingPosition> positionsOfInterest;
|
private List<InterestingPosition> positionsOfInterest;
|
||||||
|
|
||||||
|
private List<Ruin> ruins;
|
||||||
|
|
||||||
private Color backgroundColor;
|
private Color backgroundColor;
|
||||||
|
|
||||||
public Vector2 StartPosition
|
public Vector2 StartPosition
|
||||||
@@ -81,6 +90,11 @@ namespace Barotrauma
|
|||||||
get { return endPosition; }
|
get { return endPosition; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Ruin> Ruins
|
||||||
|
{
|
||||||
|
get { return ruins; }
|
||||||
|
}
|
||||||
|
|
||||||
public WrappingWall[,] WrappingWalls
|
public WrappingWall[,] WrappingWalls
|
||||||
{
|
{
|
||||||
get { return wrappingWalls; }
|
get { return wrappingWalls; }
|
||||||
@@ -116,8 +130,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
this.Difficulty = difficulty;
|
this.Difficulty = difficulty;
|
||||||
|
|
||||||
positionsOfInterest = new List<InterestingPosition>();
|
|
||||||
|
|
||||||
borders = new Rectangle(0, 0, width, height);
|
borders = new Rectangle(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,9 +160,10 @@ namespace Barotrauma
|
|||||||
sw.Start();
|
sw.Start();
|
||||||
|
|
||||||
if (loaded != null) loaded.Unload();
|
if (loaded != null) loaded.Unload();
|
||||||
|
|
||||||
loaded = this;
|
loaded = this;
|
||||||
|
|
||||||
|
positionsOfInterest = new List<InterestingPosition>();
|
||||||
|
|
||||||
renderer = new LevelRenderer(this);
|
renderer = new LevelRenderer(this);
|
||||||
|
|
||||||
Voronoi voronoi = new Voronoi(1.0);
|
Voronoi voronoi = new Voronoi(1.0);
|
||||||
@@ -170,8 +183,8 @@ namespace Barotrauma
|
|||||||
float minWidth = Submarine.Loaded == null ? 0.0f : Math.Max(Submarine.Borders.Width, Submarine.Borders.Height);
|
float minWidth = Submarine.Loaded == null ? 0.0f : Math.Max(Submarine.Borders.Width, Submarine.Borders.Height);
|
||||||
minWidth = Math.Max(minWidth, 6500.0f);
|
minWidth = Math.Max(minWidth, 6500.0f);
|
||||||
|
|
||||||
startPosition = new Vector2((int)minWidth * 2, Rand.Range((int)minWidth * 2, borders.Height - (int)minWidth * 2, false));
|
startPosition = new Vector2(minWidth * 2, Rand.Range(minWidth * 2, borders.Height - minWidth * 2, false));
|
||||||
endPosition = new Vector2(borders.Width - (int)minWidth * 2, Rand.Range((int)minWidth * 2, borders.Height - (int)minWidth * 2, false));
|
endPosition = new Vector2(borders.Width - minWidth * 2, Rand.Range(minWidth * 2, borders.Height - minWidth * 2, false));
|
||||||
|
|
||||||
List<Vector2> pathNodes = new List<Vector2>();
|
List<Vector2> pathNodes = new List<Vector2>();
|
||||||
Rectangle pathBorders = borders;// new Rectangle((int)minWidth, (int)minWidth, borders.Width - (int)minWidth * 2, borders.Height - (int)minWidth);
|
Rectangle pathBorders = borders;// new Rectangle((int)minWidth, (int)minWidth, borders.Width - (int)minWidth * 2, borders.Height - (int)minWidth);
|
||||||
@@ -189,7 +202,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
for (int i = 2; i < pathNodes.Count; i+=3 )
|
for (int i = 2; i < pathNodes.Count; i+=3 )
|
||||||
{
|
{
|
||||||
positionsOfInterest.Add(new InterestingPosition(pathNodes[i], true));
|
positionsOfInterest.Add(new InterestingPosition(pathNodes[i], PositionType.MainPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
pathNodes.Add(endPosition);
|
pathNodes.Add(endPosition);
|
||||||
@@ -258,9 +271,11 @@ namespace Barotrauma
|
|||||||
Debug.WriteLine("find cells: " + sw2.ElapsedMilliseconds + " ms");
|
Debug.WriteLine("find cells: " + sw2.ElapsedMilliseconds + " ms");
|
||||||
sw2.Restart();
|
sw2.Restart();
|
||||||
|
|
||||||
List<VoronoiCell> pathCells = CaveGenerator.GeneratePath(pathNodes, cells, cellGrid, GridCellSize,
|
List<VoronoiCell> mainPath = CaveGenerator.GeneratePath(pathNodes, cells, cellGrid, GridCellSize,
|
||||||
new Rectangle(pathBorders.X, pathBorders.Y, pathBorders.Width, borders.Height), 0.3f, mirror);
|
new Rectangle(pathBorders.X, pathBorders.Y, pathBorders.Width, borders.Height), 0.3f, mirror);
|
||||||
|
|
||||||
|
List<VoronoiCell> pathCells = new List<VoronoiCell>(mainPath);
|
||||||
|
|
||||||
EnlargeMainPath(pathCells, minWidth);
|
EnlargeMainPath(pathCells, minWidth);
|
||||||
|
|
||||||
foreach (InterestingPosition positionOfInterest in positionsOfInterest)
|
foreach (InterestingPosition positionOfInterest in positionsOfInterest)
|
||||||
@@ -284,9 +299,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
var newPathCells = CaveGenerator.GeneratePath(tunnel, cells, cellGrid, GridCellSize, pathBorders);
|
var newPathCells = CaveGenerator.GeneratePath(tunnel, cells, cellGrid, GridCellSize, pathBorders);
|
||||||
|
|
||||||
positionsOfInterest.Add(new InterestingPosition(tunnel.Last(), false));
|
positionsOfInterest.Add(new InterestingPosition(tunnel.Last(), PositionType.Cave));
|
||||||
|
|
||||||
if (tunnel.Count() > 4) positionsOfInterest.Add(new InterestingPosition(tunnel[tunnel.Count() / 2], false));
|
if (tunnel.Count() > 4) positionsOfInterest.Add(new InterestingPosition(tunnel[tunnel.Count() / 2], PositionType.Cave));
|
||||||
|
|
||||||
pathCells.AddRange(newPathCells);
|
pathCells.AddRange(newPathCells);
|
||||||
}
|
}
|
||||||
@@ -307,7 +322,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
//generate some narrow caves
|
//generate some narrow caves
|
||||||
int caveAmount = Rand.Int(3, false);
|
int caveAmount = 0;// Rand.Int(3, false);
|
||||||
List<VoronoiCell> usedCaveCells = new List<VoronoiCell>();
|
List<VoronoiCell> usedCaveCells = new List<VoronoiCell>();
|
||||||
for (int i = 0; i < caveAmount; i++)
|
for (int i = 0; i < caveAmount; i++)
|
||||||
{
|
{
|
||||||
@@ -367,7 +382,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
for (int j = cavePathCells.Count / 2; j < cavePathCells.Count; j += 10)
|
for (int j = cavePathCells.Count / 2; j < cavePathCells.Count; j += 10)
|
||||||
{
|
{
|
||||||
positionsOfInterest.Add(new InterestingPosition(cavePathCells[j].Center, false));
|
positionsOfInterest.Add(new InterestingPosition(cavePathCells[j].Center, PositionType.Cave));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,11 +404,86 @@ namespace Barotrauma
|
|||||||
cellGrid[x,y].Add(cell);
|
cellGrid[x,y].Add(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Vector2 ruinSize = new Vector2(Rand.Range(5000.0f, 8000.0f, false), Rand.Range(5000.0f, 8000.0f, false));
|
||||||
|
float ruinRadius = Math.Max(ruinSize.X, ruinSize.Y) * 0.5f;
|
||||||
|
|
||||||
|
Vector2 ruinPos = cells[Rand.Int(cells.Count, false)].Center;
|
||||||
|
|
||||||
|
int iter = 0;
|
||||||
|
|
||||||
|
while (mainPath.Any(p => Vector2.Distance(ruinPos, p.Center) < ruinRadius*2.0f))
|
||||||
|
{
|
||||||
|
Vector2 weighedPathPos = ruinPos;
|
||||||
|
iter++;
|
||||||
|
|
||||||
|
foreach (VoronoiCell pathCell in mainPath)
|
||||||
|
{
|
||||||
|
float dist = Vector2.Distance(pathCell.Center, ruinPos);
|
||||||
|
if (dist > 10000.0f) continue;
|
||||||
|
|
||||||
|
Vector2 moveAmount = Vector2.Normalize(ruinPos - pathCell.Center) * 100000.0f / dist;
|
||||||
|
|
||||||
|
//if (weighedPathPos.Y + moveAmount.Y > borders.Bottom - ruinSize.X)
|
||||||
|
//{
|
||||||
|
// moveAmount.X = (Math.Abs(moveAmount.Y) + Math.Abs(moveAmount.X))*Math.Sign(moveAmount.X);
|
||||||
|
// moveAmount.Y = 0.0f;
|
||||||
|
//}
|
||||||
|
|
||||||
|
weighedPathPos += moveAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
ruinPos = weighedPathPos;
|
||||||
|
|
||||||
|
if (iter > 10000) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
VoronoiCell closestPathCell = null;
|
||||||
|
float closestDist = 0.0f;
|
||||||
|
foreach (VoronoiCell pathCell in mainPath)
|
||||||
|
{
|
||||||
|
float dist = Vector2.Distance(pathCell.Center, ruinPos);
|
||||||
|
if (closestPathCell == null || dist < closestDist)
|
||||||
|
{
|
||||||
|
closestPathCell = pathCell;
|
||||||
|
closestDist = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ruin = new Ruin(closestPathCell, cells, new Rectangle((ruinPos - ruinSize * 0.5f).ToPoint(), ruinSize.ToPoint()));
|
||||||
|
|
||||||
|
ruins = new List<Ruin>();
|
||||||
|
ruins.Add(ruin);
|
||||||
|
|
||||||
|
ruin.RuinShapes.Sort((shape1, shape2) => shape2.DistanceFromEntrance.CompareTo(shape1.DistanceFromEntrance));
|
||||||
|
for (int i = 0; i < 4; i++ )
|
||||||
|
{
|
||||||
|
positionsOfInterest.Add(new InterestingPosition(ruin.RuinShapes[i].Rect.Center.ToVector2(), PositionType.Ruin));
|
||||||
|
}
|
||||||
|
|
||||||
startPosition.Y = borders.Height;
|
startPosition.Y = borders.Height;
|
||||||
endPosition.Y = borders.Height;
|
endPosition.Y = borders.Height;
|
||||||
|
|
||||||
|
List<VoronoiCell> cellsWithBody = new List<VoronoiCell>(cells);
|
||||||
|
foreach (RuinShape ruinShape in ruin.RuinShapes)
|
||||||
|
{
|
||||||
|
var tooClose = GetTooCloseCells(ruinShape.Rect.Center.ToVector2(), Math.Max(ruinShape.Rect.Width, ruinShape.Rect.Height));
|
||||||
|
|
||||||
|
tooClose.ForEach(c =>
|
||||||
|
{
|
||||||
|
if (c.edges.Any(e => ruinShape.Rect.Contains(e.point1) || ruinShape.Rect.Contains(e.point2))) c.CellType = CellType.Empty;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
List<VertexPositionColor> bodyVertices;
|
List<VertexPositionColor> bodyVertices;
|
||||||
bodies = CaveGenerator.GeneratePolygons(cells, out bodyVertices);
|
bodies = CaveGenerator.GeneratePolygons(cellsWithBody, out bodyVertices);
|
||||||
|
|
||||||
renderer.SetBodyVertices(bodyVertices.ToArray());
|
renderer.SetBodyVertices(bodyVertices.ToArray());
|
||||||
renderer.SetWallVertices(CaveGenerator.GenerateWallShapes(cells));
|
renderer.SetWallVertices(CaveGenerator.GenerateWallShapes(cells));
|
||||||
@@ -466,6 +556,10 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//RuinGeneration.RuinGenerator.Draw(spriteBatch);
|
||||||
|
|
||||||
|
|
||||||
Debug.WriteLine("**********************************************************************************");
|
Debug.WriteLine("**********************************************************************************");
|
||||||
Debug.WriteLine("Generated a map with " + sites.Count + " sites in " + sw.ElapsedMilliseconds + " ms");
|
Debug.WriteLine("Generated a map with " + sites.Count + " sites in " + sw.ElapsedMilliseconds + " ms");
|
||||||
Debug.WriteLine("Seed: "+seed);
|
Debug.WriteLine("Seed: "+seed);
|
||||||
@@ -572,40 +666,7 @@ namespace Barotrauma
|
|||||||
minDistance *= 0.5f;
|
minDistance *= 0.5f;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
var closeCells = GetCells(position, 1);
|
tooCloseCells.AddRange(GetTooCloseCells(position, minDistance));
|
||||||
|
|
||||||
foreach (VoronoiCell cell in closeCells)
|
|
||||||
{
|
|
||||||
bool tooClose = false;
|
|
||||||
foreach (GraphEdge edge in cell.edges)
|
|
||||||
{
|
|
||||||
if (Math.Abs(position.X - edge.point1.X) < minDistance ||
|
|
||||||
Math.Abs(position.Y - edge.point1.Y) < minDistance ||
|
|
||||||
Math.Abs(position.X - edge.point2.X) < minDistance ||
|
|
||||||
Math.Abs(position.Y - edge.point2.Y) < minDistance)
|
|
||||||
{
|
|
||||||
tooClose = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tooClose && !tooCloseCells.Contains(cell)) tooCloseCells.Add(cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (float x = -minDistance; x <= minDistance; x+=siteInterval)
|
|
||||||
{
|
|
||||||
for (float y = -minDistance; y <= minDistance; y += siteInterval)
|
|
||||||
{
|
|
||||||
Vector2 cornerPos = position + new Vector2(x,y);
|
|
||||||
|
|
||||||
int cellIndex = CaveGenerator.FindCellIndex(cornerPos, cells, cellGrid, GridCellSize);
|
|
||||||
if (cellIndex == -1) continue;
|
|
||||||
if (!tooCloseCells.Contains(cells[cellIndex]))
|
|
||||||
{
|
|
||||||
tooCloseCells.Add(cells[cellIndex]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
position += Vector2.Normalize(emptyCells[targetCellIndex].Center - position) * step;
|
position += Vector2.Normalize(emptyCells[targetCellIndex].Center - position) * step;
|
||||||
|
|
||||||
@@ -616,6 +677,47 @@ namespace Barotrauma
|
|||||||
return tooCloseCells;
|
return tooCloseCells;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<VoronoiCell> GetTooCloseCells(Vector2 position, float minDistance)
|
||||||
|
{
|
||||||
|
List<VoronoiCell> tooCloseCells = new List<VoronoiCell>();
|
||||||
|
|
||||||
|
var closeCells = GetCells(position, 3);
|
||||||
|
|
||||||
|
foreach (VoronoiCell cell in closeCells)
|
||||||
|
{
|
||||||
|
bool tooClose = false;
|
||||||
|
foreach (GraphEdge edge in cell.edges)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Vector2.Distance(edge.point1, position) < minDistance ||
|
||||||
|
Vector2.Distance(edge.point2, position) < minDistance)
|
||||||
|
{
|
||||||
|
tooClose = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tooClose && !tooCloseCells.Contains(cell)) tooCloseCells.Add(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
//for (float x = -minDistance; x <= minDistance; x+=siteInterval)
|
||||||
|
//{
|
||||||
|
// for (float y = -minDistance; y <= minDistance; y += siteInterval)
|
||||||
|
// {
|
||||||
|
// Vector2 cornerPos = position + new Vector2(x,y);
|
||||||
|
|
||||||
|
// int cellIndex = CaveGenerator.FindCellIndex(cornerPos, cells, cellGrid, GridCellSize);
|
||||||
|
// if (cellIndex == -1) continue;
|
||||||
|
// if (!tooCloseCells.Contains(cells[cellIndex]))
|
||||||
|
// {
|
||||||
|
// tooCloseCells.Add(cells[cellIndex]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
return tooCloseCells;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// remove all cells except those that are adjacent to the empty cells
|
/// remove all cells except those that are adjacent to the empty cells
|
||||||
@@ -636,7 +738,7 @@ namespace Barotrauma
|
|||||||
return newCells;
|
return newCells;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 GetRandomItemPos(float offsetFromWall = 10.0f)
|
public Vector2 GetRandomItemPos(PositionType spawnPosType, float offsetFromWall = 10.0f)
|
||||||
{
|
{
|
||||||
if (!positionsOfInterest.Any()) return Size*0.5f;
|
if (!positionsOfInterest.Any()) return Size*0.5f;
|
||||||
|
|
||||||
@@ -647,16 +749,16 @@ namespace Barotrauma
|
|||||||
int tries = 0;
|
int tries = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Vector2 startPos = ConvertUnits.ToSimUnits(Level.Loaded.GetRandomInterestingPosition(true, false));
|
Vector2 startPos = Level.Loaded.GetRandomInterestingPosition(true, spawnPosType);
|
||||||
|
|
||||||
Vector2 endPos = startPos - ConvertUnits.ToSimUnits(Vector2.UnitY * Size.Y);
|
Vector2 endPos = startPos - Vector2.UnitY * Size.Y;
|
||||||
|
|
||||||
if (Submarine.PickBody(
|
if (Submarine.PickBody(
|
||||||
startPos,
|
ConvertUnits.ToSimUnits(startPos),
|
||||||
endPos,
|
ConvertUnits.ToSimUnits(endPos),
|
||||||
null, Physics.CollisionLevel) != null)
|
null, Physics.CollisionLevel) != null)
|
||||||
{
|
{
|
||||||
position = ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition + Vector2.Normalize(startPos - endPos)*offsetFromWall);
|
position = ConvertUnits.ToDisplayUnits(Submarine.LastPickedPosition) + Vector2.Normalize(startPos - endPos)*offsetFromWall;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,18 +774,17 @@ namespace Barotrauma
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 GetRandomInterestingPosition(bool useSyncedRand, bool? preferLarge)
|
public Vector2 GetRandomInterestingPosition(bool useSyncedRand, PositionType positionType)
|
||||||
{
|
{
|
||||||
if (!positionsOfInterest.Any()) return Size * 0.5f;
|
if (!positionsOfInterest.Any()) return Size * 0.5f;
|
||||||
|
|
||||||
if (preferLarge==null)
|
var matchingPositions = positionsOfInterest.FindAll(p => positionType.HasFlag(p.PositionType));
|
||||||
|
if (!matchingPositions.Any())
|
||||||
|
{
|
||||||
return positionsOfInterest[Rand.Int(positionsOfInterest.Count, !useSyncedRand)].Position;
|
return positionsOfInterest[Rand.Int(positionsOfInterest.Count, !useSyncedRand)].Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchingPositions[Rand.Int(matchingPositions.Count, !useSyncedRand)].Position;
|
||||||
var positionsWithSpace = positionsOfInterest.FindAll(p => (bool)preferLarge == p.IsLarge);
|
|
||||||
if (!positionsWithSpace.Any()) return Size * 0.5f;
|
|
||||||
|
|
||||||
return positionsWithSpace[Rand.Int(positionsWithSpace.Count, !useSyncedRand)].Position;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update (float deltaTime)
|
public void Update (float deltaTime)
|
||||||
@@ -705,7 +806,18 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (InterestingPosition pos in positionsOfInterest)
|
foreach (InterestingPosition pos in positionsOfInterest)
|
||||||
{
|
{
|
||||||
GUI.DrawRectangle(spriteBatch, new Vector2(pos.Position.X-15.0f, -pos.Position.Y-15.0f), new Vector2(30.0f, 30.0f), Color.Gold, true);
|
Color color = Color.Yellow;
|
||||||
|
if (pos.PositionType == PositionType.Cave)
|
||||||
|
{
|
||||||
|
color = Color.DarkOrange;
|
||||||
|
}
|
||||||
|
else if (pos.PositionType == PositionType.Ruin)
|
||||||
|
{
|
||||||
|
color = Color.LightGray;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GUI.DrawRectangle(spriteBatch, new Vector2(pos.Position.X-15.0f, -pos.Position.Y-15.0f), new Vector2(30.0f, 30.0f), color, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -764,7 +876,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void Unload()
|
private void Unload()
|
||||||
{
|
{
|
||||||
renderer.Dispose();
|
if (renderer!=null) renderer.Dispose();
|
||||||
renderer = null;
|
renderer = null;
|
||||||
|
|
||||||
for (int side = 0; side < 2; side++)
|
for (int side = 0; side < 2; side++)
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Barotrauma.RuinGeneration
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// nodes of a binary tree used for generating underwater "dungeons"
|
||||||
|
/// </summary>
|
||||||
|
class BTRoom : RuinShape
|
||||||
|
{
|
||||||
|
private BTRoom[] subRooms;
|
||||||
|
|
||||||
|
public BTRoom Parent
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Corridor Corridor
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BTRoom[] SubRooms
|
||||||
|
{
|
||||||
|
get { return subRooms; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public BTRoom Adjacent
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BTRoom(Rectangle rect)
|
||||||
|
{
|
||||||
|
this.rect = rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Split(float minDivRatio, float verticalProbability = 0.5f)
|
||||||
|
{
|
||||||
|
subRooms = new BTRoom[2];
|
||||||
|
|
||||||
|
if (Rand.Range(0.0f, 1.0f, false) < verticalProbability)
|
||||||
|
{
|
||||||
|
SplitVertical(minDivRatio);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SplitHorizontal(minDivRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
subRooms[0].Parent = this;
|
||||||
|
subRooms[1].Parent = this;
|
||||||
|
|
||||||
|
subRooms[0].Adjacent = subRooms[1];
|
||||||
|
subRooms[1].Adjacent = subRooms[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SplitHorizontal(float minDivRatio)
|
||||||
|
{
|
||||||
|
float div = Rand.Range(minDivRatio, 1.0f - minDivRatio, false);
|
||||||
|
subRooms[0] = new BTRoom(new Rectangle(rect.X, rect.Y, rect.Width, (int)(rect.Height * div)));
|
||||||
|
subRooms[1] = new BTRoom(new Rectangle(rect.X, rect.Y + subRooms[0].rect.Height, rect.Width, rect.Height - subRooms[0].rect.Height));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SplitVertical(float minDivRatio)
|
||||||
|
{
|
||||||
|
float div = Rand.Range(minDivRatio, 1.0f - minDivRatio, false);
|
||||||
|
subRooms[0] = new BTRoom(new Rectangle(rect.X, rect.Y, (int)(rect.Width * div), rect.Height));
|
||||||
|
subRooms[1] = new BTRoom(new Rectangle(rect.X + subRooms[0].rect.Width, rect.Y, rect.Width - subRooms[0].rect.Width, rect.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CreateWalls()
|
||||||
|
{
|
||||||
|
Walls = new List<Line>();
|
||||||
|
|
||||||
|
Walls.Add(new Line(new Vector2(Rect.X, Rect.Y), new Vector2(Rect.Right, Rect.Y), RuinStructureType.Wall));
|
||||||
|
Walls.Add(new Line(new Vector2(Rect.X, Rect.Bottom), new Vector2(Rect.Right, Rect.Bottom), RuinStructureType.Wall));
|
||||||
|
|
||||||
|
Walls.Add(new Line(new Vector2(Rect.X, Rect.Y), new Vector2(Rect.X, Rect.Bottom), RuinStructureType.Wall));
|
||||||
|
Walls.Add(new Line(new Vector2(Rect.Right, Rect.Y), new Vector2(Rect.Right, Rect.Bottom), RuinStructureType.Wall));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Scale(Vector2 scale)
|
||||||
|
{
|
||||||
|
rect.Inflate((scale.X - 1.0f) * 0.5f * rect.Width, (scale.Y - 1.0f) * 0.5f * rect.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BTRoom> GetLeaves()
|
||||||
|
{
|
||||||
|
return GetLeaves(new List<BTRoom>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BTRoom> GetLeaves(List<BTRoom> leaves)
|
||||||
|
{
|
||||||
|
if (subRooms == null)
|
||||||
|
{
|
||||||
|
leaves.Add(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
subRooms[0].GetLeaves(leaves);
|
||||||
|
subRooms[1].GetLeaves(leaves);
|
||||||
|
}
|
||||||
|
|
||||||
|
return leaves;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GenerateCorridors(int minWidth, int maxWidth, List<Corridor> corridors)
|
||||||
|
{
|
||||||
|
if (Adjacent != null && Corridor == null)
|
||||||
|
{
|
||||||
|
Corridor = new Corridor(this, Rand.Range(minWidth, maxWidth, false), corridors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subRooms != null)
|
||||||
|
{
|
||||||
|
subRooms[0].GenerateCorridors(minWidth, maxWidth, corridors);
|
||||||
|
subRooms[1].GenerateCorridors(minWidth, maxWidth, corridors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CalculateDistancesFromEntrance(BTRoom entrance, List<Corridor> corridors)
|
||||||
|
{
|
||||||
|
entrance.CalculateDistanceFromEntrance(1, new List<Corridor>(corridors));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateDistanceFromEntrance(int currentDist, List<Corridor> corridors)
|
||||||
|
{
|
||||||
|
if (DistanceFromEntrance == 0)
|
||||||
|
{
|
||||||
|
DistanceFromEntrance = currentDist;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DistanceFromEntrance = Math.Min(currentDist, DistanceFromEntrance);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentDist++;
|
||||||
|
|
||||||
|
for (int i = corridors.Count - 1; i >= 0; i = Math.Min(i - 1, corridors.Count - 1))
|
||||||
|
{
|
||||||
|
var corridor = corridors[i];
|
||||||
|
|
||||||
|
if (!corridor.ConnectedRooms.Contains(this)) continue;
|
||||||
|
|
||||||
|
corridors.RemoveAt(i);
|
||||||
|
|
||||||
|
corridor.ConnectedRooms[corridor.ConnectedRooms[0] == this ? 1 : 0].CalculateDistanceFromEntrance(currentDist, corridors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Barotrauma.RuinGeneration
|
||||||
|
{
|
||||||
|
|
||||||
|
class Corridor : RuinShape
|
||||||
|
{
|
||||||
|
private bool isHorizontal;
|
||||||
|
|
||||||
|
public Rectangle Rect
|
||||||
|
{
|
||||||
|
get { return rect; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsHorizontal
|
||||||
|
{
|
||||||
|
get { return isHorizontal; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public BTRoom[] ConnectedRooms
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Corridor(Rectangle rect)
|
||||||
|
{
|
||||||
|
this.rect = rect;
|
||||||
|
|
||||||
|
isHorizontal = rect.Width > rect.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Corridor(BTRoom room, int width, List<Corridor> corridors)
|
||||||
|
{
|
||||||
|
System.Diagnostics.Debug.Assert(room.Adjacent != null);
|
||||||
|
|
||||||
|
ConnectedRooms = new BTRoom[2];
|
||||||
|
ConnectedRooms[0] = room;
|
||||||
|
ConnectedRooms[1] = room.Adjacent;
|
||||||
|
|
||||||
|
Rectangle room1, room2;
|
||||||
|
|
||||||
|
room1 = room.Rect;
|
||||||
|
room2 = room.Adjacent.Rect;
|
||||||
|
|
||||||
|
isHorizontal = (room1.Right <= room2.X || room2.Right <= room1.X);
|
||||||
|
|
||||||
|
//use the leaves as starting points for the corridor
|
||||||
|
if (room.SubRooms != null)
|
||||||
|
{
|
||||||
|
var leaves1 = room.GetLeaves();
|
||||||
|
var leaves2 = room.Adjacent.GetLeaves();
|
||||||
|
|
||||||
|
var suitableLeaves = GetSuitableLeafRooms(leaves1, leaves2, width, isHorizontal);
|
||||||
|
room1 = suitableLeaves[0].Rect;
|
||||||
|
room2 = suitableLeaves[1].Rect;
|
||||||
|
|
||||||
|
ConnectedRooms[0] = suitableLeaves[0];
|
||||||
|
ConnectedRooms[1] = suitableLeaves[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHorizontal)
|
||||||
|
{
|
||||||
|
int left = Math.Min(room1.Right, room2.Right);
|
||||||
|
int right = Math.Max(room1.X, room2.X);
|
||||||
|
|
||||||
|
int top = Math.Max(room1.Y, room2.Y);
|
||||||
|
int bottom = Math.Min(room1.Bottom, room2.Bottom);
|
||||||
|
|
||||||
|
int yPos = Rand.Range(top, bottom - width, false);
|
||||||
|
|
||||||
|
rect = new Rectangle(left, yPos, right - left, width);
|
||||||
|
}
|
||||||
|
else if (room1.Y > room2.Bottom || room2.Y > room1.Bottom)
|
||||||
|
{
|
||||||
|
int left = Math.Max(room1.X, room2.X);
|
||||||
|
int right = Math.Min(room1.Right, room2.Right);
|
||||||
|
|
||||||
|
int top = Math.Min(room1.Bottom, room2.Bottom);
|
||||||
|
int bottom = Math.Max(room1.Y, room2.Y);
|
||||||
|
|
||||||
|
int xPos = Rand.Range(left, right - width, false);
|
||||||
|
|
||||||
|
rect = new Rectangle(xPos, top, width, bottom - top);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("wat");
|
||||||
|
}
|
||||||
|
|
||||||
|
room.Corridor = this;
|
||||||
|
room.Adjacent.Corridor = this;
|
||||||
|
|
||||||
|
for (int i = corridors.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var corridor = corridors[i];
|
||||||
|
|
||||||
|
if (corridor.rect.Intersects(this.rect))
|
||||||
|
{
|
||||||
|
if (isHorizontal && corridor.isHorizontal)
|
||||||
|
{
|
||||||
|
if (this.rect.Width < corridor.rect.Width)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
corridors.RemoveAt(i);
|
||||||
|
}
|
||||||
|
else if (!isHorizontal && !corridor.isHorizontal)
|
||||||
|
{
|
||||||
|
if (this.rect.Height < corridor.rect.Height)
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
corridors.RemoveAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
corridors.Add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CreateWalls()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
Walls = new List<Line>();
|
||||||
|
|
||||||
|
if (IsHorizontal)
|
||||||
|
{
|
||||||
|
Walls.Add(new Line(new Vector2(Rect.X, Rect.Y), new Vector2(Rect.Right, Rect.Y), RuinStructureType.CorridorWall));
|
||||||
|
Walls.Add(new Line(new Vector2(Rect.X, Rect.Bottom), new Vector2(Rect.Right, Rect.Bottom), RuinStructureType.CorridorWall));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Walls.Add(new Line(new Vector2(Rect.X, Rect.Y), new Vector2(Rect.X, Rect.Bottom), RuinStructureType.CorridorWall));
|
||||||
|
Walls.Add(new Line(new Vector2(Rect.Right, Rect.Y), new Vector2(Rect.Right, Rect.Bottom), RuinStructureType.CorridorWall));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// find two rooms which have two face-two-face walls that we can place a corridor in between
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private BTRoom[] GetSuitableLeafRooms(List<BTRoom> leaves1, List<BTRoom> leaves2, int width, bool isHorizontal)
|
||||||
|
{
|
||||||
|
int iOffset = Rand.Int(leaves1.Count, false);
|
||||||
|
int jOffset = Rand.Int(leaves2.Count, false);
|
||||||
|
|
||||||
|
|
||||||
|
for (int iCount = 0; iCount < leaves1.Count; iCount++)
|
||||||
|
{
|
||||||
|
int i = (iCount + iOffset) % leaves1.Count;
|
||||||
|
|
||||||
|
for (int jCount = 0; jCount < leaves2.Count; jCount++)
|
||||||
|
{
|
||||||
|
int j = (jCount + jOffset) % leaves2.Count;
|
||||||
|
|
||||||
|
if (isHorizontal)
|
||||||
|
{
|
||||||
|
//if (Math.Min(leaves1[i].Rect.Bottom, leaves2[i].Rect.Bottom) - Math.Max(leaves1[i].Rect.Y, leaves2[j].Rect.Y) < width) continue;
|
||||||
|
|
||||||
|
|
||||||
|
if (leaves1[i].Rect.Y > leaves2[j].Rect.Bottom) continue;
|
||||||
|
if (leaves1[i].Rect.Bottom < leaves2[j].Rect.Y) continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//if (Math.Min(leaves1[i].Rect.Right, leaves2[i].Rect.Right) - Math.Max(leaves1[i].Rect.X, leaves2[j].Rect.X) < width) continue;
|
||||||
|
|
||||||
|
|
||||||
|
if (leaves1[i].Rect.X > leaves2[j].Rect.Right) continue;
|
||||||
|
if (leaves1[i].Rect.Right < leaves2[j].Rect.X) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return new BTRoom[] { leaves1[i], leaves2[j] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,422 @@
|
|||||||
|
using FarseerPhysics.Common;
|
||||||
|
using FarseerPhysics.Common.PolygonManipulation;
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Voronoi2;
|
||||||
|
|
||||||
|
namespace Barotrauma.RuinGeneration
|
||||||
|
{
|
||||||
|
abstract class RuinShape
|
||||||
|
{
|
||||||
|
protected Rectangle rect;
|
||||||
|
|
||||||
|
public Rectangle Rect
|
||||||
|
{
|
||||||
|
get { return rect; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int DistanceFromEntrance
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
protected set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Line> Walls;
|
||||||
|
|
||||||
|
public virtual void CreateWalls() { }
|
||||||
|
|
||||||
|
public Alignment GetLineAlignment(Line line)
|
||||||
|
{
|
||||||
|
if (line.A.Y == line.B.Y)
|
||||||
|
{
|
||||||
|
if (line.A.Y > rect.Center.Y && line.B.Y > rect.Center.Y)
|
||||||
|
{
|
||||||
|
return Alignment.Bottom;
|
||||||
|
}
|
||||||
|
else if (line.A.Y < rect.Center.Y && line.B.Y < rect.Center.Y)
|
||||||
|
{
|
||||||
|
return Alignment.Top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (line.A.X < rect.Center.X && line.B.X < rect.Center.X)
|
||||||
|
{
|
||||||
|
return Alignment.Left;
|
||||||
|
}
|
||||||
|
else if (line.A.X > rect.Center.X && line.B.X > rect.Center.X)
|
||||||
|
{
|
||||||
|
return Alignment.Right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Alignment.Center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Goes through a list of line segments and "clips off" all parts of the lines that are inside the rectangle
|
||||||
|
/// </summary>
|
||||||
|
public void SplitLines(Rectangle rectangle)
|
||||||
|
{
|
||||||
|
List<Line> newLines = new List<Line>();
|
||||||
|
|
||||||
|
foreach (Line line in Walls)
|
||||||
|
{
|
||||||
|
if (line.A.X == line.B.X) //vertical line
|
||||||
|
{
|
||||||
|
//line doesn't intersect the rectangle
|
||||||
|
if (rectangle.X > line.A.X || rectangle.Right < line.A.X ||
|
||||||
|
rectangle.Y > line.B.Y || rectangle.Bottom < line.A.Y)
|
||||||
|
{
|
||||||
|
newLines.Add(line);
|
||||||
|
}
|
||||||
|
else if (line.A.Y > rectangle.Y && line.B.Y < rectangle.Bottom)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//point A is within the rectangle -> cut a portion from the top of the line
|
||||||
|
else if (line.A.Y >= rectangle.Y && line.A.Y <= rectangle.Bottom)
|
||||||
|
{
|
||||||
|
newLines.Add(new Line(new Vector2(line.A.X, rectangle.Bottom), line.B, line.Type));
|
||||||
|
}
|
||||||
|
//point B is within the rectangle -> cut a portion from the bottom of the line
|
||||||
|
else if (line.B.Y >= rectangle.Y && line.B.Y <= rectangle.Bottom)
|
||||||
|
{
|
||||||
|
newLines.Add(new Line(line.A, new Vector2(line.A.X, rectangle.Y), line.Type));
|
||||||
|
}
|
||||||
|
//rect is in between the lines -> split the line into two
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newLines.Add(new Line(line.A, new Vector2(line.A.X, rectangle.Y), line.Type));
|
||||||
|
newLines.Add(new Line(new Vector2(line.A.X, rectangle.Bottom), line.B, line.Type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line.A.Y == line.B.Y) //horizontal line
|
||||||
|
{
|
||||||
|
//line doesn't intersect the rectangle
|
||||||
|
if (rectangle.X > line.B.X || rectangle.Right < line.A.X ||
|
||||||
|
rectangle.Y > line.A.Y || rectangle.Bottom < line.A.Y)
|
||||||
|
{
|
||||||
|
|
||||||
|
newLines.Add(line);
|
||||||
|
}
|
||||||
|
else if (line.A.X > rectangle.X && line.B.X < rectangle.Right)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//point A is within the rectangle -> cut a portion from the left side of the line
|
||||||
|
else if (line.A.X >= rectangle.X && line.A.X <= rectangle.Right)
|
||||||
|
{
|
||||||
|
newLines.Add(new Line(new Vector2(rectangle.Right, line.A.Y), line.B, line.Type));
|
||||||
|
}
|
||||||
|
//point B is within the rectangle -> cut a portion from the right side of the line
|
||||||
|
else if (line.B.X >= rectangle.X && line.B.X <= rectangle.Right)
|
||||||
|
{
|
||||||
|
newLines.Add(new Line(line.A, new Vector2(rectangle.X, line.A.Y), line.Type));
|
||||||
|
}
|
||||||
|
//rect is in between the lines -> split the line into two
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newLines.Add(new Line(line.A, new Vector2(rectangle.X, line.A.Y), line.Type));
|
||||||
|
newLines.Add(new Line(new Vector2(rectangle.Right, line.A.Y), line.B, line.Type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in StructureGenerator.SplitLines - lines must be axis aligned");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Walls = newLines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Line
|
||||||
|
{
|
||||||
|
public readonly Vector2 A, B;
|
||||||
|
|
||||||
|
public readonly RuinStructureType Type;
|
||||||
|
|
||||||
|
public Line(Vector2 a, Vector2 b, RuinStructureType type)
|
||||||
|
{
|
||||||
|
Debug.Assert(a.X <= b.X);
|
||||||
|
Debug.Assert(a.Y <= b.Y);
|
||||||
|
|
||||||
|
A = a;
|
||||||
|
B = b;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Ruin
|
||||||
|
{
|
||||||
|
private List<BTRoom> rooms;
|
||||||
|
private List<Corridor> corridors;
|
||||||
|
|
||||||
|
private List<Line> walls;
|
||||||
|
|
||||||
|
private List<RuinShape> allShapes;
|
||||||
|
|
||||||
|
public List<RuinShape> RuinShapes
|
||||||
|
{
|
||||||
|
get { return allShapes; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle Area
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ruin(VoronoiCell closestPathCell, List<VoronoiCell> caveCells, Rectangle area)
|
||||||
|
{
|
||||||
|
Area = area;
|
||||||
|
|
||||||
|
corridors = new List<Corridor>();
|
||||||
|
rooms = new List<BTRoom>();
|
||||||
|
|
||||||
|
walls = new List<Line>();
|
||||||
|
|
||||||
|
allShapes = new List<RuinShape>();
|
||||||
|
|
||||||
|
Generate(closestPathCell, caveCells, area);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Generate(VoronoiCell closestPathCell, List<VoronoiCell> caveCells, Rectangle area)
|
||||||
|
{
|
||||||
|
corridors.Clear();
|
||||||
|
rooms.Clear();
|
||||||
|
|
||||||
|
//area = new Rectangle(area.X, area.Y - area.Height, area.Width, area.Height);
|
||||||
|
|
||||||
|
int iterations = Rand.Range(3, 4, false);
|
||||||
|
|
||||||
|
float verticalProbability = Rand.Range(0.4f, 0.6f, false);
|
||||||
|
|
||||||
|
BTRoom baseRoom = new BTRoom(area);
|
||||||
|
|
||||||
|
rooms = new List<BTRoom> { baseRoom };
|
||||||
|
|
||||||
|
for (int i = 0; i < iterations; i++)
|
||||||
|
{
|
||||||
|
rooms.ForEach(l => l.Split(0.3f, verticalProbability));
|
||||||
|
|
||||||
|
rooms = baseRoom.GetLeaves();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (BTRoom leaf in rooms)
|
||||||
|
{
|
||||||
|
leaf.Scale
|
||||||
|
(
|
||||||
|
new Vector2(Rand.Range(0.5f, 0.9f, false), Rand.Range(0.5f, 0.9f, false))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
baseRoom.GenerateCorridors(200, 256, corridors);
|
||||||
|
|
||||||
|
walls = new List<Line>();
|
||||||
|
|
||||||
|
rooms.ForEach(leaf =>
|
||||||
|
{
|
||||||
|
leaf.CreateWalls();
|
||||||
|
//walls.AddRange(leaf.Walls);
|
||||||
|
});
|
||||||
|
|
||||||
|
//---------------------------
|
||||||
|
|
||||||
|
BTRoom entranceRoom = null;
|
||||||
|
float shortestDistance = 0.0f;
|
||||||
|
foreach (BTRoom leaf in rooms)
|
||||||
|
{
|
||||||
|
float distance = Vector2.Distance(leaf.Rect.Center.ToVector2(), closestPathCell.Center);
|
||||||
|
if (entranceRoom == null || distance < shortestDistance)
|
||||||
|
{
|
||||||
|
entranceRoom = leaf;
|
||||||
|
shortestDistance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rooms.Remove(entranceRoom);
|
||||||
|
|
||||||
|
//var startCell = closestPathCell;
|
||||||
|
|
||||||
|
//Rectangle startCellRect = new Rectangle(
|
||||||
|
// (int)startCell.edges.Min(e => Math.Min(e.point1.X, e.point2.X)),
|
||||||
|
// (int)startCell.edges.Min(e => Math.Min(e.point1.Y, e.point2.Y)),
|
||||||
|
// (int)startCell.edges.Max(e => Math.Max(e.point1.X, e.point2.X)),
|
||||||
|
// (int)startCell.edges.Max(e => Math.Max(e.point1.Y, e.point2.Y)));
|
||||||
|
|
||||||
|
//startCellRect.Width = startCellRect.Width - startCellRect.X;
|
||||||
|
//startCellRect.Height = startCellRect.Height - startCellRect.Y;
|
||||||
|
|
||||||
|
//int startX = Math.Min(entranceRoom.Rect.Center.X, startCellRect.Center.X);
|
||||||
|
//int endX = Math.Max(entranceRoom.Rect.Right, startCellRect.Right);
|
||||||
|
|
||||||
|
//int startY = Math.Min(entranceRoom.Rect.Center.Y, startCellRect.Center.Y);
|
||||||
|
//int endY = Math.Max(entranceRoom.Rect.Bottom, startCellRect.Bottom);
|
||||||
|
|
||||||
|
//if (entranceRoom.Rect.X > startCellRect.X && entranceRoom.Rect.Right < startCellRect.Right)
|
||||||
|
//{
|
||||||
|
// corridors.Add(new Corridor(new Rectangle(entranceRoom.Rect.Center.X, startY, 128, endY - startY)));
|
||||||
|
//}
|
||||||
|
//else if (entranceRoom.Rect.Y > startCellRect.Y && entranceRoom.Rect.Bottom < startCellRect.Bottom)
|
||||||
|
//{
|
||||||
|
// corridors.Add(new Corridor(new Rectangle(startX, entranceRoom.Rect.Center.Y, endX - startX, 128)));
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
//{
|
||||||
|
// corridors.Add(new Corridor(new Rectangle(startX, entranceRoom.Rect.Center.Y, endX - startX, 128)));
|
||||||
|
// corridors.Add(new Corridor(new Rectangle(endX, startY, 128, endY - startY)));
|
||||||
|
//}
|
||||||
|
|
||||||
|
//---------------------------
|
||||||
|
|
||||||
|
foreach (BTRoom leaf in rooms)
|
||||||
|
{
|
||||||
|
foreach (Corridor corridor in corridors)
|
||||||
|
{
|
||||||
|
leaf.SplitLines(corridor.Rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
walls.AddRange(leaf.Walls);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach (Corridor corridor in corridors)
|
||||||
|
{
|
||||||
|
List<Line> corridorWalls = new List<Line>();
|
||||||
|
|
||||||
|
corridor.CreateWalls();
|
||||||
|
|
||||||
|
foreach (BTRoom leaf in rooms)
|
||||||
|
{
|
||||||
|
corridor.SplitLines(leaf.Rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Corridor corridor2 in corridors)
|
||||||
|
{
|
||||||
|
if (corridor == corridor2) continue;
|
||||||
|
corridor.SplitLines(corridor2.Rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
walls.AddRange(corridor.Walls);
|
||||||
|
}
|
||||||
|
|
||||||
|
//leaves.Remove(entranceRoom);
|
||||||
|
|
||||||
|
BTRoom.CalculateDistancesFromEntrance(entranceRoom, corridors);
|
||||||
|
|
||||||
|
allShapes = GenerateStructures(caveCells);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<RuinShape> GenerateStructures(List<VoronoiCell> caveCells)
|
||||||
|
{
|
||||||
|
List<RuinShape> shapes = new List<RuinShape>(rooms);
|
||||||
|
shapes.AddRange(corridors);
|
||||||
|
|
||||||
|
//MapEntityPrefab hullPrefab = MapEntityPrefab.list.Find(m => m.Name == "Hull");
|
||||||
|
|
||||||
|
foreach (RuinShape leaf in shapes)
|
||||||
|
{
|
||||||
|
foreach (Line wall in leaf.Walls)
|
||||||
|
{
|
||||||
|
var structurePrefab = RuinStructure.GetRandom(leaf is BTRoom ? RuinStructureType.Wall : RuinStructureType.CorridorWall, leaf.GetLineAlignment(wall));
|
||||||
|
if (structurePrefab == null) continue;
|
||||||
|
|
||||||
|
float radius = (wall.A.X == wall.B.X) ? (structurePrefab.Prefab as StructurePrefab).Size.X * 0.5f : (structurePrefab.Prefab as StructurePrefab).Size.Y * 0.5f;
|
||||||
|
|
||||||
|
Rectangle rect = new Rectangle(
|
||||||
|
(int)(wall.A.X - radius),
|
||||||
|
(int)(wall.B.Y + radius),
|
||||||
|
(int)((wall.B.X - wall.A.X) + radius*2.0f),
|
||||||
|
(int)((wall.B.Y - wall.A.Y) + radius*2.0f));
|
||||||
|
|
||||||
|
var structure = new Structure(rect, structurePrefab.Prefab as StructurePrefab, null);
|
||||||
|
structure.MoveWithLevel = true;
|
||||||
|
structure.SetCollisionCategory(Physics.CollisionLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var background = RuinStructure.GetRandom(RuinStructureType.Back, Alignment.Center);
|
||||||
|
if (background == null) continue;
|
||||||
|
|
||||||
|
Rectangle backgroundRect = new Rectangle(leaf.Rect.X, leaf.Rect.Y + leaf.Rect.Height, leaf.Rect.Width, leaf.Rect.Height);
|
||||||
|
|
||||||
|
new Structure(backgroundRect, (background.Prefab as StructurePrefab), null).MoveWithLevel = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < shapes.Count*2; i++ )
|
||||||
|
{
|
||||||
|
Alignment[] alignments = new Alignment[] { Alignment.Top, Alignment.Bottom, Alignment.Right, Alignment.Left, Alignment.Center };
|
||||||
|
|
||||||
|
var prop = RuinStructure.GetRandom(RuinStructureType.Prop, alignments[Rand.Int(alignments.Length, false)]);
|
||||||
|
|
||||||
|
Vector2 size = (prop.Prefab is StructurePrefab) ? (prop.Prefab as StructurePrefab).Size : Vector2.Zero;
|
||||||
|
|
||||||
|
var shape = shapes[Rand.Int(shapes.Count, false)];
|
||||||
|
|
||||||
|
Vector2 position = shape.Rect.Center.ToVector2();
|
||||||
|
if (prop.Alignment.HasFlag(Alignment.Top))
|
||||||
|
{
|
||||||
|
position = new Vector2(Rand.Range(shape.Rect.X+size.X, shape.Rect.Right - size.X, false), shape.Rect.Bottom - 64);
|
||||||
|
}
|
||||||
|
else if (prop.Alignment.HasFlag(Alignment.Bottom))
|
||||||
|
{
|
||||||
|
position = new Vector2(Rand.Range(shape.Rect.X + size.X, shape.Rect.Right - size.X, false), shape.Rect.Top + 64);
|
||||||
|
}
|
||||||
|
else if (prop.Alignment.HasFlag(Alignment.Right))
|
||||||
|
{
|
||||||
|
position = new Vector2(shape.Rect.Right - 64, Rand.Range(shape.Rect.Y + size.X, shape.Rect.Bottom - size.Y, false));
|
||||||
|
}
|
||||||
|
else if (prop.Alignment.HasFlag(Alignment.Left))
|
||||||
|
{
|
||||||
|
position = new Vector2(shape.Rect.X + 64, Rand.Range(shape.Rect.Y + size.X, shape.Rect.Bottom - size.Y, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop.Prefab is ItemPrefab)
|
||||||
|
{
|
||||||
|
var item = new Item(prop.Prefab as ItemPrefab, position, null);
|
||||||
|
item.MoveWithLevel = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new Structure(new Rectangle(
|
||||||
|
(int)(position.X - size.X/2.0f), (int)(position.Y + size.Y/2.0f),
|
||||||
|
(int)size.X, (int)size.Y),
|
||||||
|
prop.Prefab as StructurePrefab, null).MoveWithLevel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shapes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(SpriteBatch spriteBatch)
|
||||||
|
{
|
||||||
|
//foreach (BTRoom room in leaves)
|
||||||
|
//{
|
||||||
|
// GUI.DrawRectangle(spriteBatch, room.Rect, Color.White);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//foreach (Corridor corr in corridors)
|
||||||
|
//{
|
||||||
|
// GUI.DrawRectangle(spriteBatch, corr.Rect, Color.Blue);
|
||||||
|
//}
|
||||||
|
|
||||||
|
foreach (Line line in walls)
|
||||||
|
{
|
||||||
|
GUI.DrawLine(spriteBatch, new Vector2(line.A.X, -line.A.Y), new Vector2(line.B.X, -line.B.Y), Color.Red, 0.0f, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace Barotrauma.RuinGeneration
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
enum RuinStructureType
|
||||||
|
{
|
||||||
|
Wall = 1, CorridorWall = 2, Prop = 4, Back = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
class RuinStructure
|
||||||
|
{
|
||||||
|
const string ConfigFile = "Content/Map/RuinConfig.xml";
|
||||||
|
|
||||||
|
private static List<RuinStructure> list;
|
||||||
|
|
||||||
|
public readonly MapEntityPrefab Prefab;
|
||||||
|
|
||||||
|
public readonly Alignment Alignment;
|
||||||
|
|
||||||
|
public readonly RuinStructureType Type;
|
||||||
|
|
||||||
|
private int commonness;
|
||||||
|
|
||||||
|
private RuinStructure(XElement element)
|
||||||
|
{
|
||||||
|
string prefab = ToolBox.GetAttributeString(element, "prefab", "").ToLowerInvariant();
|
||||||
|
Prefab = MapEntityPrefab.list.Find(s => s.Name.ToLowerInvariant() == prefab);
|
||||||
|
|
||||||
|
if (Prefab == null)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Loading ruin structure failed - structure prefab ''"+prefab+" not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string alignmentStr = ToolBox.GetAttributeString(element,"alignment","Bottom");
|
||||||
|
if (!Enum.TryParse<Alignment>(alignmentStr, true, out Alignment))
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in ruin structure ''"+prefab+"'' - "+alignmentStr+" is not a valid alignment");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string typeStr = ToolBox.GetAttributeString(element,"type","");
|
||||||
|
if (!Enum.TryParse<RuinStructureType>(typeStr,true, out Type))
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError("Error in ruin structure ''" + prefab + "'' - " + typeStr + " is not a valid type");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
commonness = ToolBox.GetAttributeInt(element, "commonness", 1);
|
||||||
|
|
||||||
|
list.Add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Load()
|
||||||
|
{
|
||||||
|
list = new List<RuinStructure>();
|
||||||
|
|
||||||
|
XDocument doc = ToolBox.TryLoadXml(ConfigFile);
|
||||||
|
if (doc == null || doc.Root == null) return;
|
||||||
|
|
||||||
|
foreach (XElement element in doc.Root.Elements())
|
||||||
|
{
|
||||||
|
new RuinStructure(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RuinStructure GetRandom(RuinStructureType type, Alignment alignment)
|
||||||
|
{
|
||||||
|
if (list==null)
|
||||||
|
{
|
||||||
|
DebugConsole.Log("Loading ruin structures...");
|
||||||
|
Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
var matchingStructures = list.FindAll(rs => rs.Type.HasFlag(type) && rs.Alignment.HasFlag(alignment));
|
||||||
|
|
||||||
|
if (!matchingStructures.Any()) return null;
|
||||||
|
|
||||||
|
int totalCommonness = matchingStructures.Sum(m => m.commonness);
|
||||||
|
|
||||||
|
int randomNumber = Rand.Int(totalCommonness + 1, false);
|
||||||
|
|
||||||
|
foreach (RuinStructure ruinStructure in matchingStructures)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (randomNumber <= ruinStructure.commonness)
|
||||||
|
{
|
||||||
|
return ruinStructure;
|
||||||
|
}
|
||||||
|
|
||||||
|
randomNumber -= ruinStructure.commonness;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -602,6 +602,15 @@ namespace Barotrauma
|
|||||||
UpdateSections();
|
UpdateSections();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetCollisionCategory(Category collisionCategory)
|
||||||
|
{
|
||||||
|
if (bodies == null) return;
|
||||||
|
foreach (Body body in bodies)
|
||||||
|
{
|
||||||
|
body.CollisionCategories = collisionCategory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateSections()
|
private void UpdateSections()
|
||||||
{
|
{
|
||||||
foreach (Body b in bodies)
|
foreach (Body b in bodies)
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ namespace Barotrauma
|
|||||||
get { return stairDirection; }
|
get { return stairDirection; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector2 Size
|
||||||
|
{
|
||||||
|
get { return size; }
|
||||||
|
}
|
||||||
|
|
||||||
public static void LoadAll(List<string> filePaths)
|
public static void LoadAll(List<string> filePaths)
|
||||||
{
|
{
|
||||||
foreach (string filePath in filePaths)
|
foreach (string filePath in filePaths)
|
||||||
|
|||||||
@@ -247,7 +247,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
suitableMusic = musicClips.Where(x => x != null && x.type == OverrideMusicType).ToList();
|
suitableMusic = musicClips.Where(x => x != null && x.type == OverrideMusicType).ToList();
|
||||||
}
|
}
|
||||||
else if (Submarine.Loaded!=null && Submarine.Loaded.AtDamageDepth)
|
else if (Character.Controlled != null && Level.Loaded != null && Level.Loaded.Ruins.Any(r => r.Area.Contains(Character.Controlled.WorldPosition)))
|
||||||
|
{
|
||||||
|
suitableMusic = musicClips.Where(x => x != null && x.type == "ruins").ToList();
|
||||||
|
}
|
||||||
|
else if (Submarine.Loaded != null && Submarine.Loaded.AtDamageDepth)
|
||||||
{
|
{
|
||||||
suitableMusic = musicClips.Where(x => x != null && x.type == "deep").ToList();
|
suitableMusic = musicClips.Where(x => x != null && x.type == "deep").ToList();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user