LADXHD/InGame/GameObjects/ObjLink.cs
2023-12-14 17:21:22 -05:00

4871 lines
183 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using ProjectZ.Base;
using ProjectZ.InGame.Controls;
using ProjectZ.InGame.GameObjects.Base;
using ProjectZ.InGame.GameObjects.Base.CObjects;
using ProjectZ.InGame.GameObjects.Base.Components;
using ProjectZ.InGame.GameObjects.Base.Systems;
using ProjectZ.InGame.GameObjects.Dungeon;
using ProjectZ.InGame.GameObjects.NPCs;
using ProjectZ.InGame.GameObjects.Things;
using ProjectZ.InGame.GameSystems;
using ProjectZ.InGame.Map;
using ProjectZ.InGame.SaveLoad;
using ProjectZ.InGame.Things;
namespace ProjectZ.InGame.GameObjects
{
public partial class ObjLink : GameObject
{
public enum State
{
Idle, Pushing, Grabbing, Pulling, Jumping, Attacking, Charging, Blocking, PreCarrying, Carrying, Throwing, CarryingItem, PickingUp, Falling,
Ocarina, OcarinaTelport, Rafting, Pushed,
FallRotateEntry,
Drowning, Drowned, Swimming,
Teleporting, MagicRod, Hookshot, Bombing, Powdering, Digging, BootKnockback,
TeleporterUpWait, TeleporterUp, TeleportFallWait, TeleportFall,
Dying, InitStunned, Stunned, Knockout,
SwordShow0, SwordShow1, SwordShowLv2,
ShowInstrumentPart0, ShowInstrumentPart1, ShowInstrumentPart2, ShowInstrumentPart3,
ShowToadstool,
CloakShow0, CloakShow1,
Intro, BedTransition,
Sequence, FinalInstruments,
Frozen
}
public State CurrentState;
private List<GameObject> _bombList = new List<GameObject>();
private List<GameObject> _ocarinaList = new List<GameObject>();
private List<GameObject> _destroyableWallList = new List<GameObject>();
// movement stuff
public float PosX => EntityPosition.X;
public float PosY => EntityPosition.Y;
public float PosZ => EntityPosition.Z;
private const float WalkSpeed = 1.0f;
private const float WalkSpeedPoP = 20 / 16f;
private const float BootsRunningSpeed = 2.0f;
private const float SwimSpeed = 0.5f;
private const float SwimSpeedA = 1.0f;
private float _currentWalkSpeed;
private float _waterSoundCounter;
private readonly Vector2[] _walkDirection = { new Vector2(-1, 0), new Vector2(0, -1), new Vector2(1, 0), new Vector2(0, 1) };
public Vector2 ForwardVector
{
get => _walkDirection[Direction];
}
private Vector2 _moveVelocity;
private Vector2 _lastMoveVelocity;
private Vector2 _lastBaseMoveVelocity;
public Vector2 LastMoveVector;
private Point _lastTilePosition;
public int Direction;
private bool _isWalking;
// player animations
public readonly Animator Animation;
private int _animationOffsetX = -7;
private int _animationOffsetY = -16;
private CSprite _sprite;
private float _spriteTransparency;
private bool _isVisible;
public bool IsVisible
{
get => _isVisible;
set
{
_isVisible = value;
_sprite.IsVisible = value;
}
}
// weapon animations
private Animator AnimatorWeapons;
private double _fallEntryCounter;
// hole stuff
private Vector2 _holeResetPoint;
private Vector2 _alternativeHoleResetPosition; // map change on hole fall
public string HoleResetRoom;
public string HoleResetEntryId;
public int HoleTeleporterId;
public bool WasHoleReset;
private double _holeTeleportCounter;
// counter to start the level change
private float _holeFallCounter;
private bool _isFallingIntoHole;
// body stuff
public BodyComponent _body;
public RectangleF BodyRectangle => _body.BodyBox.Box.Rectangle();
public RectangleF PlayerRectangle => new RectangleF(PosX - 4, PosY - 12 - PosZ, 8, 12);
private BodyDrawComponent _drawBody;
private BodyDrawShadowComponent _shadowComponent;
private DrawComponent.DrawTemplate _bodyDrawFunction;
// carried object
private GameObject _carriedGameObject;
private DrawComponent _carriedObjDrawComp;
private CarriableComponent _carriedComponent;
private Vector3 _carryStartPosition;
// show item
public GameItem ShowItem;
private Vector2 _showItemOffset;
// used to only collect the item after it was shown
private GameItemCollected _collectedShowItem;
private string _pickupDialogOverride;
private string _additionalPickupDialog;
private double _itemShowCounter;
private bool _showItem;
private bool _savedPreItemPickup;
public bool SavePreItemPickup
{
get { return _savedPreItemPickup; }
}
private const int dist0 = 30;
private const int dist1 = 15;
private readonly Vector2[] _showInstrumentOffset = {
new Vector2(-dist1, -dist0), new Vector2(dist1, -dist0), new Vector2(dist0, dist1), new Vector2(dist0, -dist1),
new Vector2(dist1, dist0),new Vector2(-dist1, dist0),new Vector2(-dist0, -dist1),new Vector2(-dist0, dist1) };
private readonly int[] _instrumentMusicIndex = { 31, 39, 40, 41, 42, 43, 44, 45 };
// show sword lv2
private float _showSwordLv2Counter;
private float _showSwordL2ParticleCounter;
private bool _shownSwordLv2Dialog;
// transition stuff
public Vector2? MapTransitionStart;
public Vector2? MapTransitionEnd;
public Vector2? NextMapPositionStart;
public Vector2? NextMapPositionEnd;
public string NextMapPositionId;
public int DirectionEntry;
public bool IsTransitioning;
public bool NextMapFallStart;
public bool NextMapFallRotateStart;
public bool TransitionOutWalking;
public bool TransitionInWalking;
private bool _wasTransitioning;
private bool _startBedTransition;
// rail jump
private Vector2 _railJumpStartPosition;
private Vector2 _railJumpTargetPosition;
private float _railJumpPositionZ;
private float _railJumpPercentage;
private float _railJumpHeight;
// swim stuff
private Vector2 _swimVelocity;
private float _swimBoostCount;
private float _diveCounter;
// store item picked up by the player
public GameItem StoreItem;
private int _storeItemWidth;
private int _storeItemHeight;
private Vector2 _storePickupPosition;
private bool _showStealMessage;
// follower
private GameObjectFollower _objFollower;
private ObjCock _objRooster;
private ObjMarin _objMaria;
private const string _spawnGhostKey = "spawn_ghost";
private ObjGhost _objGhost;
private bool _spawnGhost;
// boots
private bool _bootsHolding;
private bool _bootsRunning;
private bool _wasBootsRunning;
private bool _bootsStop;
private float _bootsCounter;
private float _bootsRunTime = 500;
private float _bootsParticleTime = 120;
// trapped state
private int _trapInteractionCount;
private bool _isTrapped;
private bool _trappedDisableItems;
// raft
private ObjRaft _objRaft;
private bool _isRafting;
// stonelifter pull
private const float PullTime = 100;
private const float PullMaxTime = 400;
private const float PullResetTime = -133;
private float _pullCounter;
private bool _isPulling;
private bool _wasPulling;
// pick up time
private const float PreCarryTime = 200;
private float _preCarryCounter;
// drown stuff
private Vector2 _drownResetPosition;
private float _drownCounter;
private float _drownResetCounter;
// sword stuff
public Box SwordDamageBox;
private float _swordPokeTime = 100;
private float _swordPokeCounter;
private Vector2[] _shootSwordOffset;
private bool _shotSword;
public CBox DamageCollider;
private Vector2 _hitVelocity;
public const int BlinkTime = 66;
public const int CooldownTime = BlinkTime * 16;
private double _hitCount;
private double _hitRepelTime;
private double _hitParticleTime;
private const float SwordChargeTime = 500;
private float _swordChargeCounter;
private bool _swordPoked;
private bool _stopCharging;
private Point[] _pokeAnimationOffset;
private bool _isHoldingSword;
private bool _isSwingingSword;
public bool CarrySword;
// items
private ObjBoomerang _boomerang = new ObjBoomerang();
private Vector2[] _boomerangOffset;
private Vector2[] _arrowOffset;
public bool HasFlippers;
// arrow
private const float ArrowSpeed = 3;
private const float ArrowSpeedPoP = 4;
// shield
public bool CarryShield;
private bool _wasBlocking;
// hookshot
public ObjHookshot Hookshot = new ObjHookshot();
private Vector2[] _hookshotOffset;
private bool _hookshotPull;
// magic rod
private Vector2[] _magicRodOffset;
private const float MagicRodSpeed = 3;
private const float MagicRodSpeedPoP = 4;
// shovel
private Vector2[] _shovelOffset;
private Point _digPosition;
private bool _hasDug;
private bool _canDig;
private Vector2[] _powderOffset;
private Vector2[] _bombOffset;
// ocarina
private float _ocarinaCounter;
private int _ocarinaNoteIndex;
private int _ocarinaSong;
// jump stuff
private bool _canJump = true;
private const float JumpAcceleration = 2.35f;
private float _railJumpSpeed;
// should probably have been a different state because we do not want to be able to use certain items while railjumping compared to normally jumping
private bool _railJump;
private bool _startedJumping;
private bool _hasStartedJumping;
// cloak transition
private int CloakTransitionTime = 2200;
private float _cloakTransitionCounter;
private float _cloakPercentage;
private int CloakTransitionOutTime = 2500;
private float _cloakTransitionOutCounter;
// teleport stuff
private ObjDungeonTeleporter _teleporter;
private string _teleportMap;
private string _teleporterId;
private float _teleportCounter;
private float _teleportCounterFull;
private int _teleportState;
// instrument stuff
// @TODO: replace
private Rectangle[] _noteSourceRectangles = { new Rectangle(145, 97, 10, 12), new Rectangle(156, 97, 6, 12) };
private bool[] _noteInit = { false, false };
private int[] _noteSpriteIndex = { 0, 0 };
private double _instrumentPickupTime;
private float _instrumentCounter;
private float _instrumentEndTime;
private int _instrumentIndex;
private int _instrumentCycleTime = 1000;
private bool _drawInstrumentEffect;
private bool _pickingUpInstrument;
private bool _pickingUpSword;
// push stuff
private Vector2 _pushStart;
private Vector2 _pushEnd;
private float _pushCounter;
private int _pushTime;
// used by the vaccuum
private float _rotationCounter;
// stunned state
private float _stunnedCounter;
private bool _stunnedParticles;
// final sequence
private int _finalIndex;
private double _finalSeqCounter;
// save position
public string SaveMap;
public Vector2 SavePosition;
public int SaveDirection;
// other stuff
public Point CollisionBoxSize;
private MapStates.FieldStates _lastFieldState;
public bool CanWalk;
public bool DisableItems;
public bool UpdatePlayer;
public bool IsPoking;
private bool _pokeStart;
private bool _isLocked;
private bool _isGrabbed;
private bool _isFlying;
private bool _inDungeon;
#if DEBUG
private bool _attackMode;
#endif
private DictAtlasEntry _stunnedParticleSprite;
public ObjLink() : base((Map.Map)null)
{
EntityPosition = new CPosition(0, 0, 0);
EntitySize = new Rectangle(-8, -16, 16, 16);
// load the player + sword animations
Animation = AnimatorSaveLoad.LoadAnimator("link0");
AnimatorWeapons = AnimatorSaveLoad.LoadAnimator("Objects/sword");
_stunnedParticleSprite = Resources.GetSprite("stunned particle");
CollisionBoxSize = new Point(8, 8);
_body = new BodyComponent(EntityPosition, -4, -10, 8, 10, 8)
{
IsPusher = true,
IsSlider = true,
MaxJumpHeight = 3,
Drag = 0.9f,
DragAir = 0.9f,
Gravity = -0.15f,
Gravity2D = 0.1f,
AbsorbPercentage = 1f,
HoleOnPull = OnHolePull,
HoleAbsorb = OnHoleAbsorb,
MoveCollision = OnMoveCollision,
CollisionTypes = Values.CollisionTypes.Normal |
Values.CollisionTypes.Enemy |
Values.CollisionTypes.PlayerItem |
Values.CollisionTypes.LadderTop,
};
DamageCollider = new CBox(EntityPosition, -5, -10, 10, 10, 8);
_powderOffset = new[]
{
new Vector2(-12, 0),
new Vector2(-2, -CollisionBoxSize.Y -5),
new Vector2(12, 0),
new Vector2(2, 10)
};
_boomerangOffset = new[]
{
new Vector2(-10, -3),
new Vector2(-2, -CollisionBoxSize.Y -1),
new Vector2(10, -3),
new Vector2(2, 6)
};
_arrowOffset = new[]
{
new Vector2(-10, 0),
new Vector2(-2, -CollisionBoxSize.Y -1),
new Vector2(10, 0),
new Vector2(2, 6)
};
_magicRodOffset = new[]
{
new Vector2(-10, -4),
new Vector2(-4, -CollisionBoxSize.Y - 8),
new Vector2(10, -4),
new Vector2(3, 4)
};
_shootSwordOffset = new[]
{
new Vector2(-10, -4),
new Vector2(-5, -CollisionBoxSize.Y - 8),
new Vector2(10, -4),
new Vector2(4, 4)
};
_hookshotOffset = new[]
{
new Vector2(-5, -4),
new Vector2(-3, -CollisionBoxSize.Y - 2),
new Vector2(5, -4),
new Vector2(3, 0)
};
_shovelOffset = new[]
{
new Vector2(-9, -1),
new Vector2(0, -14),
new Vector2(9, -1),
new Vector2(0, 1)
};
_bombOffset = new[]
{
new Vector2(-10, 0),
new Vector2(0, -CollisionBoxSize.Y - 2),
new Vector2(10, 0),
new Vector2(0, 8)
};
_pokeAnimationOffset = new[]
{
new Point(-16, -4),
new Point(-4, -CollisionBoxSize.Y - 16),
new Point(16, -4),
new Point(5, 12)
};
_sprite = new CSprite(EntityPosition);
// cant just change the offset value without changing the blocking rectangle
var animatorComponent = new AnimationComponent(Animation, _sprite, new Vector2(_animationOffsetX, _animationOffsetY));
// custom draw function
_drawBody = new BodyDrawComponent(_body, DrawLink, Values.LayerPlayer);
_bodyDrawFunction = _drawBody.Draw;
_drawBody.Draw = Draw;
AddComponent(KeyChangeListenerComponent.Index, new KeyChangeListenerComponent(OnKeyChange));
AddComponent(BodyComponent.Index, _body);
AddComponent(BaseAnimationComponent.Index, animatorComponent);
AddComponent(CollisionComponent.Index, new BodyCollisionComponent(_body, Values.CollisionTypes.Player));
AddComponent(UpdateComponent.Index, new UpdateComponent(Update));
AddComponent(DrawComponent.Index, _drawBody);
AddComponent(DrawShadowComponent.Index, _shadowComponent = new BodyDrawShadowComponent(_body, _sprite));
EntityPosition.AddPositionListener(typeof(CarriableComponent), UpdatePositionCarriedObject);
}
private void Update()
{
#if DEBUG
if (InputHandler.KeyPressed(Keys.Y))
Game1.GameManager.InitPieceOfPower();
if (InputHandler.KeyPressed(Keys.X))
_attackMode = !_attackMode;
if (_attackMode)
{
var damageBox = new Box(EntityPosition.X - 160, EntityPosition.Y - 140, 0, 320, 280, 16);
var damageOrigin = damageBox.Center;
//Map.Objects.Hit(this, damageOrigin, damageBox, HitType.Sword1, Game1.GameManager.PieceOfPowerIsActive ? 2 : 1, Game1.GameManager.PieceOfPowerIsActive);
//Map.Objects.Hit(this, damageOrigin, damageBox, HitType.Bomb, 2, false);
Map.Objects.Hit(this, damageOrigin, damageBox, HitType.Bow, 2, false);
//Map.Objects.Hit(this, damageOrigin, damageBox, HitType.Hookshot, 2, false);
//Map.Objects.Hit(this, damageOrigin, damageBox, HitType.MagicRod, 2, false);
//Map.Objects.Hit(this, damageOrigin, damageBox, HitType.MagicPowder, 2, false);
//Map.Objects.Hit(this, damageOrigin, damageBox, HitType.PegasusBootsSword, 2, false);
//Map.Objects.Hit(this, damageOrigin, damageBox, HitType.PegasusBootsPush, 2, false);
//Map.Objects.Hit(this, damageOrigin, damageBox, HitType.ThrownObject, 2, false);
//Map.Objects.Hit(this, damageOrigin, damageBox, HitType.SwordShot, 2, false);
//Map.Objects.Hit(this, damageOrigin, damageBox, HitType.SwordHold, 2, false);
//Map.Objects.Hit(this, damageOrigin, damageBox, HitType.SwordSpin, 2, false);
}
#endif
if (CurrentState == State.FallRotateEntry)
{
_fallEntryCounter += Game1.DeltaTime;
Direction = (int)(DirectionEntry + (_fallEntryCounter + 96) / 48) % 4;
if (_body.IsGrounded)
CurrentState = State.Idle;
UpdateAnimation();
}
// @HACK
// this is only needed because the player should not be able to step into the door 1 frame after finishing the transition
// this would cause the door transition to not start
if (IsTransitioning || _wasTransitioning)
{
_wasTransitioning = IsTransitioning;
return;
}
// first photo sequence
if (CurrentState == State.Pushed)
{
_pushCounter += Game1.DeltaTime;
// push towards the target position
if (_pushCounter > _pushTime)
{
EntityPosition.Set(_pushEnd);
CurrentState = State.Idle;
}
else
{
var percentage = MathF.Sin((_pushCounter / _pushTime) * MathF.PI * 0.5f);
var newPosition = Vector2.Lerp(_pushStart, _pushEnd, percentage);
EntityPosition.Set(newPosition);
}
}
// need to update the bomb to make sure it does not explode while the player is not getting updated
if (_carriedComponent != null && _carriedComponent.IsPickedUp)
{
// used to updated the position to match the animation
// gets called twice when moving
// not sure how this could be done better
UpdatePositionCarriedObject(EntityPosition);
}
if (!UpdatePlayer)
{
UpdatePlayer = true;
// only update the animation
if (!Is2DMode)
UpdateAnimation();
else
Update2DFrozen();
UpdateOcarinaAnimation();
UpdateDive();
UpdateDrawComponents();
return;
}
UpdateHeartWarningSound();
if (CurrentState == State.FinalInstruments)
{
_finalSeqCounter -= Game1.DeltaTime;
if (_finalIndex == 0)
{
if (_finalSeqCounter <= 0)
{
_finalIndex = 1;
_finalSeqCounter += 2250;
Animation.Play("show1");
Game1.GameManager.PlaySoundEffect("D360-52-34");
}
}
else if (_finalIndex == 1)
{
if (_finalSeqCounter <= 0)
((MapShowSystem)Game1.GameManager.GameSystems[typeof(MapShowSystem)]).StartEnding();
}
return;
}
else if (CurrentState == State.CloakShow0)
{
_cloakTransitionCounter += Game1.DeltaTime;
_cloakPercentage = _cloakTransitionCounter / CloakTransitionTime;
if (_cloakTransitionCounter > CloakTransitionTime)
{
_cloakPercentage = 1;
if (ShowItem.Name == "cloakBlue")
Game1.GameManager.StartDialog("cloak_blue");
if (ShowItem.Name == "cloakRed")
Game1.GameManager.StartDialog("cloak_red");
CurrentState = State.CloakShow1;
// add the item to the inventory
if (_collectedShowItem != null)
{
Game1.GameManager.CollectItem(_collectedShowItem, 0);
_collectedShowItem = null;
}
ShowItem = null;
}
}
else if (CurrentState == State.CloakShow1)
{
_cloakTransitionOutCounter += Game1.DeltaTime;
var transitionSystem = (MapTransitionSystem)Game1.GameManager.GameSystems[typeof(MapTransitionSystem)];
transitionSystem.SetColorMode(Color.White, MathHelper.Clamp(_cloakTransitionOutCounter / 1000f, 0, 1));
if (_cloakTransitionOutCounter > CloakTransitionOutTime)
{
Game1.GameManager.StartDialogPath("color_fairy_4");
Direction = 3;
MapTransitionStart = EntityPosition.Position;
MapTransitionEnd = MapTransitionStart;
TransitionOutWalking = false;
// append a map change
((MapTransitionSystem)Game1.GameManager.GameSystems[typeof(MapTransitionSystem)]).AppendMapChange(
"overworld.map", "cloakOut", false, true, Color.White, true);
}
}
else if (CurrentState == State.ShowToadstool)
{
CurrentState = State.Idle;
}
else if (CurrentState == State.SwordShowLv2)
{
_showSwordL2ParticleCounter += Game1.DeltaTime;
if (_showSwordL2ParticleCounter > 4800 && !_shownSwordLv2Dialog)
{
_shownSwordLv2Dialog = true;
_showSwordL2ParticleCounter = 0;
Game1.GameManager.SetMusic(-1, 2);
Game1.GameManager.StartDialogPath("sword2Collected");
}
// make sure to show the sword while the dialog box is open
else if (_shownSwordLv2Dialog)
{
ShowItem = null;
CurrentState = State.Idle;
}
}
else if (CurrentState == State.PickingUp && !_pickingUpInstrument && !_pickingUpSword)
{
Game1.GameManager.FreezeWorldAroundPlayer = true;
}
else if (CurrentState == State.TeleporterUpWait)
{
_holeTeleportCounter += Game1.DeltaTime;
if (_holeTeleportCounter > 1000)
{
CurrentState = State.TeleporterUp;
_holeTeleportCounter -= 1000;
_shadowComponent.Transparency = 0;
Game1.GameManager.PlaySoundEffect("D360-37-25");
}
}
else if (CurrentState == State.TeleporterUp)
{
_holeTeleportCounter += Game1.DeltaTime;
var time = 400;
EntityPosition.Z = (float)(_holeTeleportCounter / time) * 128;
Direction = (int)(_holeTeleportCounter / 64) % 4;
// fade in
var percentage = MathHelper.Clamp(1 - ((float)_holeTeleportCounter - (time - 100)) / 100, 0, 1);
_spriteTransparency = percentage;
_shadowComponent.Transparency = percentage;
if (_holeTeleportCounter > time)
{
_holeTeleportCounter -= time;
if (ObjOverworldTeleporter.TeleporterDictionary.TryGetValue(HoleTeleporterId, out var teleporter))
teleporter.SetNextTeleporterPosition();
else
CurrentState = State.Idle; // should not happen
}
}
else if (CurrentState == State.TeleportFallWait)
{
_holeTeleportCounter += Game1.DeltaTime;
var time = 350;
if (_holeTeleportCounter > time)
{
_holeTeleportCounter -= time - 50;
_body.Velocity = new Vector3(0, 0, 0);
CurrentState = State.TeleportFall;
}
}
else if (CurrentState == State.TeleportFall)
{
_holeTeleportCounter += Game1.DeltaTime;
Direction = (int)(_holeTeleportCounter / 64) % 4;
// fade in
var percentage = MathHelper.Clamp((float)_holeTeleportCounter / 100, 0, 1);
if (_body.IsGrounded)
{
percentage = 1;
CurrentState = State.Idle;
UpdateSaveLocation();
// save settings?
if (GameSettings.Autosave)
{
SaveGameSaveLoad.SaveGame(Game1.GameManager);
Game1.GameManager.InGameOverlay.InGameHud.ShowSaveIcon();
}
}
_spriteTransparency = percentage;
_shadowComponent.Transparency = percentage;
}
if (CurrentState == State.Knockout)
return;
// stunned player
if (CurrentState == State.InitStunned && _hitVelocity.Length() < 0.25f)
{
Animation.Play("stunned");
CurrentState = State.Stunned;
}
if (CurrentState == State.Stunned && _stunnedCounter > 0)
{
_stunnedCounter -= Game1.DeltaTime;
if (_stunnedCounter <= 0)
CurrentState = State.Idle;
}
AnimatorWeapons.Update();
// update all the item stuff
// this need to be before the update method to correctly start jumping?
UpdateItem();
if (Is2DMode)
Update2D();
else
Update3D();
UpdateOcarina();
UpdateDamageShader();
_hitCount -= Game1.DeltaTime;
if (_savedPreItemPickup && (CurrentState == State.Idle || CurrentState == State.Swimming))
EndPickup();
// die?
if (Game1.GameManager.CurrentHealth <= 0 && !Game1.GameManager.UseShockEffect)
OnDeath();
UpdateDrawComponents();
DisableItems = false;
HoleResetRoom = null;
CanWalk = true;
_canJump = true;
_isLocked = false;
_hasStartedJumping = _startedJumping;
_startedJumping = false;
_currentWalkSpeed = Game1.GameManager.PieceOfPowerIsActive ? WalkSpeedPoP : WalkSpeed;
}
#region Draw
private void Draw(SpriteBatch spriteBatch)
{
Game1.DebugText += "Jump Timer: " + _railJumpPercentage + "\n";
Game1.DebugText += "Player State: " + CurrentState;
if (!IsVisible)
return;
// draw the player sprite behind the sword
if (Direction != 1 && !_isTrapped)
_bodyDrawFunction(spriteBatch);
// draw the sword/magic rod
if (CurrentState == State.Attacking ||
CurrentState == State.Charging ||
CurrentState == State.SwordShow0 ||
CurrentState == State.MagicRod ||
(_bootsRunning && CarrySword))
{
var changeColor = _swordChargeCounter <= 0 &&
Game1.TotalGameTime % (8 / 0.06) >= 4 / 0.06 &&
ObjectManager.CurrentEffect != Resources.DamageSpriteShader0.Effect;
// change the draw shader
if (changeColor)
{
spriteBatch.End();
ObjectManager.SpriteBatchBegin(spriteBatch, Resources.DamageSpriteShader0);
}
AnimatorWeapons.Draw(spriteBatch, new Vector2(EntityPosition.X - 7, EntityPosition.Y - 16 - EntityPosition.Z), Color.White);
if (changeColor)
{
spriteBatch.End();
ObjectManager.SpriteBatchBegin(spriteBatch, null);
}
}
// draw the sword after the first pickup
if (CurrentState == State.SwordShow1)
{
var itemSword = Game1.GameManager.ItemManager["sword1"];
var position = new Vector2(
BodyRectangle.X - itemSword.SourceRectangle.Value.Width / 2f,
(EntityPosition.Y - EntityPosition.Z - 15) - itemSword.SourceRectangle.Value.Height);
ItemDrawHelper.DrawItem(spriteBatch, itemSword, position, Color.White, 1, true);
}
// draw the toadstool
if (CurrentState == State.ShowToadstool)
{
var itemToadstool = Game1.GameManager.ItemManager["toadstool"];
var position = new Vector2(
BodyRectangle.X - itemToadstool.SourceRectangle.Value.Width / 2f,
(EntityPosition.Y - EntityPosition.Z - 15) - itemToadstool.SourceRectangle.Value.Height);
ItemDrawHelper.DrawItem(spriteBatch, itemToadstool, position, Color.White, 1);
}
// draw the player sprite in front of the sword
if (Direction == 1 && !_isTrapped)
_bodyDrawFunction(spriteBatch);
if (_drawInstrumentEffect)
DrawInstrumentEffect(spriteBatch);
// draw the picked up store item
if (StoreItem != null)
ItemDrawHelper.DrawItem(spriteBatch, StoreItem, _storePickupPosition, Color.White, 1, true);
// draw the shown item
if (ShowItem != null)
{
var itemPosition = EntityPosition.Position + _showItemOffset;
itemPosition.Y -= EntityPosition.Z;
if (CurrentState == State.CloakShow0)
{
ItemDrawHelper.DrawItem(spriteBatch, ShowItem, itemPosition, Color.White * (1 - _cloakPercentage), 1, true);
}
else if (ShowItem.Name == "sword2")
{
var swordImage = Resources.GetSprite("sword2Show");
DrawHelper.DrawNormalized(spriteBatch, swordImage.Texture, itemPosition, swordImage.ScaledRectangle, Color.White, swordImage.Scale);
}
else
ItemDrawHelper.DrawItem(spriteBatch, ShowItem, itemPosition, Color.White, 1, true);
}
// draw the object the player is carrying
if (_carriedObjDrawComp != null)
{
_carriedObjDrawComp.IsActive = true;
_carriedObjDrawComp.Draw(spriteBatch);
_carriedObjDrawComp.IsActive = false;
}
// draw the dots over the head in the stunned state
if (CurrentState == State.Stunned && _stunnedParticles)
{
var rotation = (float)(Game1.TotalGameTime / 1200) * MathF.PI * 2;
var offset0 = new Vector2(MathF.Cos(rotation) * 8 - 2, MathF.Sin(rotation) * 3 - 2);
DrawHelper.DrawNormalized(spriteBatch, _stunnedParticleSprite,
offset0 + new Vector2(EntityPosition.X, EntityPosition.Y - EntityPosition.Z - 18), Color.White);
var offset1 = new Vector2(MathF.Cos(rotation + MathF.PI) * 8 - 2, MathF.Sin(rotation + MathF.PI) * 3 - 2);
DrawHelper.DrawNormalized(spriteBatch, _stunnedParticleSprite,
offset1 + new Vector2(EntityPosition.X, EntityPosition.Y - EntityPosition.Z - 18), Color.White);
}
if (CurrentState == State.SwordShowLv2)
DrawSwordL2Particles(spriteBatch);
// draw the notes while showing an instrument
{
var leftNotePosition = new Vector2(EntityPosition.X - 8, EntityPosition.Y - 24);
DrawNote(spriteBatch, leftNotePosition, new Vector2(-0.4f, -1.0f), 0);
var rightNotePosition = new Vector2(EntityPosition.X + 8, EntityPosition.Y - 24);
DrawNote(spriteBatch, rightNotePosition, new Vector2(0.4f, -1.0f), 1);
}
if (CurrentState == State.FinalInstruments)
DrawFinalInstruments(spriteBatch);
if (Game1.DebugMode)
{
// draw the save hole position
spriteBatch.Draw(Resources.SprWhite,
new Vector2(_holeResetPoint.X - 5, _holeResetPoint.Y - 5), new Rectangle(0, 0,
10, 10), Color.HotPink * 0.65f);
// weapon damage rectangle
var swordRectangle = SwordDamageBox.Rectangle();
spriteBatch.Draw(Resources.SprWhite,
new Vector2(swordRectangle.X, swordRectangle.Y), new Rectangle(0, 0,
(int)swordRectangle.Width, (int)swordRectangle.Height), Color.Blue * 0.75f);
}
}
private void DrawSwordL2Particles(SpriteBatch spriteBatch)
{
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(-32, -16), -125, 300, 200, 0);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(-32, -16), -125 - 250, 300, 200, 0);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(-32, -32), 0, 300, 200, 1);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(-32, -32), -250, 300, 200, 1);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(-24, -52), -50, 450, 50, 2);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(-24, -52), -50 - 250, 450, 50, 2);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(0, -64), -75, 450, 50, 3);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(0, -64), -75 - 250, 450, 50, 3);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(24, -52), -50, 450, 50, 4);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(24, -52), -50 - 250, 450, 50, 4);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(32, -32), 0, 300, 200, 5);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(32, -32), -250, 300, 200, 5);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(32, -16), -125, 300, 200, 6);
DrawSwordParticle(spriteBatch, new Vector2(EntityPosition.X - 4, EntityPosition.Y - 22), new Vector2(32, -16), -125 - 250, 300, 200, 6);
}
private void DrawInstrumentEffect(SpriteBatch spriteBatch)
{
var fadeTime = 100;
var speed = 500;
var center = new Vector2(EntityPosition.X, EntityPosition.Y - 20);
{
var time = (float)(Game1.TotalGameTime % speed);
var state = MathF.Sin((time / speed) * MathF.PI * 0.475f);
var distance = 32 - 20 * state;
var transparency = MathHelper.Clamp(time / fadeTime, 0, 1) *
MathHelper.Clamp((speed - time) / fadeTime, 0, 1);
var sourceRectangle = time < (speed / 1.65f) ? new Rectangle(194, 114, 12, 12) : new Rectangle(194, 98, 12, 12);
for (var y = 0; y < 2; y++)
for (var x = 0; x < 2; x++)
{
var position = new Vector2(
center.X - 6 + (x * 2 - 1) * distance,
center.Y - 6 + (y * 2 - 1) * distance);
spriteBatch.Draw(Resources.SprItem, position, sourceRectangle,
Color.White * transparency, 0, Vector2.Zero, Vector2.One,
(x == 0 ? SpriteEffects.FlipHorizontally : SpriteEffects.None) |
(y == 0 ? SpriteEffects.FlipVertically : SpriteEffects.None), 0);
}
}
{
var time = (float)((Game1.TotalGameTime + speed / 2) % speed);
var state = MathF.Sin((time / speed) * MathF.PI * 0.475f);
var distance = 40 - 34 * state;
var transparency = MathHelper.Clamp(time / fadeTime, 0, 1) *
MathHelper.Clamp((speed - time) / fadeTime, 0, 1);
var sourceRectangle = time < (speed / 1.65f) ? new Rectangle(176, 116, 16, 8) : new Rectangle(176, 100, 16, 8);
for (var y = 0; y < 2; y++)
for (var x = 0; x < 2; x++)
{
var rotation = (float)((x * 2 + y) * Math.PI / 2);
var position = new Vector2(
center.X + (y == 0 ? (x * 2 - 1) * distance : 0),
center.Y + (y == 0 ? 0 : (x * 2 - 1) * distance));
spriteBatch.Draw(Resources.SprItem, position, sourceRectangle,
Color.White * transparency, rotation, new Vector2(16, 4), Vector2.One, SpriteEffects.None, 0);
}
}
}
private void DrawFinalInstruments(SpriteBatch spriteBatch)
{
if (_finalIndex != 1)
return;
var percentage = 0.25f + Math.Clamp((float)(2500 - _finalSeqCounter) / 2000, 0, 1) * 0.75f;
// draw the instruments
for (var i = 0; i < 8; i++)
{
var itemInstrument = Game1.GameManager.ItemManager["instrument" + i];
var position = new Vector2(EntityPosition.X - 8, EntityPosition.Y - 60) + _showInstrumentOffset[i] * percentage;
ItemDrawHelper.DrawItem(spriteBatch, itemInstrument, position, Color.White, 1, true);
}
}
private void DrawLink(SpriteBatch spriteBatch)
{
_sprite.Draw(spriteBatch);
// draw the colored cloak
var texture = _sprite.SprTexture;
var cloakColor = Game1.GameManager.CloakColor;
if (CurrentState == State.CloakShow0 && ShowItem != null && ShowItem.Name == "cloakBlue")
cloakColor = Color.Lerp(cloakColor, ItemDrawHelper.CloakColors[1], _cloakPercentage);
else if (CurrentState == State.CloakShow0 && ShowItem != null && ShowItem.Name == "cloakRed")
cloakColor = Color.Lerp(cloakColor, ItemDrawHelper.CloakColors[2], _cloakPercentage);
_sprite.Color = cloakColor * _spriteTransparency;
_sprite.SprTexture = Resources.SprLinkCloak;
_sprite.Draw(spriteBatch);
_sprite.Color = Color.White * _spriteTransparency;
_sprite.SprTexture = texture;
}
private void DrawNote(SpriteBatch spriteBatch, Vector2 position, Vector2 direction, int noteIndex)
{
var timeOffset = noteIndex * _instrumentCycleTime / 2;
if (_instrumentCounter < timeOffset ||
(CurrentState != State.ShowInstrumentPart1 || _drawInstrumentEffect) &&
((_instrumentCounter - timeOffset) / _instrumentCycleTime + 1) * _instrumentCycleTime + timeOffset > _instrumentEndTime)
return;
var time = (_instrumentCounter + timeOffset) % _instrumentCycleTime;
var transparency = 1.0f;
// fade out
if (time > _instrumentCycleTime - 100)
{
_noteInit[noteIndex] = false;
transparency = (_instrumentCycleTime - time) / 100f;
}
// fade in
else if (time < 100)
{
if (!_noteInit[noteIndex])
{
_noteInit[noteIndex] = true;
_noteSpriteIndex[noteIndex] = Game1.RandomNumber.Next(0, 2);
}
transparency = time / 100;
}
position += direction * time * 0.02f + new Vector2(-direction.X, direction.Y) * (float)Math.Sin(time * 0.015) * 0.75f;
position += new Vector2(
-_noteSourceRectangles[_noteSpriteIndex[noteIndex]].Width / 2f,
-_noteSourceRectangles[_noteSpriteIndex[noteIndex]].Height);
spriteBatch.Draw(Resources.SprItem, position,
_noteSourceRectangles[_noteSpriteIndex[noteIndex]], Color.White * transparency);
}
private void DrawSwordParticle(SpriteBatch spriteBatch, Vector2 position, Vector2 direction, int timeOffset, int fullTime, int timeDelay, int index)
{
var fadeTime = 50;
var particleTime = (_showSwordL2ParticleCounter + timeOffset) % (fullTime + timeDelay);
var percentage = particleTime / fullTime;
var colorTransparency = Math.Min((fullTime - particleTime) / fadeTime, particleTime / fadeTime);
var particlePosition = position + percentage * direction;
var spriteParticle = Resources.GetSprite("sword_particle_" + index);
if (0 < particleTime && particleTime < fullTime)
DrawHelper.DrawNormalized(spriteBatch, spriteParticle.Texture,
particlePosition - spriteParticle.Origin, spriteParticle.ScaledRectangle, Color.White * colorTransparency, spriteParticle.Scale);
}
private void DrawLight(SpriteBatch spriteBatch)
{
DrawHelper.DrawLight(spriteBatch, new Rectangle((int)EntityPosition.X - 45, (int)EntityPosition.Y - 45, 90, 90), new Color(255, 255, 255) * 0.125f);
}
public void DrawTransition(SpriteBatch spriteBatch)
{
if (!IsVisible)
return;
_bodyDrawFunction(spriteBatch);
if (_drawInstrumentEffect)
DrawInstrumentEffect(spriteBatch);
// draw the shown item
if (ShowItem != null)
{
var itemPosition = EntityPosition.Position + _showItemOffset;
ItemDrawHelper.DrawItem(spriteBatch, ShowItem, itemPosition, Color.White, 1, true);
}
}
#endregion
private void OnKeyChange()
{
var strCloak = "cloak_transition";
var cloakTransition = Game1.GameManager.SaveManager.GetString(strCloak);
if (cloakTransition == "1")
{
_cloakTransitionCounter = 0;
_cloakPercentage = 0;
_cloakTransitionOutCounter = 0;
Game1.GameManager.SaveManager.RemoveString(strCloak);
Game1.GameManager.SaveManager.SetString(strCloak, "0");
CurrentState = State.CloakShow0;
}
// play animation?
var strAnimation = "link_direction";
var newDirection = Game1.GameManager.SaveManager.GetString(strAnimation);
if (!string.IsNullOrEmpty(newDirection))
{
Direction = int.Parse(newDirection);
UpdateAnimation();
Game1.GameManager.SaveManager.SetString(strAnimation, null);
}
// start moving? [set:link_move,-16,32]
var moveValue = Game1.GameManager.SaveManager.GetString("link_move");
if (!string.IsNullOrEmpty(moveValue))
{
var split = moveValue.Split(',');
var directionX = float.Parse(split[0], CultureInfo.InvariantCulture);
var directionY = float.Parse(split[1], CultureInfo.InvariantCulture);
var velocity = new Vector2(directionX, directionY);
_body.VelocityTarget = velocity;
Direction = AnimationHelper.GetDirection(velocity);
_isWalking = true;
Game1.GameManager.SaveManager.SetString("link_move_collision", "0");
Game1.GameManager.SaveManager.RemoveString("link_move");
}
var idleValue = Game1.GameManager.SaveManager.GetString("link_idle");
if (!string.IsNullOrEmpty(idleValue))
{
CurrentState = State.Idle;
Game1.GameManager.SaveManager.RemoveString("link_idle");
}
var hideHudValue = Game1.GameManager.SaveManager.GetString("hide_hud");
if (!string.IsNullOrEmpty(hideHudValue))
{
Game1.GameManager.InGameOverlay.HideHud(true);
Game1.GameManager.SaveManager.RemoveString("hide_hud");
}
// start moving? [set:link_push,-16,0,200]
var pushValue = Game1.GameManager.SaveManager.GetString("link_push");
if (!string.IsNullOrEmpty(pushValue))
{
var split = pushValue.Split(',');
// init movement
if (split.Length == 1)
{
_pushStart = EntityPosition.Position;
_pushEnd = new Vector2(80, 94);
_pushTime = int.Parse(split[0]);
}
else
{
var offsetX = float.Parse(split[0], CultureInfo.InvariantCulture);
var offsetY = float.Parse(split[1], CultureInfo.InvariantCulture);
_pushStart = EntityPosition.Position;
_pushEnd = _pushStart + new Vector2(offsetX, offsetY);
_pushTime = int.Parse(split[2]);
}
_pushCounter = 0;
CurrentState = State.Pushed;
Game1.GameManager.SaveManager.RemoveString("link_push");
}
// link animation
var animationValue = Game1.GameManager.SaveManager.GetString("link_animation");
if (!string.IsNullOrEmpty(animationValue))
{
Animation.Play(animationValue);
CurrentState = State.Sequence;
Game1.GameManager.SaveManager.RemoveString("link_animation");
}
var linkFinal = Game1.GameManager.SaveManager.GetString("link_final");
if (!string.IsNullOrEmpty(linkFinal))
{
_finalIndex = 0;
_finalSeqCounter = 1500;
Animation.Play("final_stand_down");
CurrentState = State.FinalInstruments;
Game1.GameManager.SetMusic(62, 2);
Game1.GameManager.SaveManager.RemoveString("link_final");
}
// start diving?
var diveValue = Game1.GameManager.SaveManager.GetString("link_dive");
if (!string.IsNullOrEmpty(diveValue))
{
_diveCounter = int.Parse(diveValue);
CurrentState = State.Swimming;
Game1.GameManager.SaveManager.RemoveString("link_dive");
}
// boomerang trading
// can be exchanged for: shovel, feather
var boomerangValue = Game1.GameManager.SaveManager.GetString("boomerang_trade");
if (!string.IsNullOrEmpty(boomerangValue))
{
Game1.GameManager.SaveManager.RemoveString("boomerang_trade");
if (Game1.GameManager.Equipment[1] != null &&
(Game1.GameManager.Equipment[1].Name == "shovel" ||
Game1.GameManager.Equipment[1].Name == "feather" ||
Game1.GameManager.Equipment[1].Name == "magicRod" ||
Game1.GameManager.Equipment[1].Name == "hookshot"))
{
Game1.GameManager.SaveManager.SetString("tradded_item", Game1.GameManager.Equipment[1].Name);
Game1.GameManager.Equipment[1] = null;
Game1.GameManager.StartDialogPath("npc_hidden_boomerang");
}
else
{
Game1.GameManager.StartDialogPath("npc_hidden_reject");
}
}
var boomerangReturnValue = Game1.GameManager.SaveManager.GetString("boomerang_trade_return");
if (!string.IsNullOrEmpty(boomerangReturnValue))
{
Game1.GameManager.SaveManager.RemoveString("boomerang_trade_return");
// remove the boomerang
Game1.GameManager.RemoveItem("boomerang", 1);
// return the traded item
var tradedItem = Game1.GameManager.SaveManager.GetString("tradded_item");
var item = new GameItemCollected(tradedItem);
MapManager.ObjLink.PickUpItem(item, true);
_pickupDialogOverride = "npc_hidden_4";
}
var spawnGhostValue = Game1.GameManager.SaveManager.GetString(_spawnGhostKey);
if (!string.IsNullOrEmpty(spawnGhostValue))
{
_spawnGhost = true;
}
}
private void OnMoveCollision(Values.BodyCollision collision)
{
// knockback
if (CurrentState == State.Idle && _wasBootsRunning)
{
var knockBack = false;
if ((collision & Values.BodyCollision.Horizontal) != 0 && Direction % 2 == 0)
{
var dirX = (collision & Values.BodyCollision.Left) != 0 ? -1 : 1;
_body.Velocity.X = -dirX;
Game1.GameManager.ShakeScreen(750, 2, 1, 5.5f, 2.5f, dirX, 1);
knockBack = true;
}
if ((collision & Values.BodyCollision.Vertical) != 0 && Direction % 2 != 0)
{
var dirY = (collision & Values.BodyCollision.Top) != 0 ? -1 : 1;
_body.Velocity.Y = -dirY;
Game1.GameManager.ShakeScreen(750, 1, 2, 2.5f, 5.5f, 1, dirY);
knockBack = true;
}
if (knockBack)
{
_bootsRunning = false;
_bootsCounter = 0;
_body.Velocity.Z = 2.0f;
CurrentState = State.BootKnockback;
var damageOrigin = BodyRectangle.Center;
var damageBox = _body.BodyBox.Box;
damageBox.X += AnimationHelper.DirectionOffset[Direction].X;
damageBox.Y += AnimationHelper.DirectionOffset[Direction].Y;
Game1.GameManager.PlaySoundEffect("D360-11-0B");
Map.Objects.Hit(this, damageOrigin, damageBox, HitType.PegasusBootsPush, 0, false);
}
}
// what is this?
if ((collision & Values.BodyCollision.Floor) != 0)
{
_moveVelocity = _lastMoveVelocity * 0.5f;
_lastBaseMoveVelocity = _moveVelocity;
}
if (CurrentState == State.BootKnockback &&
(collision & Values.BodyCollision.Floor) != 0)
{
CurrentState = State.Idle;
_body.Velocity.Z = 0;
}
if (Is2DMode)
OnMoveCollision2D(collision);
else
{
// colliding horizontally or vertically? -> start pushing
if (CurrentState == State.Idle && _isWalking && (
(collision & Values.BodyCollision.Horizontal) != 0 && (Direction == 0 || Direction == 2) ||
(collision & Values.BodyCollision.Vertical) != 0 && (Direction == 1 || Direction == 3)))
{
var box = _body.BodyBox.Box;
// offset by one in the walk direction
box.X += AnimationHelper.DirectionOffset[Direction].X;
box.Y += AnimationHelper.DirectionOffset[Direction].Y;
var cBox = Box.Empty;
var outBox = Box.Empty;
// check if the object we are walking into is actually an object where the push animation should be played
if (Map.Objects.Collision(box, cBox, _body.CollisionTypes, Values.CollisionTypes.PushIgnore, Direction, _body.Level, ref outBox))
CurrentState = State.Pushing;
}
if (CurrentState == State.Swimming)
{
if ((collision & Values.BodyCollision.Horizontal) != 0)
_moveVelocity.X = 0;
if ((collision & Values.BodyCollision.Vertical) != 0)
_moveVelocity.Y = 0;
}
// used for scripting (final stript stop at the top of the stairs)
Game1.GameManager.SaveManager.SetString("link_move_collision", "1");
// stop the hit velocity if the are colliding with a wall
// this was done because the player pushes into the hitVelocity direction
if ((collision & Values.BodyCollision.Horizontal) != 0 && _body.VelocityTarget.X == 0)
_hitVelocity.X = 0;
if ((collision & Values.BodyCollision.Vertical) != 0 && _body.VelocityTarget.Y == 0)
_hitVelocity.Y = 0;
if (CurrentState == State.Charging &&
((collision & Values.BodyCollision.Left) != 0 && Direction == 0 ||
(collision & Values.BodyCollision.Top) != 0 && Direction == 1 ||
(collision & Values.BodyCollision.Right) != 0 && Direction == 2 ||
(collision & Values.BodyCollision.Bottom) != 0 && Direction == 3))
{
if (_swordPokeCounter <= 0)
{
IsPoking = true;
_pokeStart = true;
Animation.Play("poke_" + Direction);
AnimatorWeapons.Play("poke_" + Direction);
CurrentState = State.Attacking;
_swordChargeCounter = SwordChargeTime;
}
_swordPokeCounter -= Game1.DeltaTime;
}
}
}
private void OnHolePull(Vector2 direction, float percentage)
{
// disable jumping if the player stands on top of a hole
// if the hole is 14x14 the player should not be able to stand between the holes and jump out of them
// player 8x10
// hole area while standing between 4 14x14 holes: 2x10 + 2x8 = 36
// 1 - 36/80 = 0.55
if (percentage >= 0.55f)
_canJump = false;
}
private void Update3D()
{
_isWalking = false;
WasHoleReset = false;
if (CurrentState == State.Intro)
{
var walkVelocity = ControlHandler.GetMoveVector2();
if (Animation.CurrentAnimation.Id == "intro_sit" &&
!Game1.GameManager.InGameOverlay.TextboxOverlay.IsOpen && walkVelocity.Length() > Values.ControllerDeadzone)
{
CurrentState = State.Idle;
Direction = 2;
StartRailJump(EntityPosition.Position + new Vector2(12, 4), 1, 1);
Animation.Play("intro_jump");
Game1.GameManager.SaveManager.SetString("played_intro", "1");
}
return;
}
// finished jumping into the bed?
if (_startBedTransition && CurrentState == State.Idle)
{
CurrentState = State.BedTransition;
_startBedTransition = false;
Animation.Play("bed");
}
if (CurrentState == State.BedTransition)
return;
if (CurrentState == State.SwordShow0)
{
if (!Animation.IsPlaying)
{
Animation.Play("show2");
_showSwordLv2Counter = 500;
CurrentState = State.SwordShow1;
Game1.GameManager.PlaySoundEffect("D360-07-07");
var animation = new ObjAnimator(Map, 0, 0, Values.LayerTop, "Particles/swordPoke", "run", true);
animation.EntityPosition.Set(new Vector2(
BodyRectangle.X,
EntityPosition.Y - EntityPosition.Z - 30));
Map.Objects.SpawnObject(animation);
}
else
return;
}
else if (CurrentState == State.SwordShow1)
{
_showSwordLv2Counter -= Game1.DeltaTime;
if (_showSwordLv2Counter < 0)
CurrentState = State.Idle;
}
if (_isRafting && (CurrentState == State.Rafting || CurrentState == State.Charging))
{
var moveVelocity = ControlHandler.GetMoveVector2();
var moveVelocityLength = moveVelocity.Length();
if (moveVelocityLength > 1)
moveVelocity.Normalize();
if (moveVelocityLength > Values.ControllerDeadzone)
{
_isWalking = true;
_objRaft.TargetVelocity(moveVelocity * 0.5f);
if (CurrentState != State.Charging)
{
var vectorDirection = ToDirection(moveVelocity);
Direction = vectorDirection;
}
}
}
if (_isFlying && CurrentState == State.Carrying)
{
var moveVelocity = ControlHandler.GetMoveVector2();
var moveVelocityLength = moveVelocity.Length();
if (moveVelocityLength > 1)
moveVelocity.Normalize();
if (moveVelocityLength > Values.ControllerDeadzone)
{
_objRooster.TargetVelocity(moveVelocity, 0.5f, Direction);
var vectorDirection = ToDirection(moveVelocity);
Direction = vectorDirection;
}
}
// we need to prevent overlays from being opened because they do not stop the music and it would run out of sync
if ((ShowItem != null && ShowItem.Name.StartsWith("instrument")) ||
CurrentState == State.ShowInstrumentPart0 ||
CurrentState == State.ShowInstrumentPart1 ||
CurrentState == State.ShowInstrumentPart2 ||
CurrentState == State.ShowInstrumentPart3)
Game1.GameManager.InGameOverlay.DisableInventoryToggle = true;
if (CurrentState == State.ShowInstrumentPart0)
{
// is the sound effect still playing?
if (_instrumentPickupTime + 7500 < Game1.TotalGameTime)
{
Game1.GameManager.SetMusic(_instrumentMusicIndex[_instrumentIndex], 2);
Game1.GbsPlayer.Play();
Game1.GbsPlayer.SoundGenerator.SetStopTime(8);
CurrentState = State.ShowInstrumentPart1;
}
}
else if (CurrentState == State.ShowInstrumentPart1)
{
_instrumentCounter += Game1.DeltaTime;
if (_instrumentCounter > 3500)
{
_drawInstrumentEffect = true;
Game1.GameManager.PlaySoundEffect("D360-43-2B", false);
}
if (Game1.GbsPlayer.SoundGenerator.WasStopped && Game1.GbsPlayer.SoundGenerator.FinishedPlaying())
{
Game1.GameManager.SetMusic(-1, 0);
Game1.GameManager.SetMusic(-1, 2);
Game1.GameManager.PlaySoundEffect("D378-44-2C");
_instrumentCounter = 0;
CurrentState = State.ShowInstrumentPart2;
}
}
else if (CurrentState == State.ShowInstrumentPart2)
{
_instrumentCounter += Game1.DeltaTime;
var transitionSystem = (MapTransitionSystem)Game1.GameManager.GameSystems[typeof(MapTransitionSystem)];
transitionSystem.SetColorMode(Color.White, MathHelper.Clamp(_instrumentCounter / 500f, 0, 1));
if (_instrumentCounter > 2500)
{
Direction = 3;
UpdateAnimation();
CurrentState = State.ShowInstrumentPart3;
ShowItem = null;
_drawInstrumentEffect = false;
Game1.GameManager.StartDialogPath($"instrument{_instrumentIndex}Collected");
}
}
else if (CurrentState == State.ShowInstrumentPart3)
{
MapTransitionStart = EntityPosition.Position;
MapTransitionEnd = MapTransitionStart;
TransitionOutWalking = false;
EndPickup();
// append a map change
((MapTransitionSystem)Game1.GameManager.GameSystems[typeof(MapTransitionSystem)]).AppendMapChange(
"overworld.map", $"d{_instrumentIndex + 1}Finished", false, true, Color.White, true);
}
if (CurrentState == State.Teleporting)
{
if (_teleportCounterFull < 1250 || Direction <= 2)
_teleportCounter += Game1.DeltaTime;
_teleportCounterFull += Game1.DeltaTime;
var rotationSpeed = 150 - (float)Math.Sin((_teleportCounterFull / 2000f) * Math.PI) * 50;
if (_teleportCounter > rotationSpeed)
{
_teleportCounter -= rotationSpeed;
Direction = (Direction + 1) % 4;
UpdateAnimation();
}
var transitionSystem = (MapTransitionSystem)Game1.GameManager.GameSystems[typeof(MapTransitionSystem)];
if (_teleportState == 0 && _teleportCounterFull >= 1250)
{
if (_teleporter != null)
{
_teleportState = 1;
EntityPosition.Set(_teleporter.TeleportPosition);
_teleporter.Lock();
var goalPosition = Game1.GameManager.MapManager.GetCameraTarget();
MapManager.Camera.SoftUpdate(goalPosition);
}
else if (Direction == 3 && _teleportCounterFull >= 1450)
{
MapTransitionStart = EntityPosition.Position;
MapTransitionEnd = EntityPosition.Position;
TransitionOutWalking = false;
transitionSystem.AppendMapChange(_teleportMap, _teleporterId, false, true, Color.White, true);
}
transitionSystem.SetColorMode(Color.White, 1);
}
var fadeOutTime = 250.0f;
var fadeoutStart = 1750;
var fadeoutEnd = 1750 + fadeOutTime;
// fading in
if (_teleportCounterFull >= 750 && _teleportCounterFull < 1250)
{
transitionSystem.SetColorMode(Color.White, (_teleportCounterFull - 750) / 500f);
}
// fading out
else if (_teleportState == 1 && _teleportCounterFull >= fadeoutStart && _teleportCounterFull < fadeoutEnd)
{
transitionSystem.SetColorMode(Color.White, 1 - (_teleportCounterFull - fadeoutStart) / fadeOutTime);
}
// finished?
else if (_teleportState == 1 && _teleportCounterFull >= fadeoutEnd)
{
_drawBody.Layer = Values.LayerPlayer;
transitionSystem.SetColorMode(Color.White, 0);
CurrentState = State.Idle;
}
}
UpdateSwimming();
UpdateIgnoresZ();
// hinox should throw the player farther than normal
if (CurrentState == State.Stunned)
_body.DragAir = 0.95f;
else
_body.DragAir = 0.9f;
// save the last position the player is grounded to use for the reset position if the player drowns
if (CurrentState != State.Jumping && CurrentState != State.Drowning && CurrentState != State.Drowned && _body.IsGrounded)
{
var bodyCenter = new Vector2(EntityPosition.X, EntityPosition.Y - _body.Height / 2f);
// center the position
// can lead to the position being inside something
bodyCenter.X = (int)(bodyCenter.X / 16) * 16 + 8;
bodyCenter.Y = (int)(bodyCenter.Y / 16) * 16 + 8 + _body.Height / 2f;
// found new reset position?
if (!Map.GetFieldState(bodyCenter).HasFlag(MapStates.FieldStates.DeepWater))
{
var bodyBox = new Box(
bodyCenter.X + _body.OffsetX,
bodyCenter.Y + _body.OffsetY, 0, _body.Width, _body.Height, _body.Depth);
var cBox = Box.Empty;
// check it the player is not standing inside something
if (!Map.Objects.Collision(bodyBox, Box.Empty, _body.CollisionTypes | Values.CollisionTypes.DrownExclude, 0, 0, ref cBox))
_drownResetPosition = bodyCenter;
}
}
// walk
UpdateWalking();
if (CurrentState == State.Drowning)
{
if (_drownCounter < 300)
{
_body.Velocity = Vector3.Zero;
// align the player to the pixel grid
EntityPosition.Set(new Vector2(
MathF.Round(EntityPosition.X), MathF.Round(EntityPosition.Y)));
}
_drownCounter -= Game1.DeltaTime;
if (_drownCounter <= 0)
{
IsVisible = false;
CurrentState = State.Drowned;
_drownResetCounter = 500;
}
}
if (CurrentState == State.Drowned)
{
_drownResetCounter -= Game1.DeltaTime;
if (_drownResetCounter <= 0)
{
CurrentState = State.Idle;
CanWalk = true;
IsVisible = true;
_hitCount = CooldownTime;
Game1.GameManager.CurrentHealth -= 2;
_body.CurrentFieldState = MapStates.FieldStates.None;
EntityPosition.Set(_drownResetPosition);
}
}
if (CurrentState == State.Swimming)
{
if (_diveCounter > -100)
{
_diveCounter -= Game1.DeltaTime;
// stop diving
if (ControlHandler.ButtonPressed(CButtons.B))
_diveCounter = 0;
}
// start diving
else if (ControlHandler.ButtonPressed(CButtons.B))
{
StartDiving(1500);
}
if (_swimBoostCount > -300)
_swimBoostCount -= Game1.DeltaTime;
else if (ControlHandler.ButtonPressed(CButtons.A))
_swimBoostCount = 300;
if (_swimBoostCount > 0)
_moveVelocity *= SwimSpeedA;
else
_moveVelocity *= SwimSpeed;
var distance = _moveVelocity - _swimVelocity;
var length = distance.Length();
if (distance != Vector2.Zero)
distance.Normalize();
if (length < 0.045f)
_swimVelocity = _moveVelocity;
else
_swimVelocity += distance * (_swimBoostCount > 0 ? 0.06f : 0.045f) * Game1.TimeMultiplier;
_moveVelocity = _swimVelocity;
}
// slows down the walk movement when the player is hit
var moveMultiplier = MathHelper.Clamp(1f - _hitVelocity.Length(), 0, 1);
// move the player
if (CurrentState != State.Hookshot)
{
_body.VelocityTarget = _moveVelocity * moveMultiplier + _hitVelocity;
}
LastMoveVector = _moveVelocity;
_moveVelocity = Vector2.Zero;
if (_hitCount > 0 && _hitVelocity.Length() > 0.05f * Game1.TimeMultiplier)
{
var hitNormal = _hitVelocity;
hitNormal.Normalize();
var slowDownAmount = 0.05f + MathHelper.Clamp(_hitVelocity.Length() / 25f, 0, 0.05f);
_hitVelocity -= hitNormal * slowDownAmount * Game1.TimeMultiplier;
}
else
_hitVelocity = Vector2.Zero;
// update the jump logic
UpdateJump();
// hole falling logic
{
// update position used to reset the player if he falls into a hole
UpdateSavePosition();
// change the room?
if (_isFallingIntoHole)
{
_holeFallCounter -= Game1.DeltaTime;
if (_holeFallCounter <= 0)
{
_isFallingIntoHole = false;
if (HoleResetRoom != null)
{
// append a map change
((MapTransitionSystem)Game1.GameManager.GameSystems[
typeof(MapTransitionSystem)]).AppendMapChange(HoleResetRoom, HoleResetEntryId);
}
// teleport on hole fall?
else if (HoleTeleporterId >= 0)
{
_holeTeleportCounter = 0;
CurrentState = State.TeleporterUpWait;
}
}
}
HoleTeleporterId = -1;
// finished falling down the hole?
if (CurrentState == State.Falling && !Animation.IsPlaying)
OnHoleReset();
}
// update links animation
UpdateAnimation();
UpdateGhostSpawn();
// stop push animation
if (CurrentState == State.Pushing)
CurrentState = State.Idle;
_lastFieldState = _body.CurrentFieldState;
}
private void UpdateSwimming()
{
// we cant use the field state of the body because the raft updates the state while exiting
var fieldState = SystemBody.GetFieldState(_body);
// start/stop swimming or drowning
if (!_isRafting && !_isFlying && fieldState.HasFlag(MapStates.FieldStates.DeepWater) && CurrentState != State.Dying)
{
if (CurrentState != State.Jumping && _body.IsGrounded && CurrentState != State.PickingUp)
{
ReleaseCarriedObject();
var inLava = fieldState.HasFlag(MapStates.FieldStates.Lava);
if ((HasFlippers && !inLava) && CurrentState != State.Swimming)
{
CurrentState = State.Swimming;
// only push the player if he walks into the water and does not jump
if (!_lastFieldState.HasFlag(fieldState))
_body.Velocity = new Vector3(_body.VelocityTarget.X, _body.VelocityTarget.Y, 0) * 0.75f;
// splash effect
var splashAnimator = new ObjAnimator(Map, 0, 0, 0, 3, Values.LayerPlayer, "Particles/splash", "idle", true);
splashAnimator.EntityPosition.Set(new Vector2(
_body.Position.X + _body.OffsetX + _body.Width / 2f,
_body.Position.Y + _body.OffsetY + _body.Height - _body.Position.Z - 6));
Map.Objects.SpawnObject(splashAnimator);
Game1.GameManager.PlaySoundEffect("D360-14-0E");
_diveCounter = 0;
_swimBoostCount = 0;
_swimVelocity = Vector2.Zero;
}
else if (!HasFlippers || inLava)
{
if (CurrentState != State.Drowning && CurrentState != State.Drowned)
{
// only push the player if he walks into the water and does not jump
if (!_lastFieldState.HasFlag(fieldState))
_body.Velocity = new Vector3(_body.VelocityTarget.X, _body.VelocityTarget.Y, 0) * 0.5f;
// splash effect
var splashAnimator = new ObjAnimator(Map, 0, 0, 0, 3, Values.LayerPlayer, "Particles/splash", "idle", true);
splashAnimator.EntityPosition.Set(new Vector2(
_body.Position.X + _body.OffsetX + _body.Width / 2f,
_body.Position.Y + _body.OffsetY + _body.Height - _body.Position.Z - 6));
Map.Objects.SpawnObject(splashAnimator);
Game1.GameManager.PlaySoundEffect("D370-03-03");
CurrentState = State.Drowning;
_drownCounter = 650;
// blink in lava
_hitCount = inLava ? CooldownTime : 0;
}
}
}
}
else if (CurrentState == State.Swimming && (!IsTransitioning || !Map.Is2dMap))
CurrentState = State.Idle;
if (CurrentState == State.Swimming)
{
EntityPosition.Z = 0;
_body.IsGrounded = true;
}
}
private void UpdateIgnoresZ()
{
if (CurrentState == State.Swimming ||
CurrentState == State.Hookshot ||
CurrentState == State.TeleporterUp ||
CurrentState == State.TeleportFallWait || _isFlying || _isGrabbed || _isClimbing)
_body.IgnoresZ = true;
else
_body.IgnoresZ = false;
}
private void UpdateWalking()
{
if (CurrentState != State.Idle && (CurrentState != State.Carrying || _isFlying) && CurrentState != State.Charging && CurrentState != State.Swimming &&
CurrentState != State.CarryingItem && (CurrentState != State.MagicRod || _body.IsGrounded) && (CurrentState != State.Jumping || _railJump) &&
CurrentState != State.Pushing && CurrentState != State.Blocking && CurrentState != State.Attacking ||
!CanWalk || _isRafting) return;
var walkVelocity = Vector2.Zero;
if (!_isLocked && (CurrentState != State.Attacking || !_body.IsGrounded))
walkVelocity = ControlHandler.GetMoveVector2();
var walkVelLength = walkVelocity.Length();
if (walkVelLength > 1)
walkVelocity.Normalize();
var vectorDirection = ToDirection(walkVelocity);
if (_bootsRunning && (walkVelLength < Values.ControllerDeadzone || vectorDirection != (Direction + 2) % 4))
{
if (!_bootsStop)
{
_moveVelocity = AnimationHelper.DirectionOffset[Direction] * BootsRunningSpeed;
// can move up or down while running
if (Direction % 2 != 0)
_moveVelocity.X += walkVelocity.X;
else if (Direction % 2 == 0)
_moveVelocity.Y += walkVelocity.Y;
}
}
else if (walkVelLength > Values.ControllerDeadzone)
{
_bootsCounter %= _bootsParticleTime;
_bootsRunning = false;
#if DEBUG
if (InputHandler.KeyDown(Keys.LeftShift))
walkVelocity *= 0.25f;
#endif
// slow down in the grass
if (_body.CurrentFieldState.HasFlag(MapStates.FieldStates.Grass) && _body.IsGrounded)
_currentWalkSpeed *= 0.8f;
// slow down in the water
if (_body.CurrentFieldState.HasFlag(MapStates.FieldStates.Water) && _body.IsGrounded)
{
_currentWalkSpeed *= 0.8f;
_waterSoundCounter += Game1.DeltaTime;
if (_waterSoundCounter > 250)
{
_waterSoundCounter -= 250;
Game1.GameManager.PlaySoundEffect("D360-14-0E", false);
}
}
// do not walk when trapped
if (!_isTrapped)
{
_isWalking = true;
if (_body.IsGrounded)
{
// after hitting the ground we still have _lastMoveVelocity
if (!_body.WasGrounded)
_moveVelocity = Vector2.Zero;
_moveVelocity += walkVelocity * _currentWalkSpeed;
}
}
// update the direction the player is facing
if (CurrentState != State.Attacking && CurrentState != State.Charging)
Direction = vectorDirection;
}
_lastBaseMoveVelocity = _moveVelocity;
// when we walk of a cliff set the air move vector
// we need to make sure that the player did not started jumping
if (!_startedJumping && !_hasStartedJumping && _body.WasGrounded && !_body.IsGrounded)
_lastMoveVelocity = _moveVelocity;
// the player has momentum when he is in the air and can not be controlled directly like on the ground
if (!_body.IsGrounded || _body.Velocity.Z > 0)
{
var distance = (_lastMoveVelocity - walkVelocity * _currentWalkSpeed).Length();
// trying to move in the air? => slowly change the direction in the air
if (distance > 0 && walkVelocity != Vector2.Zero)
{
var amount = Math.Clamp((0.05f / distance) * Game1.TimeMultiplier, 0, 1);
_lastMoveVelocity = Vector2.Lerp(_lastMoveVelocity, walkVelocity * _currentWalkSpeed, amount);
}
_moveVelocity = _lastMoveVelocity;
}
}
private void UpdateAnimation()
{
if (Game1.GameManager.UseShockEffect)
return;
var shieldString = Game1.GameManager.ShieldLevel == 2 ? "ms_" : "s_";
if (!CarryShield)
shieldString = "_";
if (_bootsHolding || _bootsRunning)
{
if (!_bootsRunning)
Animation.Play("walk" + shieldString + Direction);
else
{
// run while blocking with the shield
Animation.Play((CarryShield ? "walkb" : "walk") + shieldString + Direction);
}
Animation.SpeedMultiplier = 2.0f;
return;
}
Animation.SpeedMultiplier = 1.0f;
if (CurrentState == State.Idle && !_isWalking ||
CurrentState == State.Charging && !_isWalking ||
CurrentState == State.Rafting && !_isWalking ||
CurrentState == State.Teleporting ||
CurrentState == State.ShowInstrumentPart3 ||
CurrentState == State.TeleportFall ||
CurrentState == State.TeleporterUp ||
CurrentState == State.FallRotateEntry)
Animation.Play("stand" + shieldString + Direction);
else if ((
CurrentState == State.Idle ||
CurrentState == State.Charging ||
CurrentState == State.Rafting) && _isWalking)
Animation.Play("walk" + shieldString + Direction);
else if (CurrentState == State.Blocking)
Animation.Play((!_isWalking ? "standb" : "walkb") + shieldString + Direction);
else if ((CurrentState == State.Carrying || CurrentState == State.CarryingItem) && !_isFlying)
Animation.Play((!_isWalking ? "standc_" : "walkc_") + Direction);
else if (CurrentState == State.Carrying && _isFlying)
Animation.Play("flying_" + Direction);
else if (CurrentState == State.Pushing)
Animation.Play("push_" + Direction);
else if (CurrentState == State.Grabbing)
Animation.Play("grab_" + Direction);
else if (CurrentState == State.Pulling)
Animation.Play("pull_" + Direction);
else if (CurrentState == State.Swimming)
{
Animation.Play(_diveCounter > 0 ? "dive" : "swim_" + Direction);
if (_swimVelocity.Length() < 0.1 && !IsTransitioning)
Animation.IsPlaying = false;
}
else if (CurrentState == State.Drowning)
Animation.Play(_drownCounter > 300 ? "swim_" + Direction : "dive");
}
private void UpdateHeartWarningSound()
{
if (Game1.GameManager.CurrentHealth <= 4)
{
}
}
private void UpdateDive()
{
_diveCounter -= Game1.DeltaTime;
}
private void UpdateDamageShader()
{
if (_hitCount > 0)
_sprite.SpriteShader = (CooldownTime - _hitCount) % (BlinkTime * 2) < BlinkTime ? Resources.DamageSpriteShader0 : null;
else
_sprite.SpriteShader = null;
}
private void UpdateSavePosition()
{
var bodyCenter = _body.BodyBox.Box.Center;
var currentTilePosition = new Point(((int)bodyCenter.X - Map.MapOffsetX * 16) / 160, ((int)bodyCenter.Y - Map.MapOffsetY * 16) / 128);
var tileDiff = currentTilePosition - _lastTilePosition;
var newResetPosition = _holeResetPoint;
_lastTilePosition = currentTilePosition;
// update position?
if (tileDiff != Point.Zero)
{
var tileSize = 16;
_alternativeHoleResetPosition = Vector2.Zero;
if (tileDiff.X == 0)
newResetPosition.X = EntityPosition.X;
else
{
if (tileDiff.X > 0)
newResetPosition.X = (int)(bodyCenter.X / tileSize) * tileSize;
else
newResetPosition.X = (int)(bodyCenter.X / tileSize + 1) * tileSize;
}
if (tileDiff.Y == 0)
newResetPosition.Y = EntityPosition.Y;
else
{
if (tileDiff.Y > 0)
newResetPosition.Y = (int)(bodyCenter.Y / tileSize) * tileSize;
else
newResetPosition.Y = (int)(bodyCenter.Y / tileSize + 1) * tileSize;
}
// check if there is no hole at the new position
var bodyBox = new Box(newResetPosition.X + _body.BodyBox.OffsetX, newResetPosition.Y + _body.BodyBox.OffsetY, 0, _body.Width, _body.Height, 8);
var outBox = Box.Empty;
if (!Map.Objects.Collision(bodyBox, Box.Empty, Values.CollisionTypes.Hole, 0, 0, ref outBox))
_holeResetPoint = newResetPosition;
}
}
public void UpdateSaveLocation()
{
MapManager.ObjLink.SaveMap = Map.MapName;
MapManager.ObjLink.SavePosition = EntityPosition.Position;
MapManager.ObjLink.SaveDirection = Direction;
}
private void SetHoleResetPosition(Vector2 newResetPosition)
{
_holeResetPoint = newResetPosition;
var offset = Map != null ? new Point(Map.MapOffsetX, Map.MapOffsetY) : Point.Zero;
_lastTilePosition = new Point(((int)newResetPosition.X - offset.X * 16) / 160, ((int)newResetPosition.Y - offset.Y * 16) / 128);
}
private void UpdateDrawComponents()
{
if (_drawInstrumentEffect)
_drawBody.Layer = Values.LayerTop;
else
_drawBody.Layer = (CurrentState == State.Swimming && _diveCounter > 0) ? Values.LayerBottom : Values.LayerPlayer;
if (CurrentState == State.Swimming && _diveCounter > 0 ||
CurrentState == State.Drowning ||
CurrentState == State.Drowned ||
CurrentState == State.BedTransition ||
_isTrapped)
_shadowComponent.IsActive = false;
else
_shadowComponent.IsActive = true;
}
private void StartDiving(int diveTime)
{
// splash effect
var splashAnimator = new ObjAnimator(Map, 0, 0, 0, 0, Values.LayerTop, "Particles/splash", "idle", true);
splashAnimator.EntityPosition.Set(new Vector2(
_body.Position.X + _body.OffsetX + _body.Width / 2f,
_body.Position.Y + _body.OffsetY + _body.Height - _body.Position.Z - 3));
Map.Objects.SpawnObject(splashAnimator);
Game1.GameManager.PlaySoundEffect("D360-14-0E");
_diveCounter = diveTime;
}
private void OnHoleReset()
{
// change the room?
if (HoleResetRoom != null)
return;
_isFallingIntoHole = false;
CurrentState = State.Idle;
CanWalk = true;
_hitCount = CooldownTime;
Game1.GameManager.InflictDamage(2);
MoveToHoleResetPosition();
}
private void MoveToHoleResetPosition()
{
WasHoleReset = true;
EntityPosition.Set(_holeResetPoint);
// alternative reset point
var cBox = Box.Empty;
if (_alternativeHoleResetPosition != Vector2.Zero &&
Map.Objects.Collision(_body.BodyBox.Box, Box.Empty, _body.CollisionTypes, 0, 0, ref cBox))
{
EntityPosition.Set(_alternativeHoleResetPosition);
}
}
private bool InteractWithObject()
{
var boxSize = 6;
var interactionBox = new Box(
EntityPosition.X + _walkDirection[Direction].X * (BodyRectangle.Width / 2 + boxSize / 2) - boxSize / 2,
BodyRectangle.Center.Y + _walkDirection[Direction].Y * (BodyRectangle.Height / 2 + boxSize / 2) - boxSize / 2, 0,
boxSize, boxSize, 16);
return Map.Objects.InteractWithObject(interactionBox);
}
private void ReturnToIdle()
{
// Return to idle or to rafting if that was the player was rafting before
if (_isRafting)
CurrentState = State.Rafting;
else
CurrentState = State.Idle;
}
private void UpdateGhostSpawn()
{
if (!_spawnGhost || !Map.IsOverworld)
return;
var dungeonEntryPosition = new Vector2(1840, 272);
var distance = MapManager.ObjLink.EntityPosition.Position - dungeonEntryPosition;
if (MathF.Abs(distance.X) > 512 || MathF.Abs(distance.Y) > 256)
{
_spawnGhost = false;
Game1.GameManager.SaveManager.RemoveString(_spawnGhostKey);
Game1.GameManager.CollectItem(new GameItemCollected("ghost") { Count = 1 }, 0);
UpdateFollower(false);
_objGhost.StartFollowing();
}
}
#region item stuff
private void UpdateItem()
{
if (CurrentState == State.Blocking)
CurrentState = State.Idle;
else
_wasBlocking = false;
if (CurrentState == State.Grabbing || CurrentState == State.Pulling)
CurrentState = State.Idle;
_isPulling = false;
_isHoldingSword = false;
_bootsHolding = false;
if (!_isLocked)
{
// interact with object
if ((CurrentState == State.Idle || CurrentState == State.Pushing || CurrentState == State.Swimming || CurrentState == State.CarryingItem) &&
ControlHandler.ButtonPressed(CButtons.A) && InteractWithObject())
InputHandler.ResetInputState();
if (_isTrapped && !_trappedDisableItems &&
(ControlHandler.ButtonPressed(CButtons.A) ||
ControlHandler.ButtonPressed(CButtons.B) ||
ControlHandler.ButtonPressed(CButtons.X) ||
ControlHandler.ButtonPressed(CButtons.Y)))
{
_trapInteractionCount--;
if (_trapInteractionCount <= 0)
FreeTrappedPlayer();
}
// use/hold item
if (!DisableItems && (!_isTrapped || !_trappedDisableItems))
{
for (var i = 0; i < Values.HandItemSlots; i++)
{
if (Game1.GameManager.Equipment[i] != null &&
ControlHandler.ButtonPressed((CButtons)((int)CButtons.A * Math.Pow(2, i))))
UseItem(Game1.GameManager.Equipment[i]);
if (Game1.GameManager.Equipment[i] != null &&
ControlHandler.ButtonDown((CButtons)((int)CButtons.A * Math.Pow(2, i))))
HoldItem(Game1.GameManager.Equipment[i],
ControlHandler.LastButtonDown((CButtons)((int)CButtons.A * Math.Pow(2, i))));
}
}
}
UpdatePegasusBoots();
// shield pushing
if (CurrentState == State.Blocking || _bootsRunning && CarryShield)
UpdateShieldPush();
// pick up animation
if (CurrentState == State.PreCarrying)
{
_preCarryCounter += Game1.DeltaTime;
// change the animation of the player depending on where the picked up object is
if (_preCarryCounter > 100)
Animation.Play("standc_" + Direction);
UpdatePositionCarriedObject(EntityPosition);
}
// stop attacking
if (CurrentState == State.Attacking && !Animation.IsPlaying)
{
_isSwingingSword = false;
if (!_isHoldingSword || _swordPoked || _stopCharging)
ReturnToIdle();
else
{
// start charging sword
CurrentState = State.Charging;
AnimatorWeapons.Play("stand_" + Direction);
_swordPokeCounter = _swordPokeTime;
}
}
if (CurrentState == State.Charging)
UpdateCharging();
// hit stuff with the sword
if (CurrentState == State.Attacking || _bootsRunning && CarrySword)
UpdateAttacking();
if (CurrentState == State.PickingUp)
UpdatePickup();
if (!Animation.IsPlaying &&
(CurrentState == State.Powdering || CurrentState == State.Bombing || CurrentState == State.MagicRod || CurrentState == State.Throwing))
ReturnToIdle();
if (CurrentState == State.Hookshot)
UpdateHookshot();
if (CurrentState == State.Digging)
UpdateDigging();
_wasPulling = _isPulling;
}
private void UseItem(GameItemCollected item)
{
switch (item.Name)
{
case "sword1":
case "sword2":
UseSword();
break;
case "feather":
UseFeather();
break;
case "toadstool":
UseToadstool();
break;
case "powder":
UsePowder();
break;
case "bomb":
UseBomb();
break;
case "bow":
UseArrow();
break;
case "shovel":
UseShovel();
break;
case "stonelifter":
case "stonelifter2":
UseStoneLifter();
break;
case "hookshot":
UseHookshot();
break;
case "boomerang":
UseBoomerang();
break;
case "magicRod":
UseMagicRod();
break;
case "ocarina":
UseOcarina();
break;
}
}
private void HoldItem(GameItemCollected item, bool lastKeyDown)
{
switch (item.Name)
{
case "sword1":
HoldSword();
break;
case "sword2":
HoldSword();
break;
case "shield":
case "mirrorShield":
HoldShield(lastKeyDown);
break;
case "stonelifter":
case "stonelifter2":
HoldStoneLifter();
break;
case "pegasusBoots":
HoldPegasusBoots();
break;
}
}
private void UseSword()
{
if (CurrentState != State.Idle && CurrentState != State.Pushing && CurrentState != State.Rafting &&
(CurrentState != State.Jumping || _railJump) && (CurrentState != State.Swimming || !Map.Is2dMap))
return;
var slashSounds = new[] { "D378-02-02", "D378-20-14", "D378-21-15", "D378-24-18" };
Game1.GameManager.PlaySoundEffect(slashSounds[Game1.RandomNumber.Next(0, 4)]);
Animation.Play("attack_" + Direction);
AnimatorWeapons.Play("attack_" + Direction);
_swordChargeCounter = SwordChargeTime;
IsPoking = false;
_pokeStart = false;
_stopCharging = false;
_swordPoked = false;
_shotSword = false;
StopRaft();
CurrentState = State.Attacking;
}
private void HoldSword()
{
_isHoldingSword = true;
}
private void UseFeather()
{
if (Is2DMode)
Jump2D();
else
Jump();
}
private void UseToadstool()
{
CurrentState = State.ShowToadstool;
Animation.Play("show2");
Game1.GameManager.StartDialogPath("toadstool_hole");
}
private void UsePowder()
{
if (CurrentState != State.Idle &&
CurrentState != State.Jumping &&
CurrentState != State.Rafting &&
(CurrentState != State.Swimming || !Map.Is2dMap))
return;
// remove one powder from the inventory
if (!Game1.GameManager.RemoveItem("powder", 1))
return;
var spawnPosition = new Vector2(EntityPosition.X, EntityPosition.Y) + _powderOffset[Direction];
Map.Objects.SpawnObject(new ObjPowder(Map, spawnPosition.X, spawnPosition.Y, EntityPosition.Z, true));
if (CurrentState != State.Jumping)
{
StopRaft();
CurrentState = State.Powdering;
Animation.Play("powder_" + Direction);
}
}
private void UseBomb()
{
// throw the object the player is currently carrying
if (_carriedGameObject != null)
{
ThrowCarriedObject();
return;
}
if (CurrentState != State.Idle &&
CurrentState != State.Rafting &&
(CurrentState != State.Swimming || !Map.Is2dMap))
return;
// pick up the bomb if there is one infront of the player
var recInteraction = new RectangleF(
EntityPosition.X + _walkDirection[Direction].X * (_body.Width / 2) - 4,
EntityPosition.Y - _body.Height / 2 + _walkDirection[Direction].Y * (_body.Height / 2) - 4, 8, 8);
// find a bomb to carry
_bombList.Clear();
Map.Objects.GetObjectsOfType(_bombList, typeof(ObjBomb),
(int)recInteraction.X, (int)recInteraction.Y, (int)recInteraction.Width, (int)recInteraction.Height);
// pick up the first bomb
foreach (var objBomb in _bombList)
{
var carriableComponent = objBomb.Components[CarriableComponent.Index] as CarriableComponent;
if (!carriableComponent.IsActive ||
!carriableComponent.Rectangle.Rectangle.Intersects(recInteraction))
continue;
carriableComponent?.StartGrabbing?.Invoke();
StartPickup(carriableComponent);
Animation.Play("pull_" + Direction);
return;
}
// remove one bomb from the inventory
if (!Game1.GameManager.RemoveItem("bomb", 1))
return;
var spawnPosition = new Vector2(EntityPosition.X, EntityPosition.Y) + _bombOffset[Direction];
Map.Objects.SpawnObject(new ObjBomb(Map, spawnPosition.X, spawnPosition.Y, true, false, 2000));
CurrentState = State.Bombing;
// play animation
Animation.Play("powder_" + Direction);
}
private void UseArrow()
{
if (CurrentState != State.Idle &&
CurrentState != State.Jumping &&
CurrentState != State.Rafting &&
CurrentState != State.Bombing &&
(CurrentState != State.Swimming || !Map.Is2dMap))
return;
// remove one powder from the inventory
if (!Game1.GameManager.RemoveItem("bow", 1))
return;
var spawnPosition = new Vector3(
EntityPosition.X + _arrowOffset[Direction].X, EntityPosition.Y + _arrowOffset[Direction].Y + (Map.Is2dMap ? -4 : 0), EntityPosition.Z + (Map.Is2dMap ? 0 : 4));
Map.Objects.SpawnObject(new ObjArrow(
Map, spawnPosition, Direction, Game1.GameManager.PieceOfPowerIsActive ? ArrowSpeedPoP : ArrowSpeed));
if (CurrentState != State.Jumping)
{
StopRaft();
CurrentState = State.Powdering;
Animation.Play("powder_" + Direction);
}
Game1.GameManager.PlaySoundEffect("D378-10-0A");
}
private void UseShovel()
{
if (CurrentState != State.Idle || _isClimbing)
return;
CurrentState = State.Digging;
_hasDug = false;
// play animation
Animation.Play("dig_" + Direction);
_digPosition = new Point(
(int)((EntityPosition.X + _shovelOffset[Direction].X) / Values.TileSize),
(int)((EntityPosition.Y + _shovelOffset[Direction].Y) / Values.TileSize));
_canDig = Map.CanDig(_digPosition);
if (_canDig)
Game1.GameManager.PlaySoundEffect("D378-14-0E");
else
Game1.GameManager.PlaySoundEffect("D360-07-07");
}
private void UseStoneLifter()
{
if (_carriedComponent == null || CurrentState != State.Carrying)
return;
if (Map.Is2dMap && _isClimbing)
return;
ThrowCarriedObject();
}
private void HoldStoneLifter()
{
if (CurrentState != State.Idle)
return;
GameObject grabbedObject = null;
if (_carriedComponent == null)
{
var recInteraction = new RectangleF(
EntityPosition.X + _walkDirection[Direction].X * (_body.Width / 2) - 1,
EntityPosition.Y - _body.Height / 2 + _walkDirection[Direction].Y * (_body.Height / 2) - 1, 2, 2);
// find an object to carry
grabbedObject = Map.Objects.GetCarryableObjects(recInteraction);
if (grabbedObject != null)
{
var carriableComponent = grabbedObject.Components[CarriableComponent.Index] as CarriableComponent;
if (carriableComponent.IsActive)
{
CurrentState = State.Grabbing;
if (!carriableComponent.IsHeavy || Game1.GameManager.StoneGrabberLevel > 1)
carriableComponent?.StartGrabbing?.Invoke();
}
}
}
if (_wasPulling)
_pullCounter += Game1.DeltaTime;
else
_pullCounter = 0;
if (CurrentState == State.Grabbing)
{
var carriableComponent = grabbedObject.Components[CarriableComponent.Index] as CarriableComponent;
// is the player pulling in the opposite direction?
var moveVec = ControlHandler.GetMoveVector2();
if (carriableComponent?.Pull != null)
{
// do not continuously play the pull animation
if (!carriableComponent.Pull(_pullCounter > 0 ? moveVec : Vector2.Zero) && _pullCounter < 0)
_pullCounter = PullResetTime;
}
if (moveVec.Length() > 0.5)
{
// pulling into the oposite direction
var moveDir = AnimationHelper.GetDirection(moveVec);
if ((moveDir + 2) % 4 == Direction)
{
// do not show the pull animation while resetting
if (_pullCounter >= 0)
CurrentState = State.Pulling;
_isPulling = true;
if (!carriableComponent.IsHeavy || Game1.GameManager.StoneGrabberLevel > 1)
{
// start carrying the object
if (_pullCounter >= PullTime && grabbedObject != null)
StartPickup(carriableComponent);
if (_pullCounter > PullMaxTime)
_pullCounter = PullResetTime;
}
}
}
}
}
private void UseHookshot()
{
if (CurrentState != State.Idle && CurrentState != State.Rafting && (!Map.Is2dMap || CurrentState != State.Swimming))
return;
var hookshotDirection = CurrentState == State.Swimming ? _swimDirection : Direction;
var spawnPosition = new Vector3(
EntityPosition.X + _hookshotOffset[hookshotDirection].X,
EntityPosition.Y + _hookshotOffset[hookshotDirection].Y, EntityPosition.Z);
Hookshot.Start(Map, spawnPosition, AnimationHelper.DirectionOffset[hookshotDirection]);
Map.Objects.SpawnObject(Hookshot);
CurrentState = State.Hookshot;
_body.VelocityTarget = Vector2.Zero;
_body.HoleAbsorption = Vector2.Zero;
_body.IgnoreHoles = true;
StopRaft();
// play animation
Animation.Play("powder_" + hookshotDirection);
}
private void UseBoomerang()
{
if ((CurrentState != State.Idle &&
CurrentState != State.Jumping &&
(CurrentState != State.Swimming || !Map.Is2dMap)) || !_boomerang.IsReady)
return;
var spawnPosition = new Vector3(EntityPosition.X + _boomerangOffset[Direction].X, EntityPosition.Y + _boomerangOffset[Direction].Y, EntityPosition.Z);
// can throw into multiple directions
var boomerangVector = _lastBaseMoveVelocity;
if (boomerangVector != Vector2.Zero)
boomerangVector.Normalize();
else
boomerangVector = _walkDirection[Direction];
_boomerang.Start(Map, spawnPosition, boomerangVector);
Map.Objects.SpawnObject(_boomerang);
if (CurrentState != State.Jumping)
{
CurrentState = State.Powdering;
Animation.Play("powder_" + Direction);
}
}
private void UseMagicRod()
{
if (CurrentState != State.Idle &&
CurrentState != State.Rafting &&
(CurrentState != State.Swimming || !Map.Is2dMap) &&
(CurrentState != State.Jumping || _railJump))
return;
var spawnPosition = new Vector3(EntityPosition.X + _magicRodOffset[Direction].X, EntityPosition.Y + _magicRodOffset[Direction].Y, EntityPosition.Z);
Map.Objects.SpawnObject(new ObjMagicRodShot(Map, spawnPosition, AnimationHelper.DirectionOffset[Direction] *
(Game1.GameManager.PieceOfPowerIsActive ? MagicRodSpeedPoP : MagicRodSpeed), Direction));
CurrentState = State.MagicRod;
_swordChargeCounter = SwordChargeTime;
Game1.GameManager.PlaySoundEffect("D378-13-0D");
StopRaft();
// play animation
Animation.Play("rod_" + Direction);
AnimatorWeapons.Play("rod_" + Direction);
}
private void UseOcarina()
{
if (CurrentState != State.Idle || _isClimbing)
return;
_ocarinaNoteIndex = 0;
_ocarinaCounter = 0;
Game1.GbsPlayer.Pause();
if (Game1.GameManager.SelectedOcarinaSong == 0)
Game1.GameManager.PlaySoundEffect("D370-09-09");
else if (Game1.GameManager.SelectedOcarinaSong == 1)
Game1.GameManager.PlaySoundEffect("D370-11-0B");
else if (Game1.GameManager.SelectedOcarinaSong == 2)
Game1.GameManager.PlaySoundEffect("D370-10-0A");
else
Game1.GameManager.PlaySoundEffect("D370-21-15");
_ocarinaSong = Game1.GameManager.SelectedOcarinaSong;
CurrentState = State.Ocarina;
Direction = 3;
Animation.Play("ocarina");
}
private void UpdateOcarina()
{
if (CurrentState == State.Ocarina)
{
// finished playing the ocarina song?
if (!Animation.IsPlaying)
{
FinishedOcarinaSong();
return;
}
UpdateOcarinaAnimation();
}
else if (CurrentState == State.OcarinaTelport)
{
// show the animation while teleporting
CurrentState = State.Idle;
}
}
private void UpdateOcarinaAnimation()
{
if (CurrentState != State.Ocarina)
return;
_ocarinaCounter += Game1.DeltaTime;
if (_ocarinaCounter > 100 + _ocarinaNoteIndex * 910)
{
_ocarinaNoteIndex++;
var dir = _ocarinaNoteIndex % 2 == 1 ? -1 : 1;
var objNote = new ObjNote(Map, new Vector2(EntityPosition.X + dir * 7, EntityPosition.Y), dir);
Map.Objects.SpawnObject(objNote);
}
}
private void FinishedOcarinaSong()
{
// continue playing music
if (_ocarinaSong != 1)
Game1.GbsPlayer.Play();
if (_ocarinaSong == -1)
{
CurrentState = State.Idle;
Game1.GameManager.StartDialogPath("ocarina_bad");
return;
}
if (_ocarinaSong == 1)
{
CurrentState = State.OcarinaTelport;
MapTransitionStart = EntityPosition.Position;
MapTransitionEnd = EntityPosition.Position;
TransitionOutWalking = false;
Game1.GameManager.PlaySoundEffect("D360-44-2C");
// load the map
var transitionSystem = (MapTransitionSystem)Game1.GameManager.GameSystems[typeof(MapTransitionSystem)];
if (Map.DungeonMode)
{
// respawn at the dungeon entry
MapManager.ObjLink.SetNextMapPosition(MapManager.ObjLink.SavePosition);
transitionSystem.AppendMapChange(MapManager.ObjLink.SaveMap, null, false, false, Color.White, true);
}
else
{
// append a map change
transitionSystem.AppendMapChange("overworld.map", "ocarina_entry", false, false, Color.White, true);
}
transitionSystem.StartTeleportTransition = true;
return;
}
CurrentState = State.Idle;
var recInteraction = new RectangleF(EntityPosition.X - 64, EntityPosition.Y - 64 - 8, 128, 128);
_ocarinaList.Clear();
Map.Objects.GetComponentList(_ocarinaList,
(int)recInteraction.X, (int)recInteraction.Y, (int)recInteraction.Width, (int)recInteraction.Height, OcarinaListenerComponent.Mask);
// notify ocarina listener components around the player
foreach (var objOcarinaListener in _ocarinaList)
{
if (recInteraction.Contains(objOcarinaListener.EntityPosition.Position))
{
var ocarinaComponent = (OcarinaListenerComponent)objOcarinaListener.Components[OcarinaListenerComponent.Index];
ocarinaComponent.OcarinaPlayedFunction(Game1.GameManager.SelectedOcarinaSong);
}
}
}
private void HoldShield(bool lastKeyDown)
{
if (CurrentState != State.Idle && CurrentState != State.Pushing)
return;
if (!_wasBlocking)
Game1.GameManager.PlaySoundEffect("D378-22-16");
_wasBlocking = true;
CurrentState = State.Blocking;
}
private void HoldPegasusBoots()
{
if (CurrentState == State.BootKnockback || _isTrapped)
return;
_bootsHolding = true;
}
private void UpdateShieldPush()
{
if (Animation.CollisionRectangle.IsEmpty || _isTrapped)
return;
// push with the shield
var shieldRectangle = new Box(
EntityPosition.X + Animation.CollisionRectangle.X - 7,
EntityPosition.Y + Animation.CollisionRectangle.Y - 16, 0,
Animation.CollisionRectangle.Width,
Animation.CollisionRectangle.Height, 12);
var pushedRectangle = Map.Objects.PushObject(shieldRectangle,
_walkDirection[Direction] + _body.VelocityTarget * 0.5f, PushableComponent.PushType.Impact);
// get repelled from the pushed object
if (pushedRectangle != null)
{
_bootsRunning = false;
_bootsCounter = 0;
_body.Velocity += new Vector3(
-_walkDirection[Direction].X * pushedRectangle.RepelMultiplier,
-_walkDirection[Direction].Y * pushedRectangle.RepelMultiplier, 0);
if (pushedRectangle.RepelParticle)
{
Game1.GameManager.PlaySoundEffect("D360-07-07");
// poke particle
Map.Objects.SpawnObject(new ObjAnimator(Map,
(int)(pushedRectangle.PushableBox.Box.X + pushedRectangle.PushableBox.Box.Width / 2),
(int)(pushedRectangle.PushableBox.Box.Y + pushedRectangle.PushableBox.Box.Height / 2),
Values.LayerTop, "Particles/swordPoke", "run", true));
}
else
{
Game1.GameManager.PlaySoundEffect("D360-09-09");
}
}
}
private void UpdateCharging()
{
// stop charging
if (_isHoldingSword)
{
// poke objects that walk into the sowrd
RectangleF collisionRectangle = AnimatorWeapons.CollisionRectangle;
var damageOrigin = BodyRectangle.Center;
SwordDamageBox = new Box(
collisionRectangle.X + EntityPosition.X + _animationOffsetX,
collisionRectangle.Y + EntityPosition.Y - EntityPosition.Z + _animationOffsetY, 0,
collisionRectangle.Width,
collisionRectangle.Height, 4);
var hitType = Game1.GameManager.SwordLevel == 1 ? HitType.Sword1 : HitType.Sword2;
var damage = Game1.GameManager.SwordLevel == 1 ? 1 : 2;
// red cloak doubles damage
if (Game1.GameManager.CloakType == GameManager.CloakRed)
damage *= 2;
// piece of power double the damage
if (Game1.GameManager.PieceOfPowerIsActive)
damage *= 2;
var pieceOfPower = Game1.GameManager.PieceOfPowerIsActive || Game1.GameManager.CloakType == GameManager.CloakRed;
var hitCollision = Map.Objects.Hit(this, damageOrigin, SwordDamageBox, hitType | HitType.SwordHold, damage, pieceOfPower, out var direction, true);
// start poking?
if (hitCollision != Values.HitCollision.None &&
hitCollision != Values.HitCollision.NoneBlocking)
{
_swordPoked = true;
Animation.Play("poke_" + Direction);
AnimatorWeapons.Play("poke_" + Direction);
CurrentState = State.Attacking;
// get repelled
RepelPlayer(hitCollision, direction);
}
else if (_swordChargeCounter > 0)
{
_swordChargeCounter -= Game1.DeltaTime;
// finished charging?
if (_swordChargeCounter <= 0)
Game1.GameManager.PlaySoundEffect("D360-04-04");
}
}
else
{
// start charge attack
if (_swordChargeCounter <= 0)
StartSwordSpin();
else
ReturnToIdle();
}
}
private void StartSwordSpin()
{
CurrentState = State.Attacking;
Animation.Play("swing_" + Direction);
AnimatorWeapons.Play("swing_" + Direction);
Game1.GameManager.PlaySoundEffect("D378-03-03");
_swordChargeCounter = SwordChargeTime;
_isSwingingSword = true;
}
private void UpdateAttacking()
{
if (_bootsRunning && CarrySword)
AnimatorWeapons.Play("stand_" + Direction);
if (AnimatorWeapons.CollisionRectangle.IsEmpty)
return;
var damageOrigin = BodyRectangle.Center;
if (Map.Is2dMap)
damageOrigin.Y -= 4;
RectangleF collisionRectangle = AnimatorWeapons.CollisionRectangle;
// this lerps the collision box between frames
// a rotation collision box would probably be a better option
if (AnimatorWeapons.CurrentAnimation.Frames.Length > AnimatorWeapons.CurrentFrameIndex + 1)
{
var frameState = (float)(AnimatorWeapons.FrameCounter / AnimatorWeapons.CurrentFrame.FrameTime);
var collisionRectangleNextFrame = AnimatorWeapons.GetCollisionBox(
AnimatorWeapons.CurrentAnimation.Frames[AnimatorWeapons.CurrentFrameIndex + 1]);
collisionRectangle = new RectangleF(
MathHelper.Lerp(collisionRectangle.X, collisionRectangleNextFrame.X, frameState),
MathHelper.Lerp(collisionRectangle.Y, collisionRectangleNextFrame.Y, frameState),
MathHelper.Lerp(collisionRectangle.Width, collisionRectangleNextFrame.Width, frameState),
MathHelper.Lerp(collisionRectangle.Height, collisionRectangleNextFrame.Height, frameState));
}
SwordDamageBox = new Box(
collisionRectangle.X + EntityPosition.X + _animationOffsetX,
collisionRectangle.Y + EntityPosition.Y - EntityPosition.Z + _animationOffsetY, 0,
collisionRectangle.Width,
collisionRectangle.Height, 4);
var hitType = _bootsRunning ? HitType.PegasusBootsSword :
(Game1.GameManager.SwordLevel == 1 ? HitType.Sword1 : HitType.Sword2);
var damage = Game1.GameManager.SwordLevel == 1 ? 1 : 2;
if (_isSwingingSword)
{
damage *= 2;
hitType |= HitType.SwordSpin;
}
if (_bootsRunning)
damage *= 2;
// piece of power double the damage
if (Game1.GameManager.PieceOfPowerIsActive)
damage *= 2;
// red cloak doubles the damage
if (Game1.GameManager.CloakType == GameManager.CloakRed)
damage *= 2;
var pieceOfPower = Game1.GameManager.PieceOfPowerIsActive || Game1.GameManager.SwordLevel == 2;
var hitCollision = Map.Objects.Hit(this, damageOrigin, SwordDamageBox, hitType, damage, pieceOfPower, out var direction, true);
if (_pokeStart)
{
_pokeStart = false;
if (hitCollision != Values.HitCollision.NoneBlocking)
{
var swordRectangle = AnimatorWeapons.CollisionRectangle;
var swordBox = new Box(
swordRectangle.X + EntityPosition.X + _animationOffsetX,
swordRectangle.Y + EntityPosition.Y - EntityPosition.Z + _animationOffsetY, 0,
swordRectangle.Width, swordRectangle.Height, 4);
var destroyableWall = DestroyableWall(swordBox);
if (destroyableWall)
Game1.GameManager.PlaySoundEffect("D378-23-17");
else
Game1.GameManager.PlaySoundEffect("D360-07-07");
var pokeParticle = new ObjAnimator(Map, 0, 0, Values.LayerTop, "Particles/swordPoke", "run", true);
pokeParticle.EntityPosition.X = EntityPosition.X + _pokeAnimationOffset[Direction].X;
pokeParticle.EntityPosition.Y = EntityPosition.Y + _pokeAnimationOffset[Direction].Y;
Map.Objects.SpawnObject(pokeParticle);
}
}
if (hitCollision != Values.HitCollision.None && hitCollision != Values.HitCollision.NoneBlocking)
_stopCharging = true;
// shoot the sword if the player has the l2 sword and full health
if (!_shotSword && Game1.GameManager.SwordLevel == 2 && Game1.GameManager.CurrentHealth >= Game1.GameManager.MaxHearths * 4 && AnimatorWeapons.CurrentFrameIndex == 2)
{
_shotSword = true;
var spawnPosition = new Vector3(EntityPosition.X + _shootSwordOffset[Direction].X, EntityPosition.Y + _shootSwordOffset[Direction].Y - EntityPosition.Z, 0);
var objSwordShot = new ObjSwordShot(Map, spawnPosition, Direction);
Map.Objects.SpawnObject(objSwordShot);
}
// spawn hit particle?
if ((hitCollision & Values.HitCollision.Particle) != 0 && _hitParticleTime + 225 < Game1.TotalGameTime)
{
_hitParticleTime = Game1.TotalGameTime;
SwordPoke(collisionRectangle);
}
RepelPlayer(hitCollision, direction);
}
private void RepelPlayer(Values.HitCollision collisionType, Vector2 direction)
{
// repel the player
if ((collisionType & Values.HitCollision.Repelling) != 0 &&
_hitRepelTime + 225 < Game1.TotalGameTime)
{
_hitRepelTime = Game1.TotalGameTime;
var multiplier = Map.Is2dMap ? 1.5f : (_bootsRunning ? 1.5f : 1.0f);
if ((collisionType & Values.HitCollision.Repelling0) != 0)
multiplier = 3.00f;
if ((collisionType & Values.HitCollision.Repelling1) != 0)
multiplier = 2.25f;
if (_bootsRunning)
_bootsStop = true;
_body.Velocity += new Vector3(-direction.X, -direction.Y, 0) * multiplier;
}
}
private void SwordPoke(RectangleF collisionRectangle)
{
Game1.GameManager.PlaySoundEffect("D360-07-07");
// poke particle
Map.Objects.SpawnObject(new ObjAnimator(Map,
(int)(EntityPosition.X - 8 + collisionRectangle.X + collisionRectangle.Width / 2),
(int)(EntityPosition.Y - 15 + collisionRectangle.Y + collisionRectangle.Height / 2),
Values.LayerTop, "Particles/swordPoke", "run", true));
}
private void UpdatePickup()
{
if (ShowItem == null)
return;
_itemShowCounter -= Game1.DeltaTime;
if (_itemShowCounter <= 0)
{
// show pick up text
if (_showItem && CurrentState == State.PickingUp)
{
_showItem = false;
// show pickup dialog
if (ShowItem.PickUpDialog != null)
{
if (string.IsNullOrEmpty(_pickupDialogOverride))
Game1.GameManager.StartDialogPath(ShowItem.PickUpDialog);
else
{
Game1.GameManager.StartDialogPath(_pickupDialogOverride);
_pickupDialogOverride = null;
}
if (!string.IsNullOrEmpty(_additionalPickupDialog))
{
Game1.GameManager.StartDialogPath(_additionalPickupDialog);
_additionalPickupDialog = null;
}
}
_itemShowCounter = 250;
if (ShowItem.Name == "sword1")
_itemShowCounter = 5850;
else if (ShowItem.Name.StartsWith("instrument"))
_itemShowCounter = 1000;
}
else
{
Game1.GameManager.SaveManager.SetString("player_shows_item", "0");
// add the item to the inventory
if (_collectedShowItem != null)
{
Game1.GameManager.CollectItem(_collectedShowItem, 0);
_collectedShowItem = null;
}
// spawn the follower if one was picked up
UpdateFollower(false);
// sword spin
if (ShowItem.Name == "sword1")
{
Game1.GameManager.PlaySoundEffect("D378-03-03");
Animation.Play("swing_3");
AnimatorWeapons.Play("swing_3");
CurrentState = State.SwordShow0;
_swordChargeCounter = 1; // don't blink
ShowItem = null;
}
else if (ShowItem.Name.StartsWith("instrument"))
{
// make sure that the music is not playing
Game1.GameManager.StopPieceOfPower();
Game1.GameManager.StopGuardianAcorn();
_instrumentCounter = 0;
CurrentState = State.ShowInstrumentPart0;
}
else
{
ShowItem = null;
if (CurrentState == State.PickingUp)
CurrentState = State.Idle;
}
}
}
}
private void EndPickup()
{
_savedPreItemPickup = false;
SaveGameSaveLoad.ClearSaveState();
Game1.GameManager.SaveManager.DisableHistory();
}
private void UpdateHookshot()
{
if (Hookshot.IsMoving)
return;
_body.IgnoreHoles = false;
ReturnToIdle();
}
private void UpdateDigging()
{
if (Animation.CurrentFrameIndex > 0 && !_hasDug)
{
_hasDug = true;
if (_canDig)
Map.Dig(_digPosition, EntityPosition.Position, Direction);
}
if (!Animation.IsPlaying)
CurrentState = State.Idle;
}
private void UpdatePegasusBoots()
{
_wasBootsRunning = _bootsRunning;
if (CurrentState != State.Idle || _isClimbing || Map.Is2dMap && Direction % 2 != 0)
{
_bootsHolding = false;
_bootsRunning = false;
_bootsCounter = 0;
return;
}
// stop running but start charging with a time boost
if (_bootsStop && _body.Velocity.Length() < 0.25f)
{
_bootsStop = false;
_bootsRunning = false;
_bootsCounter = _bootsRunTime - 300;
}
if (_bootsHolding || _bootsRunning)
{
var lastCounter = _bootsCounter;
_bootsCounter += Game1.DeltaTime;
// spawn particles
if (_bootsCounter % _bootsParticleTime < lastCounter % _bootsParticleTime)
{
// water splash effect while running water?
if (_body.CurrentFieldState.HasFlag(MapStates.FieldStates.Water))
{
Game1.GameManager.PlaySoundEffect("D360-14-0E");
var splashAnimator = new ObjAnimator(_body.Owner.Map, 0, 0, 0, 3, 1, "Particles/splash", "idle", true);
splashAnimator.EntityPosition.Set(new Vector2(
_body.Position.X + _body.OffsetX + _body.Width / 2f,
_body.Position.Y + _body.OffsetY + _body.Height - _body.Position.Z - 3));
Map.Objects.SpawnObject(splashAnimator);
}
else
{
Game1.GameManager.PlaySoundEffect("D378-07-07");
var animator = new ObjAnimator(Map, (int)EntityPosition.X, (int)(EntityPosition.Y + 1),
0, -1 - (int)EntityPosition.Z, Values.LayerPlayer, "Particles/run", "spawn", true);
Map.Objects.SpawnObject(animator);
}
}
// start running
if (!_bootsRunning && _bootsCounter > _bootsRunTime)
{
_bootsRunning = true;
_wasBootsRunning = true;
_bootsStop = false;
}
}
else
{
_bootsCounter = 0;
}
}
private bool Jump(bool force = false, bool playSoundEffect = true)
{
if ((!force && (
CurrentState != State.Idle &&
CurrentState != State.Attacking &&
CurrentState != State.Charging &&
CurrentState != State.Pushing &&
CurrentState != State.Blocking &&
CurrentState != State.Rafting)) ||
_isTrapped || !_canJump)
{
if (_isTrapped && playSoundEffect)
Game1.GameManager.PlaySoundEffect("D360-13-0D");
return false;
}
if (!_body.IsGrounded)
return false;
// release the carried object if the player is carrying something
ReleaseCarriedObject();
if (playSoundEffect)
Game1.GameManager.PlaySoundEffect("D360-13-0D");
if (_isRafting)
{
// do not move while jumping
_moveVelocity = Vector2.Zero;
_lastMoveVelocity = Vector2.Zero;
StopRaft();
}
else
{
// base move velocity does not contain the velocity added in the air
// so when we hit the floor and directly jump afterwards we do not get the velocity of the previouse jump
_lastMoveVelocity = _lastBaseMoveVelocity;
}
_startedJumping = true;
_body.Velocity.Z = JumpAcceleration;
// while attacking the player can still jump but without the animation
if (CurrentState != State.Attacking &&
CurrentState != State.Charging)
{
// start the jump animation
Animation.Play("jump_" + Direction);
CurrentState = State.Jumping;
}
return true;
}
private void UpdateJump()
{
if (CurrentState != State.Jumping)
return;
if (_railJump)
{
_railJumpPercentage += Game1.TimeMultiplier * _railJumpSpeed;
var amount = MathF.Sin(_railJumpPercentage * (MathF.PI * 0.3f)) / MathF.Sin(MathF.PI * 0.3f);
var newPosition = Vector2.Lerp(_railJumpStartPosition, _railJumpTargetPosition, amount);
EntityPosition.Set(newPosition);
EntityPosition.Z = MathF.Sin(_railJumpPercentage * MathF.PI) * _railJumpHeight + _railJumpPercentage * _railJumpPositionZ;
if (_railJumpPercentage >= 1)
{
_railJump = false;
_body.IgnoreHeight = false;
_body.IgnoresZ = false;
_body.Velocity.Z = -1f;
_body.JumpStartHeight = _railJumpPositionZ;
EntityPosition.Set(_railJumpTargetPosition);
EntityPosition.Z = _railJumpPositionZ;
_lastMoveVelocity = Vector2.Zero;
}
}
// touched the ground
if (!_railJump && _body.IsGrounded && _body.Velocity.Z <= 0)
{
if ((_body.CurrentFieldState & (MapStates.FieldStates.Water | MapStates.FieldStates.DeepWater)) == 0)
Game1.GameManager.PlaySoundEffect("D378-07-07");
if ((_body.CurrentFieldState & MapStates.FieldStates.DeepWater) == 0)
Game1.GameManager.PlaySoundEffect("D360-14-0E");
ReturnToIdle();
}
}
private void ThrowCarriedObject()
{
Game1.GameManager.PlaySoundEffect("D360-08-08");
// play a little throw animation
Animation.Play("throw_" + Direction);
CurrentState = State.Throwing;
_carriedComponent.Throw(_walkDirection[Direction] * 3f);
RemoveCarriedObject();
}
private void StartPickup(CarriableComponent carriableComponent)
{
if (carriableComponent?.Init == null)
return;
_carriedComponent = carriableComponent;
Game1.GameManager.PlaySoundEffect("D370-02-02");
_carryStartPosition = _carriedComponent.Init();
_carriedComponent.IsPickedUp = true;
CurrentState = State.PreCarrying;
_preCarryCounter = 0;
_carriedGameObject = carriableComponent.Owner;
_carriedObjDrawComp = carriableComponent.Owner.Components[DrawComponent.Index] as DrawComponent;
if (_carriedObjDrawComp != null)
_carriedObjDrawComp.IsActive = false;
}
private void UpdatePositionCarriedObject(CPosition newPosition)
{
if (_carriedComponent == null)
return;
var targetPosition = new Vector3(EntityPosition.X, EntityPosition.Y, EntityPosition.Z + _carriedComponent.CarryHeight);
if (CurrentState == State.PreCarrying)
{
// finished pickup animation?
if (_preCarryCounter >= PreCarryTime)
{
_preCarryCounter = PreCarryTime;
CurrentState = State.Carrying;
}
var pickupTime = 1 - MathF.Cos((_preCarryCounter / PreCarryTime) * (MathF.PI / 2));
var carryPositionXY = Vector2.Lerp(
new Vector2(_carryStartPosition.X, _carryStartPosition.Y),
new Vector2(targetPosition.X, targetPosition.Y),
1 - MathF.Cos(pickupTime * (MathF.PI / 2)));
var carryPositionZ = MathHelper.Lerp(_carryStartPosition.Z, targetPosition.Z,
MathF.Sin(pickupTime * (MathF.PI / 2)));
if (!_carriedComponent.UpdatePosition(new Vector3(carryPositionXY.X, carryPositionXY.Y, carryPositionZ)))
{
CurrentState = State.Idle;
ReleaseCarriedObject();
}
}
else if (!_isFlying)
{
// move the carried object up/down with the walk animation
if (Direction % 2 == 0)
targetPosition.Z += _isWalking ? Animation.CurrentFrameIndex : 1;
else if (Map.Is2dMap)
targetPosition.Z += 1;
if (!_carriedComponent.UpdatePosition(targetPosition))
{
CurrentState = State.Idle;
ReleaseCarriedObject();
}
}
}
#endregion
private void StopRaft()
{
if (_isRafting)
{
_objRaft.Body.VelocityTarget = Vector2.Zero;
_objRaft.Body.AdditionalMovementVT = Vector2.Zero;
_objRaft.Body.LastAdditionalMovementVT = Vector2.Zero;
}
}
private void StealItem()
{
StopHoldingItem();
// used in ObjStoreItem to not return the item to the shelf
Game1.GameManager.SaveManager.SetString("result", "0");
Game1.GameManager.SaveName = "Thief";
// add the item to the inventory
var strItem = Game1.GameManager.SaveManager.GetString("itemShopItem");
var strCount = Game1.GameManager.SaveManager.GetString("itemShopCount");
var item = new GameItemCollected(strItem)
{
Count = int.Parse(strCount)
};
// gets picked up
PickUpItem(item, false, false);
Game1.GameManager.SaveManager.SetString("stoleItem", "1");
_showStealMessage = true;
}
private void OnHoleAbsorb()
{
if (CurrentState == State.Falling ||
CurrentState == State.TeleporterUpWait ||
CurrentState == State.TeleporterUp ||
CurrentState == State.PickingUp ||
CurrentState == State.Dying)
return;
CurrentState = State.Falling;
FreeTrappedPlayer();
ReleaseCarriedObject();
_railJump = false;
_isFallingIntoHole = true;
_holeFallCounter = 350;
Animation.Play("fall");
Game1.GameManager.PlaySoundEffect("D370-12-0C");
}
private void OnDeath()
{
if (CurrentState == State.Dying)
return;
// has potion?
var potion = Game1.GameManager.GetItem("potion");
if (potion != null && potion.Count >= 1)
{
Game1.GameManager.RemoveItem("potion", 1);
Game1.GameManager.HealPlayer(99);
ItemDrawHelper.EnableHeartAnimationSound();
return;
}
Game1.GameManager.StopMusic(true);
Game1.GameManager.PlaySoundEffect("D370-08-08");
CurrentState = State.Dying;
Animation.Play("dying");
// set the correct start frame depending on the direction the player is facing
int[] dirToFrame = { 0, 2, 1, 3 };
Animation.SetFrame(dirToFrame[Direction]);
((GameOverSystem)Game1.GameManager.GameSystems[typeof(GameOverSystem)]).StartDeath();
}
private void ReleaseCarriedObject()
{
// let the carried item fall down
if (_carriedComponent == null)
return;
_carriedComponent.Throw(new Vector2(0, 0));
RemoveCarriedObject();
}
private void RemoveCarriedObject()
{
_carriedComponent.IsPickedUp = false;
_carriedComponent = null;
_carriedGameObject = null;
if (_carriedObjDrawComp != null)
{
_carriedObjDrawComp.IsActive = true;
_carriedObjDrawComp = null;
}
}
private void UpdateFollower(bool mapInit)
{
var hasFollower = false;
// check if marin is following the player
var itemMarin = Game1.GameManager.GetItem("marin");
if (itemMarin != null && itemMarin.Count > 0)
{
_objFollower = _objMaria;
hasFollower = true;
}
// check if the rooster is following the player
var itemRooster = Game1.GameManager.GetItem("rooster");
if (itemRooster != null && itemRooster.Count > 0)
{
_objFollower = _objRooster;
hasFollower = true;
}
// check if the ghost is following the player
var itemGhost = Game1.GameManager.GetItem("ghost");
if (itemGhost != null && itemGhost.Count > 0)
{
_objFollower = _objGhost;
hasFollower = true;
}
if (hasFollower)
{
// check if the follower is already spawned
if (_objFollower.Map != Map)
{
if (mapInit && NextMapPositionStart.HasValue)
_objFollower.EntityPosition.Set(NextMapPositionStart.Value);
else
_objFollower.EntityPosition.Set(EntityPosition.Position);
_objFollower.Map = Map;
Map.Objects.SpawnObject(_objFollower);
}
}
// remove the current follower from the map
else if (_objFollower != null)
{
Map.Objects.DeleteObjects.Add(_objFollower);
_objFollower = null;
}
}
private void UpdateStoreItemPosition(CPosition position)
{
_storePickupPosition.X = position.X - _storeItemWidth / 2f;
_storePickupPosition.Y = position.Y - EntityPosition.Z - 14 - _storeItemHeight;
}
#region public
public void InitGame()
{
Animation.Play((CarryShield ? "stands_" : "stand_") + Direction);
_spriteTransparency = 1;
_inDungeon = false;
NextMapFallStart = false;
NextMapFallRotateStart = false;
Game1.GameManager.SwordLevel = 0;
Game1.GameManager.ShieldLevel = 0;
Game1.GameManager.StoneGrabberLevel = 0;
Game1.GameManager.SelectedOcarinaSong = -1;
Game1.GameManager.OcarinaSongs[0] = 0;
Game1.GameManager.OcarinaSongs[1] = 0;
Game1.GameManager.OcarinaSongs[2] = 0;
Game1.GameManager.HasMagnifyingLens = false;
_spawnGhost = false;
HasFlippers = false;
StoreItem = null;
_body.IsActive = true;
_objMaria = new ObjMarin(Map, 0, 0);
_objRooster = new ObjCock(Map, 0, 0, null);
_objGhost = new ObjGhost(Map, 0, 0);
MapInit();
CurrentState = State.Idle;
}
public void MapInit()
{
if (CurrentState != State.Swimming && CurrentState != State.OcarinaTelport)
CurrentState = State.Idle;
_boomerang.Reset();
Hookshot.Reset();
_hookshotPull = false;
_railJump = false;
IsVisible = true;
_isRafting = false;
_isFlying = false;
_isClimbing = false;
_isTrapped = false;
_shadowComponent.IsActive = true;
_isGrabbed = false;
ShowItem = null;
_collectedShowItem = null;
_objFollower = null;
_hitRepelTime = 0;
_hitParticleTime = 0;
_hitCount = 0;
_sprite.SpriteShader = null;
_moveVelocity = Vector2.Zero;
_lastMoveVelocity = Vector2.Zero;
_hitVelocity = Vector2.Zero;
_body.Velocity = Vector3.Zero;
_body.IgnoreHeight = false;
_body.IgnoreHoles = false;
_body.DeepWaterOffset = -3;
_body.Level = 0;
_body.IsGrounded = true;
_bootsHolding = false;
_bootsRunning = false;
_bootsCounter = 0;
_carriedGameObject = null;
_carriedComponent = null;
_carriedObjDrawComp = null;
_drawInstrumentEffect = false;
_diveCounter = 0;
_swimVelocity = Vector2.Zero;
if (NextMapFallStart)
{
EntityPosition.Z = 64;
_body.Velocity.Z = -3.75f;
_body.IgnoresZ = false;
_body.JumpStartHeight = EntityPosition.Z;
NextMapFallStart = false;
}
if (NextMapFallRotateStart)
{
EntityPosition.Z = 160;
_body.Velocity.Z = -3.75f;
_body.IgnoresZ = false;
_body.IsGrounded = false;
_body.JumpStartHeight = EntityPosition.Z;
_fallEntryCounter = 0;
CurrentState = State.FallRotateEntry;
NextMapFallRotateStart = false;
}
if (NextMapPositionEnd.HasValue)
SetHoleResetPosition(NextMapPositionEnd.Value);
if (Is2DMode)
MapInit2D();
// reset guardian acorn and piece of power except when in a dungeon
if (!_inDungeon || Map == null || !Map.DungeonMode)
{
Game1.GameManager.StopGuardianAcorn();
Game1.GameManager.StopPieceOfPower();
}
if (Map != null && Map.DungeonMode)
_inDungeon = true;
else
_inDungeon = false;
Game1.GameManager.UseShockEffect = false;
}
public void InitEnding()
{
CurrentState = State.Sequence;
Animation.Play("stand_1");
}
public void FinishLoadingMap(Map.Map map)
{
Map = map;
Is2DMode = map.Is2dMap;
if (NextMapPositionStart.HasValue)
SetPosition(NextMapPositionStart.Value);
MapInit();
UpdateFollower(true);
if (_objFollower != null)
_objFollower.EntityPosition.Set(NextMapPositionStart.Value);
}
public void Respawn()
{
Animation.Play((CarryShield ? "stands_" : "stand_") + Direction);
StoreItem = null;
_body.IsActive = true;
var hearts = 3;
if (Game1.GameManager.MaxHearths >= 14)
hearts = 10;
else if (Game1.GameManager.MaxHearths >= 10)
hearts = 7;
else if (Game1.GameManager.MaxHearths >= 6)
hearts = 5;
Game1.GameManager.CurrentHealth = hearts * 4;
Game1.GameManager.DeathCount++;
MapInit();
}
public void StartIntro()
{
// set the music
Game1.GameManager.SetMusic(27, 2);
CurrentState = State.Intro;
Animation.Play("intro");
NextMapPositionStart = null;
NextMapPositionEnd = null;
SetPosition(new Vector2(56, 51));
MapManager.Camera.ForceUpdate(Game1.GameManager.MapManager.GetCameraTarget());
MapManager.ObjLink.SaveMap = Map.MapName;
MapManager.ObjLink.SavePosition = new Vector2(70, 70);
MapManager.ObjLink.SaveDirection = 3;
}
public void SetPosition(Vector2 newPosition)
{
_body.VelocityTarget = Vector2.Zero;
EntityPosition.Set(new Vector2(newPosition.X, newPosition.Y));
}
public void FreezePlayer()
{
UpdatePlayer = false;
_isWalking = false;
_bootsRunning = false;
// stop movement
// on the boat the player should still move up/down while playing the sequence
if (Map != null && !Map.Is2dMap)
{
// make sure to fall down when jumping into a game sequence
_body.Velocity.X = 0;
_body.Velocity.Y = 0;
if (CurrentState == State.Jumping || CurrentState == State.Powdering)
CurrentState = State.Idle;
}
_body.VelocityTarget = Vector2.Zero;
_moveVelocity = Vector2.Zero;
_hitVelocity = Vector2.Zero;
_swimVelocity = Vector2.Zero;
// stop push animation
if (CurrentState == State.Pushing)
CurrentState = State.Idle;
if (Map != null && Map.Is2dMap)
UpdateAnimation2D();
else
UpdateAnimation();
}
public bool HitPlayer(Box box, HitType type, int damage, float pushMultiplier = 1.75f)
{
var boxDir = BodyRectangle.Center - box.Center;
// if the player is standing inside the box the hit is not blockable
var blockable = Math.Abs(boxDir.X) > box.Width / 2 ||
Math.Abs(boxDir.Y) > box.Height / 2;
var intersection = BodyRectangle.GetIntersection(box.Rectangle());
var direction = BodyRectangle.Center - intersection.Center;
if (direction == Vector2.Zero)
direction = boxDir;
if (direction != Vector2.Zero)
direction.Normalize();
return HitPlayer(direction * pushMultiplier, type, damage, blockable);
}
public bool HitPlayer(Vector2 direction, HitType type, int damage, bool blockable, int damageCooldown = CooldownTime)
{
if (_hitCount > 0 ||
CurrentState == State.Dying ||
CurrentState == State.PickingUp ||
CurrentState == State.Drowning ||
CurrentState == State.Drowned ||
CurrentState == State.Knockout ||
IsDiving() ||
Game1.GameManager.UseShockEffect ||
!UpdatePlayer ||
_isTrapped)
return false;
// block the attack?
if (blockable && (CurrentState == State.Blocking || _bootsRunning && CarryShield))
{
_bootsHolding = false;
_bootsRunning = false;
_bootsCounter = 0;
// is the player blocking this direction
var vectorDirection = ToDirection(-direction);
if (Direction == vectorDirection)
return false;
}
// jump a little if we get hit by a spike
if ((type & HitType.Spikes) != 0)
{
_body.Velocity.Z = 1.0f;
}
// redirect the down force to the sides
if (Map.Is2dMap && _body.IsGrounded && direction.Y > 0)
{
direction.X += Math.Sign(direction.X) * Math.Abs(direction.Y) * 0.5f;
direction.Y = 0;
}
// fall down on damage taken while climbing
if (Map.Is2dMap && _isClimbing)
_isClimbing = false;
if (!_isRafting)
_hitVelocity += direction;
if (_hitCount > 0)
return false;
Game1.GameManager.PlaySoundEffect("D370-03-03");
_hitCount = damageCooldown;
Game1.GameManager.InflictDamage(damage);
// TODO_2: this should be optional (in config file or game settings?)
//if(false)
{
// freeze the screen and shake
var freezeTime = 67;
var shakeMult = (100.0f / freezeTime) * MathF.PI;
Game1.FreezeTime = Game1.TotalGameTime + freezeTime;
Game1.GameManager.ShakeScreen(freezeTime, (int)(direction.X * 2), (int)(direction.Y * 2), shakeMult, shakeMult);
UpdateDamageShader();
}
return true;
}
public void FreezeAnimationState()
{
CurrentState = State.Frozen;
Animation.Pause();
}
public void StartOcarinaDuo()
{
CurrentState = State.Ocarina;
_ocarinaNoteIndex = 0;
_ocarinaCounter = 0;
Animation.Play("ocarina_duo");
}
public void StopOcarinaDuo()
{
CurrentState = State.Idle;
}
public void StartFlying(ObjCock objCock)
{
_isFlying = true;
_objRooster = objCock;
}
public void StopFlying()
{
_isFlying = false;
_body.IgnoresZ = false;
_body.IsGrounded = false;
_body.JumpStartHeight = 0;
_lastMoveVelocity = Vector2.Zero;
if (_objRooster != null)
_objRooster.StopFlying();
}
public void SeqLockPlayer()
{
UpdatePlayer = false;
if (Map.Is2dMap)
UpdateAnimation2D();
else
UpdateAnimation();
}
public void LockPlayer()
{
_isLocked = true;
}
public void TrapPlayer(bool disableItems = false)
{
_isTrapped = true;
_trappedDisableItems = disableItems;
_trapInteractionCount = 8;
}
public bool StealShield()
{
// steal the shield if it is in the first 4 slots
for (var i = 0; i < 4; i++)
{
if (Game1.GameManager.Equipment[i] != null &&
Game1.GameManager.Equipment[i].Name == "shield")
{
Game1.GameManager.RemoveItem("shield", 1);
return true;
}
}
return false;
}
public void FreeTrappedPlayer()
{
_isTrapped = false;
}
public void ShortenDive()
{
_diveCounter = 350;
}
public void StartRaftRiding(ObjRaft objRaft)
{
if (CurrentState != State.Jumping)
CurrentState = State.Rafting;
_isRafting = true;
_objRaft = objRaft;
_body.VelocityTarget = Vector2.Zero;
_body.IgnoreHeight = true;
}
public void RaftJump(Vector2 targetPosition)
{
if (CurrentState == State.Jumping)
return;
CurrentState = State.Jumping;
Game1.GameManager.PlaySoundEffect("D360-13-0D");
Direction = 3;
Animation.Play("jump_" + Direction);
if (_objRaft != null)
{
_objRaft.Jump(targetPosition, 100);
}
}
public void ExitRaft()
{
CurrentState = State.Idle;
_isRafting = false;
_objRaft = null;
EntityPosition.Set(new Vector2(EntityPosition.X, EntityPosition.Y - 1));
}
public void SetHoleResetPosition(Vector2 position, int direction)
{
if (direction == 0)
_alternativeHoleResetPosition = new Vector2(position.X + MathF.Ceiling(_body.Width / 2f), position.Y + 8 + MathF.Ceiling(_body.Height / 2f));
else if (direction == 1)
_alternativeHoleResetPosition = new Vector2(position.X + 8, position.Y + _body.Height);
else if (direction == 2)
_alternativeHoleResetPosition = new Vector2(position.X + 16 - MathF.Ceiling(_body.Width / 2f), position.Y + 8 + MathF.Ceiling(_body.Height / 2f));
else if (direction == 3)
_alternativeHoleResetPosition = new Vector2(position.X + 8, position.Y + 16);
// also used for the drown reseet point
_drownResetPosition = _alternativeHoleResetPosition;
}
public void Knockout(Vector2 direction, string resetDoor)
{
if (CurrentState == State.Knockout)
return;
CurrentState = State.Knockout;
MapTransitionStart = MapManager.ObjLink.EntityPosition.Position;
MapTransitionEnd = MapManager.ObjLink.EntityPosition.Position + direction * 80;
TransitionOutWalking = false;
// append a map change
var transitionSystem = ((MapTransitionSystem)Game1.GameManager.GameSystems[typeof(MapTransitionSystem)]);
transitionSystem.AppendMapChange(Map.MapName, resetDoor, false, false, Color.White, false);
transitionSystem.StartKnockoutTransition = true;
}
public void GroundStun(int stunTime = 1250)
{
// do not stun the player when he is in the air
if (_body.IsGrounded && CurrentState != State.Jumping)
Stun(stunTime);
}
public void Stun(int stunTime, bool particle = false)
{
if (CurrentState == State.Dying)
return;
CurrentState = State.InitStunned;
_stunnedParticles = particle;
_stunnedCounter = stunTime;
}
public void StartGrab()
{
_isGrabbed = true;
}
public void EndGrab()
{
_isGrabbed = false;
}
public void StartThrow(Vector3 direction)
{
_body.Velocity = direction;
_body.IsGrounded = false;
_body.JumpStartHeight = 0;
}
public void StartHoldingItem(GameItem item)
{
CurrentState = State.CarryingItem;
StoreItem = item;
_storeItemWidth = item.SourceRectangle.Value.Width;
_storeItemHeight = item.SourceRectangle.Value.Height;
EntityPosition.AddPositionListener(typeof(ObjLink), UpdateStoreItemPosition);
UpdateStoreItemPosition(EntityPosition);
Game1.GameManager.SaveManager.SetString("holdItem", "1");
}
public void StopHoldingItem()
{
CurrentState = State.Idle;
StoreItem = null;
// this removes all listeners with the ObjLink as a key
EntityPosition.PositionChangedDict.Remove(typeof(ObjLink));
Game1.GameManager.SaveManager.SetString("holdItem", "0");
}
public void SlowDown(float speed)
{
if (CurrentState != State.Jumping)
_currentWalkSpeed = speed;
}
public void StartBedTransition()
{
_startBedTransition = true;
}
public void StartJump()
{
if (CurrentState != State.Dying && CurrentState != State.PickingUp)
Jump(true);
}
public void StartRailJump(Vector2 goalPosition, float jumpHeightMultiply, float jumpSpeedMultiply, float goalPositionZ = 0)
{
if (CurrentState == State.Swimming)
CurrentState = State.Idle;
if (!Jump(false, false))
return;
Game1.GameManager.PlaySoundEffect("D360-08-08");
_railJump = true;
_railJumpStartPosition = EntityPosition.Position;
_railJumpTargetPosition = goalPosition;
// values for distance of 16
_railJumpSpeed = 0.045f * jumpSpeedMultiply;
_railJumpHeight = 12 * jumpHeightMultiply;
_railJumpPositionZ = goalPositionZ;
_railJumpPercentage = 0;
_body.IgnoreHeight = true;
_body.IgnoresZ = true;
_body.Velocity.Z = 0;
}
public Vector2 RailJumpTarget()
{
return _railJumpTargetPosition;
}
public float RailJumpSpeed()
{
return _railJumpSpeed;
}
public float RailJumpHeight()
{
return _railJumpHeight;
}
public float GetRailJumpAmount()
{
if (!_railJump)
return 0;
return _railJumpPercentage;
}
public void RotatePlayer()
{
if (_bootsRunning)
return;
_rotationCounter += Game1.DeltaTime;
// 8 frames per direction
if (_rotationCounter > 133)
{
_rotationCounter -= 133;
if (!_isWalking)
{
Direction = (Direction + 1) % 4;
// rotate the sword if the player is currently charging
if (CurrentState == State.Charging)
AnimatorWeapons.Play("stand_" + Direction);
}
}
}
public void StartTeleportation(ObjDungeonTeleporter teleporter)
{
_teleporter = teleporter;
CurrentState = State.Teleporting;
_drawBody.Layer = Values.LayerTop;
_teleportState = 0;
_teleportCounter = 0;
_teleportCounterFull = 0;
}
public void ShockPlayer(int time)
{
// stop running to not continuously run into the enemy
_bootsHolding = false;
_bootsRunning = false;
_bootsCounter = 0;
CurrentState = State.Idle;
// shock the player
Game1.GameManager.UseShockEffect = true;
Game1.GameManager.ShakeScreen(time, 4, 0, 8.5f, 0);
Game1.GameManager.InflictDamage(4);
}
public void StartHookshotPull()
{
_hookshotPull = true;
if (Map.Is2dMap)
{
_body.Velocity.Y = 0;
_body.LastVelocityCollision = Values.BodyCollision.None;
}
// if the player is on the upper level he will not get pulled through water and we can move through colliders
if ((_body.CurrentFieldState & MapStates.FieldStates.UpperLevel) != 0)
{
_body.IsGrounded = false;
_body.Level = MapStates.GetLevel(_body.CurrentFieldState);
}
}
public bool UpdateHookshotPull()
{
var distance = _body.BodyBox.Box.Center - Hookshot.HookshotPosition.Position;
var pullVector = AnimationHelper.DirectionOffset[Direction];
// reached the end of the hook or collided with an object before
if (distance.Length() < (distance + pullVector).Length() ||
(_body.LastVelocityCollision != Values.BodyCollision.None && (_body.SlideOffset == Vector2.Zero || _body.BodyBox.Box.Contains(Hookshot.HookshotPosition.Position))) ||
CurrentState == State.Dying)
{
_hookshotPull = false;
_body.IgnoresZ = false;
_body.IgnoreHoles = false;
_body.Level = 0;
return false;
}
_body.VelocityTarget = pullVector * 3;
return true;
}
public void StartTeleportation(string teleportMap, string teleporterId)
{
_teleporter = null;
CurrentState = State.Teleporting;
_drawBody.Layer = Values.LayerTop;
_teleportMap = teleportMap;
_teleporterId = teleporterId;
_teleportState = 0;
_teleportCounter = 0;
_teleportCounterFull = 0;
ReleaseCarriedObject();
}
public void StartWorldTelportation(Vector2 newPosition)
{
CurrentState = State.TeleportFallWait;
var positionDistance = EntityPosition.Position - newPosition;
var fallPosition = new Vector3(newPosition.X, newPosition.Y, 128);
EntityPosition.Set(fallPosition);
if (_objFollower != null)
{
var itemGhost = Game1.GameManager.GetItem("ghost");
if (itemGhost != null && itemGhost.Count >= 0)
_objFollower.EntityPosition.Set(new Vector2(fallPosition.X, fallPosition.Y));
else
_objFollower.EntityPosition.Set(fallPosition);
}
// only jump to the new position if it is a different teleporter at a different location
if (positionDistance.Length() > 64)
MapManager.Camera.ForceUpdate(Game1.GameManager.MapManager.GetCameraTarget());
}
public void SetWalkingDirection(int direction)
{
Direction = direction;
UpdateAnimation();
}
public void PickUpItem(GameItemCollected itemCollected, bool showItem, bool showDialog = true, bool playSound = true)
{
if (itemCollected == null)
return;
var item = Game1.GameManager.ItemManager[itemCollected.Name];
// the base item has the max count and other information
var baseItem = Game1.GameManager.ItemManager[item.Name];
// save the game before entering the show animation to support exiting the game while the item is shown
_savedPreItemPickup = true;
if (item.PickUpDialog != null && !Game1.GameManager.SaveManager.HistoryEnabled)
{
SaveGameSaveLoad.FillSaveState(Game1.GameManager);
Game1.GameManager.SaveManager.EnableHistory();
}
_showItem = false;
_pickingUpInstrument = false;
_pickingUpSword = false;
// upgrade the sword
var equipmentPosition = 0;
if (item.Name == "sword1")
{
_pickingUpSword = true;
Game1.GameManager.SetMusic(14, 2);
}
else if (item.Name == "sword2")
{
equipmentPosition = Game1.GameManager.GetEquipmentSlot("sword1");
Game1.GameManager.RemoveItem("sword1", 99);
Game1.GameManager.CollectItem(itemCollected, equipmentPosition);
Game1.GameManager.SetMusic(14, 2);
}
else if (item.Name == "mirrorShield")
{
equipmentPosition = Game1.GameManager.GetEquipmentSlot("shield");
Game1.GameManager.RemoveItem("shield", 99);
Game1.GameManager.CollectItem(itemCollected, equipmentPosition);
}
else if (baseItem.Name == "shield")
{
var mirrorShield = Game1.GameManager.GetItem("mirrorShield");
if (mirrorShield != null)
{
Game1.GameManager.PlaySoundEffect(item.SoundEffectName, true, 1, 0, item.TurnDownMusic);
return;
}
}
else if (itemCollected.Name == "stonelifter2")
{
equipmentPosition = Game1.GameManager.GetEquipmentSlot("stonelifter");
Game1.GameManager.RemoveItem("stonelifter", 99);
Game1.GameManager.CollectItem(itemCollected, equipmentPosition);
}
else if (itemCollected.Name == "heartMeterFull")
{
Game1.GameManager.SetMusic(36, 2);
}
else if (itemCollected.Name == "heartMeter")
{
var heart = Game1.GameManager.GetItem("heartMeter");
// hearts was expanded => show different dialog
if (heart?.Count == 3)
_additionalPickupDialog = "heartMeterFilled";
}
// hearth
if (item.Name == "heart")
{
Game1.GameManager.CurrentHealth += itemCollected.Count * 4;
if (Game1.GameManager.CurrentHealth > Game1.GameManager.MaxHearths * 4)
Game1.GameManager.CurrentHealth = Game1.GameManager.MaxHearths * 4;
}
// pick up item is an accessory
else if ((item.ShowAnimation == 1 || item.ShowAnimation == 2) && showItem)
{
// stop player movement
_body.Velocity = Vector3.Zero;
_body.VelocityTarget = Vector2.Zero;
_moveVelocity = Vector2.Zero;
_hitVelocity = Vector2.Zero;
// pick up and show an item
ShowItem = item;
// hold the item over the head with one or two hands (to the left side or the middle)
if (item.ShowAnimation == 1)
_showItemOffset.X = 0;
else
_showItemOffset.X = -4;
_showItemOffset.Y = -15;
if (ShowItem.Name == "guardianAcorn")
Game1.GameManager.InitGuardianAcorn();
else if (ShowItem.Name == "pieceOfPower")
Game1.GameManager.InitPieceOfPower();
// @HACK: piece of power shows the sword image when picked up
if (ShowItem.Name == "pieceOfPower")
{
var swordItem = Game1.GameManager.GetItem("sword1");
if (swordItem != null && swordItem.Count > 0)
ShowItem = Game1.GameManager.ItemManager["sword1PoP"];
else
ShowItem = Game1.GameManager.ItemManager["sword2PoP"];
}
// make sure to use the right source rectangle if the shown item does not have one
var sourceRectangle = ShowItem.SourceRectangle ?? baseItem.SourceRectangle.Value;
if (ShowItem.MapSprite != null)
sourceRectangle = ShowItem.MapSprite.SourceRectangle;
else if (baseItem.MapSprite != null)
sourceRectangle = baseItem.MapSprite.SourceRectangle;
// spawn pickup animation
if (item.ShowEffect)
Map.Objects.SpawnObject(new ObjPickupAnimation(Map,
EntityPosition.X + _showItemOffset.X, EntityPosition.Y - EntityPosition.Z + _showItemOffset.Y - sourceRectangle.Height / 2));
_showItemOffset -= new Vector2(sourceRectangle.Width / 2f, sourceRectangle.Height);
CurrentState = State.PickingUp;
Game1.GameManager.SaveManager.SetString("player_shows_item", "1");
Animation.Play("show" + item.ShowAnimation);
_itemShowCounter = item.ShowTime;
_showItem = true;
// make sure to collect the item the player is currently showing
if (_collectedShowItem != null)
Game1.GameManager.CollectItem(_collectedShowItem, 0);
_collectedShowItem = itemCollected;
if (ShowItem.Name == "sword2")
{
_shownSwordLv2Dialog = false;
_showSwordL2ParticleCounter = 0;
CurrentState = State.SwordShowLv2;
}
// not sure if this is what should happen here
ReleaseCarriedObject();
}
else
{
Game1.GameManager.CollectItem(itemCollected, equipmentPosition);
}
if (item.Name.StartsWith("instrument"))
{
// stop playing music
Game1.GameManager.SetMusic(26, 2);
_instrumentPickupTime = Game1.TotalGameTime;
_instrumentIndex = int.Parse(item.Name.Replace("instrument", ""));
_pickingUpInstrument = true;
}
if (item.PickUpDialog != null && !_showItem && showDialog)
{
Game1.GameManager.StartDialogPath(item.PickUpDialog);
}
// play sound
if (playSound && item.SoundEffectName != null)
Game1.GameManager.PlaySoundEffect(item.SoundEffectName, true, 1, 0, item.TurnDownMusic);
if (item.MusicName >= 0)
Game1.GameManager.SetMusic(item.MusicName, 1);
}
#region map change
public void SetNextMapPosition(Vector2 playerPosition)
{
// this will be used to set the position of the player after loading the map
// one of them should always be null
// the playerPosition is used after loading a savestate
NextMapPositionStart = playerPosition;
NextMapPositionEnd = playerPosition;
NextMapPositionId = null;
}
public void SetNextMapPosition(string nextMapPositionId)
{
// this will be used to set the position of the player after loading the map
// one of them should always be null
// the nextMapPositionId is used after going though a door
NextMapPositionId = nextMapPositionId;
NextMapPositionStart = null;
NextMapPositionEnd = null;
}
public void OnAppendMapChange()
{
if (_objMaria != null)
_objMaria.OnAppendMapChange();
}
public void StartTransitioning()
{
IsTransitioning = true;
_drawBody.Layer = Values.LayerTop;
// if the transitioning starts from a jump the player would have no animation otherwise
//_moved = true;
_isWalking = true;
_bootsRunning = false;
// stole item?
if (StoreItem != null)
StealItem();
ReleaseCarriedObject();
// release the cock if link is flying
if (MapManager.ObjLink.IsFlying())
MapManager.ObjLink.StopFlying();
// make sure the player walks
if (MapTransitionStart.HasValue && MapTransitionEnd.HasValue &&
CurrentState != State.Swimming && CurrentState != State.BedTransition && CurrentState != State.Knockout && CurrentState != State.OcarinaTelport)
CurrentState = State.Idle;
_body.VelocityTarget = Vector2.Zero;
if (Map.Is2dMap)
{
if (_ladderCollision)
{
_isClimbing = true;
Direction = 1;
}
// prefent the player from falling down while climbing up a ladder
//if ((Direction % 2) != 0)
_body.IgnoresZ = true;
// fall down
//else if (_body.Velocity.Y < 0)
_body.Velocity.Y = 0.0f;
}
else
{
_body.Velocity = Vector3.Zero;
}
}
public void UpdateMapTransitionOut(float state)
{
if (MapTransitionStart.HasValue && MapTransitionEnd.HasValue)
{
var newPosition = Vector2.Lerp(MapTransitionStart.Value, MapTransitionEnd.Value, state);
// fall down to the ground
//if (Map.Is2dMap && (Direction % 2) == 0)
// newPosition.Y = EntityPosition.Y;
SetPosition(newPosition);
}
// lock the camera while transitioning
if (!Map.Is2dMap || Direction == 1)
Game1.GameManager.MapManager.UpdateCameraY = MapTransitionStart == MapTransitionEnd;
_isWalking = TransitionOutWalking;
if (Is2DMode)
UpdateAnimation2D();
else
UpdateAnimation();
}
public void UpdateMapTransitionIn(float state)
{
// make sure to not start falling while transitioning into a 2d map with a ladder
if (state == 0 && Map.Is2dMap)
_body.IgnoresZ = true;
if (DirectionEntry >= 0)
Direction = DirectionEntry;
if (NextMapPositionStart.HasValue && NextMapPositionEnd.HasValue)
{
var newPosition = Vector2.Lerp(NextMapPositionStart.Value, NextMapPositionEnd.Value, state);
SetPosition(newPosition);
// transition the follower out
if (_objFollower != null && NextMapPositionStart.Value != NextMapPositionEnd.Value)
{
var followerPosition = Vector2.Lerp(NextMapPositionStart.Value, NextMapPositionEnd.Value, state * 0.5f);
_objFollower.SetPosition(followerPosition);
}
}
// lock the camera while transitioning
if (!Map.Is2dMap || Direction == 1)
Game1.GameManager.MapManager.UpdateCameraY = NextMapPositionStart == NextMapPositionEnd;
_isWalking = TransitionInWalking;
// set the hole and water reset position to be at the transition entrance
_holeResetPoint = EntityPosition.Position;
_drownResetPosition = EntityPosition.Position;
UpdateSwimming();
UpdateIgnoresZ();
if (Is2DMode)
UpdateAnimation2D();
else
UpdateAnimation();
}
public void EndTransitioning()
{
_body.HoleAbsorption = Vector2.Zero;
IsTransitioning = false;
if (!Map.Is2dMap)
{
_body.Velocity.X = 0;
_body.Velocity.Y = 0;
}
// this is because the water is deeper than 0
if ((SystemBody.GetFieldState(_body) & MapStates.FieldStates.DeepWater) == 0 && CurrentState != State.Swimming && !_isClimbing)
_body.IgnoresZ = false;
_drawBody.Layer = Values.LayerPlayer;
MapManager.Camera.CameraFollowMultiplier = 1.0f;
if (_showStealMessage)
{
_showStealMessage = false;
Game1.GameManager.StartDialogPath("shopkeeper_steal");
}
// restart the music
if (Game1.GameManager.PieceOfPowerIsActive || Game1.GameManager.GuardianAcornIsActive)
Game1.GameManager.StartPieceOfPowerMusic();
}
#endregion
public Vector2 GetSwimVelocity()
{
return _swimVelocity;
}
public ObjMarin GetMarin()
{
return _objMaria;
}
#endregion
#region is functions
public bool IsDiving()
{
return _diveCounter > 0;
}
public bool IsGrounded()
{
return _body.IsGrounded && !_railJump && !_isFlying;
}
public bool IsJumping()
{
return CurrentState == State.Jumping;
}
public bool IsRailJumping()
{
return _railJump;
}
public bool IsHoleAbsorb()
{
return _isFallingIntoHole;
}
public bool IsDashing()
{
return _bootsRunning;
}
public bool IsStunned()
{
return CurrentState == State.Stunned;
}
public bool IsTrapped()
{
return _isTrapped;
}
public bool IsFlying()
{
return _isFlying && CurrentState == State.Carrying;
}
public bool IsUsingHookshot()
{
return CurrentState == State.Hookshot;
}
#endregion
}
}