Merge branch 'master' into moRags

This commit is contained in:
Alex Noir
2017-12-17 22:41:45 +03:00
81 changed files with 770 additions and 256 deletions
@@ -15,6 +15,8 @@ namespace Barotrauma
{ {
protected float soundTimer; protected float soundTimer;
protected float soundInterval; protected float soundInterval;
protected float nameTimer;
protected bool nameVisible;
private List<CharacterSound> sounds; private List<CharacterSound> sounds;
@@ -295,18 +297,50 @@ namespace Barotrauma
} }
if (this == controlled) return; if (this == controlled) return;
nameTimer -= (float)Timing.Step;
if (nameTimer <= 0.0f)
{
//Ideally it shouldn't send the character entirely if we can't see them but /shrug, this isn't the most hacker-proof game atm
Limb selfHead = controlled != null ? controlled.AnimController.GetLimb(LimbType.Head) : null;
Limb targHead = this.AnimController.GetLimb(LimbType.Head);
if (controlled != null && controlled.Submarine == Submarine)
{
if (selfHead != null && targHead != null)
{
Body closestBody = Submarine.CheckVisibility(selfHead.SimPosition, targHead.SimPosition);
Structure wall = null;
if (closestBody != null)
wall = closestBody.UserData as Structure;
nameVisible = closestBody == null || wall == null || !wall.CastShadow;
}
else
nameVisible = false;
}
else
nameVisible = true; //Ideally it should check for visibility from outside the sub/from sub-to-sub, but this will work for now.
nameTimer = Rand.Range(0.5f, 2f);
}
if (!nameVisible)
return;
if (info != null) if (info != null)
{ {
Vector2 namePos = new Vector2(pos.X, pos.Y - 110.0f - (5.0f / cam.Zoom)) - GUI.Font.MeasureString(Info.Name) * 0.5f / cam.Zoom; string name = Info.DisplayName;
if (controlled == null && name != Info.Name)
name += " (Disguised)";
Vector2 namePos = new Vector2(pos.X, pos.Y - 110.0f - (5.0f / cam.Zoom)) - GUI.Font.MeasureString(name) * 0.5f / cam.Zoom;
Color nameColor = Color.White; Color nameColor = Color.White;
if (Character.Controlled != null && TeamID != Character.Controlled.TeamID) if (Character.Controlled != null && TeamID != Character.Controlled.TeamID)
{ {
nameColor = Color.Red; nameColor = Color.Red;
} }
GUI.Font.DrawString(spriteBatch, Info.Name, namePos + new Vector2(1.0f / cam.Zoom, 1.0f / cam.Zoom), Color.Black, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.001f); GUI.Font.DrawString(spriteBatch, name, namePos + new Vector2(1.0f / cam.Zoom, 1.0f / cam.Zoom), Color.Black, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.001f);
GUI.Font.DrawString(spriteBatch, Info.Name, namePos, nameColor, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.0f); GUI.Font.DrawString(spriteBatch, name, namePos, nameColor, 0.0f, Vector2.Zero, 1.0f / cam.Zoom, SpriteEffects.None, 0.0f);
if (GameMain.DebugDraw) if (GameMain.DebugDraw)
{ {
@@ -242,7 +242,7 @@ namespace Barotrauma
string focusName = character.FocusedCharacter.SpeciesName; string focusName = character.FocusedCharacter.SpeciesName;
if (character.FocusedCharacter.Info != null) if (character.FocusedCharacter.Info != null)
{ {
focusName = character.FocusedCharacter.Info.Name; focusName = character.FocusedCharacter.Info.DisplayName;
} }
Vector2 textPos = startPos; Vector2 textPos = startPos;
textPos -= new Vector2(GUI.Font.MeasureString(focusName).X / 2, 20); textPos -= new Vector2(GUI.Font.MeasureString(focusName).X / 2, 20);
@@ -143,11 +143,12 @@ namespace Barotrauma
msg.ReadFloat(), msg.ReadFloat(),
msg.ReadFloat()); msg.ReadFloat());
float rotation = msg.ReadFloat();
int index = 0; int index = 0;
if (GameMain.NetworkMember.Character == this && AllowInput) if (GameMain.NetworkMember.Character == this)
{ {
var posInfo = new CharacterStateInfo(pos, networkUpdateID, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation); var posInfo = new CharacterStateInfo(pos, rotation, networkUpdateID, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation);
while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID)) while (index < memState.Count && NetIdUtils.IdMoreRecent(posInfo.ID, memState[index].ID))
index++; index++;
@@ -155,7 +156,7 @@ namespace Barotrauma
} }
else else
{ {
var posInfo = new CharacterStateInfo(pos, sendingTime, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation); var posInfo = new CharacterStateInfo(pos, rotation, sendingTime, facingRight ? Direction.Right : Direction.Left, selectedEntity, animation);
while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp) while (index < memState.Count && posInfo.Timestamp > memState[index].Timestamp)
index++; index++;
@@ -32,7 +32,7 @@ namespace Barotrauma
} }
public GUIMessageBox(string headerText, string text) public GUIMessageBox(string headerText, string text)
: this(headerText, text, new string[] {"OK"}) : this(headerText, text, new string[] {"OK"}, DefaultWidth, 0)
{ {
this.Buttons[0].OnClicked = Close; this.Buttons[0].OnClicked = Close;
} }
@@ -39,7 +39,7 @@ namespace Barotrauma
case 3: case 3:
case 4: case 4:
SlotPositions[i] = new Vector2( SlotPositions[i] = new Vector2(
spacing * 2 + rectWidth + (spacing + rectWidth) * (i - 2), spacing * 2 + rectWidth + (spacing + rectWidth) * (i - 1),
GameMain.GraphicsHeight - (spacing + rectHeight) * 3); GameMain.GraphicsHeight - (spacing + rectHeight) * 3);
useOnSelfButton[i - 3] = new GUIButton( useOnSelfButton[i - 3] = new GUIButton(
@@ -52,16 +52,24 @@ namespace Barotrauma
break; break;
//face
case 5: case 5:
SlotPositions[i] = new Vector2( SlotPositions[i] = new Vector2(
spacing * 2 + rectWidth + (spacing + rectWidth) * (i - 5), spacing * 2 + rectWidth + (spacing + rectWidth) * (i - 5),
GameMain.GraphicsHeight - (spacing + rectHeight) * 3); GameMain.GraphicsHeight - (spacing + rectHeight) * 3);
break;
//id card
case 6:
SlotPositions[i] = new Vector2(
spacing * 2 + rectWidth + (spacing + rectWidth) * (i - 5),
GameMain.GraphicsHeight - (spacing + rectHeight) * 3);
break; break;
default: default:
SlotPositions[i] = new Vector2( SlotPositions[i] = new Vector2(
spacing * 2 + rectWidth + (spacing + rectWidth) * ((i - 6) % 5), spacing * 2 + rectWidth + (spacing + rectWidth) * ((i - 7) % 5),
GameMain.GraphicsHeight - (spacing + rectHeight) * ((i > 10) ? 2 : 1)); GameMain.GraphicsHeight - (spacing + rectHeight) * ((i > 11) ? 2 : 1));
break; break;
} }
} }
@@ -247,6 +255,13 @@ namespace Barotrauma
new Vector2(15.0f, 16.0f), Vector2.One, new Vector2(15.0f, 16.0f), Vector2.One,
SpriteEffects.None, 0.1f); SpriteEffects.None, 0.1f);
} }
else if (i == 6)
{
spriteBatch.Draw(icons, new Vector2(slotRect.Center.X, slotRect.Center.Y),
new Rectangle(62, 36, 22, 18), Color.White * 0.7f, 0.0f,
new Vector2(11.0f, 9.0f), Vector2.One,
SpriteEffects.None, 0.1f);
}
} }
base.Draw(spriteBatch); base.Draw(spriteBatch);
@@ -7,7 +7,7 @@ using System;
namespace Barotrauma.Items.Components namespace Barotrauma.Items.Components
{ {
partial class Door : ItemComponent, IDrawableComponent, IServerSerializable partial class Door : Pickable, IDrawableComponent, IServerSerializable
{ {
private ConvexHull convexHull; private ConvexHull convexHull;
private ConvexHull convexHull2; private ConvexHull convexHull2;
@@ -20,7 +20,7 @@ namespace Barotrauma.Items.Components
if (GameMain.Server != null) if (GameMain.Server != null)
{ {
item.CreateServerEvent(this); item.CreateServerEvent(this);
GameServer.Log(Character.Controlled + (IsActive ? " turned on " : " turned off ") + item.Name, ServerLog.MessageType.ItemInteraction); GameServer.Log(Character.Controlled.LogName + (IsActive ? " turned on " : " turned off ") + item.Name, ServerLog.MessageType.ItemInteraction);
} }
else if (GameMain.Client != null) else if (GameMain.Client != null)
{ {
@@ -39,7 +39,7 @@ namespace Barotrauma.Items.Components
if (GameMain.Server != null) if (GameMain.Server != null)
{ {
item.CreateServerEvent(this); item.CreateServerEvent(this);
GameServer.Log(Character.Controlled + " set the pumping speed of " + item.Name + " to " + (int)(flowPercentage) + " %", ServerLog.MessageType.ItemInteraction); GameServer.Log(Character.Controlled.LogName + " set the pumping speed of " + item.Name + " to " + (int)(flowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
} }
else if (GameMain.Client != null) else if (GameMain.Client != null)
{ {
@@ -58,7 +58,7 @@ namespace Barotrauma.Items.Components
if (GameMain.Server != null) if (GameMain.Server != null)
{ {
item.CreateServerEvent(this); item.CreateServerEvent(this);
GameServer.Log(Character.Controlled + " set the pumping speed of " + item.Name + " to " + (int)(flowPercentage) + " %", ServerLog.MessageType.ItemInteraction); GameServer.Log(Character.Controlled.LogName + " set the pumping speed of " + item.Name + " to " + (int)(flowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
} }
else if (GameMain.Client != null) else if (GameMain.Client != null)
{ {
@@ -19,7 +19,7 @@ namespace Barotrauma.Items.Components
if (GameMain.Server != null) if (GameMain.Server != null)
{ {
item.CreateServerEvent(this); item.CreateServerEvent(this);
GameServer.Log(Character.Controlled + " set the recharge speed of " + item.Name + " to " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction); GameServer.Log(Character.Controlled.LogName + " set the recharge speed of " + item.Name + " to " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction);
} }
else if (GameMain.Client != null) else if (GameMain.Client != null)
{ {
@@ -38,7 +38,7 @@ namespace Barotrauma.Items.Components
if (GameMain.Server != null) if (GameMain.Server != null)
{ {
item.CreateServerEvent(this); item.CreateServerEvent(this);
GameServer.Log(Character.Controlled + " set the recharge speed of " + item.Name + " to " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction); GameServer.Log(Character.Controlled.LogName + " set the recharge speed of " + item.Name + " to " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction);
} }
else if (GameMain.Client != null) else if (GameMain.Client != null)
{ {
@@ -102,11 +102,11 @@ namespace Barotrauma.Items.Components
{ {
if (GameMain.Client != null) if (GameMain.Client != null)
{ {
panel.Item.CreateClientEvent<ConnectionPanel>(panel); panel.Item.CreateClientEvent(panel);
} }
else if (GameMain.Server != null) else if (GameMain.Server != null)
{ {
panel.Item.CreateServerEvent<ConnectionPanel>(panel); panel.Item.CreateServerEvent(panel);
} }
draggingConnected = null; draggingConnected = null;
@@ -174,12 +174,12 @@ namespace Barotrauma.Items.Components
var otherConnection = draggingConnected.OtherConnection(this); var otherConnection = draggingConnected.OtherConnection(this);
if (otherConnection == null) if (otherConnection == null)
{ {
GameServer.Log(Character.Controlled + " connected a wire to " + GameServer.Log(Character.Controlled.LogName + " connected a wire to " +
Item.Name + " (" + Name + ")", ServerLog.MessageType.ItemInteraction); Item.Name + " (" + Name + ")", ServerLog.MessageType.ItemInteraction);
} }
else else
{ {
GameServer.Log(Character.Controlled + " connected a wire from " + GameServer.Log(Character.Controlled.LogName + " connected a wire from " +
Item.Name + " (" + Name + ") to " + otherConnection.item.Name + " (" + otherConnection.Name + ")", ServerLog.MessageType.ItemInteraction); Item.Name + " (" + Name + ") to " + otherConnection.item.Name + " (" + otherConnection.Name + ")", ServerLog.MessageType.ItemInteraction);
} }
@@ -23,7 +23,6 @@ namespace Barotrauma.Items.Components
HighlightedWire = null; HighlightedWire = null;
Connection.DrawConnections(spriteBatch, this, character); Connection.DrawConnections(spriteBatch, this, character);
} }
} }
} }
@@ -296,9 +296,26 @@ namespace Barotrauma
} }
else else
{ {
toolTip = string.IsNullOrEmpty(Items[i].Description) ? string description = Items[i].Description;
if (Items[i].Prefab.NameMatches("ID Card"))
{
string[] readTags = Items[i].Tags.Split(',');
string idName = null;
string idJob = null;
foreach (string tag in readTags)
{
string[] s = tag.Split(':');
if (s[0] == "name")
idName = s[1];
if (s[0] == "job")
idJob = s[1];
}
if (idName != null)
description = "This belongs to " + idName + (idJob != null ? ", the " + idJob + ".\n" : ".\n") + description;
}
toolTip = string.IsNullOrEmpty(description) ?
Items[i].Name : Items[i].Name :
Items[i].Name + '\n' + Items[i].Description; Items[i].Name + '\n' + description;
} }
DrawToolTip(spriteBatch, toolTip, slots[i].Rect); DrawToolTip(spriteBatch, toolTip, slots[i].Rect);
@@ -106,6 +106,16 @@ namespace Barotrauma
return true; return true;
} }
private bool EnterIDCardDesc(GUITextBox textBox, string text)
{
IdCardDesc = text;
textBox.Text = text;
textBox.Color = Color.Green;
textBox.Deselect();
return true;
}
private bool EnterIDCardTags(GUITextBox textBox, string text) private bool EnterIDCardTags(GUITextBox textBox, string text)
{ {
IdCardTags = text.Split(','); IdCardTags = text.Split(',');
@@ -143,7 +153,7 @@ namespace Barotrauma
private GUIComponent CreateEditingHUD(bool inGame = false) private GUIComponent CreateEditingHUD(bool inGame = false)
{ {
int width = 500; int width = 500;
int height = spawnType == SpawnType.Path ? 100 : 140; int height = spawnType == SpawnType.Path ? 100 : 200;
int x = GameMain.GraphicsWidth / 2 - width / 2, y = 10; int x = GameMain.GraphicsWidth / 2 - width / 2, y = 10;
editingHUD = new GUIFrame(new Rectangle(x, y, width, height), Color.Black * 0.5f); editingHUD = new GUIFrame(new Rectangle(x, y, width, height), Color.Black * 0.5f);
@@ -172,8 +182,19 @@ namespace Barotrauma
y = 40 + 20; y = 40 + 20;
new GUITextBlock(new Rectangle(0, y, 100, 20), "ID Card desc:", Color.Transparent, Color.White, Alignment.TopLeft, null, editingHUD);
GUITextBox propertyBox = new GUITextBox(new Rectangle(100, y, 350, 20), "", editingHUD);
propertyBox.MaxTextLength = 150;
propertyBox.Text = idCardDesc;
propertyBox.OnEnterPressed = EnterIDCardDesc;
propertyBox.OnTextChanged = TextBoxChanged;
propertyBox.ToolTip = "Characters spawning at this spawnpoint will have the specified description added to their ID card. This can be used to describe additional access levels their card has on the sub.";
y = y + 30;
new GUITextBlock(new Rectangle(0, y, 100, 20), "ID Card tags:", Color.Transparent, Color.White, Alignment.TopLeft, null, editingHUD); new GUITextBlock(new Rectangle(0, y, 100, 20), "ID Card tags:", Color.Transparent, Color.White, Alignment.TopLeft, null, editingHUD);
GUITextBox propertyBox = new GUITextBox(new Rectangle(100, y, 200, 20), "", editingHUD); propertyBox = new GUITextBox(new Rectangle(100, y, 350, 20), "", editingHUD);
propertyBox.MaxTextLength = 60;
propertyBox.Text = string.Join(", ", idCardTags); propertyBox.Text = string.Join(", ", idCardTags);
propertyBox.OnEnterPressed = EnterIDCardTags; propertyBox.OnEnterPressed = EnterIDCardTags;
propertyBox.OnTextChanged = TextBoxChanged; propertyBox.OnTextChanged = TextBoxChanged;
@@ -182,7 +203,8 @@ namespace Barotrauma
y = y + 30; y = y + 30;
new GUITextBlock(new Rectangle(0, y, 100, 20), "Assigned job:", Color.Transparent, Color.White, Alignment.TopLeft, null, editingHUD); new GUITextBlock(new Rectangle(0, y, 100, 20), "Assigned job:", Color.Transparent, Color.White, Alignment.TopLeft, null, editingHUD);
propertyBox = new GUITextBox(new Rectangle(100, y, 200, 20), "", editingHUD); propertyBox = new GUITextBox(new Rectangle(100, y, 350, 20), "", editingHUD);
propertyBox.MaxTextLength = 60;
propertyBox.Text = (assignedJob == null) ? "None" : assignedJob.Name; propertyBox.Text = (assignedJob == null) ? "None" : assignedJob.Name;
propertyBox.OnEnterPressed = EnterAssignedJob; propertyBox.OnEnterPressed = EnterAssignedJob;
propertyBox.OnTextChanged = TextBoxChanged; propertyBox.OnTextChanged = TextBoxChanged;
@@ -453,10 +453,11 @@ namespace Barotrauma
{ {
damage = MathHelper.Clamp(damage+Rand.Range(-10.0f, 10.0f), 0.0f, 100.0f); damage = MathHelper.Clamp(damage+Rand.Range(-10.0f, 10.0f), 0.0f, 100.0f);
var sounds = damageSounds.FindAll(s => var sounds = damageSounds.FindAll(s =>
damage >= s.damageRange.X && s.damageRange == null ||
damage <= s.damageRange.Y && (damage >= s.damageRange.X &&
damage <= s.damageRange.Y) &&
s.damageType == damageType && s.damageType == damageType &&
(string.IsNullOrEmpty(s.requiredTag) || (tags != null && tags.Contains(s.requiredTag)))); (tags == null ? string.IsNullOrEmpty(s.requiredTag) : tags.Contains(s.requiredTag)));
if (!sounds.Any()) return; if (!sounds.Any()) return;
@@ -976,6 +976,12 @@
<None Include="$(MSBuildThisFileDirectory)Content\Items\Reactor\reactor.ogg"> <None Include="$(MSBuildThisFileDirectory)Content\Items\Reactor\reactor.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Tools\bump.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Tools\crowbar.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Tools\extinguisher.ogg"> <None Include="$(MSBuildThisFileDirectory)Content\Items\Tools\extinguisher.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
@@ -1021,6 +1027,9 @@
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\stungrenade.ogg"> <None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\stungrenade.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Include="$(MSBuildThisFileDirectory)Content\Items\Weapons\syringegun.ogg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="$(MSBuildThisFileDirectory)Content\Map\TutorialSub.sub"> <None Include="$(MSBuildThisFileDirectory)Content\Map\TutorialSub.sub">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
@@ -61,7 +61,7 @@
<joint limb1="0" limb1anchor="64,-264" limb2="2" 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" canbesevered="true"/> <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"/> <joint limb1="0" limb1anchor="140,268" limb2="4" limb2anchor="0,0" lowerlimit="87" upperlimit="93" canbesevered="false"/>
</ragdoll> </ragdoll>
@@ -1,17 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<Character name ="human" humanoid="true" genders="true" maleheadid="1,8" femaleheadid="1,7" needsair="false" doesbleed="false"> <Character name="husk" humanoid="true" genders="true" maleheadid="1,8" femaleheadid="1,7" needsair="false" doesbleed="false">
<name firstname="Content/Characters/Human/[GENDER]firstnames.txt" lastname="Content/Characters/Human/lastnames.txt" />
<name firstname="Content/Characters/Human/[GENDER]firstnames.txt" lastname="Content/Characters/Human/lastnames.txt" /> <ai
combatstrength="100"
attackhumans="500"
attackrooms="5.0"
attackweaker="50"
attackstronger="-30"
sight="0.5"
hearing="1.0"
attackcooldown="5.0"/>
<ragdoll headposition="134" torsoposition="108" <ragdoll headposition="134" torsoposition="108"
stepsize="42.0, 12.0" stepsize="42.0, 12.0"
walkanimspeed="4.58" walkanimspeed="4.58"
movementlerp="0.4" movementlerp="0.4"
legtorque="15.0" legtorque="15.0"
thightorque="-5.0" thightorque="-5.0"
walkspeed="1.5" swimspeed="2.5" walkspeed="1.5" swimspeed="2.5"
runspeedmultiplier="2.0" swimspeedmultiplier="1.5" runspeedmultiplier="2.0" swimspeedmultiplier="1.5"
impacttolerance="7.5"> impacttolerance="7.5">
<collider height="80" radius="15"/> <collider height="80" radius="15"/>
<collider height="40" radius="15"/> <collider height="40" radius="15"/>
@@ -115,9 +125,5 @@
<joint limb1="1" limb1anchor="25,10" limb2="13" limb2anchor="25,0" lowerlimit="-40" upperlimit="0" canbesevered="true"/> <joint limb1="1" limb1anchor="25,10" limb2="13" limb2anchor="25,0" lowerlimit="-40" upperlimit="0" canbesevered="true"/>
</ragdoll> </ragdoll>
<ai attackhumans="500" attackrooms="5.0" attackweaker="50" attackstronger="-30"
sight="0.5" hearing="1.0"
attackcooldown="5.0"/>
</Character> </Character>
@@ -41,7 +41,7 @@
<Wearable limbtype="Head" slots="Any,Face"> <Wearable limbtype="Head" slots="Any,Face">
<sprite texture="DivingMask.png" limb="Head" sourcerect="1,1,37,38"/> <sprite texture="DivingMask.png" limb="Head" sourcerect="1,1,37,38"/>
<StatusEffect type="OnWearing" target="Character" ObstructVision="true" setvalue="true" disabledeltatime="true"/> <StatusEffect type="OnWearing" target="Character" HideFace="true" ObstructVision="true" setvalue="true" disabledeltatime="true"/>
<StatusEffect type="OnWearing" target="Contained,Character" OxygenAvailable="1000.0" Condition="-0.5"> <StatusEffect type="OnWearing" target="Contained,Character" OxygenAvailable="1000.0" Condition="-0.5">
<RequiredItem type="Contained" name="Oxygen Tank"/> <RequiredItem type="Contained" name="Oxygen Tank"/>
</StatusEffect> </StatusEffect>
@@ -92,7 +92,7 @@
<sprite texture="DivingSuit.png" limb="RightFoot" sourcerect="30,100,20,25" origin="0.5,0.5" depth="0.13" inheritlimbdepth="false" hidelimb="true"/> <sprite texture="DivingSuit.png" limb="RightFoot" sourcerect="30,100,20,25" origin="0.5,0.5" depth="0.13" inheritlimbdepth="false" hidelimb="true"/>
<sprite texture="DivingSuit.png" limb="LeftFoot" sourcerect="30,100,20,25" origin="0.5,0.5" depth="0.13" inheritlimbdepth="false" hidelimb="true"/> <sprite texture="DivingSuit.png" limb="LeftFoot" sourcerect="30,100,20,25" origin="0.5,0.5" depth="0.13" inheritlimbdepth="false" hidelimb="true"/>
<StatusEffect type="OnWearing" target="Character" ObstructVision="true" PressureProtection="100.0" SpeedMultiplier="0.6" LowPassMultiplier="0.2" setvalue="true" disabledeltatime="true"/> <StatusEffect type="OnWearing" target="Character" HideFace="true" ObstructVision="true" PressureProtection="100.0" SpeedMultiplier="0.6" LowPassMultiplier="0.2" setvalue="true" disabledeltatime="true"/>
<StatusEffect type="OnWearing" target="Contained,Character" OxygenAvailable="1000.0" Condition="-0.5"> <StatusEffect type="OnWearing" target="Contained,Character" OxygenAvailable="1000.0" Condition="-0.5">
<RequiredItem type="Contained" name="Oxygen Tank"/> <RequiredItem type="Contained" name="Oxygen Tank"/>
</StatusEffect> </StatusEffect>
@@ -6,11 +6,13 @@
<Sprite texture ="door.png" sourcerect="1,0,48,208" depth="0.01" origin="0.5,0.5"/> <Sprite texture ="door.png" sourcerect="1,0,48,208" depth="0.01" origin="0.5,0.5"/>
<Door canbeselected="true"> <Door canbeselected="true" selectkey="Action" msg="Force Open [Crowbar]" PickingTime="10.0">
<requireditem name="Crowbar" type="Equipped"/>
<Sprite texture ="door.png" sourcerect="80,0,19,208" depth="0.05" origin="0.5,0.0"/> <Sprite texture ="door.png" sourcerect="80,0,19,208" depth="0.05" origin="0.5,0.0"/>
<WeldedSprite texture ="door.png" sourcerect="99,0,32,188" depth="0.0" origin="0.5,0.5"/> <WeldedSprite texture ="door.png" sourcerect="99,0,32,188" depth="0.0" origin="0.5,0.5"/>
<BrokenSprite texture ="door.png" sourcerect="133,0,58,208" depth="0.051" origin="0.5,0.0" scale="true"/> <BrokenSprite texture ="door.png" sourcerect="133,0,58,208" depth="0.051" origin="0.5,0.0" scale="true"/>
<sound file="door.ogg" type="OnUse" range="500.0"/> <sound file="door.ogg" type="OnUse" range="500.0"/>
<sound file="Content/Items/Tools/Crowbar.ogg" type="OnPicked" range="2000.0"/>
</Door> </Door>
<AiTarget sightrange="500.0"/> <AiTarget sightrange="500.0"/>
@@ -35,11 +37,13 @@
<Sprite texture="door.png" sourcerect="1,0,48,208" depth="0.01" origin="0.5,0.5"/> <Sprite texture="door.png" sourcerect="1,0,48,208" depth="0.01" origin="0.5,0.5"/>
<Door window="0,-32,10,75" canbeselected="true"> <Door window="0,-32,10,75" canbeselected="true" selectkey="Action" msg="Force Open [Crowbar]" PickingTime="10.0">
<requireditem name="Crowbar" type="Equipped"/>
<Sprite texture="door.png" sourcerect="56,0,19,208" depth="0.05" origin="0.5,0.0"/> <Sprite texture="door.png" sourcerect="56,0,19,208" depth="0.05" origin="0.5,0.0"/>
<WeldedSprite texture="door.png" sourcerect="9,0,32,188" depth="0.0" origin="0.5,0.5"/> <WeldedSprite texture="door.png" sourcerect="9,0,32,188" depth="0.0" origin="0.5,0.5"/>
<BrokenSprite texture="door.png" sourcerect="192,0,40,208" depth="0.051" origin="0.5,0.0" scale="true"/> <BrokenSprite texture="door.png" sourcerect="192,0,40,208" depth="0.051" origin="0.5,0.0" scale="true"/>
<sound file="door.ogg" type="OnUse" range="500.0"/> <sound file="door.ogg" type="OnUse" range="500.0"/>
<sound file="Content/Items/Tools/Crowbar.ogg" type="OnPicked" range="2000.0"/>
</Door> </Door>
<AiTarget sightrange="500.0"/> <AiTarget sightrange="500.0"/>
@@ -64,11 +68,13 @@
<Sprite texture="hatch.png" sourcerect="0,0,128,46" depth="0.01" origin="0.5,0.5"/> <Sprite texture="hatch.png" sourcerect="0,0,128,46" depth="0.01" origin="0.5,0.5"/>
<Door canbeselected="true" horizontal="true"> <Door canbeselected="true" horizontal="true" selectkey="Action" msg="Force Open [Crowbar]" PickingTime="10.0">
<requireditem name="Crowbar" type="Equipped"/>
<Sprite texture="hatch.png" sourcerect="128,0,128,19" depth="0.05" origin="0.0,0.5"/> <Sprite texture="hatch.png" sourcerect="128,0,128,19" depth="0.05" origin="0.0,0.5"/>
<WeldedSprite texture="hatch.png" sourcerect="0,56,108,33" depth="0.0" origin="0.5,0.5"/> <WeldedSprite texture="hatch.png" sourcerect="0,56,108,33" depth="0.0" origin="0.5,0.5"/>
<BrokenSprite texture="hatch.png" sourcerect="128,21,128,58" depth="0.051" origin="0.0,0.5" scale="true"/> <BrokenSprite texture="hatch.png" sourcerect="128,21,128,58" depth="0.051" origin="0.0,0.5" scale="true"/>
<sound file="door.ogg" type="OnUse" range="500.0"/> <sound file="door.ogg" type="OnUse" range="500.0"/>
<sound file="Content/Items/Tools/Crowbar.ogg" type="OnPicked" range="2000.0"/>
</Door> </Door>
<AiTarget sightrange="500.0"/> <AiTarget sightrange="500.0"/>
@@ -40,13 +40,16 @@
<fabricableitem name="And Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/> <fabricableitem name="And Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Or Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/> <fabricableitem name="Or Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Not Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/> <fabricableitem name="Not Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Relay Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Delay Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Light Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/> <fabricableitem name="Light Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Oxygen Detector" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/> <fabricableitem name="Oxygen Detector" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Water Detector" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/> <fabricableitem name="Water Detector" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Signal Check Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/> <fabricableitem name="Signal Check Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="RegEx Find Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/> <fabricableitem name="RegEx Find Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Oscillator" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Wifi Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/> <fabricableitem name="Wifi Component" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Emergency Siren" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Alarm Buzzer" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/> <fabricableitem name="Alarm Buzzer" requireditems="Steel Bar, FPGA Circuit" requiredtime="10"/>
<fabricableitem name="Underwater Scooter" requireditems="Steel Bar, Polycarbonate Bar, Polycarbonate Bar, FPGA Circuit" requiredtime="30"/> <fabricableitem name="Underwater Scooter" requireditems="Steel Bar, Polycarbonate Bar, Polycarbonate Bar, FPGA Circuit" requiredtime="30"/>
@@ -96,6 +99,7 @@
<sound file="fabricator.ogg" type="OnActive" range="1000.0" loop="true"/> <sound file="fabricator.ogg" type="OnActive" range="1000.0" loop="true"/>
<fabricableitem name="Medical Syringe" requireditems="Steel Bar" requiredtime="10"/>
<fabricableitem name="Chloral Hydrate" requireditems="Chlorine, Ethanol" requiredtime="20"> <fabricableitem name="Chloral Hydrate" requireditems="Chlorine, Ethanol" requiredtime="20">
<RequiredSkill name="Medical" level="30"/> <RequiredSkill name="Medical" level="30"/>
</fabricableitem> </fabricableitem>
@@ -38,6 +38,7 @@
<Wearable limbtype="Head" slots="Any,Face"> <Wearable limbtype="Head" slots="Any,Face">
<sprite texture="clownmask.png" limb="Head" origin="0.5,0.5"/> <sprite texture="clownmask.png" limb="Head" origin="0.5,0.5"/>
<StatusEffect type="OnWearing" target="Character" HideFace="true"/>
</Wearable> </Wearable>
</Item> </Item>
@@ -25,6 +25,15 @@
<ItemContainer capacity="1" hideitems="true"> <ItemContainer capacity="1" hideitems="true">
<Containable name="chem"/> <Containable name="chem"/>
</ItemContainer> </ItemContainer>
<Projectile launchimpulse="20.0" sticktocharacters="true">
<Attack damage="5" bleedingdamage="0.2" structuredamage="1" damagetype="Blunt" stun="0.1" targetforce="5"/>
<StatusEffect type="OnImpact" target="Contained, Character" Condition="-50.0" disabledeltatime="true" >
<sound file="Content/Items/Medical/syringe.ogg" range="500"/>
<RequiredItem name="chem" type="Contained"/>
<Use/>
</StatusEffect>
</Projectile>
</Item> </Item>
<Item <Item
@@ -68,7 +68,7 @@
<Body radius="6" height="22" density="5"/> <Body radius="6" height="22" density="5"/>
<Holdable handle1="0,0" slots="RightHand,Any"/> <Holdable handle1="0,0" slots="Any,RightHand,LeftHand"/>
</Item> </Item>
<Item <Item
@@ -86,7 +86,7 @@
<Body radius="6" height="22" density="5"/> <Body radius="6" height="22" density="5"/>
<Holdable handle1="0,0" slots="RightHand,Any"/> <Holdable handle1="0,0" slots="Any,RightHand,LeftHand"/>
</Item> </Item>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

@@ -116,7 +116,7 @@
<Body width="12" height="33" density="5"/> <Body width="12" height="33" density="5"/>
<Holdable slots="RightHand,Any" holdpos="30,-15" handle1="0,5" handle2="0,-5"> <Holdable slots="Any,RightHand,LeftHand" holdpos="30,-15" handle1="0,5" handle2="0,-5">
<StatusEffect type="OnFire" target="This" Condition="-100.0" disabledeltatime="true"> <StatusEffect type="OnFire" target="This" Condition="-100.0" disabledeltatime="true">
<sound file="Content/Items/Reactor/explosion.ogg"/> <sound file="Content/Items/Reactor/explosion.ogg"/>
<Explosion range="250.0" structuredamage="15" damage="25" stun="5" force="3.0"/> <Explosion range="250.0" structuredamage="15" damage="25" stun="5" force="3.0"/>
@@ -175,7 +175,7 @@
price="10"> price="10">
<Sprite texture ="tools.png" sourcerect="0,50,26,7" depth="0.55"/> <Sprite texture ="tools.png" sourcerect="0,50,26,7" depth="0.55"/>
<Body width="30" height="7" density="50"/> <Body width="30" height="7" density="50"/>
@@ -185,6 +185,23 @@
</MeleeWeapon> </MeleeWeapon>
</Item> </Item>
<Item
name="Crowbar"
category="Equipment"
Tags="smallitem"
price="15">
<Sprite texture ="tools.png" sourcerect="0,65,64,12" depth="0.55"/>
<Body width="60" height="10" density="50"/>
<MeleeWeapon slots="RightHand+LeftHand,Any"
controlpose="true" aimpos="50,0" handle1="-5,0" handle2="-3,5" holdangle="30" reload="1.7">
<Attack damage="20" stun="0.6" damagetype="Blunt" sound="Content/Items/Weapons/smack.ogg"/>
</MeleeWeapon>
</Item>
<Item <Item
name="Handheld Sonar" name="Handheld Sonar"
category="Equipment" category="Equipment"
@@ -218,8 +235,7 @@
<Item <Item
name="Flashlight" name="Flashlight"
category="Equipment" category="Equipment"
Tags="smallitem" Tags="smallitem"
price="10"> price="10">
<Deconstruct time="15"> <Deconstruct time="15">
@@ -231,12 +247,11 @@
<Body width="27" height="10" density="15"/> <Body width="27" height="10" density="15"/>
<Holdable slots="Any,RightHand,LeftHand" aimpos="100,0" handle1="0,0"> <Holdable slots="Any,RightHand,LeftHand,Face" holdpos="30,-15" aimpos="100,0" handle1="-13" handle2="-13">
<StatusEffect type="OnActive" target="Contained" Condition="-0.2"/> <StatusEffect type="OnActive" target="Contained" Condition="-0.2"/>
</Holdable> </Holdable>
<LightComponent LightColor="1.0,1.0,1.0,1.0" Flicker="0.1" range="800" powerconsumption="10" IsOn="true"> <LightComponent LightColor="1.0,1.0,1.0,1.0" Flicker="0.1" range="800" powerconsumption="10" IsOn="true">
<LightTexture texture="Content/Lights/lightcone.png" origin="0.0, 0.5" size="2.0,1.0"/> <LightTexture texture="Content/Lights/lightcone.png" origin="0.0, 0.5" size="2.0,1.0"/>
</LightComponent> </LightComponent>
@@ -36,11 +36,12 @@
category="Machine" category="Machine"
type="Controller" type="Controller"
linkable="true" linkable="true"
disableitemusagewhenselected="true"
> >
<Sprite texture ="railgunetc.png" depth="0.8" sourcerect="182,0,61,97"/> <Sprite texture ="railgunetc.png" depth="0.8" sourcerect="182,0,61,97"/>
<Controller UserPos="-35.0, -50.0" direction ="Right" canbeselected = "true"> <Controller UserPos="-35.0, -50.0" direction ="Right" canbeselected="true">
<limbposition limb="Head" position="-5,-62"/> <limbposition limb="Head" position="-5,-62"/>
<limbposition limb="Torso" position="-5,-108"/> <limbposition limb="Torso" position="-5,-108"/>
<limbposition limb="LeftHand" position="43,-85"/> <limbposition limb="LeftHand" position="43,-85"/>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 17 KiB

@@ -16,7 +16,7 @@
<Body width="64" height="5" density="20"/> <Body width="64" height="5" density="20"/>
<Pickable slots="Any"/> <Pickable slots="Any"/>
<Projectile launchimpulse="20.0" doesstick="true"> <Projectile launchimpulse="20.0" sticktocharacters="true">
<Attack damage="20" bleedingdamage="2" structuredamage="50" damagetype="Blunt" stun="0.2" targetforce="50"/> <Attack damage="20" bleedingdamage="2" structuredamage="50" damagetype="Blunt" stun="0.2" targetforce="50"/>
</Projectile> </Projectile>
</Item> </Item>
@@ -56,6 +56,38 @@
</ItemContainer> </ItemContainer>
</Item> </Item>
<Item
name="Syringe Gun"
category="Equipment"
price="700"
tags="weapon">
<Deconstruct time="10">
<Item name="Steel Bar"/>
<Item name="Aluminium"/>
<Item name="Polycarbonate Bar"/>
</Deconstruct>
<Sprite texture="weapons.png" sourcerect="62,97,44,24" depth="0.55"/>
<Body width="40" height="25" density="50"/>
<Holdable slots="Any,RightHand,LeftHand" controlpose="true"
aimpos="90,10" handle1="-10,-7"/>
<RangedWeapon barrelpos="30,20" spread="0" unskilledspread="10">
<Sound file="syringegun.ogg" type="OnUse"/>
<RequiredItems name="Medical Syringe" type="Contained" msg="Please load a Syringe"/>
<RequiredSkill name="Weapons" level="15"/>
<RequiredSkill name="Medical" level="30"/>
</RangedWeapon>
<ItemContainer capacity="1" itempos="0,10" hideitems="false">
<Containable name="Medical Syringe"/>
</ItemContainer>
</Item>
<Item <Item
name="Revolver Round" name="Revolver Round"
category="Equipment" category="Equipment"
@@ -68,7 +100,7 @@
<Body width="8" height="3" density="40"/> <Body width="8" height="3" density="40"/>
<Pickable slots="Any"/> <Pickable slots="Any"/>
<Projectile hitscan="true" doesstick="false" removeonhit="true" > <Projectile hitscan="true" removeonhit="true" >
<Attack damage="40" bleedingdamage="3" structuredamage="100" damagetype="Blunt" stun="0.5" targetforce="50"/> <Attack damage="40" bleedingdamage="3" structuredamage="100" damagetype="Blunt" stun="0.5" targetforce="50"/>
</Projectile> </Projectile>
</Item> </Item>
@@ -117,7 +149,7 @@
<Body width="11" height="24" density="30"/> <Body width="11" height="24" density="30"/>
<Throwable slots="Any,RightHand,LeftHand" holdpos="0,0" handle1="0,0" throwforce="4.0" aimpos="35,-10"> <Throwable slots="Any,RightHand,LeftHand" holdpos="0,0" handle1="0,0" throwforce="4.0" aimpos="35,-10">
<StatusEffect type="OnUse" target="This" Condition="-100.0" delay="3.0"> <StatusEffect type="OnSecondaryUse" target="This" Condition="-100.0" delay="3.0">
<sound file="Content/Items/Weapons/stungrenade.ogg"/> <sound file="Content/Items/Weapons/stungrenade.ogg"/>
<Explosion range="500" damage="5" stun="25" force="0.1" smoke="false"/> <Explosion range="500" damage="5" stun="25" force="0.1" smoke="false"/>
</StatusEffect> </StatusEffect>
@@ -134,7 +166,7 @@
<Body width="11" height="24" density="30"/> <Body width="11" height="24" density="30"/>
<Throwable slots="Any,RightHand,LeftHand" holdpos="0,0" handle1="0,0" throwforce="4.0" aimpos="35,-10"> <Throwable slots="Any,RightHand,LeftHand" holdpos="0,0" handle1="0,0" throwforce="4.0" aimpos="35,-10">
<StatusEffect type="OnUse" target="This" Condition="-100.0" delay="3.0"> <StatusEffect type="OnSecondaryUse" target="This" Condition="-100.0" delay="3.0">
<sound file="Content/Items/Weapons/stungrenade.ogg"/> <sound file="Content/Items/Weapons/stungrenade.ogg"/>
<Explosion range="500" damage="5" stun="1" force="0.1"/> <Explosion range="500" damage="5" stun="1" force="0.1"/>
<Fire size="300.0"/> <Fire size="300.0"/>
@@ -10,8 +10,5 @@
<Body width="16" height="16" density="20"/> <Body width="16" height="16" density="20"/>
<Pickable/> <Pickable slots="Card,Any"/>
</Item> </Item>
+7 -6
View File
@@ -8,7 +8,7 @@
<Skill name="Medical" level="10,30"/> <Skill name="Medical" level="10,30"/>
</Skills> </Skills>
<Items> <Items>
<Item name="ID Card"/> <Item name="ID Card" equip="true"/>
<Item name="Captain's Cap" equip="true"/> <Item name="Captain's Cap" equip="true"/>
<Item name="Captain's Jacket" equip="true"/> <Item name="Captain's Jacket" equip="true"/>
<Item name="Captain's Trousers" equip="true"/> <Item name="Captain's Trousers" equip="true"/>
@@ -30,7 +30,7 @@
<Skill name="Medical" level="10,20"/> <Skill name="Medical" level="10,20"/>
</Skills> </Skills>
<Items> <Items>
<Item name="ID Card"/> <Item name="ID Card" equip="true"/>
<Item name="Wrench"/> <Item name="Wrench"/>
<Item name="Screwdriver"/> <Item name="Screwdriver"/>
<Item name="Orange Jumpsuit" equip="true"/> <Item name="Orange Jumpsuit" equip="true"/>
@@ -48,7 +48,8 @@
<Skill name="Medical" level="10,20"/> <Skill name="Medical" level="10,20"/>
</Skills> </Skills>
<Items> <Items>
<Item name="ID Card"/> <Item name="ID Card" equip="true"/>
<Item name="Crowbar"/>
<Item name="Wrench"/> <Item name="Wrench"/>
<Item name="Screwdriver"/> <Item name="Screwdriver"/>
<Item name="Blue Jumpsuit" equip="true"/> <Item name="Blue Jumpsuit" equip="true"/>
@@ -66,7 +67,7 @@
<Skill name="Electrical Engineering" level="10,20"/> <Skill name="Electrical Engineering" level="10,20"/>
</Skills> </Skills>
<Items> <Items>
<Item name="ID Card"/> <Item name="ID Card" equip="true"/>
<Item name="Stun Baton"/> <Item name="Stun Baton"/>
<Item name="Battery Cell"/> <Item name="Battery Cell"/>
<Item name="Handcuffs"/> <Item name="Handcuffs"/>
@@ -86,7 +87,7 @@
<Skill name="Medical" level="60,70"/> <Skill name="Medical" level="60,70"/>
</Skills> </Skills>
<Items> <Items>
<Item name="ID Card"/> <Item name="ID Card" equip="true"/>
<Item name="Doctor's Coat" equip="true"/> <Item name="Doctor's Coat" equip="true"/>
<Item name="Doctor's Trousers" equip="true"/> <Item name="Doctor's Trousers" equip="true"/>
<Item name="Health Scanner HUD"/> <Item name="Health Scanner HUD"/>
@@ -105,7 +106,7 @@
<Skill name="Medical" level="10,20"/> <Skill name="Medical" level="10,20"/>
</Skills> </Skills>
<Items> <Items>
<Item name="ID Card"/> <Item name="ID Card" equip="true"/>
<Item name="Wrench"/> <Item name="Wrench"/>
<Item name="Screwdriver"/> <Item name="Screwdriver"/>
<Item name="Headset" equip="true"> <Item name="Headset" equip="true">
@@ -16,8 +16,8 @@
<damagesound file="Content/Sounds/Damage/GlassImpact3.ogg" damagerange="10.0,20.0" damagesoundtype="StructureBlunt" requiredtag="glass"/> <damagesound file="Content/Sounds/Damage/GlassImpact3.ogg" damagerange="10.0,20.0" damagesoundtype="StructureBlunt" requiredtag="glass"/>
<damagesound file="Content/Sounds/Damage/GlassBreak1.ogg" damagerange="20.0,50.0" damagesoundtype="StructureBlunt" requiredtag="glass"/> <damagesound file="Content/Sounds/Damage/GlassBreak1.ogg" damagerange="20.0,50.0" damagesoundtype="StructureBlunt" requiredtag="glass"/>
<damagesound file="Content/Sounds/Damage/GlassBreak1.ogg" damagerange="25.0,80.0" damagesoundtype="StructureBlunt" requiredtag="glass"/> <damagesound file="Content/Sounds/Damage/GlassBreak2.ogg" damagerange="25.0,80.0" damagesoundtype="StructureBlunt" requiredtag="glass"/>
<damagesound file="Content/Sounds/Damage/GlassBreak1.ogg" damagerange="50.0,100.0" damagesoundtype="StructureBlunt" requiredtag="glass"/> <damagesound file="Content/Sounds/Damage/GlassBreak3.ogg" damagerange="50.0,100.0" damagesoundtype="StructureBlunt" requiredtag="glass"/>
<damagesound file="Content/Sounds/Damage/StructureCrunch1.ogg" damagerange="0.0,40.0" damagesoundtype="StructureSlash"/> <damagesound file="Content/Sounds/Damage/StructureCrunch1.ogg" damagerange="0.0,40.0" damagesoundtype="StructureSlash"/>
<damagesound file="Content/Sounds/Damage/StructureCrunch2.ogg" damagerange="5.0,70.0" damagesoundtype="StructureSlash"/> <damagesound file="Content/Sounds/Damage/StructureCrunch2.ogg" damagerange="5.0,70.0" damagesoundtype="StructureSlash"/>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

@@ -84,9 +84,13 @@ namespace Barotrauma
{ {
levitatingCollider = false; levitatingCollider = false;
Collider.FarseerBody.FixedRotation = false; Collider.FarseerBody.FixedRotation = false;
Collider.LinearVelocity = (GetLimb(LimbType.Waist).SimPosition - Collider.SimPosition) * 20.0f; if (Math.Abs(Collider.Rotation-GetLimb(LimbType.Torso).Rotation)>Math.PI*0.6f)
Collider.SmoothRotate(GetLimb(LimbType.Torso).Rotation); {
Collider.SetTransform(Collider.SimPosition, MathHelper.WrapAngle(Collider.Rotation + (float)Math.PI));
}
Collider.SmoothRotate(GetLimb(LimbType.Torso).Rotation);
Collider.LinearVelocity = (GetLimb(LimbType.Waist).SimPosition - Collider.SimPosition) * 20.0f;
return; return;
} }
@@ -1083,8 +1087,6 @@ namespace Barotrauma
public override void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle) public override void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle)
{ {
Holdable holdable = item.GetComponent<Holdable>();
if (character.IsUnconscious || character.Stun > 0.0f) aim = false; if (character.IsUnconscious || character.Stun > 0.0f) aim = false;
//calculate the handle positions //calculate the handle positions
@@ -1102,7 +1104,6 @@ namespace Barotrauma
bool usingController = character.SelectedConstruction != null && character.SelectedConstruction.GetComponent<Controller>() != null; bool usingController = character.SelectedConstruction != null && character.SelectedConstruction.GetComponent<Controller>() != null;
float itemAngle; float itemAngle;
if (Anim != Animation.Climbing && !usingController && character.Stun <= 0.0f && aim && itemPos != Vector2.Zero) if (Anim != Animation.Climbing && !usingController && character.Stun <= 0.0f && aim && itemPos != Vector2.Zero)
{ {
@@ -1114,6 +1115,7 @@ namespace Barotrauma
itemAngle = (torso.body.Rotation + holdAngle * Dir); itemAngle = (torso.body.Rotation + holdAngle * Dir);
Holdable holdable = item.GetComponent<Holdable>();
if (holdable.ControlPose) if (holdable.ControlPose)
{ {
head.body.SmoothRotate(itemAngle); head.body.SmoothRotate(itemAngle);
@@ -1339,13 +1339,34 @@ namespace Barotrauma
} }
} }
Vector2 positionError = serverPos.Position - localPos.Position; Hull serverHull = Hull.FindHull(serverPos.Position, character.CurrentHull, false);
for (int i = localPosIndex; i < character.MemLocalState.Count; i++) Hull clientHull = Hull.FindHull(localPos.Position, serverHull, false);
Vector2 positionError = serverPos.Position - localPos.Position;
float rotationError = serverPos.Rotation - localPos.Rotation;
if (serverHull!=clientHull && ((serverHull==null) || (clientHull==null) || (serverHull.Submarine != clientHull.Submarine)))
{ {
character.MemLocalState[i].Translate(positionError); //hull subs don't match => just teleport the player to exactly this position to avoid mismatches,
//since this would completely break the camera
positionError = Collider.SimPosition - serverPos.Position;
character.MemLocalState.Clear();
}
else
{
for (int i = localPosIndex; i < character.MemLocalState.Count; i++)
{
Hull pointHull = Hull.FindHull(character.MemLocalState[i].Position, clientHull, false);
if (pointHull != clientHull && ((pointHull == null) || (clientHull == null) || (pointHull.Submarine == clientHull.Submarine))) break;
character.MemLocalState[i].Translate(positionError, rotationError);
}
} }
Collider.SetTransform(Collider.SimPosition + positionError, Collider.Rotation); Collider.SetTransform(Collider.SimPosition + positionError, Collider.Rotation + rotationError);
foreach (Limb limb in Limbs)
{
limb.body.SetTransform(limb.body.SimPosition + positionError, limb.body.Rotation);
}
} }
if (character.MemLocalState.Count > 120) character.MemLocalState.RemoveRange(0, character.MemLocalState.Count - 120); if (character.MemLocalState.Count > 120) character.MemLocalState.RemoveRange(0, character.MemLocalState.Count - 120);
@@ -138,6 +138,27 @@ namespace Barotrauma
return info != null && !string.IsNullOrWhiteSpace(info.Name) ? info.Name : SpeciesName; return info != null && !string.IsNullOrWhiteSpace(info.Name) ? info.Name : SpeciesName;
} }
} }
//Only used by server logs to determine "true identity" of the player for cases when they're disguised
public string LogName
{
get
{
return info != null && !string.IsNullOrWhiteSpace(info.Name) ? info.Name + (info.DisplayName != info.Name ? " (as " + info.DisplayName + ")" : "") : SpeciesName;
}
}
private float hideFaceTimer;
public bool HideFace
{
get
{
return hideFaceTimer > 0.0f;
}
set
{
hideFaceTimer = MathHelper.Clamp(hideFaceTimer + (value ? 1.0f : -0.5f), 0.0f, 10.0f);
}
}
public string ConfigPath public string ConfigPath
{ {
@@ -591,7 +612,7 @@ namespace Barotrauma
{ {
AnimController = new HumanoidAnimController(this, doc.Root.Element("ragdoll")); AnimController = new HumanoidAnimController(this, doc.Root.Element("ragdoll"));
AnimController.TargetDir = Direction.Right; AnimController.TargetDir = Direction.Right;
inventory = new CharacterInventory(16, this); inventory = new CharacterInventory(17, this);
} }
else else
{ {
@@ -926,13 +947,16 @@ namespace Barotrauma
} }
} }
for (int i = 0; i < selectedItems.Length; i++ ) if (SelectedConstruction == null || !SelectedConstruction.Prefab.DisableItemUsageWhenSelected)
{ {
if (selectedItems[i] == null) continue; for (int i = 0; i < selectedItems.Length; i++ )
if (i == 1 && selectedItems[0] == selectedItems[1]) continue; {
if (selectedItems[i] == null) continue;
if (i == 1 && selectedItems[0] == selectedItems[1]) continue;
if (IsKeyDown(InputType.Use)) selectedItems[i].Use(deltaTime, this); if (IsKeyDown(InputType.Use)) selectedItems[i].Use(deltaTime, this);
if (IsKeyDown(InputType.Aim) && selectedItems[i] != null) selectedItems[i].SecondaryUse(deltaTime, this); if (IsKeyDown(InputType.Aim) && selectedItems[i] != null) selectedItems[i].SecondaryUse(deltaTime, this);
}
} }
if (selectedConstruction != null) if (selectedConstruction != null)
@@ -1406,6 +1430,8 @@ namespace Barotrauma
item.Submarine = Submarine; item.Submarine = Submarine;
} }
} }
HideFace = false;
if (isDead) return; if (isDead) return;
@@ -1633,7 +1659,7 @@ namespace Barotrauma
var attackingCharacter = attacker as Character; var attackingCharacter = attacker as Character;
if (attackingCharacter != null && attackingCharacter.AIController == null) if (attackingCharacter != null && attackingCharacter.AIController == null)
{ {
GameServer.Log(Name + " attacked by " + attackingCharacter.Name+". Damage: "+attackResult.Damage+" Bleeding damage: "+attackResult.Bleeding, ServerLog.MessageType.Attack); GameServer.Log(LogName + " attacked by " + attackingCharacter.LogName +". Damage: "+attackResult.Damage+" Bleeding damage: "+attackResult.Bleeding, ServerLog.MessageType.Attack);
} }
if (GameMain.Client == null && if (GameMain.Client == null &&
@@ -1798,7 +1824,7 @@ namespace Barotrauma
AnimController.Frozen = false; AnimController.Frozen = false;
GameServer.Log(Name+" has died (Cause of death: "+causeOfDeath+")", ServerLog.MessageType.Attack); GameServer.Log(LogName+" has died (Cause of death: "+causeOfDeath+")", ServerLog.MessageType.Attack);
if (OnDeath != null) OnDeath(this, causeOfDeath); if (OnDeath != null) OnDeath(this, causeOfDeath);
@@ -12,7 +12,34 @@ namespace Barotrauma
partial class CharacterInfo partial class CharacterInfo
{ {
public string Name; public string Name;
public string DisplayName
{
get {
string disguiseName = "?";
if (Character != null && Character.HideFace)
{
if (Character.Inventory != null)
{
var idCard = Character.Inventory.FindItem("ID Card");
if (idCard != null && Character.Inventory.IsInLimbSlot(idCard, InvSlotType.Card)) //Disguise as the ID card name if it's equipped
{
string[] readTags = idCard.Tags.Split(',');
foreach (string tag in readTags)
{
string[] s = tag.Split(':');
if (s[0] == "name")
{
disguiseName = s[1];
break;
}
}
}
}
return disguiseName;
}
return Name;
}
}
public Character Character; public Character Character;
public readonly string File; public readonly string File;
@@ -15,18 +15,18 @@ namespace Barotrauma
public readonly AnimController.Animation Animation; public readonly AnimController.Animation Animation;
public CharacterStateInfo(Vector2 pos, float time, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None) public CharacterStateInfo(Vector2 pos, float rotation, float time, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None)
: this(pos, 0, time, dir, interact, animation) : this(pos, rotation, 0, time, dir, interact, animation)
{ {
} }
public CharacterStateInfo(Vector2 pos, UInt16 ID, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None) public CharacterStateInfo(Vector2 pos, float rotation, UInt16 ID, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None)
: this(pos, ID, 0.0f, dir, interact, animation) : this(pos, rotation, ID, 0.0f, dir, interact, animation)
{ {
} }
protected CharacterStateInfo(Vector2 pos, UInt16 ID, float time, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None) protected CharacterStateInfo(Vector2 pos, float rotation, UInt16 ID, float time, Direction dir, Entity interact, AnimController.Animation animation = AnimController.Animation.None)
: base(pos, ID, time) : base(pos, rotation, ID, time)
{ {
Direction = dir; Direction = dir;
Interact = interact; Interact = interact;
@@ -197,6 +197,7 @@ namespace Barotrauma
{ {
var posInfo = new CharacterStateInfo( var posInfo = new CharacterStateInfo(
SimPosition, SimPosition,
AnimController.Collider.Rotation,
LastNetworkUpdateID, LastNetworkUpdateID,
AnimController.TargetDir, AnimController.TargetDir,
SelectedCharacter == null ? (Entity)selectedConstruction : (Entity)SelectedCharacter, SelectedCharacter == null ? (Entity)selectedConstruction : (Entity)SelectedCharacter,
@@ -471,6 +472,7 @@ namespace Barotrauma
tempBuffer.Write(SimPosition.X); tempBuffer.Write(SimPosition.X);
tempBuffer.Write(SimPosition.Y); tempBuffer.Write(SimPosition.Y);
tempBuffer.Write(AnimController.Collider.Rotation);
tempBuffer.WritePadBits(); tempBuffer.WritePadBits();
@@ -130,6 +130,10 @@ namespace Barotrauma
{ {
item.AddTag(s); item.AddTag(s);
} }
item.AddTag("name:" + character.Name);
item.AddTag("job:" + Name);
if (!string.IsNullOrWhiteSpace(spawnPoint.IdCardDesc))
item.Description = spawnPoint.IdCardDesc;
} }
if (parentItem != null) parentItem.Combine(item); if (parentItem != null) parentItem.Combine(item);
@@ -265,7 +265,7 @@ namespace Barotrauma
{ {
SerializableProperty property; SerializableProperty property;
if (!target.SerializableProperties.TryGetValue(propertyNames[i], out property)) continue; if (target == null || target.SerializableProperties == null || !target.SerializableProperties.TryGetValue(propertyNames[i], out property)) continue;
if (duration > 0.0f) if (duration > 0.0f)
{ {
@@ -97,7 +97,7 @@ namespace Barotrauma
NewMessage("***************", Color.Cyan); NewMessage("***************", Color.Cyan);
foreach (Client c in GameMain.Server.ConnectedClients) foreach (Client c in GameMain.Server.ConnectedClients)
{ {
NewMessage("- " + c.ID.ToString() + ": " + c.Name + ", " + c.Connection.RemoteEndPoint.Address.ToString(), Color.Cyan); NewMessage("- " + c.ID.ToString() + ": " + c.Name + (c.Character != null ? " playing " + c.Character.LogName : "") + ", " + c.Connection.RemoteEndPoint.Address.ToString(), Color.Cyan);
} }
NewMessage("***************", Color.Cyan); NewMessage("***************", Color.Cyan);
})); }));
@@ -114,6 +114,18 @@ namespace Barotrauma
NewMessage("The code words are: " + traitorManager.codeWords + ", response: " + traitorManager.codeResponse + ".", Color.Cyan); NewMessage("The code words are: " + traitorManager.codeWords + ", response: " + traitorManager.codeResponse + ".", Color.Cyan);
})); }));
commands.Add(new Command("itemlist", "itemlist: List all the item prefabs available for spawning.", (string[] args) =>
{
NewMessage("***************", Color.Cyan);
foreach (MapEntityPrefab ep in MapEntityPrefab.List)
{
var itemPrefab = ep as ItemPrefab;
if (itemPrefab == null || itemPrefab.Name == null) continue;
NewMessage("- " + itemPrefab.Name, Color.Cyan);
}
NewMessage("***************", Color.Cyan);
}));
commands.Add(new Command("createfilelist", "", (string[] args) => commands.Add(new Command("createfilelist", "", (string[] args) =>
{ {
UpdaterUtil.SaveFileList("filelist.xml"); UpdaterUtil.SaveFileList("filelist.xml");
@@ -360,7 +372,11 @@ namespace Barotrauma
commands.Add(new Command("giveperm", "giveperm [id]: Grants administrative permissions to the player with the specified client ID.", (string[] args) => commands.Add(new Command("giveperm", "giveperm [id]: Grants administrative permissions to the player with the specified client ID.", (string[] args) =>
{ {
if (GameMain.Server == null) return; if (GameMain.Server == null) return;
if (args.Length < 1) return; if (args.Length < 1)
{
NewMessage("giveperm [id]: Grants administrative permissions to the player with the specified client ID.", Color.Cyan);
return;
}
int id; int id;
int.TryParse(args[0], out id); int.TryParse(args[0], out id);
@@ -370,7 +386,13 @@ namespace Barotrauma
ThrowError("Client id \"" + id + "\" not found."); ThrowError("Client id \"" + id + "\" not found.");
return; return;
} }
NewMessage("Valid permissions are:",Color.White);
NewMessage(" - all",Color.White);
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
{
NewMessage(" - " + permission.ToString(),Color.White);
}
ShowQuestionPrompt("Permission to grant to \"" + client.Name + "\"?", (perm) => ShowQuestionPrompt("Permission to grant to \"" + client.Name + "\"?", (perm) =>
{ {
ClientPermissions permission = ClientPermissions.None; ClientPermissions permission = ClientPermissions.None;
@@ -380,7 +402,11 @@ namespace Barotrauma
} }
else else
{ {
Enum.TryParse<ClientPermissions>(perm, out permission); if (!Enum.TryParse<ClientPermissions>(perm, out permission))
{
ThrowError("\"" + perm + "\" sn't a valid permission!");
return;
}
} }
client.SetPermissions(client.Permissions | permission); client.SetPermissions(client.Permissions | permission);
GameMain.Server.UpdateClientPermissions(client); GameMain.Server.UpdateClientPermissions(client);
@@ -391,7 +417,11 @@ namespace Barotrauma
commands.Add(new Command("revokeperm", "revokeperm [id]: Revokes administrative permissions to the player with the specified client ID.", (string[] args) => commands.Add(new Command("revokeperm", "revokeperm [id]: Revokes administrative permissions to the player with the specified client ID.", (string[] args) =>
{ {
if (GameMain.Server == null) return; if (GameMain.Server == null) return;
if (args.Length < 1) return; if (args.Length < 1)
{
NewMessage("revokeperm [id]: Revokes administrative permissions to the player with the specified client ID.", Color.Cyan);
return;
}
int id; int id;
int.TryParse(args[0], out id); int.TryParse(args[0], out id);
@@ -402,6 +432,12 @@ namespace Barotrauma
return; return;
} }
NewMessage("Valid permissions are:", Color.White);
NewMessage(" - all", Color.White);
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
{
NewMessage(" - " + permission.ToString(), Color.White);
}
ShowQuestionPrompt("Permission to revoke from \"" + client.Name + "\"?", (perm) => ShowQuestionPrompt("Permission to revoke from \"" + client.Name + "\"?", (perm) =>
{ {
ClientPermissions permission = ClientPermissions.None; ClientPermissions permission = ClientPermissions.None;
@@ -411,7 +447,11 @@ namespace Barotrauma
} }
else else
{ {
Enum.TryParse<ClientPermissions>(perm, out permission); if (!Enum.TryParse<ClientPermissions>(perm, out permission))
{
ThrowError("\"" + perm + "\" isn't a valid permission!");
return;
}
} }
client.SetPermissions(client.Permissions & ~permission); client.SetPermissions(client.Permissions & ~permission);
GameMain.Server.UpdateClientPermissions(client); GameMain.Server.UpdateClientPermissions(client);
@@ -34,7 +34,7 @@ namespace Barotrauma
base.Init(); base.Init();
Vector2 position = Level.Loaded.GetRandomItemPos( Vector2 position = Level.Loaded.GetRandomItemPos(
Level.PositionType.Cave | Level.PositionType.MainPath | Level.PositionType.Ruin, 500.0f, 30.0f); Level.PositionType.Cave | Level.PositionType.MainPath | Level.PositionType.Ruin, 500.0f, 10000.0f, 30.0f);
item = new Item(itemPrefab, position, null); item = new Item(itemPrefab, position, null);
item.MoveWithLevel = true; item.MoveWithLevel = true;
@@ -28,7 +28,7 @@ namespace Barotrauma
public override void Start(Level level) public override void Start(Level level)
{ {
Vector2 spawnPos; Vector2 spawnPos;
Level.Loaded.TryGetInterestingPosition(true, Level.PositionType.MainPath, true, out spawnPos); Level.Loaded.TryGetInterestingPosition(true, Level.PositionType.MainPath, Level.Loaded.Size.X * 0.3f, out spawnPos);
monster = Character.Create(monsterFile, spawnPos, null, GameMain.Client != null, true, false); monster = Character.Create(monsterFile, spawnPos, null, GameMain.Client != null, true, false);
monster.Enabled = false; monster.Enabled = false;
@@ -46,7 +46,7 @@ namespace Barotrauma
public override void Start(Level level) public override void Start(Level level)
{ {
Vector2 position = Level.Loaded.GetRandomItemPos(spawnPositionType, 100.0f, 30.0f); Vector2 position = Level.Loaded.GetRandomItemPos(spawnPositionType, 100.0f, Level.Loaded.Size.X * 0.3f, 30.0f);
item = new Item(itemPrefab, position, null); item = new Item(itemPrefab, position, null);
item.MoveWithLevel = true; item.MoveWithLevel = true;
@@ -85,7 +85,7 @@ namespace Barotrauma
if (disallowed) return null; if (disallowed) return null;
Vector2 spawnPos; Vector2 spawnPos;
if (!Level.Loaded.TryGetInterestingPosition(true, spawnPosType, true, out spawnPos)) if (!Level.Loaded.TryGetInterestingPosition(true, spawnPosType, 20000.0f, out spawnPos))
{ {
//no suitable position found, disable the event //no suitable position found, disable the event
repeat = false; repeat = false;
@@ -10,7 +10,7 @@ namespace Barotrauma
[Flags] [Flags]
public enum InvSlotType public enum InvSlotType
{ {
None = 0, Any = 1, RightHand = 2, LeftHand = 4, Head = 8, Torso = 16, Legs = 32, Face=64 None = 0, Any = 1, RightHand = 2, LeftHand = 4, Head = 8, Torso = 16, Legs = 32, Face=64, Card=128
}; };
partial class CharacterInventory : Inventory partial class CharacterInventory : Inventory
@@ -18,7 +18,7 @@ namespace Barotrauma
private Character character; private Character character;
public static InvSlotType[] limbSlots = new InvSlotType[] { public static InvSlotType[] limbSlots = new InvSlotType[] {
InvSlotType.Head, InvSlotType.Torso, InvSlotType.Legs, InvSlotType.LeftHand, InvSlotType.RightHand, InvSlotType.Face, InvSlotType.Head, InvSlotType.Torso, InvSlotType.Legs, InvSlotType.LeftHand, InvSlotType.RightHand, InvSlotType.Face, InvSlotType.Card,
InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any,
InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any}; InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any};
@@ -699,12 +699,12 @@ namespace Barotrauma.Items.Components
if (docked) if (docked)
{ {
if (item.Submarine != null && dockingTarget?.item?.Submarine != null) if (item.Submarine != null && dockingTarget?.item?.Submarine != null)
GameServer.Log(sender.Name + " docked " + item.Submarine.Name + " to " + dockingTarget.item.Submarine.Name, ServerLog.MessageType.ItemInteraction); GameServer.Log(sender.LogName + " docked " + item.Submarine.Name + " to " + dockingTarget.item.Submarine.Name, ServerLog.MessageType.ItemInteraction);
} }
else else
{ {
if (item.Submarine != null && prevDockingTarget?.item?.Submarine != null) if (item.Submarine != null && prevDockingTarget?.item?.Submarine != null)
GameServer.Log(sender.Name + " undocked " + item.Submarine.Name + " from " + prevDockingTarget.item.Submarine.Name, ServerLog.MessageType.ItemInteraction); GameServer.Log(sender.LogName + " undocked " + item.Submarine.Name + " from " + prevDockingTarget.item.Submarine.Name, ServerLog.MessageType.ItemInteraction);
} }
} }
} }
@@ -13,7 +13,7 @@ using Barotrauma.Lights;
namespace Barotrauma.Items.Components namespace Barotrauma.Items.Components
{ {
partial class Door : ItemComponent, IDrawableComponent, IServerSerializable partial class Door : Pickable, IDrawableComponent, IServerSerializable
{ {
private Gap linkedGap; private Gap linkedGap;
@@ -203,12 +203,13 @@ namespace Barotrauma.Items.Components
#endif #endif
} }
public override bool OnPicked(Character picker)
public override bool Pick(Character picker)
{ {
isOpen = !isOpen; SetState(predictedState == null ? !isOpen : !predictedState.Value, false, true); //crowbar function
#if CLIENT
return true; PlaySound(ActionType.OnPicked, item.WorldPosition);
#endif
return false;
} }
public override bool Select(Character character) public override bool Select(Character character)
@@ -419,7 +420,7 @@ namespace Barotrauma.Items.Components
bool newState = predictedState == null ? isOpen : predictedState.Value; bool newState = predictedState == null ? isOpen : predictedState.Value;
if (sender != null && wasOpen != newState) if (sender != null && wasOpen != newState)
{ {
GameServer.Log(sender.Name + (newState ? " opened " : " closed ") + item.Name, ServerLog.MessageType.ItemInteraction); GameServer.Log(sender.LogName + (newState ? " opened " : " closed ") + item.Name, ServerLog.MessageType.ItemInteraction);
} }
} }
@@ -184,13 +184,13 @@ namespace Barotrauma.Items.Components
item.SetTransform(rightHand.SimPosition, 0.0f); item.SetTransform(rightHand.SimPosition, 0.0f);
} }
bool alreadySelected = character.HasSelectedItem(item); bool alreadySelected = character.HasEquippedItem(item);
if (picker.TrySelectItem(item)) if (picker.TrySelectItem(item) || picker.HasEquippedItem(item))
{ {
item.body.Enabled = true; item.body.Enabled = true;
IsActive = true; IsActive = true;
if (!alreadySelected) GameServer.Log(character.Name + " equipped " + item.Name, ServerLog.MessageType.ItemInteraction); if (!alreadySelected) GameServer.Log(character.LogName + " equipped " + item.Name, ServerLog.MessageType.ItemInteraction);
} }
} }
@@ -200,7 +200,7 @@ namespace Barotrauma.Items.Components
picker.DeselectItem(item); picker.DeselectItem(item);
GameServer.Log(character.Name + " unequipped " + item.Name, ServerLog.MessageType.ItemInteraction); GameServer.Log(character.LogName + " unequipped " + item.Name, ServerLog.MessageType.ItemInteraction);
item.body.Enabled = false; item.body.Enabled = false;
IsActive = false; IsActive = false;
@@ -224,7 +224,7 @@ namespace Barotrauma.Items.Components
} }
} }
protected override bool OnPicked(Character picker) public override bool OnPicked(Character picker)
{ {
if (base.OnPicked(picker)) if (base.OnPicked(picker))
{ {
@@ -235,7 +235,7 @@ namespace Barotrauma.Items.Components
item.CreateServerEvent(this); item.CreateServerEvent(this);
if (picker != null) if (picker != null)
{ {
Networking.GameServer.Log(picker.Name + " detached " + item.Name + " from a wall", ServerLog.MessageType.ItemInteraction); Networking.GameServer.Log(picker.LogName + " detached " + item.Name + " from a wall", ServerLog.MessageType.ItemInteraction);
} }
} }
return true; return true;
@@ -290,7 +290,7 @@ namespace Barotrauma.Items.Components
if (GameMain.Server != null) if (GameMain.Server != null)
{ {
item.CreateServerEvent(this); item.CreateServerEvent(this);
GameServer.Log(character.Name + " attached " + item.Name+" to a wall", ServerLog.MessageType.ItemInteraction); GameServer.Log(character.LogName + " attached " + item.Name+" to a wall", ServerLog.MessageType.ItemInteraction);
} }
item.Drop(); item.Drop();
} }
@@ -308,7 +308,7 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam) public override void Update(float deltaTime, Camera cam)
{ {
if (item.body == null || !item.body.Enabled) return; if (item.body == null || !item.body.Enabled) return;
if (picker == null || !picker.HasSelectedItem(item)) if (picker == null || !picker.HasEquippedItem(item))
{ {
IsActive = false; IsActive = false;
return; return;
@@ -320,7 +320,37 @@ namespace Barotrauma.Items.Components
item.Submarine = picker.Submarine; item.Submarine = picker.Submarine;
picker.AnimController.HoldItem(deltaTime, item, handlePos, holdPos, aimPos, picker.IsKeyDown(InputType.Aim), holdAngle); if (picker.HasSelectedItem(item))
{
picker.AnimController.HoldItem(deltaTime, item, handlePos, holdPos, aimPos, picker.IsKeyDown(InputType.Aim), holdAngle);
}
else
{
Limb equipLimb = null;
if (picker.Inventory.IsInLimbSlot(item, InvSlotType.Face) || picker.Inventory.IsInLimbSlot(item, InvSlotType.Head))
{
equipLimb = picker.AnimController.GetLimb(LimbType.Head);
}
else if (picker.Inventory.IsInLimbSlot(item, InvSlotType.Torso))
{
equipLimb = picker.AnimController.GetLimb(LimbType.Torso);
}
else if (picker.Inventory.IsInLimbSlot(item, InvSlotType.Legs))
{
equipLimb = picker.AnimController.GetLimb(LimbType.Waist);
}
if (equipLimb != null)
{
float itemAngle = (equipLimb.Rotation + holdAngle * picker.AnimController.Dir);
Matrix itemTransfrom = Matrix.CreateRotationZ(equipLimb.Rotation);
Vector2 transformedHandlePos = Vector2.Transform(handlePos[0], itemTransfrom);
item.body.ResetDynamics();
item.SetTransform(equipLimb.SimPosition - transformedHandlePos, itemAngle);
}
}
} }
protected void Flip(Item item) protected void Flip(Item item)
@@ -137,7 +137,7 @@ namespace Barotrauma.Items.Components
} }
else else
{ {
ac.HoldItem(deltaTime, item, handlePos, new Vector2(hitPos, 0.0f), aimPos, false, holdAngle); ac.HoldItem(deltaTime, item, handlePos, holdPos, aimPos, false, holdAngle);
} }
} }
else else
@@ -255,12 +255,12 @@ namespace Barotrauma.Items.Components
{ {
GameMain.Server.CreateEntityEvent(item, new object[] { Networking.NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnUse, targetCharacter.ID }); GameMain.Server.CreateEntityEvent(item, new object[] { Networking.NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnUse, targetCharacter.ID });
string logStr = picker?.Name + " used " + item.Name; string logStr = picker?.LogName + " used " + item.Name;
if (item.ContainedItems != null && item.ContainedItems.Length > 0) if (item.ContainedItems != null && item.ContainedItems.Length > 0)
{ {
logStr += "(" + string.Join(", ", item.ContainedItems.Select(i => i?.Name)) + ")"; logStr += "(" + string.Join(", ", item.ContainedItems.Select(i => i?.Name)) + ")";
} }
logStr += " on " + targetCharacter + "."; logStr += " on " + targetCharacter.LogName + ".";
Networking.GameServer.Log(logStr, Networking.ServerLog.MessageType.Attack); Networking.GameServer.Log(logStr, Networking.ServerLog.MessageType.Attack);
} }
@@ -70,7 +70,7 @@ namespace Barotrauma.Items.Components
} }
} }
protected virtual bool OnPicked(Character picker) public virtual bool OnPicked(Character picker)
{ {
if (picker.Inventory.TryPutItem(item, picker, allowedSlots)) if (picker.Inventory.TryPutItem(item, picker, allowedSlots))
{ {
@@ -89,6 +89,7 @@ namespace Barotrauma.Items.Components
#if CLIENT #if CLIENT
if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) GUI.PlayUISound(GUISoundType.PickItem); if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) GUI.PlayUISound(GUISoundType.PickItem);
PlaySound(ActionType.OnPicked, item.WorldPosition);
#endif #endif
return true; return true;
@@ -11,6 +11,7 @@ namespace Barotrauma.Items.Components
float throwPos; float throwPos;
bool throwing; bool throwing;
bool throwDone;
[Serialize(1.0f, false)] [Serialize(1.0f, false)]
public float ThrowForce public float ThrowForce
@@ -27,18 +28,14 @@ namespace Barotrauma.Items.Components
public override bool Use(float deltaTime, Character character = null) public override bool Use(float deltaTime, Character character = null)
{ {
if (character == null) return false; return true; //We do the actual throwing in Aim because Use might be used by chems
if (!character.IsKeyDown(InputType.Aim) || throwing) return false;
throwing = true;
IsActive = true;
return true;
} }
public override void SecondaryUse(float deltaTime, Character character = null) public override bool SecondaryUse(float deltaTime, Character character = null)
{ {
if (throwing) return; if (!throwDone) return false; //This should only be triggered in update
throwDone = false;
return true;
} }
public override void Drop(Character dropper) public override void Drop(Character dropper)
@@ -57,7 +54,14 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam) public override void Update(float deltaTime, Camera cam)
{ {
if (!item.body.Enabled) return; if (!item.body.Enabled) return;
if (!picker.HasSelectedItem(item)) IsActive = false; if (!picker.HasSelectedItem(item))
{
IsActive = false;
return;
}
if (picker.IsKeyDown(InputType.Aim) && picker.IsKeyHit(InputType.Use))
throwing = true;
if (!picker.IsKeyDown(InputType.Aim) && !throwing) throwPos = 0.0f; if (!picker.IsKeyDown(InputType.Aim) && !throwing) throwPos = 0.0f;
@@ -93,7 +97,7 @@ namespace Barotrauma.Items.Components
Vector2 throwVector = picker.CursorWorldPosition - picker.WorldPosition; Vector2 throwVector = picker.CursorWorldPosition - picker.WorldPosition;
throwVector = Vector2.Normalize(throwVector); throwVector = Vector2.Normalize(throwVector);
GameServer.Log(picker.Name + " threw " + item.Name, ServerLog.MessageType.ItemInteraction); GameServer.Log(picker.LogName + " threw " + item.Name, ServerLog.MessageType.ItemInteraction);
item.Drop(); item.Drop();
item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f); item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f);
@@ -103,7 +107,8 @@ namespace Barotrauma.Items.Components
Limb rightHand = ac.GetLimb(LimbType.RightHand); Limb rightHand = ac.GetLimb(LimbType.RightHand);
item.body.AngularVelocity = rightHand.body.AngularVelocity; item.body.AngularVelocity = rightHand.body.AngularVelocity;
throwDone = true;
ApplyStatusEffects(ActionType.OnSecondaryUse, deltaTime, picker); //Stun grenades, flares, etc. all have their throw-related things handled in "onSecondaryUse"
throwing = false; throwing = false;
} }
} }
@@ -291,7 +291,10 @@ namespace Barotrauma.Items.Components
} }
//called when the item is equipped and right mouse button is pressed //called when the item is equipped and right mouse button is pressed
public virtual void SecondaryUse(float deltaTime, Character character = null) { } public virtual bool SecondaryUse(float deltaTime, Character character = null)
{
return false;
}
//called when the item is placed in a "limbslot" //called when the item is placed in a "limbslot"
public virtual void Equip(Character character) { } public virtual void Equip(Character character) { }
@@ -503,13 +506,15 @@ namespace Barotrauma.Items.Components
} }
List<RelatedItem> prevRequiredItems = new List<RelatedItem>(requiredItems); List<RelatedItem> prevRequiredItems = new List<RelatedItem>(requiredItems);
requiredItems.Clear(); bool overrideRequiredItems = false;
foreach (XElement subElement in componentElement.Elements()) foreach (XElement subElement in componentElement.Elements())
{ {
switch (subElement.Name.ToString().ToLowerInvariant()) switch (subElement.Name.ToString().ToLowerInvariant())
{ {
case "requireditem": case "requireditem":
if (!overrideRequiredItems) requiredItems.Clear();
overrideRequiredItems = true;
RelatedItem newRequiredItem = RelatedItem.Load(subElement); RelatedItem newRequiredItem = RelatedItem.Load(subElement);
if (newRequiredItem == null) continue; if (newRequiredItem == null) continue;
@@ -160,20 +160,20 @@ namespace Barotrauma.Items.Components
return true; return true;
} }
public override void SecondaryUse(float deltaTime, Character character = null) public override bool SecondaryUse(float deltaTime, Character character = null)
{ {
if (this.character == null || this.character != character || this.character.SelectedConstruction != item || !character.CanInteractWith(item)) if (this.character == null || this.character != character || this.character.SelectedConstruction != item || !character.CanInteractWith(item))
{ {
character = null; character = null;
return; return false;
} }
if (character == null) return; if (character == null) return false;
Entity focusTarget = GetFocusTarget(); Entity focusTarget = GetFocusTarget();
if (focusTarget == null) if (focusTarget == null)
{ {
item.SendSignal(0, XMLExtensions.Vector2ToString(character.CursorWorldPosition), "position_out", character); item.SendSignal(0, XMLExtensions.Vector2ToString(character.CursorWorldPosition), "position_out", character);
return; return false;
} }
character.ViewTarget = focusTarget; character.ViewTarget = focusTarget;
@@ -191,6 +191,8 @@ namespace Barotrauma.Items.Components
{ {
item.SendSignal(0, XMLExtensions.Vector2ToString(character.CursorWorldPosition), "position_out", character); item.SendSignal(0, XMLExtensions.Vector2ToString(character.CursorWorldPosition), "position_out", character);
} }
return true;
} }
private Item GetFocusTarget() private Item GetFocusTarget()
@@ -105,7 +105,7 @@ namespace Barotrauma.Items.Components
if (user != null) if (user != null)
{ {
GameServer.Log(user.Name + (IsActive ? " activated " : " deactivated ") + item.Name, ServerLog.MessageType.ItemInteraction); GameServer.Log(user.LogName + (IsActive ? " activated " : " deactivated ") + item.Name, ServerLog.MessageType.ItemInteraction);
} }
#if CLIENT #if CLIENT
@@ -159,7 +159,7 @@ namespace Barotrauma.Items.Components
if (user != null) if (user != null)
{ {
GameServer.Log(user.Name + " started fabricating " + selectedItem.TargetItem.Name + " in " + item.Name, ServerLog.MessageType.ItemInteraction); GameServer.Log(user.LogName + " started fabricating " + selectedItem.TargetItem.Name + " in " + item.Name, ServerLog.MessageType.ItemInteraction);
} }
#if CLIENT #if CLIENT
@@ -184,7 +184,7 @@ namespace Barotrauma.Items.Components
{ {
if (fabricatedItem != null && user != null) if (fabricatedItem != null && user != null)
{ {
GameServer.Log(user.Name + " cancelled the fabrication of " + fabricatedItem.TargetItem.Name + " in " + item.Name, ServerLog.MessageType.ItemInteraction); GameServer.Log(user.LogName + " cancelled the fabrication of " + fabricatedItem.TargetItem.Name + " in " + item.Name, ServerLog.MessageType.ItemInteraction);
} }
IsActive = false; IsActive = false;
@@ -157,11 +157,11 @@ namespace Barotrauma.Items.Components
{ {
if (newFlowPercentage != FlowPercentage) if (newFlowPercentage != FlowPercentage)
{ {
GameServer.Log(c.Character + " set the pumping speed of " + item.Name + " to " + (int)(newFlowPercentage) + " %", ServerLog.MessageType.ItemInteraction); GameServer.Log(c.Character.LogName + " set the pumping speed of " + item.Name + " to " + (int)(newFlowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
} }
if (newIsActive != IsActive) if (newIsActive != IsActive)
{ {
GameServer.Log(c.Character + (newIsActive ? " turned on " : " turned off ") + item.Name, ServerLog.MessageType.ItemInteraction); GameServer.Log(c.Character.LogName + (newIsActive ? " turned on " : " turned off ") + item.Name, ServerLog.MessageType.ItemInteraction);
} }
FlowPercentage = newFlowPercentage; FlowPercentage = newFlowPercentage;
@@ -173,7 +173,7 @@ namespace Barotrauma.Items.Components
{ {
if (Timing.TotalTime >= (float)nextServerLogWriteTime) if (Timing.TotalTime >= (float)nextServerLogWriteTime)
{ {
GameServer.Log(lastUser + " adjusted reactor settings: " + GameServer.Log(lastUser.LogName + " adjusted reactor settings: " +
"Temperature: " + (int)temperature + "Temperature: " + (int)temperature +
", Fission rate: " + (int)fissionRate + ", Fission rate: " + (int)fissionRate +
", Cooling rate: " + (int)coolingRate + ", Cooling rate: " + (int)coolingRate +
@@ -201,7 +201,7 @@ namespace Barotrauma.Items.Components
if (item.CanClientAccess(c)) if (item.CanClientAccess(c))
{ {
RechargeSpeed = newRechargeSpeed; RechargeSpeed = newRechargeSpeed;
GameServer.Log(c.Character + " set the recharge speed of "+item.Name+" to "+ (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction); GameServer.Log(c.Character.LogName + " set the recharge speed of "+item.Name+" to "+ (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction);
} }
item.CreateServerEvent(this); item.CreateServerEvent(this);
@@ -88,7 +88,16 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam) public override void Update(float deltaTime, Camera cam)
{ {
if (currPowerConsumption == 0.0f) return; if (currPowerConsumption == 0.0f)
{
//if the item consumes no power, ignore the voltage requirement and
//apply OnActive statuseffects as long as this component is active
if (powerConsumption == 0.0f)
{
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
}
return;
}
#if CLIENT #if CLIENT
if (voltage > minVoltage) if (voltage > minVoltage)
@@ -12,9 +12,14 @@ namespace Barotrauma.Items.Components
{ {
class Projectile : ItemComponent class Projectile : ItemComponent
{ {
private float launchImpulse; //continuous collision detection is used while the projectile is moving faster than this
const float ContinuousCollisionThreshold = 5.0f;
private bool doesStick; //a duration during which the projectile won't drop from the body it's stuck to
private const float PersistentStickJointDuration = 1.0f;
private float launchImpulse;
private PrismaticJoint stickJoint; private PrismaticJoint stickJoint;
private Body stickTarget; private Body stickTarget;
@@ -24,6 +29,8 @@ namespace Barotrauma.Items.Components
public Character User; public Character User;
private float persistentStickJointTimer;
[Serialize(10.0f, false)] [Serialize(10.0f, false)]
public float LaunchImpulse public float LaunchImpulse
{ {
@@ -39,10 +46,32 @@ namespace Barotrauma.Items.Components
} }
[Serialize(false, false)] [Serialize(false, false)]
//backwards compatibility, can stick to anything
public bool DoesStick public bool DoesStick
{ {
get { return doesStick; } get;
set { doesStick = value; } set;
}
[Serialize(false, false)]
public bool StickToCharacters
{
get;
set;
}
[Serialize(false, false)]
public bool StickToStructures
{
get;
set;
}
[Serialize(false, false)]
public bool StickToItems
{
get;
set;
} }
[Serialize(false, false)] [Serialize(false, false)]
@@ -106,7 +135,7 @@ namespace Barotrauma.Items.Components
IsActive = true; IsActive = true;
if (stickJoint == null || !doesStick) return; if (stickJoint == null) return;
if (stickTarget != null) if (stickTarget != null)
{ {
@@ -182,7 +211,7 @@ namespace Barotrauma.Items.Components
//the raycast didn't hit anything -> the projectile flew somewhere outside the level and is permanently lost //the raycast didn't hit anything -> the projectile flew somewhere outside the level and is permanently lost
if (!hitSomething) if (!hitSomething)
{ {
Item.Spawner.AddToRemoveQueue(item); Entity.Spawner.AddToRemoveQueue(item);
} }
} }
@@ -190,8 +219,23 @@ namespace Barotrauma.Items.Components
{ {
ApplyStatusEffects(ActionType.OnActive, deltaTime, null); ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
if (stickJoint != null && if (item.body != null && item.body.FarseerBody.IsBullet)
(stickJoint.JointTranslation < stickJoint.LowerLimit * 0.9f || stickJoint.JointTranslation > stickJoint.UpperLimit * 0.9f)) {
if (item.body.LinearVelocity.LengthSquared() < ContinuousCollisionThreshold * ContinuousCollisionThreshold)
{
item.body.FarseerBody.IsBullet = false;
}
}
if (stickJoint == null) return;
if (persistentStickJointTimer > 0.0f)
{
persistentStickJointTimer -= deltaTime;
return;
}
if (stickJoint.JointTranslation < stickJoint.LowerLimit * 0.9f || stickJoint.JointTranslation > stickJoint.UpperLimit * 0.9f)
{ {
if (stickTarget != null) if (stickTarget != null)
{ {
@@ -218,7 +262,7 @@ namespace Barotrauma.Items.Components
stickJoint = null; stickJoint = null;
IsActive = false; if (!item.body.FarseerBody.IsBullet) IsActive = false;
} }
} }
@@ -237,6 +281,7 @@ namespace Barotrauma.Items.Components
} }
AttackResult attackResult = new AttackResult(); AttackResult attackResult = new AttackResult();
Character character = null;
if (attack != null) if (attack != null)
{ {
var submarine = target.Body.UserData as Submarine; var submarine = target.Body.UserData as Submarine;
@@ -248,11 +293,13 @@ namespace Barotrauma.Items.Components
return true; return true;
} }
Limb limb; Limb limb = target.Body.UserData as Limb;
Structure structure; Structure structure;
if ((limb = (target.Body.UserData as Limb)) != null) if (limb != null)
{ {
attackResult = attack.DoDamageToLimb(User, limb, item.WorldPosition, 1.0f); attackResult = attack.DoDamageToLimb(User, limb, item.WorldPosition, 1.0f);
if (limb.character != null)
character = limb.character;
} }
else if ((structure = (target.Body.UserData as Structure)) != null) else if ((structure = (target.Body.UserData as Structure)) != null)
{ {
@@ -260,14 +307,11 @@ namespace Barotrauma.Items.Components
} }
} }
ApplyStatusEffects(ActionType.OnUse, 1.0f); ApplyStatusEffects(ActionType.OnUse, 1.0f, character);
ApplyStatusEffects(ActionType.OnImpact, 1.0f); ApplyStatusEffects(ActionType.OnImpact, 1.0f, character);
IsActive = false;
item.body.FarseerBody.OnCollision -= OnProjectileCollision; item.body.FarseerBody.OnCollision -= OnProjectileCollision;
item.body.FarseerBody.IsBullet = false;
item.body.CollisionCategories = Physics.CollisionItem; item.body.CollisionCategories = Physics.CollisionItem;
item.body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel; item.body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel;
@@ -280,17 +324,20 @@ namespace Barotrauma.Items.Components
{ {
item.body.LinearVelocity *= 0.1f; item.body.LinearVelocity *= 0.1f;
} }
else if (doesStick) else if (Vector2.Dot(item.body.LinearVelocity, collisionNormal) < 0.0f &&
(DoesStick ||
(StickToCharacters && target.Body.UserData is Limb) ||
(StickToStructures && target.Body.UserData is Structure) ||
(StickToItems && target.Body.UserData is Item)))
{ {
Vector2 dir = new Vector2( Vector2 dir = new Vector2(
(float)Math.Cos(item.body.Rotation), (float)Math.Cos(item.body.Rotation),
(float)Math.Sin(item.body.Rotation)); (float)Math.Sin(item.body.Rotation));
StickToTarget(target.Body, dir);
item.body.LinearVelocity *= 0.5f;
if (Vector2.Dot(item.body.LinearVelocity, collisionNormal) < 0.0f) return Hitscan;
{
StickToTarget(target.Body, dir);
return Hitscan;
}
} }
else else
{ {
@@ -306,7 +353,7 @@ namespace Barotrauma.Items.Components
{ {
contained.SetTransform(item.SimPosition, contained.body.Rotation); contained.SetTransform(item.SimPosition, contained.body.Rotation);
} }
contained.Condition = 0.0f; //contained.Condition = 0.0f; //Let the freaking .xml handle it jeez
} }
} }
@@ -333,6 +380,8 @@ namespace Barotrauma.Items.Components
stickJoint.UpperLimit = ConvertUnits.ToSimUnits(item.Sprite.size.X * 0.3f); stickJoint.UpperLimit = ConvertUnits.ToSimUnits(item.Sprite.size.X * 0.3f);
} }
persistentStickJointTimer = PersistentStickJointDuration;
item.body.FarseerBody.IgnoreCollisionWith(targetBody); item.body.FarseerBody.IgnoreCollisionWith(targetBody);
stickTarget = targetBody; stickTarget = targetBody;
GameMain.World.AddJoint(stickJoint); GameMain.World.AddJoint(stickJoint);
@@ -118,9 +118,9 @@ namespace Barotrauma.Items.Components
} }
public override void SecondaryUse(float deltaTime, Character character = null) public override bool SecondaryUse(float deltaTime, Character character = null)
{ {
if (reload > 0.0f) return; if (reload > 0.0f) return false;
bool first = true; bool first = true;
for (int i = 0; i < ropeBodies.Length - 1; i++) for (int i = 0; i < ropeBodies.Length - 1; i++)
@@ -157,7 +157,8 @@ namespace Barotrauma.Items.Components
//ropeBodies[i + 1].ApplyForce(dist / length * pullForce * 0.1f); //ropeBodies[i + 1].ApplyForce(dist / length * pullForce * 0.1f);
} }
} }
return true;
} }
private void NextSection(int i) private void NextSection(int i)
@@ -215,7 +215,7 @@ namespace Barotrauma.Items.Components
if (existingWire.Locked) if (existingWire.Locked)
{ {
//this should not be possible unless the client is running a modified version of the game //this should not be possible unless the client is running a modified version of the game
GameServer.Log(c.Character.Name + " attempted to disconnect a locked wire from " + GameServer.Log(c.Character.LogName + " attempted to disconnect a locked wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.Error); Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.Error);
continue; continue;
} }
@@ -224,20 +224,37 @@ namespace Barotrauma.Items.Components
if (existingWire.Connections[0] == null && existingWire.Connections[1] == null) if (existingWire.Connections[0] == null && existingWire.Connections[1] == null)
{ {
GameServer.Log(c.Character.Name + " disconnected a wire from " + GameServer.Log(c.Character.LogName + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.ItemInteraction); Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.ItemInteraction);
} }
else if (existingWire.Connections[0] != null) else if (existingWire.Connections[0] != null)
{ {
GameServer.Log(c.Character.Name + " disconnected a wire from " + GameServer.Log(c.Character.LogName + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[0].Item.Name + " (" + existingWire.Connections[0].Name + ")", ServerLog.MessageType.ItemInteraction); Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[0].Item.Name + " (" + existingWire.Connections[0].Name + ")", ServerLog.MessageType.ItemInteraction);
//wires that are not in anyone's inventory (i.e. not currently being rewired)
//can never be connected to only one connection
// -> the client must have dropped the wire from the connection panel
if (existingWire.Item.ParentInventory == null)
{
//let other clients know the item was also disconnected from the other connection
existingWire.Connections[0].Item.CreateServerEvent(existingWire.Connections[0].Item.GetComponent<ConnectionPanel>());
existingWire.Item.Drop(c.Character);
}
} }
else if (existingWire.Connections[1] != null) else if (existingWire.Connections[1] != null)
{ {
GameServer.Log(c.Character.Name + " disconnected a wire from " + GameServer.Log(c.Character.LogName + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[1].Item.Name + " (" + existingWire.Connections[1].Name + ")", ServerLog.MessageType.ItemInteraction); Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[1].Item.Name + " (" + existingWire.Connections[1].Name + ")", ServerLog.MessageType.ItemInteraction);
}
if (existingWire.Item.ParentInventory == null)
{
//let other clients know the item was also disconnected from the other connection
existingWire.Connections[1].Item.CreateServerEvent(existingWire.Connections[1].Item.GetComponent<ConnectionPanel>());
existingWire.Item.Drop(c.Character);
}
}
Connections[i].Wires[j] = null; Connections[i].Wires[j] = null;
} }
@@ -259,13 +276,13 @@ namespace Barotrauma.Items.Components
if (otherConnection == null) if (otherConnection == null)
{ {
GameServer.Log(c.Character.Name + " connected a wire to " + GameServer.Log(c.Character.LogName + " connected a wire to " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")", Connections[i].Item.Name + " (" + Connections[i].Name + ")",
ServerLog.MessageType.ItemInteraction); ServerLog.MessageType.ItemInteraction);
} }
else else
{ {
GameServer.Log(c.Character.Name + " connected a wire from " + GameServer.Log(c.Character.LogName + " connected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + Connections[i].Item.Name + " (" + Connections[i].Name + ") to " +
(otherConnection == null ? "none" : otherConnection.Item.Name + " (" + (otherConnection.Name) + ")"), (otherConnection == null ? "none" : otherConnection.Item.Name + " (" + (otherConnection.Name) + ")"),
ServerLog.MessageType.ItemInteraction); ServerLog.MessageType.ItemInteraction);
@@ -281,6 +298,9 @@ namespace Barotrauma.Items.Components
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime) public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{ {
List<Wire> prevWires = Connections.SelectMany(c => Array.FindAll(c.Wires, w => w != null)).ToList();
List<Wire> newWires = new List<Wire>();
foreach (Connection connection in Connections) foreach (Connection connection in Connections)
{ {
connection.ClearConnections(); connection.ClearConnections();
@@ -289,16 +309,33 @@ namespace Barotrauma.Items.Components
{ {
ushort wireId = msg.ReadUInt16(); ushort wireId = msg.ReadUInt16();
Item wireItem = MapEntity.FindEntityByID(wireId) as Item; Item wireItem = Entity.FindEntityByID(wireId) as Item;
if (wireItem == null) continue; if (wireItem == null) continue;
Wire wireComponent = wireItem.GetComponent<Wire>(); Wire wireComponent = wireItem.GetComponent<Wire>();
if (wireComponent == null) continue; if (wireComponent == null) continue;
newWires.Add(wireComponent);
connection.Wires[i] = wireComponent; connection.Wires[i] = wireComponent;
wireComponent.Connect(connection, false); wireComponent.Connect(connection, false);
} }
} }
foreach (Wire wire in prevWires)
{
if (wire.Connections[0] == null && wire.Connections[1] == null)
{
wire.Item.Drop(null);
}
//wires that are not in anyone's inventory (i.e. not currently being rewired) can never be connected to only one connection
// -> someone must have dropped the wire from the connection panel
else if (wire.Item.ParentInventory == null &&
(wire.Connections[0] != null ^ wire.Connections[1] != null))
{
wire.Item.Drop(null);
}
}
} }
} }
} }
@@ -242,7 +242,7 @@ namespace Barotrauma.Items.Components
return true; return true;
} }
public override void SecondaryUse(float deltaTime, Character character = null) public override bool SecondaryUse(float deltaTime, Character character = null)
{ {
if (nodes.Count > 1) if (nodes.Count > 1)
{ {
@@ -251,6 +251,7 @@ namespace Barotrauma.Items.Components
} }
Drawable = IsActive || sections.Count > 0; Drawable = IsActive || sections.Count > 0;
return true;
} }
public override bool Pick(Character picker) public override bool Pick(Character picker)
@@ -307,18 +308,18 @@ namespace Barotrauma.Items.Components
{ {
if (connections[0] != null && connections[1] != null) if (connections[0] != null && connections[1] != null)
{ {
GameServer.Log(user.Name + " disconnected a wire from " + GameServer.Log(user.LogName + " disconnected a wire from " +
connections[0].Item.Name + " (" + connections[0].Name + ") to "+ connections[0].Item.Name + " (" + connections[0].Name + ") to "+
connections[1].Item.Name + " (" + connections[1].Name + ")", ServerLog.MessageType.ItemInteraction); connections[1].Item.Name + " (" + connections[1].Name + ")", ServerLog.MessageType.ItemInteraction);
} }
else if (connections[0] != null) else if (connections[0] != null)
{ {
GameServer.Log(user.Name + " disconnected a wire from " + GameServer.Log(user.LogName + " disconnected a wire from " +
connections[0].Item.Name + " (" + connections[0].Name + ")", ServerLog.MessageType.ItemInteraction); connections[0].Item.Name + " (" + connections[0].Name + ")", ServerLog.MessageType.ItemInteraction);
} }
else if (connections[1] != null) else if (connections[1] != null)
{ {
GameServer.Log(user.Name + " disconnected a wire from " + GameServer.Log(user.LogName + " disconnected a wire from " +
connections[1].Item.Name + " (" + connections[1].Name + ")", ServerLog.MessageType.ItemInteraction); connections[1].Item.Name + " (" + connections[1].Name + ")", ServerLog.MessageType.ItemInteraction);
} }
} }
@@ -175,7 +175,7 @@ namespace Barotrauma.Items.Components
if (character != null) if (character != null)
{ {
string msg = character.Name + " launched " + item.Name + " (projectile: " + projectiles[0].Item.Name; string msg = character.LogName + " launched " + item.Name + " (projectile: " + projectiles[0].Item.Name;
if (projectiles[0].Item.ContainedItems == null || projectiles[0].Item.ContainedItems.All(i => i == null)) if (projectiles[0].Item.ContainedItems == null || projectiles[0].Item.ContainedItems.All(i => i == null))
{ {
msg += ")"; msg += ")";
@@ -212,11 +212,11 @@ namespace Barotrauma
{ {
if (Owner == c.Character) if (Owner == c.Character)
{ {
GameServer.Log(c.Character + " picked up " + item.Name, ServerLog.MessageType.Inventory); GameServer.Log(c.Character.LogName+ " picked up " + item.Name, ServerLog.MessageType.Inventory);
} }
else else
{ {
GameServer.Log(c.Character + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory); GameServer.Log(c.Character.LogName + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory);
} }
} }
} }
@@ -227,11 +227,11 @@ namespace Barotrauma
{ {
if (Owner == c.Character) if (Owner == c.Character)
{ {
GameServer.Log(c.Character + " dropped " + item.Name, ServerLog.MessageType.Inventory); GameServer.Log(c.Character.LogName + " dropped " + item.Name, ServerLog.MessageType.Inventory);
} }
else else
{ {
GameServer.Log(c.Character + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory); GameServer.Log(c.Character.LogName + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory);
} }
} }
} }
@@ -119,9 +119,12 @@ namespace Barotrauma
get { return prefab.Name; } get { return prefab.Name; }
} }
private string description;
[Editable, Serialize("", true)]
public string Description public string Description
{ {
get { return prefab.Description; } get { return description == null ? prefab.Description : description; }
set { description = value; }
} }
public float ImpactTolerance public float ImpactTolerance
@@ -800,6 +803,7 @@ namespace Barotrauma
if (!ic.WasUsed) if (!ic.WasUsed)
{ {
ic.StopSounds(ActionType.OnUse); ic.StopSounds(ActionType.OnUse);
ic.StopSounds(ActionType.OnSecondaryUse);
} }
#endif #endif
ic.WasUsed = false; ic.WasUsed = false;
@@ -1167,11 +1171,28 @@ namespace Barotrauma
public void SecondaryUse(float deltaTime, Character character = null) public void SecondaryUse(float deltaTime, Character character = null)
{ {
if (condition == 0.0f) return;
bool remove = false;
foreach (ItemComponent ic in components) foreach (ItemComponent ic in components)
{ {
if (!ic.HasRequiredContainedItems(character == Character.Controlled)) continue; if (!ic.HasRequiredContainedItems(character == Character.Controlled)) continue;
ic.SecondaryUse(deltaTime, character); if (ic.SecondaryUse(deltaTime, character))
{
ic.WasUsed = true;
#if CLIENT
ic.PlaySound(ActionType.OnSecondaryUse, WorldPosition);
#endif
ic.ApplyStatusEffects(ActionType.OnSecondaryUse, deltaTime, character);
if (ic.DeleteOnUse) remove = true;
}
} }
if (remove) Remove();
} }
public List<ColoredText> GetHUDTexts(Character character) public List<ColoredText> GetHUDTexts(Character character)
@@ -1341,12 +1362,12 @@ namespace Barotrauma
if (ContainedItems == null || ContainedItems.All(i => i == null)) if (ContainedItems == null || ContainedItems.All(i => i == null))
{ {
GameServer.Log(c.Character.Name + " used item " + Name, ServerLog.MessageType.ItemInteraction); GameServer.Log(c.Character.LogName + " used item " + Name, ServerLog.MessageType.ItemInteraction);
} }
else else
{ {
GameServer.Log( GameServer.Log(
c.Character.Name + " used item " + Name + " (contained items: " + string.Join(", ", Array.FindAll(ContainedItems, i => i != null).Select(i => i.Name)) + ")", c.Character.LogName + " used item " + Name + " (contained items: " + string.Join(", ", Array.FindAll(ContainedItems, i => i != null).Select(i => i.Name)) + ")",
ServerLog.MessageType.ItemInteraction); ServerLog.MessageType.ItemInteraction);
} }
@@ -1440,6 +1461,7 @@ namespace Barotrauma
if (GameMain.Server == null) return; if (GameMain.Server == null) return;
msg.Write(Prefab.Name); msg.Write(Prefab.Name);
msg.Write(Description);
msg.Write(ID); msg.Write(ID);
if (ParentInventory == null || ParentInventory.Owner == null) if (ParentInventory == null || ParentInventory.Owner == null)
@@ -1458,7 +1480,8 @@ namespace Barotrauma
msg.Write(index < 0 ? (byte)255 : (byte)index); msg.Write(index < 0 ? (byte)255 : (byte)index);
} }
if (Name == "ID Card") msg.Write(Tags); //TODO: See if tags are different from their prefab before sending 'em
msg.Write(Tags);
} }
public static Item ReadSpawnData(NetBuffer msg, bool spawn = true) public static Item ReadSpawnData(NetBuffer msg, bool spawn = true)
@@ -1466,6 +1489,7 @@ namespace Barotrauma
if (GameMain.Server != null) return null; if (GameMain.Server != null) return null;
string itemName = msg.ReadString(); string itemName = msg.ReadString();
string itemDesc = msg.ReadString();
ushort itemId = msg.ReadUInt16(); ushort itemId = msg.ReadUInt16();
ushort inventoryId = msg.ReadUInt16(); ushort inventoryId = msg.ReadUInt16();
@@ -1489,11 +1513,7 @@ namespace Barotrauma
} }
} }
string tags = ""; string tags = msg.ReadString();
if (itemName == "ID Card")
{
tags = msg.ReadString();
}
if (!spawn) return null; if (!spawn) return null;
@@ -1523,6 +1543,7 @@ namespace Barotrauma
var item = new Item(itemPrefab, pos, sub); var item = new Item(itemPrefab, pos, sub);
item.Description = itemDesc;
item.ID = itemId; item.ID = itemId;
if (sub != null) if (sub != null)
{ {
@@ -134,6 +134,13 @@ namespace Barotrauma
private set; private set;
} }
[Serialize(false, false)]
public bool DisableItemUsageWhenSelected
{
get;
private set;
}
public bool CanSpriteFlipX public bool CanSpriteFlipX
{ {
get { return canSpriteFlipX; } get { return canSpriteFlipX; }
@@ -74,6 +74,15 @@ namespace Barotrauma
{ {
if (item.CurrentHull != hull || item.FireProof || item.Condition <= 0.0f) continue; if (item.CurrentHull != hull || item.FireProof || item.Condition <= 0.0f) continue;
//don't apply OnFire effects if the item is inside a fireproof container
//(or if it's inside a container that's inside a fireproof container, etc)
Item container = item.Container;
while (container != null)
{
if (container.FireProof) return;
container = container.Container;
}
if (Vector2.Distance(item.WorldPosition, worldPosition) > attack.Range * 0.1f) continue; if (Vector2.Distance(item.WorldPosition, worldPosition) > attack.Range * 0.1f) continue;
item.ApplyStatusEffects(ActionType.OnFire, 1.0f); item.ApplyStatusEffects(ActionType.OnFire, 1.0f);
@@ -217,7 +217,15 @@ namespace Barotrauma
foreach (Item item in Item.ItemList) foreach (Item item in Item.ItemList)
{ {
if (item.CurrentHull != hull || item.FireProof || item.Condition <= 0.0f) continue; if (item.CurrentHull != hull || item.FireProof || item.Condition <= 0.0f) continue;
if (item.ParentInventory != null && item.ParentInventory.Owner is Character) return;
//don't apply OnFire effects if the item is inside a fireproof container
//(or if it's inside a container that's inside a fireproof container, etc)
Item container = item.Container;
while (container != null)
{
if (container.FireProof) return;
container = container.Container;
}
float range = (float)Math.Sqrt(size.X) * 10.0f; float range = (float)Math.Sqrt(size.X) * 10.0f;
if (item.Position.X < position.X - range || item.Position.X > position.X + size.X + range) continue; if (item.Position.X < position.X - range || item.Position.X > position.X + size.X + range) continue;
@@ -163,8 +163,11 @@ namespace Barotrauma
searchPos[1] = new Vector2(rect.Center.X, rect.Y - rect.Height); searchPos[1] = new Vector2(rect.Center.X, rect.Y - rect.Height);
} }
hulls[0] = Hull.FindHullOld(searchPos[0], null, false); for (int i = 0; i < 2; i++)
hulls[1] = Hull.FindHullOld(searchPos[1], null, false); {
hulls[i] = Hull.FindHullOld(searchPos[i], null, false);
if (hulls[i] == null) hulls[i] = Hull.FindHullOld(searchPos[i], null, false, true);
}
if (hulls[0] == null && hulls[1] == null) return; if (hulls[0] == null && hulls[1] == null) return;
@@ -558,23 +558,23 @@ namespace Barotrauma
return null; return null;
} }
//returns the water block which contains the point (or null if it isn't inside any) //returns the water block which contains the point (or null if it isn't inside any)
public static Hull FindHullOld(Vector2 position, Hull guess = null, bool useWorldCoordinates = true) public static Hull FindHullOld(Vector2 position, Hull guess = null, bool useWorldCoordinates = true, bool inclusive = false)
{ {
return FindHullOld(position, hullList, guess, useWorldCoordinates); return FindHullOld(position, hullList, guess, useWorldCoordinates, inclusive);
} }
public static Hull FindHullOld(Vector2 position, List<Hull> hulls, Hull guess = null, bool useWorldCoordinates = true) public static Hull FindHullOld(Vector2 position, List<Hull> hulls, Hull guess = null, bool useWorldCoordinates = true, bool inclusive = false)
{ {
if (guess != null && hulls.Contains(guess)) if (guess != null && hulls.Contains(guess))
{ {
if (Submarine.RectContains(useWorldCoordinates ? guess.WorldRect : guess.rect, position)) return guess; if (Submarine.RectContains(useWorldCoordinates ? guess.WorldRect : guess.rect, position, inclusive)) return guess;
} }
foreach (Hull hull in hulls) foreach (Hull hull in hulls)
{ {
if (Submarine.RectContains(useWorldCoordinates ? hull.WorldRect : hull.rect, position)) return hull; if (Submarine.RectContains(useWorldCoordinates ? hull.WorldRect : hull.rect, position, inclusive)) return hull;
} }
return null; return null;
@@ -817,7 +817,7 @@ namespace Barotrauma
//50% chance of placing the ruins at a cave //50% chance of placing the ruins at a cave
if (Rand.Range(0.0f, 1.0f, Rand.RandSync.Server) < 0.5f) if (Rand.Range(0.0f, 1.0f, Rand.RandSync.Server) < 0.5f)
{ {
TryGetInterestingPosition(true, PositionType.Cave, false, out ruinPos); TryGetInterestingPosition(true, PositionType.Cave, 0.0f, out ruinPos);
} }
ruinPos.Y = Math.Min(ruinPos.Y, borders.Y + borders.Height - ruinSize.Y / 2); ruinPos.Y = Math.Min(ruinPos.Y, borders.Y + borders.Height - ruinSize.Y / 2);
@@ -894,7 +894,7 @@ namespace Barotrauma
} }
} }
public Vector2 GetRandomItemPos(PositionType spawnPosType, float randomSpread, float offsetFromWall = 10.0f) public Vector2 GetRandomItemPos(PositionType spawnPosType, float randomSpread, float minDistFromSubs, float offsetFromWall = 10.0f)
{ {
if (!positionsOfInterest.Any()) return Size*0.5f; if (!positionsOfInterest.Any()) return Size*0.5f;
@@ -906,7 +906,7 @@ namespace Barotrauma
do do
{ {
Vector2 startPos; Vector2 startPos;
Level.Loaded.TryGetInterestingPosition(true, spawnPosType, true, out startPos); Loaded.TryGetInterestingPosition(true, spawnPosType, minDistFromSubs, out startPos);
startPos += Rand.Vector(Rand.Range(0.0f, randomSpread, Rand.RandSync.Server), Rand.RandSync.Server); startPos += Rand.Vector(Rand.Range(0.0f, randomSpread, Rand.RandSync.Server), Rand.RandSync.Server);
@@ -935,7 +935,7 @@ namespace Barotrauma
public bool TryGetInterestingPosition(bool useSyncedRand, PositionType positionType, bool avoidSubs, out Vector2 position) public bool TryGetInterestingPosition(bool useSyncedRand, PositionType positionType, float minDistFromSubs, out Vector2 position)
{ {
if (!positionsOfInterest.Any()) if (!positionsOfInterest.Any())
{ {
@@ -945,17 +945,20 @@ namespace Barotrauma
var matchingPositions = positionsOfInterest.FindAll(p => positionType.HasFlag(p.PositionType)); var matchingPositions = positionsOfInterest.FindAll(p => positionType.HasFlag(p.PositionType));
if (avoidSubs) if (minDistFromSubs > 0.0f)
{ {
foreach (Submarine sub in Submarine.Loaded) foreach (Submarine sub in Submarine.Loaded)
{ {
float minDist = Math.Max(sub.Borders.Width, sub.Borders.Height); matchingPositions.RemoveAll(p => Vector2.DistanceSquared(p.Position, sub.WorldPosition) < minDistFromSubs * minDistFromSubs);
matchingPositions.RemoveAll(p => Vector2.Distance(p.Position, sub.WorldPosition) < minDist);
} }
} }
if (!matchingPositions.Any()) if (!matchingPositions.Any())
{ {
#if DEBUG
DebugConsole.ThrowError("Could not find a suitable position of interest. (PositionType: " + positionType + ", minDistFromSubs: " + minDistFromSubs + "\n" + Environment.StackTrace);
#endif
position = positionsOfInterest[Rand.Int(positionsOfInterest.Count, (useSyncedRand ? Rand.RandSync.Server : Rand.RandSync.Unsynced))].Position; position = positionsOfInterest[Rand.Int(positionsOfInterest.Count, (useSyncedRand ? Rand.RandSync.Server : Rand.RandSync.Unsynced))].Position;
return false; return false;
} }
@@ -506,15 +506,15 @@ namespace Barotrauma
float impact = Vector2.Dot(f2.Body.LinearVelocity, -normal)*f2.Body.Mass*0.1f; float impact = Vector2.Dot(f2.Body.LinearVelocity, -normal)*f2.Body.Mass*0.1f;
if (impact < 10.0f) return true;
#if CLIENT #if CLIENT
SoundPlayer.PlayDamageSound(DamageSoundType.StructureBlunt, impact, SoundPlayer.PlayDamageSound(DamageSoundType.StructureBlunt, impact,
new Vector2( new Vector2(
sections[section].rect.X + sections[section].rect.Width / 2, sections[section].rect.X + sections[section].rect.Width / 2,
sections[section].rect.Y - sections[section].rect.Height / 2)); sections[section].rect.Y - sections[section].rect.Height / 2), tags: Tags);
#endif #endif
if (impact < 10.0f) return true;
AddDamage(section, impact); AddDamage(section, impact);
} }
} }
@@ -661,10 +661,10 @@ namespace Barotrauma
#if CLIENT #if CLIENT
GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f); GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f);
if (playSound && !SectionBodyDisabled(i)) if (playSound)// && !SectionBodyDisabled(i))
{ {
DamageSoundType damageSoundType = (attack.DamageType == DamageType.Blunt) ? DamageSoundType.StructureBlunt : DamageSoundType.StructureSlash; DamageSoundType damageSoundType = (attack.DamageType == DamageType.Blunt) ? DamageSoundType.StructureBlunt : DamageSoundType.StructureSlash;
SoundPlayer.PlayDamageSound(damageSoundType, damageAmount, worldPosition); SoundPlayer.PlayDamageSound(damageSoundType, damageAmount, worldPosition, tags: Tags);
} }
#endif #endif
@@ -491,10 +491,18 @@ namespace Barotrauma
return new Rectangle((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y); return new Rectangle((int)pos.X, (int)pos.Y, (int)size.X, (int)size.Y);
} }
public static bool RectContains(Rectangle rect, Vector2 pos) public static bool RectContains(Rectangle rect, Vector2 pos, bool inclusive = false)
{ {
return (pos.X > rect.X && pos.X < rect.X + rect.Width if (inclusive)
&& pos.Y < rect.Y && pos.Y > rect.Y - rect.Height); {
return (pos.X >= rect.X && pos.X <= rect.X + rect.Width
&& pos.Y <= rect.Y && pos.Y >= rect.Y - rect.Height);
}
else
{
return (pos.X > rect.X && pos.X < rect.X + rect.Width
&& pos.Y < rect.Y && pos.Y > rect.Y - rect.Height);
}
} }
public static bool RectsOverlap(Rectangle rect1, Rectangle rect2, bool inclusive=true) public static bool RectsOverlap(Rectangle rect1, Rectangle rect2, bool inclusive=true)
@@ -1258,7 +1266,7 @@ namespace Barotrauma
return; return;
} }
subBody.MemPos.Insert(index, new PosInfo(newTargetPosition, sendingTime)); subBody.MemPos.Insert(index, new PosInfo(newTargetPosition, 0.0f, sendingTime));
} }
} }
@@ -21,6 +21,7 @@ namespace Barotrauma
protected SpawnType spawnType; protected SpawnType spawnType;
//characters spawning at the waypoint will be given an ID card with these tags //characters spawning at the waypoint will be given an ID card with these tags
private string idCardDesc;
private string[] idCardTags; private string[] idCardTags;
//only characters with this job will be spawned at the waypoint //only characters with this job will be spawned at the waypoint
@@ -57,6 +58,11 @@ namespace Barotrauma
} }
} }
public string IdCardDesc
{
get { return idCardDesc; }
private set { idCardDesc = value; }
}
public string[] IdCardTags public string[] IdCardTags
{ {
get { return idCardTags; } get { return idCardTags; }
@@ -113,6 +119,7 @@ namespace Barotrauma
public override MapEntity Clone() public override MapEntity Clone()
{ {
var clone = new WayPoint(rect, Submarine); var clone = new WayPoint(rect, Submarine);
clone.idCardDesc = idCardDesc;
clone.idCardTags = idCardTags; clone.idCardTags = idCardTags;
clone.spawnType = spawnType; clone.spawnType = spawnType;
clone.assignedJob = assignedJob; clone.assignedJob = assignedJob;
@@ -570,6 +577,11 @@ namespace Barotrauma
Enum.TryParse<SpawnType>(element.GetAttributeString("spawn", "Path"), out w.spawnType); Enum.TryParse<SpawnType>(element.GetAttributeString("spawn", "Path"), out w.spawnType);
string idCardDescString = element.GetAttributeString("idcarddesc", "");
if (!string.IsNullOrWhiteSpace(idCardDescString))
{
w.IdCardDesc = idCardDescString;
}
string idCardTagString = element.GetAttributeString("idcardtags", ""); string idCardTagString = element.GetAttributeString("idcardtags", "");
if (!string.IsNullOrWhiteSpace(idCardTagString)) if (!string.IsNullOrWhiteSpace(idCardTagString))
{ {
@@ -604,6 +616,7 @@ namespace Barotrauma
new XAttribute("y", (int)(rect.Y - Submarine.HiddenSubPosition.Y)), new XAttribute("y", (int)(rect.Y - Submarine.HiddenSubPosition.Y)),
new XAttribute("spawn", spawnType)); new XAttribute("spawn", spawnType));
if (!string.IsNullOrWhiteSpace(idCardDesc)) element.Add(new XAttribute("idcarddesc", idCardDesc));
if (idCardTags.Length > 0) if (idCardTags.Length > 0)
{ {
element.Add(new XAttribute("idcardtags", string.Join(",", idCardTags))); element.Add(new XAttribute("idcardtags", string.Join(",", idCardTags)));
@@ -105,18 +105,18 @@ namespace Barotrauma.Networking
return ApplyDistanceEffect(listener, Sender, Text, SpeakRange); return ApplyDistanceEffect(listener, Sender, Text, SpeakRange);
} }
public static string ApplyDistanceEffect(Entity listener, Entity Sender, string text, float range) public static string ApplyDistanceEffect(Entity listener, Entity Sender, string text, float range, float obstructionmult = 2.0f)
{ {
if (listener.WorldPosition == Sender.WorldPosition) return text; if (listener.WorldPosition == Sender.WorldPosition) return text;
float dist = Vector2.Distance(listener.WorldPosition, Sender.WorldPosition); float dist = Vector2.Distance(listener.WorldPosition, Sender.WorldPosition);
if (dist > range) return ""; if (dist > range) return "";
if (Submarine.CheckVisibility(listener.SimPosition, Sender.SimPosition) != null) dist *= 2.0f; if (Submarine.CheckVisibility(listener.SimPosition, Sender.SimPosition) != null) dist = (dist + 100f) * obstructionmult;
if (dist > range) return ""; if (dist > range) return "";
float garbleAmount = dist / range; float garbleAmount = dist / range;
if (garbleAmount < 0.5f) return text; if (garbleAmount < 0.3f) return text;
int startIndex = Math.Max(text.IndexOf(':') + 1, 1); int startIndex = Math.Max(text.IndexOf(':') + 1, 1);
@@ -1848,7 +1848,7 @@ namespace Barotrauma.Networking
case ChatMessageType.Default: case ChatMessageType.Default:
if (!receiver.IsDead) if (!receiver.IsDead)
{ {
return ChatMessage.ApplyDistanceEffect(receiver, sender, message, ChatMessage.SpeakRange); return ChatMessage.ApplyDistanceEffect(receiver, sender, message, ChatMessage.SpeakRange, 3.0f);
} }
break; break;
case ChatMessageType.Radio: case ChatMessageType.Radio:
@@ -533,7 +533,9 @@ namespace Barotrauma.Networking
foreach (string s in shuttleSpawnPoints[i].IdCardTags) foreach (string s in shuttleSpawnPoints[i].IdCardTags)
{ {
item.AddTag(s); item.AddTag(s);
} }
if (!string.IsNullOrWhiteSpace(shuttleSpawnPoints[i].IdCardDesc))
item.Description = shuttleSpawnPoints[i].IdCardDesc;
} }
#if CLIENT #if CLIENT
GameMain.GameSession.CrewManager.AddCharacter(character); GameMain.GameSession.CrewManager.AddCharacter(character);
@@ -16,22 +16,29 @@ namespace Barotrauma
private set; private set;
} }
public float Rotation
{
get;
private set;
}
public readonly float Timestamp; public readonly float Timestamp;
public readonly UInt16 ID; public readonly UInt16 ID;
public PosInfo(Vector2 pos, float time) public PosInfo(Vector2 pos, float rotation, float time)
: this(pos, 0, time) : this(pos, rotation, 0, time)
{ {
} }
public PosInfo(Vector2 pos, UInt16 ID) public PosInfo(Vector2 pos, float rotation, UInt16 ID)
: this(pos, ID, 0.0f) : this(pos, rotation, ID, 0.0f)
{ {
} }
protected PosInfo(Vector2 pos, UInt16 ID, float time) protected PosInfo(Vector2 pos, float rotation, UInt16 ID, float time)
{ {
Position = pos; Position = pos;
Rotation = rotation;
this.ID = ID; this.ID = ID;
Timestamp = time; Timestamp = time;
@@ -52,9 +59,9 @@ namespace Barotrauma
} }
} }
public void Translate(Vector2 amount) public void Translate(Vector2 posAmount,float rotationAmount)
{ {
Position += amount; Position += posAmount; Rotation += rotationAmount;
} }
} }