d4c8fd5649
commit 1ec6577ad95e1d7ebc8cbfa261c9893c55ea987c Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 17:10:31 2019 +0200 Don't attempt to move character's hands in UpdateUseItem if the character is disabled. May be causing "attempted to move pulljoint extremely far" errors (see #895) commit 1aabc5110ce8e0ec208adce6380cbafd255b576f Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 16:47:50 2019 +0200 removed syringes from the fabricator commit 0a80a2d8029275f6cffdae580d1ba86cd44dd1a2 Merge: 039c04818 686d4c482 Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 16:43:55 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit 039c04818e3598f2e4cdef4065434000a48bb229 Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 16:43:51 2019 +0200 Updated: Alien artifacts to spawn inside containers tagged artifactholders in salvage missions & artifact events commit 686d4c482f692bcc31eb37aeaea0d5074a537fe9 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 16:42:11 2019 +0200 Fixed a bunch more buttons/sliders being invisible while pressed commit 823728511547f14a3dcb4fcf5025db592ea3dac9 Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 16:13:36 2019 +0200 Reset the unsaved changes when exitting the character editor (Not applied when the switching between the game view and the character editor). commit 9ecc56db4e73dd2ccd577130014020a1a502ae15 Merge: efbeda895 b824fc3f2 Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 16:04:57 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit efbeda895fceecb8b4701f23ae5a51057aa44efb Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 16:03:54 2019 +0200 Fix crash on trying to undo limb/joint deletion. Undo does not currently work on these cases, but the ragdoll can be reset to the original state from the reset button. commit b824fc3f281aed76e8e0ed78ffb16d2213d2fda1 Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 16:03:03 2019 +0200 removed syringe from medical doctor default kit commit c40c716962c7ae1a16d791b0fbd744627a2283c5 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 16:01:33 2019 +0200 Nerfed door welding (takes 4x longer to weld a door shut now) commit 7a27fcab1cec322fe75bcfad553aa42a37ec7d53 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 16:01:09 2019 +0200 Fixed StatusEffects not being able to target item components. Caused doors to be impossible to weld and most likely other issues with item StatusEffects as well. Closes #1053 commit 50c09ad85ee44018418f537827c009892f4feb23 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 15:52:38 2019 +0200 Fixed depth charges disappearing from loaders when interacting them with both hand slots full. Closes #1046 commit 648a5ba889623f776f184fb30b99133a8551234a Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 15:47:16 2019 +0200 Allow to delete the main limb in the character editor. Should not crash anymore. commit 751bda4d29b81c58c1b1df1653158543a3b7710d Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 15:46:53 2019 +0200 Add a bunch of null checks to prevent crashes when the main limb is null. commit 05c068f7aa35f7070e2cf19c526eff0c8d196b53 Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 15:35:20 2019 +0200 Syringes removed from medical.xml due to being legacy items we should no longer support. commit 74389aa95e29fc7415de48230c8f12fd4a0a6847 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 15:30:13 2019 +0200 Attempt to fix LightSource removal causing nullref exceptions. commit 0907516bcac599b5ae20dc8e35f3a66adb8704b5 Merge: 659e1c58d f042994f4 Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 15:25:07 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit 659e1c58d3fb03d21acf2bb6065d07d1ac2ab914 Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 15:24:59 2019 +0200 Added: Yes to All / No to All to the prompts when deleting multiple containers with contents. Fixed: Aforementioned prompts staying active when quitting the submarine editor. Moved: Logic for the prompts from ItemContainer.cs to SubEditorScreen.cs commit f042994f4b7eeff8cf5a6a68715c7c6aa6b8ddfb Merge: 70a968a16 5a2ca22bd Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 15:08:15 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit 70a968a165c383c2ee765164b4507aa6072e0504 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 15:08:01 2019 +0200 Use inventory icons in the extra cargo menu, layout fixes commit 5a2ca22bde4be43f4577d20ae4e0a1ec20a23497 Merge: b2f89ea59 9ca7440be Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 15:06:11 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit b2f89ea59d481c109046d1edbd2807a516502b0c Author: ezjamsen <ezjames.fi@gmail.com> Date: Mon Feb 4 15:05:39 2019 +0200 redesigned walls in junction compartment of Typhon, closing #1042 commit 9ca7440be41a4fc2082b73618e90312af57c0817 Author: itchyOwl <lauri.harkanen@gmail.com> Date: Mon Feb 4 15:05:35 2019 +0200 Add some null checks to prevent crashing if the xml document or the source element is not found. commit 6d1331e9b86a5583761bc374c5dfb42868b03f45 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 15:03:53 2019 +0200 Fixed the layout of the extra cargo menu in server settings. Closes #1038 commit 02ac14076ace0418a5d35df7a574f99811d56017 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 14:10:34 2019 +0200 Fixed fire sounds persisting in menus. Closes #1047 commit d7d4516ddc9e21a2dba8f7bfd14a61ba7a805d4a Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 14:06:03 2019 +0200 Added a null check to CampaignUI to help diagnose #1029 commit 0fee58808c261cecd4a602db22e39dfb855ee018 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 13:55:50 2019 +0200 Fixed "attempting to remove an already removed item" console errors when ending a round. commit 5e4448024ce00231e9e479aa238ed4b134b07321 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 13:53:59 2019 +0200 Fixed crashing when ending a round while a character is outside the sub. Closes #1040 commit e3ff050561a8f823fc8abfddfec9d22ad4dc14a5 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 13:35:28 2019 +0200 Fixed battery positioning in charging docks. Closes #1041 commit d383aec6cb7f4525906fa858375729d4ad4fc0d4 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 13:26:00 2019 +0200 Fixed debugconsole adding the file number after the extension ("file123.txt (2)" instead of "file123 (2).txt"). Closes #1043 commit fee18b7ebcaea949c3f7d0c8027ab6253769b49c Merge: d03807237 c06e8990f Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 12:10:12 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit d038072372ab1993a44542298fe4031db6448ae4 Author: Eetu <pitkanen.eetu@gmail.com> Date: Mon Feb 4 12:10:04 2019 +0200 Fixed: Setting an item's condition to zero in the SubmarineEditor causing its OnBroken status effects to be fired commit c06e8990f97af7ae9b4788b281bf2801cdd8e2ff Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 11:43:35 2019 +0200 Fixed chatbox being deselected in the net lobby when receiving a lobby update from the server. Closes #1019 commit 2962647c37cec01fdb01092b94c25063c74c9ee0 Merge: b77bc3654 c89df8750 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 10:41:24 2019 +0200 Merge branch 'dev' of https://github.com/Regalis11/Barotrauma into dev commit b77bc365470c8cfb86dc83e4b21e5b36e0e28918 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 10:41:08 2019 +0200 Warning about automatic hull generation not working correctly with sloped walls when using the autohull command commit 85ef20a48532e06ef0c2774aa81e1fb517814b14 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 10:40:20 2019 +0200 Log the name of the item in the "attempting to remove an already removed item" error commit b6e32d4009a898db9c97316bcb6236170a7a92fe Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 10:39:46 2019 +0200 Fixed sliders not moving in the PowerContainer interface when an AI character is operating it commit 4b4848b5caa7bf3893e4ae2f5afef3c980f60e46 Author: Joonas Rikkonen <poe.regalis@gmail.com> Date: Mon Feb 4 10:39:09 2019 +0200 Nullref fix in AIObjectiveGoto commit c89df87500c9026b3a6e75139391e64a4b1073e7 Author: Juan Pablo Arce <juanjp600@users.noreply.github.com> Date: Sun Feb 3 21:02:59 2019 -0300 whoops commit a85cc7705ea7611fff02fff7c18bc9826f03029a Author: Juan Pablo Arce <juanjp600@users.noreply.github.com> Date: Sun Feb 3 21:01:51 2019 -0300 ReduceAffliction loops back around if there's a surplus on index 0 commit e0047df3e089fd8be1646aecbd53b86b69949b13 Author: Juan Pablo Arce <juanjp600@users.noreply.github.com> Date: Sun Feb 3 19:45:52 2019 -0300 Fixed ReduceAffliction freezing Thanks to nilanthanimosus for catching this
708 lines
29 KiB
C#
708 lines
29 KiB
C#
using FarseerPhysics;
|
|
using FarseerPhysics.Dynamics.Joints;
|
|
using Microsoft.Xna.Framework;
|
|
using System;
|
|
|
|
namespace Barotrauma
|
|
{
|
|
class FishAnimController : AnimController
|
|
{
|
|
public override RagdollParams RagdollParams
|
|
{
|
|
get { return FishRagdollParams; }
|
|
protected set { FishRagdollParams = value as FishRagdollParams; }
|
|
}
|
|
|
|
private FishRagdollParams _ragdollParams;
|
|
public FishRagdollParams FishRagdollParams
|
|
{
|
|
get
|
|
{
|
|
if (_ragdollParams == null)
|
|
{
|
|
_ragdollParams = FishRagdollParams.GetDefaultRagdollParams(character.SpeciesName);
|
|
}
|
|
return _ragdollParams;
|
|
}
|
|
protected set
|
|
{
|
|
_ragdollParams = value;
|
|
}
|
|
}
|
|
|
|
private FishWalkParams _fishWalkParams;
|
|
public FishWalkParams FishWalkParams
|
|
{
|
|
get
|
|
{
|
|
if (_fishWalkParams == null)
|
|
{
|
|
_fishWalkParams = FishWalkParams.GetDefaultAnimParams(character);
|
|
}
|
|
return _fishWalkParams;
|
|
}
|
|
set { _fishWalkParams = value; }
|
|
}
|
|
|
|
private FishRunParams _fishRunParams;
|
|
public FishRunParams FishRunParams
|
|
{
|
|
get
|
|
{
|
|
if (_fishRunParams == null)
|
|
{
|
|
_fishRunParams = FishRunParams.GetDefaultAnimParams(character);
|
|
}
|
|
return _fishRunParams;
|
|
}
|
|
set { _fishRunParams = value; }
|
|
}
|
|
|
|
private FishSwimSlowParams _fishSwimSlowParams;
|
|
public FishSwimSlowParams FishSwimSlowParams
|
|
{
|
|
get
|
|
{
|
|
if (_fishSwimSlowParams == null)
|
|
{
|
|
_fishSwimSlowParams = FishSwimSlowParams.GetDefaultAnimParams(character);
|
|
}
|
|
return _fishSwimSlowParams;
|
|
}
|
|
set { _fishSwimSlowParams = value; }
|
|
}
|
|
|
|
private FishSwimFastParams _fishSwimFastParams;
|
|
public FishSwimFastParams FishSwimFastParams
|
|
{
|
|
get
|
|
{
|
|
if (_fishSwimFastParams == null)
|
|
{
|
|
_fishSwimFastParams = FishSwimFastParams.GetDefaultAnimParams(character);
|
|
}
|
|
return _fishSwimFastParams;
|
|
}
|
|
set { _fishSwimFastParams = value; }
|
|
}
|
|
|
|
public IFishAnimation CurrentFishAnimation => CurrentAnimationParams as IFishAnimation;
|
|
public new FishGroundedParams CurrentGroundedParams => base.CurrentGroundedParams as FishGroundedParams;
|
|
public new FishSwimParams CurrentSwimParams => base.CurrentSwimParams as FishSwimParams;
|
|
|
|
public float? TailAngle => GetValidOrNull(CurrentAnimationParams, CurrentFishAnimation?.TailAngleInRadians);
|
|
public float FootTorque => CurrentFishAnimation.FootTorque;
|
|
public float HeadTorque => CurrentFishAnimation.HeadTorque;
|
|
public float TorsoTorque => CurrentFishAnimation.TorsoTorque;
|
|
public float TailTorque => CurrentFishAnimation.TailTorque;
|
|
public float HeadMoveForce => CurrentGroundedParams.HeadMoveForce;
|
|
public float TorsoMoveForce => CurrentGroundedParams.TorsoMoveForce;
|
|
public float FootMoveForce => CurrentGroundedParams.FootMoveForce;
|
|
|
|
public override GroundedMovementParams WalkParams
|
|
{
|
|
get { return FishWalkParams; }
|
|
set { FishWalkParams = value as FishWalkParams; }
|
|
}
|
|
|
|
public override GroundedMovementParams RunParams
|
|
{
|
|
get { return FishRunParams; }
|
|
set { FishRunParams = value as FishRunParams; }
|
|
}
|
|
|
|
public override SwimParams SwimSlowParams
|
|
{
|
|
get { return FishSwimSlowParams; }
|
|
set { FishSwimSlowParams = value as FishSwimSlowParams; }
|
|
}
|
|
|
|
public override SwimParams SwimFastParams
|
|
{
|
|
get { return FishSwimFastParams; }
|
|
set { FishSwimFastParams = value as FishSwimFastParams; }
|
|
}
|
|
|
|
private float flipTimer;
|
|
|
|
public FishAnimController(Character character, string seed, FishRagdollParams ragdollParams = null) : base(character, seed, ragdollParams) { }
|
|
|
|
public override void UpdateAnim(float deltaTime)
|
|
{
|
|
if (Frozen) return;
|
|
if (MainLimb == null) { return; }
|
|
|
|
if (character.IsDead || character.IsUnconscious || character.Stun > 0.0f)
|
|
{
|
|
Collider.Enabled = false;
|
|
Collider.FarseerBody.FixedRotation = false;
|
|
//set linear velocity even though the collider is disabled,
|
|
//because the character won't be able to switch back from ragdoll mode until the velocity of the collider is low enough
|
|
Collider.LinearVelocity = MainLimb.LinearVelocity;
|
|
Collider.SetTransformIgnoreContacts(MainLimb.SimPosition, MainLimb.Rotation);
|
|
|
|
if (character.IsDead && deathAnimTimer < deathAnimDuration)
|
|
{
|
|
deathAnimTimer += deltaTime;
|
|
UpdateDying(deltaTime);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
deathAnimTimer = 0.0f;
|
|
}
|
|
|
|
//re-enable collider
|
|
if (!Collider.Enabled)
|
|
{
|
|
var lowestLimb = FindLowestLimb();
|
|
|
|
Collider.SetTransform(new Vector2(
|
|
Collider.SimPosition.X,
|
|
Math.Max(lowestLimb.SimPosition.Y + (Collider.radius + Collider.height / 2), Collider.SimPosition.Y)),
|
|
0.0f);
|
|
|
|
Collider.Enabled = true;
|
|
}
|
|
|
|
ResetPullJoints();
|
|
|
|
if (strongestImpact > 0.0f)
|
|
{
|
|
character.Stun = MathHelper.Clamp(strongestImpact * 0.5f, character.Stun, 5.0f);
|
|
strongestImpact = 0.0f;
|
|
}
|
|
|
|
if (inWater && !forceStanding)
|
|
{
|
|
Collider.FarseerBody.FixedRotation = false;
|
|
UpdateSineAnim(deltaTime);
|
|
}
|
|
else if (CanEnterSubmarine && (currentHull != null || forceStanding) && CurrentGroundedParams != null)
|
|
{
|
|
//rotate collider back upright
|
|
float standAngle = dir == Direction.Right ? CurrentGroundedParams.ColliderStandAngleInRadians : -CurrentGroundedParams.ColliderStandAngleInRadians;
|
|
if (Math.Abs(MathUtils.GetShortestAngle(Collider.Rotation, standAngle)) > 0.001f)
|
|
{
|
|
Collider.AngularVelocity = MathUtils.GetShortestAngle(Collider.Rotation, standAngle) * 60.0f;
|
|
Collider.FarseerBody.FixedRotation = false;
|
|
}
|
|
else
|
|
{
|
|
Collider.FarseerBody.FixedRotation = true;
|
|
}
|
|
|
|
UpdateWalkAnim(deltaTime);
|
|
}
|
|
|
|
//don't flip or drag when simply physics is enabled
|
|
if (SimplePhysicsEnabled) { return; }
|
|
|
|
if (!character.IsRemotePlayer && (character.AIController == null || character.AIController.CanFlip))
|
|
{
|
|
if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror))
|
|
{
|
|
if (targetMovement.X > 0.1f && targetMovement.X > Math.Abs(targetMovement.Y) * 0.2f)
|
|
{
|
|
TargetDir = Direction.Right;
|
|
}
|
|
else if (targetMovement.X < -0.1f && targetMovement.X < -Math.Abs(targetMovement.Y) * 0.2f)
|
|
{
|
|
TargetDir = Direction.Left;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
float refAngle = 0.0f;
|
|
Limb refLimb = GetLimb(LimbType.Head);
|
|
if (refLimb == null)
|
|
{
|
|
refAngle = CurrentAnimationParams.TorsoAngleInRadians;
|
|
refLimb = GetLimb(LimbType.Torso);
|
|
}
|
|
else
|
|
{
|
|
refAngle = CurrentAnimationParams.HeadAngleInRadians;
|
|
}
|
|
|
|
float rotation = refLimb.Rotation;
|
|
if (!float.IsNaN(refAngle)) { rotation -= refAngle * Dir; }
|
|
|
|
rotation = MathHelper.ToDegrees(MathUtils.WrapAngleTwoPi(rotation));
|
|
|
|
if (rotation < 0.0f) rotation += 360;
|
|
|
|
if (rotation > 20 && rotation < 160)
|
|
{
|
|
TargetDir = Direction.Left;
|
|
}
|
|
else if (rotation > 200 && rotation < 340)
|
|
{
|
|
TargetDir = Direction.Right;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (character.SelectedCharacter != null) DragCharacter(character.SelectedCharacter, deltaTime);
|
|
|
|
if (!CurrentFishAnimation.Flip || IsStuck) return;
|
|
if (character.AIController != null && !character.AIController.CanFlip) return;
|
|
|
|
flipTimer += deltaTime;
|
|
|
|
if (TargetDir != Direction.None && TargetDir != dir)
|
|
{
|
|
if (flipTimer > 1.0f || character.IsRemotePlayer)
|
|
{
|
|
Flip();
|
|
if (!inWater || (CurrentSwimParams != null && CurrentSwimParams.Mirror))
|
|
{
|
|
Mirror();
|
|
}
|
|
flipTimer = 0.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
private float eatTimer = 0.0f;
|
|
|
|
public override void DragCharacter(Character target, float deltaTime)
|
|
{
|
|
if (target == null) return;
|
|
|
|
Limb mouthLimb = Array.Find(Limbs, l => l != null && l.MouthPos.HasValue);
|
|
if (mouthLimb == null) mouthLimb = GetLimb(LimbType.Head);
|
|
|
|
if (mouthLimb == null)
|
|
{
|
|
DebugConsole.ThrowError("Character \"" + character.SpeciesName + "\" failed to eat a target (a head or a limb with a mouthpos required)");
|
|
return;
|
|
}
|
|
|
|
Character targetCharacter = target;
|
|
float eatSpeed = character.Mass / targetCharacter.Mass * 0.1f;
|
|
eatTimer += deltaTime * eatSpeed;
|
|
|
|
Vector2 mouthPos = GetMouthPosition().Value;
|
|
Vector2 attackSimPosition = character.Submarine == null ? ConvertUnits.ToSimUnits(target.WorldPosition) : target.SimPosition;
|
|
|
|
Vector2 limbDiff = attackSimPosition - mouthPos;
|
|
float limbDist = limbDiff.Length();
|
|
if (limbDist < 1.0f)
|
|
{
|
|
//pull the target character to the position of the mouth
|
|
//(+ make the force fluctuate to waggle the character a bit)
|
|
targetCharacter.AnimController.MainLimb.MoveToPos(mouthPos, (float)(Math.Sin(eatTimer) + 10.0f));
|
|
targetCharacter.AnimController.MainLimb.body.SmoothRotate(mouthLimb.Rotation);
|
|
targetCharacter.AnimController.Collider.MoveToPos(mouthPos, (float)(Math.Sin(eatTimer) + 10.0f));
|
|
|
|
//pull the character's mouth to the target character (again with a fluctuating force)
|
|
float pullStrength = (float)(Math.Sin(eatTimer) * Math.Max(Math.Sin(eatTimer * 0.5f), 0.0f));
|
|
mouthLimb.body.ApplyForce(limbDiff * mouthLimb.Mass * 50.0f * pullStrength);
|
|
|
|
character.ApplyStatusEffects(ActionType.OnEating, deltaTime);
|
|
|
|
if (eatTimer % 1.0f < 0.5f && (eatTimer - deltaTime * eatSpeed) % 1.0f > 0.5f)
|
|
{
|
|
//apply damage to the target character to get some blood particles flying
|
|
targetCharacter.AnimController.MainLimb.AddDamage(targetCharacter.SimPosition, 0.0f, 20.0f, 0.0f, false);
|
|
|
|
//keep severing joints until there is only one limb left
|
|
LimbJoint[] nonSeveredJoints = Array.FindAll(targetCharacter.AnimController.LimbJoints,
|
|
l => !l.IsSevered && l.CanBeSevered && l.LimbA != null && !l.LimbA.IsSevered && l.LimbB != null && !l.LimbB.IsSevered);
|
|
if (nonSeveredJoints.Length == 0)
|
|
{
|
|
//only one limb left, the character is now full eaten
|
|
Entity.Spawner.AddToRemoveQueue(targetCharacter);
|
|
character.SelectedCharacter = null;
|
|
}
|
|
else //sever a random joint
|
|
{
|
|
targetCharacter.AnimController.SeverLimbJoint(nonSeveredJoints[Rand.Int(nonSeveredJoints.Length)]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
character.SelectedCharacter = null;
|
|
}
|
|
}
|
|
|
|
void UpdateSineAnim(float deltaTime)
|
|
{
|
|
if (CurrentSwimParams == null) { return; }
|
|
movement = TargetMovement;
|
|
|
|
if (movement.LengthSquared() > 0.00001f)
|
|
{
|
|
Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, 0.5f);
|
|
}
|
|
|
|
//limbs are disabled when simple physics is enabled, no need to move them
|
|
if (SimplePhysicsEnabled) { return; }
|
|
|
|
MainLimb.PullJointEnabled = true;
|
|
//MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
|
|
|
|
if (movement.LengthSquared() < 0.00001f)
|
|
{
|
|
WalkPos = MathHelper.SmoothStep(WalkPos, MathHelper.PiOver2, deltaTime * 5);
|
|
MainLimb.PullJointWorldAnchorB = Vector2.Lerp(MainLimb.PullJointWorldAnchorB, Collider.SimPosition, 0.5f);
|
|
return;
|
|
}
|
|
|
|
float movementAngle = MathUtils.VectorToAngle(movement) - MathHelper.PiOver2;
|
|
|
|
float mainLimbAngle = (MainLimb.type == LimbType.Torso ? TorsoAngle.Value : HeadAngle.Value) * Dir;
|
|
while (MainLimb.Rotation - (movementAngle + mainLimbAngle) > MathHelper.Pi)
|
|
{
|
|
movementAngle += MathHelper.TwoPi;
|
|
}
|
|
while (MainLimb.Rotation - (movementAngle + mainLimbAngle) < -MathHelper.Pi)
|
|
{
|
|
movementAngle -= MathHelper.TwoPi;
|
|
}
|
|
|
|
if (CurrentSwimParams.RotateTowardsMovement)
|
|
{
|
|
Collider.SmoothRotate(movementAngle, CurrentSwimParams.SteerTorque);
|
|
if (TorsoAngle.HasValue)
|
|
{
|
|
Limb torso = GetLimb(LimbType.Torso);
|
|
if (torso != null)
|
|
{
|
|
SmoothRotateWithoutWrapping(torso, movementAngle + TorsoAngle.Value * Dir, MainLimb, TorsoTorque);
|
|
}
|
|
}
|
|
if (HeadAngle.HasValue)
|
|
{
|
|
Limb head = GetLimb(LimbType.Head);
|
|
if (head != null)
|
|
{
|
|
SmoothRotateWithoutWrapping(head, movementAngle + HeadAngle.Value * Dir, MainLimb, HeadTorque);
|
|
}
|
|
}
|
|
if (TailAngle.HasValue)
|
|
{
|
|
Limb tail = GetLimb(LimbType.Tail);
|
|
//tail?.body.SmoothRotate(movementAngle + TailAngle.Value * Dir, TailTorque);
|
|
if (tail != null)
|
|
{
|
|
SmoothRotateWithoutWrapping(tail, movementAngle + TailAngle.Value * Dir, MainLimb, TailTorque);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
movementAngle = Dir > 0 ? -MathHelper.PiOver2 : MathHelper.PiOver2;
|
|
if (MainLimb.type == LimbType.Head && HeadAngle.HasValue)
|
|
{
|
|
Collider.SmoothRotate(HeadAngle.Value * Dir, CurrentSwimParams.SteerTorque);
|
|
}
|
|
else if (MainLimb.type == LimbType.Torso && TorsoAngle.HasValue)
|
|
{
|
|
Collider.SmoothRotate(TorsoAngle.Value * Dir, CurrentSwimParams.SteerTorque);
|
|
}
|
|
if (TorsoAngle.HasValue)
|
|
{
|
|
Limb torso = GetLimb(LimbType.Torso);
|
|
torso?.body.SmoothRotate(TorsoAngle.Value * Dir, TorsoTorque);
|
|
}
|
|
if (HeadAngle.HasValue)
|
|
{
|
|
Limb head = GetLimb(LimbType.Head);
|
|
head?.body.SmoothRotate(HeadAngle.Value * Dir, HeadTorque);
|
|
}
|
|
if (TailAngle.HasValue)
|
|
{
|
|
Limb tail = GetLimb(LimbType.Tail);
|
|
tail?.body.SmoothRotate(TailAngle.Value * Dir, TailTorque);
|
|
}
|
|
}
|
|
|
|
var waveLength = Math.Abs(CurrentSwimParams.WaveLength * RagdollParams.JointScale);
|
|
var waveAmplitude = Math.Abs(CurrentSwimParams.WaveAmplitude);
|
|
if (waveLength > 0 && waveAmplitude > 0)
|
|
{
|
|
WalkPos -= movement.Length() / Math.Abs(waveLength);
|
|
WalkPos = MathUtils.WrapAngleTwoPi(WalkPos);
|
|
}
|
|
|
|
foreach (var limb in Limbs)
|
|
{
|
|
switch (limb.type)
|
|
{
|
|
case LimbType.LeftFoot:
|
|
case LimbType.RightFoot:
|
|
if (CurrentSwimParams.FootAnglesInRadians.ContainsKey(limb.limbParams.ID))
|
|
{
|
|
SmoothRotateWithoutWrapping(limb, movementAngle + CurrentSwimParams.FootAnglesInRadians[limb.limbParams.ID] * Dir, MainLimb, FootTorque);
|
|
}
|
|
break;
|
|
case LimbType.Tail:
|
|
if (waveLength > 0 && waveAmplitude > 0)
|
|
{
|
|
float waveRotation = (float)Math.Sin(WalkPos);
|
|
limb.body.ApplyTorque(waveRotation * limb.Mass * CurrentSwimParams.TailTorque * waveAmplitude);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < Limbs.Length; i++)
|
|
{
|
|
if (Limbs[i].SteerForce <= 0.0f) continue;
|
|
|
|
Vector2 pullPos = Limbs[i].PullJointWorldAnchorA;
|
|
Limbs[i].body.ApplyForce(movement * Limbs[i].SteerForce * Limbs[i].Mass, pullPos);
|
|
}
|
|
|
|
if (CurrentSwimParams.UseSineMovement)
|
|
{
|
|
MainLimb.PullJointWorldAnchorB = Vector2.SmoothStep(MainLimb.PullJointWorldAnchorB, Collider.SimPosition, (float)Math.Abs(Math.Sin(WalkPos)));
|
|
}
|
|
else
|
|
{
|
|
//MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
|
|
MainLimb.PullJointWorldAnchorB = Vector2.Lerp(MainLimb.PullJointWorldAnchorB, Collider.SimPosition, 0.5f);
|
|
}
|
|
|
|
floorY = Limbs[0].SimPosition.Y;
|
|
}
|
|
|
|
void UpdateWalkAnim(float deltaTime)
|
|
{
|
|
if (CurrentGroundedParams == null) { return; }
|
|
movement = MathUtils.SmoothStep(movement, TargetMovement, 0.2f);
|
|
|
|
Collider.LinearVelocity = new Vector2(
|
|
movement.X,
|
|
Collider.LinearVelocity.Y > 0.0f ? Collider.LinearVelocity.Y * 0.5f : Collider.LinearVelocity.Y);
|
|
|
|
//limbs are disabled when simple physics is enabled, no need to move them
|
|
if (SimplePhysicsEnabled) { return; }
|
|
|
|
float mainLimbHeight = ColliderHeightFromFloor;
|
|
|
|
Vector2 colliderBottom = GetColliderBottom();
|
|
|
|
float movementAngle = 0.0f;
|
|
float mainLimbAngle = (MainLimb.type == LimbType.Torso ? TorsoAngle.Value : HeadAngle.Value) * Dir;
|
|
while (MainLimb.Rotation - (movementAngle + mainLimbAngle) > MathHelper.Pi)
|
|
{
|
|
movementAngle += MathHelper.TwoPi;
|
|
}
|
|
while (MainLimb.Rotation - (movementAngle + mainLimbAngle) < -MathHelper.Pi)
|
|
{
|
|
movementAngle -= MathHelper.TwoPi;
|
|
}
|
|
|
|
Limb torso = GetLimb(LimbType.Torso);
|
|
if (torso != null)
|
|
{
|
|
if (TorsoAngle.HasValue)
|
|
{
|
|
SmoothRotateWithoutWrapping(torso, movementAngle + TorsoAngle.Value * Dir, MainLimb, TorsoTorque);
|
|
}
|
|
if (TorsoPosition.HasValue)
|
|
{
|
|
Vector2 pos = colliderBottom + Vector2.UnitY * TorsoPosition.Value;
|
|
|
|
if (torso != MainLimb)
|
|
pos.X = torso.SimPosition.X;
|
|
else
|
|
mainLimbHeight = TorsoPosition.Value;
|
|
|
|
torso.MoveToPos(pos, TorsoMoveForce);
|
|
torso.PullJointEnabled = true;
|
|
torso.PullJointWorldAnchorB = pos;
|
|
}
|
|
}
|
|
|
|
Limb head = GetLimb(LimbType.Head);
|
|
if (head != null)
|
|
{
|
|
if (HeadAngle.HasValue)
|
|
{
|
|
SmoothRotateWithoutWrapping(head, movementAngle + HeadAngle.Value * Dir, MainLimb, HeadTorque);
|
|
}
|
|
if (HeadPosition.HasValue)
|
|
{
|
|
Vector2 pos = colliderBottom + Vector2.UnitY * HeadPosition.Value;
|
|
|
|
if (head != MainLimb)
|
|
pos.X = head.SimPosition.X;
|
|
else
|
|
mainLimbHeight = HeadPosition.Value;
|
|
|
|
head.MoveToPos(pos, HeadMoveForce);
|
|
head.PullJointEnabled = true;
|
|
head.PullJointWorldAnchorB = pos;
|
|
}
|
|
}
|
|
|
|
if (TailAngle.HasValue)
|
|
{
|
|
var tail = GetLimb(LimbType.Tail);
|
|
if (tail != null)
|
|
{
|
|
SmoothRotateWithoutWrapping(tail, movementAngle + TailAngle.Value * Dir, MainLimb, TailTorque);
|
|
}
|
|
}
|
|
|
|
WalkPos -= MainLimb.LinearVelocity.X * (CurrentAnimationParams.CycleSpeed / RagdollParams.JointScale / 100.0f);
|
|
|
|
Vector2 transformedStepSize = Vector2.Zero;
|
|
if (Math.Abs(TargetMovement.X) > 0.01f)
|
|
{
|
|
transformedStepSize = new Vector2(
|
|
(float)Math.Cos(WalkPos) * StepSize.Value.X * 3.0f,
|
|
(float)Math.Sin(WalkPos) * StepSize.Value.Y * 2.0f);
|
|
}
|
|
|
|
foreach (Limb limb in Limbs)
|
|
{
|
|
switch (limb.type)
|
|
{
|
|
case LimbType.LeftFoot:
|
|
case LimbType.RightFoot:
|
|
Vector2 footPos = new Vector2(limb.SimPosition.X, colliderBottom.Y);
|
|
|
|
if (limb.RefJointIndex > -1)
|
|
{
|
|
if (LimbJoints.Length <= limb.RefJointIndex)
|
|
{
|
|
DebugConsole.ThrowError($"Reference joint index {limb.RefJointIndex} is out of array. This is probably due to a missing joint. If you just deleted a joint, don't do that without first removing the reference joint indices from the limbs. If this is not the case, please ensure that you have defined the index to the right joint.");
|
|
}
|
|
else
|
|
{
|
|
footPos.X = LimbJoints[limb.RefJointIndex].WorldAnchorA.X;
|
|
}
|
|
}
|
|
footPos.X += limb.StepOffset.X * Dir;
|
|
footPos.Y += limb.StepOffset.Y;
|
|
|
|
if (limb.type == LimbType.LeftFoot)
|
|
{
|
|
limb.DebugRefPos = footPos + Vector2.UnitX * movement.X * 0.1f;
|
|
limb.DebugTargetPos = footPos + new Vector2(
|
|
transformedStepSize.X + movement.X * 0.1f,
|
|
(transformedStepSize.Y > 0.0f) ? transformedStepSize.Y : 0.0f);
|
|
limb.MoveToPos(limb.DebugTargetPos, FootMoveForce);
|
|
}
|
|
else if (limb.type == LimbType.RightFoot)
|
|
{
|
|
limb.DebugRefPos = footPos + Vector2.UnitX * movement.X * 0.1f;
|
|
limb.DebugTargetPos = footPos + new Vector2(
|
|
-transformedStepSize.X + movement.X * 0.1f,
|
|
(-transformedStepSize.Y > 0.0f) ? -transformedStepSize.Y : 0.0f);
|
|
limb.MoveToPos(limb.DebugTargetPos, FootMoveForce);
|
|
}
|
|
|
|
if (CurrentGroundedParams.FootAnglesInRadians.ContainsKey(limb.limbParams.ID))
|
|
{
|
|
SmoothRotateWithoutWrapping(limb,
|
|
movementAngle + CurrentGroundedParams.FootAnglesInRadians[limb.limbParams.ID] * Dir,
|
|
MainLimb, FootTorque);
|
|
}
|
|
break;
|
|
case LimbType.LeftLeg:
|
|
case LimbType.RightLeg:
|
|
if (Math.Abs(CurrentGroundedParams.LegTorque) > 0.001f) limb.body.ApplyTorque(limb.Mass * CurrentGroundedParams.LegTorque * Dir);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateDying(float deltaTime)
|
|
{
|
|
if (deathAnimDuration <= 0.0f) return;
|
|
|
|
float animStrength = (1.0f - deathAnimTimer / deathAnimDuration);
|
|
|
|
Limb head = GetLimb(LimbType.Head);
|
|
Limb tail = GetLimb(LimbType.Tail);
|
|
|
|
if (head != null && !head.IsSevered) head.body.ApplyTorque((float)(Math.Sqrt(head.Mass) * Dir * Math.Sin(WalkPos)) * 30.0f * animStrength);
|
|
if (tail != null && !tail.IsSevered) tail.body.ApplyTorque((float)(Math.Sqrt(tail.Mass) * -Dir * Math.Sin(WalkPos)) * 30.0f * animStrength);
|
|
|
|
WalkPos += deltaTime * 10.0f * animStrength;
|
|
|
|
Vector2 centerOfMass = GetCenterOfMass();
|
|
|
|
foreach (Limb limb in Limbs)
|
|
{
|
|
#if CLIENT
|
|
if (limb.LightSource != null)
|
|
{
|
|
limb.LightSource.Color = Color.Lerp(limb.InitialLightSourceColor, Color.TransparentBlack, deathAnimTimer / deathAnimDuration);
|
|
}
|
|
#endif
|
|
if (limb.type == LimbType.Head || limb.type == LimbType.Tail || limb.IsSevered || !limb.body.Enabled) continue;
|
|
if (limb.Mass <= 0.0f)
|
|
{
|
|
string errorMsg = "Creature death animation error: invalid limb mass on character \"" + character.SpeciesName + "\" (type: " + limb.type + ", mass: " + limb.Mass + ")";
|
|
DebugConsole.ThrowError(errorMsg);
|
|
GameAnalyticsManager.AddErrorEventOnce("FishAnimController.UpdateDying:InvalidMass" + character.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
|
deathAnimTimer = deathAnimDuration;
|
|
return;
|
|
}
|
|
|
|
Vector2 diff = (centerOfMass - limb.SimPosition);
|
|
if (!MathUtils.IsValid(diff))
|
|
{
|
|
string errorMsg = "Creature death animation error: invalid diff (center of mass: " + centerOfMass + ", limb position: " + limb.SimPosition + ")";
|
|
DebugConsole.ThrowError(errorMsg);
|
|
GameAnalyticsManager.AddErrorEventOnce("FishAnimController.UpdateDying:InvalidDiff" + character.ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
|
deathAnimTimer = deathAnimDuration;
|
|
return;
|
|
}
|
|
|
|
limb.body.ApplyForce(diff * (float)(Math.Sin(WalkPos) * Math.Sqrt(limb.Mass)) * 30.0f * animStrength);
|
|
}
|
|
}
|
|
|
|
private void SmoothRotateWithoutWrapping(Limb limb, float angle, Limb referenceLimb, float torque)
|
|
{
|
|
//make sure the angle "has the same number of revolutions" as the reference limb
|
|
//(e.g. we don't want to rotate the legs to 0 if the torso is at 360, because that'd blow up the hip joints)
|
|
while (referenceLimb.Rotation - angle > MathHelper.TwoPi)
|
|
{
|
|
angle += MathHelper.TwoPi;
|
|
}
|
|
while (referenceLimb.Rotation - angle < -MathHelper.TwoPi)
|
|
{
|
|
angle -= MathHelper.TwoPi;
|
|
}
|
|
|
|
limb?.body.SmoothRotate(angle, torque, wrapAngle: false);
|
|
}
|
|
|
|
public override void Flip()
|
|
{
|
|
base.Flip();
|
|
foreach (Limb l in Limbs)
|
|
{
|
|
if (!l.DoesFlip) continue;
|
|
l.body.SetTransform(l.SimPosition, -l.body.Rotation);
|
|
}
|
|
}
|
|
|
|
private void Mirror()
|
|
{
|
|
Vector2 centerOfMass = GetCenterOfMass();
|
|
|
|
foreach (Limb l in Limbs)
|
|
{
|
|
TrySetLimbPosition(l,
|
|
centerOfMass,
|
|
new Vector2(centerOfMass.X - (l.SimPosition.X - centerOfMass.X), l.SimPosition.Y),
|
|
true);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|