Move files and folders to new repo format to enable multi-project format
This commit is contained in:
67
Zennysoft.Game.Ma/src/player/IPlayer.cs
Normal file
67
Zennysoft.Game.Ma/src/player/IPlayer.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Collections;
|
||||
using Chickensoft.SaveFileBuilder;
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public interface IPlayer : IKillable, IProvide<ISaveChunk<PlayerData>>
|
||||
{
|
||||
public void Attack();
|
||||
|
||||
public void ToggleInventory();
|
||||
|
||||
public void ToggleMinimap();
|
||||
|
||||
public void PlayerPause();
|
||||
|
||||
public void TakeDamage(double damage, ElementType elementType = ElementType.None, bool isCriticalHit = false);
|
||||
|
||||
public void Knockback(float impulse);
|
||||
|
||||
public void GainExp(int expGained);
|
||||
|
||||
public void LevelUp();
|
||||
|
||||
public void Move(float delta);
|
||||
|
||||
public void TeleportPlayer(Transform3D newTransform);
|
||||
|
||||
public IDungeonRoom GetCurrentRoom();
|
||||
|
||||
public void HealHP(int amount);
|
||||
|
||||
public void RaiseHP(int amount);
|
||||
|
||||
public void HealVT(int amount);
|
||||
|
||||
public void RaiseVT(int amount);
|
||||
|
||||
public void ModifyBonusAttack(int amount);
|
||||
|
||||
public void ModifyBonusDefense(int amount);
|
||||
|
||||
public void ModifyMaximumHP(int amount);
|
||||
|
||||
public void ModifyMaximumVT(int amount);
|
||||
|
||||
public void ModifyBonusLuck(double amount);
|
||||
|
||||
public Inventory Inventory { get; }
|
||||
|
||||
public PlayerStatController Stats { get; }
|
||||
|
||||
public Vector3 CurrentPosition { get; }
|
||||
|
||||
public Basis CurrentBasis { get; }
|
||||
|
||||
public IAutoProp<Weapon> EquippedWeapon { get; }
|
||||
|
||||
public IAutoProp<Armor> EquippedArmor { get; }
|
||||
|
||||
public IAutoProp<Accessory> EquippedAccessory { get; }
|
||||
|
||||
public void Equip(EquipableItem equipable);
|
||||
|
||||
public void Unequip(EquipableItem equipable);
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/player/IPlayer.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/player/IPlayer.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://6xoiq6pmxkcu
|
||||
599
Zennysoft.Game.Ma/src/player/Player.cs
Normal file
599
Zennysoft.Game.Ma/src/player/Player.cs
Normal file
@@ -0,0 +1,599 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Collections;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.SaveFileBuilder;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Player : CharacterBody3D, IPlayer
|
||||
{
|
||||
#region Dependency Injection
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
private PlayerLogic.IBinding PlayerBinding { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
#region Save
|
||||
public ISaveChunk<PlayerData> PlayerChunk { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
public double CurrentHP => Stats.CurrentHP.Value;
|
||||
|
||||
public Vector3 CurrentPosition => GlobalPosition;
|
||||
|
||||
public Basis CurrentBasis => Transform.Basis;
|
||||
public PlayerStatController Stats { get; set; } = default!;
|
||||
|
||||
public Inventory Inventory { get; private set; } = default!;
|
||||
|
||||
public IAutoProp<Weapon> EquippedWeapon => _equippedWeapon;
|
||||
private AutoProp<Weapon> _equippedWeapon { get; set; } = new AutoProp<Weapon>(new Weapon());
|
||||
|
||||
public IAutoProp<Armor> EquippedArmor => _equippedArmor;
|
||||
private AutoProp<Armor> _equippedArmor { get; set; } = new AutoProp<Armor>(new Armor());
|
||||
|
||||
public IAutoProp<Accessory> EquippedAccessory => _equippedAccessory;
|
||||
private AutoProp<Accessory> _equippedAccessory { get; set; } = new AutoProp<Accessory>(new Accessory());
|
||||
|
||||
private PlayerLogic.Settings Settings { get; set; } = default!;
|
||||
|
||||
private PlayerLogic PlayerLogic { get; set; } = default!;
|
||||
|
||||
|
||||
#region Dependencies
|
||||
[Dependency]
|
||||
public IGame Game => this.DependOn<IGame>();
|
||||
|
||||
[Dependency]
|
||||
public ISaveChunk<GameData> GameChunk => this.DependOn<ISaveChunk<GameData>>();
|
||||
|
||||
ISaveChunk<PlayerData> IProvide<ISaveChunk<PlayerData>>.Value() => PlayerChunk;
|
||||
#endregion
|
||||
|
||||
#region Event Signals
|
||||
[Signal]
|
||||
public delegate void InventoryButtonPressedEventHandler();
|
||||
[Signal]
|
||||
public delegate void MinimapButtonHeldEventHandler();
|
||||
#endregion
|
||||
|
||||
#region Exports
|
||||
[Export]
|
||||
public PlayerStatResource PlayerStatResource { get; set; } = default!;
|
||||
|
||||
[Export]
|
||||
private WeaponStats _defaultWeapon { get; set; } = default!;
|
||||
[Export]
|
||||
private ArmorStats _defaultArmor { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
#region Node Dependencies
|
||||
[Node] private IAnimationPlayer AnimationPlayer { get; set; } = default!;
|
||||
|
||||
[Node] private AnimatedSprite2D SwordSlashAnimation { get; set; } = default!;
|
||||
|
||||
[Node] private IHitbox Hitbox { get; set; } = default!;
|
||||
|
||||
[Node] private Area3D CollisionDetector { get; set; } = default!;
|
||||
|
||||
[Node] private Timer HealthTimer { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
|
||||
private bool flipAttack = false;
|
||||
|
||||
private float _healthTimerWaitTime = 3.0f;
|
||||
|
||||
private bool reduceOnTick = true;
|
||||
|
||||
private float _knockbackStrength = 0.0f;
|
||||
private Vector3 _knockbackDirection = Vector3.Zero;
|
||||
|
||||
private Dictionary<int, int> _expToNextLevel;
|
||||
|
||||
#region Initialization
|
||||
public void Initialize()
|
||||
{
|
||||
AnimationPlayer.AnimationFinished += OnAnimationFinished;
|
||||
_expToNextLevel = new Dictionary<int, int>
|
||||
{
|
||||
{ 2, 12 },
|
||||
{ 3, 39 },
|
||||
{ 4, 87 },
|
||||
{ 5, 162 },
|
||||
{ 6, 270 },
|
||||
{ 7, 417 },
|
||||
{ 8, 609 }
|
||||
};
|
||||
}
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
Settings = new PlayerLogic.Settings() { RotationSpeed = PlayerStatResource.RotationSpeed, MoveSpeed = PlayerStatResource.MoveSpeed, Acceleration = PlayerStatResource.Acceleration };
|
||||
Stats = new PlayerStatController();
|
||||
Stats.Init(
|
||||
new PlayerStats
|
||||
{
|
||||
CurrentHP = PlayerStatResource.CurrentHP,
|
||||
MaximumHP = PlayerStatResource.MaximumHP,
|
||||
CurrentVT = PlayerStatResource.CurrentVT,
|
||||
MaximumVT = PlayerStatResource.MaximumVT,
|
||||
CurrentAttack = PlayerStatResource.CurrentAttack,
|
||||
BonusAttack = PlayerStatResource.BonusAttack,
|
||||
MaxAttack = PlayerStatResource.MaxAttack,
|
||||
CurrentDefense = PlayerStatResource.CurrentDefense,
|
||||
BonusDefense = PlayerStatResource.BonusDefense,
|
||||
MaxDefense = PlayerStatResource.MaxDefense,
|
||||
CurrentExp = PlayerStatResource.CurrentExp,
|
||||
CurrentLevel = PlayerStatResource.CurrentLevel,
|
||||
ExpToNextLevel = PlayerStatResource.ExpToNextLevel,
|
||||
Luck = PlayerStatResource.Luck
|
||||
});
|
||||
|
||||
Inventory = new Inventory();
|
||||
|
||||
PlayerLogic = new PlayerLogic();
|
||||
PlayerLogic.Set(this as IPlayer);
|
||||
PlayerLogic.Set(Settings);
|
||||
PlayerLogic.Set(Stats);
|
||||
|
||||
var defaultWeapon = new Weapon();
|
||||
defaultWeapon.ItemStats = _defaultWeapon;
|
||||
var defaultArmor = new Armor();
|
||||
defaultArmor.ItemStats = _defaultArmor;
|
||||
Inventory.TryAdd(defaultWeapon);
|
||||
Inventory.TryAdd(defaultArmor);
|
||||
|
||||
EquippedWeapon.Sync += EquippedWeapon_Sync;
|
||||
EquippedArmor.Sync += EquippedArmor_Sync;
|
||||
EquippedAccessory.Sync += EquippedAccessory_Sync;
|
||||
Stats.CurrentHP.Sync += CurrentHP_Sync;
|
||||
Stats.CurrentExp.Sync += CurrentEXP_Sync;
|
||||
|
||||
Equip(defaultWeapon);
|
||||
Equip(defaultArmor);
|
||||
|
||||
HealthTimer.WaitTime = _healthTimerWaitTime;
|
||||
HealthTimer.Timeout += OnHealthTimerTimeout;
|
||||
Hitbox.AreaEntered += Hitbox_AreaEntered;
|
||||
CollisionDetector.AreaEntered += CollisionDetector_AreaEntered;
|
||||
}
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
PlayerChunk = new SaveChunk<PlayerData>(
|
||||
onSave: (chunk) => new PlayerData()
|
||||
{
|
||||
PlayerStats = new PlayerStats()
|
||||
{
|
||||
CurrentHP = Stats.CurrentHP.Value,
|
||||
MaximumHP = Stats.MaximumHP.Value,
|
||||
CurrentVT = Stats.CurrentVT.Value,
|
||||
MaximumVT = Stats.MaximumVT.Value,
|
||||
CurrentAttack = Stats.CurrentAttack.Value,
|
||||
BonusAttack = Stats.BonusAttack.Value,
|
||||
MaxAttack = Stats.MaxAttack.Value,
|
||||
CurrentDefense = Stats.CurrentDefense.Value,
|
||||
BonusDefense = Stats.BonusDefense.Value,
|
||||
MaxDefense = Stats.MaxDefense.Value,
|
||||
CurrentExp = Stats.CurrentExp.Value,
|
||||
CurrentLevel = Stats.CurrentLevel.Value,
|
||||
ExpToNextLevel = Stats.ExpToNextLevel.Value,
|
||||
Luck = Stats.Luck.Value
|
||||
},
|
||||
Inventory = Inventory
|
||||
},
|
||||
onLoad: (chunk, data) =>
|
||||
{
|
||||
Stats.Init(data.PlayerStats);
|
||||
Inventory = data.Inventory;
|
||||
}
|
||||
);
|
||||
|
||||
PlayerBinding = PlayerLogic.Bind();
|
||||
|
||||
PlayerBinding
|
||||
.Handle((in PlayerLogic.Output.Animations.Attack output) =>
|
||||
{
|
||||
var attackSpeed = EquippedWeapon.Value.AttackSpeed;
|
||||
AnimationPlayer.SetSpeedScale((float)attackSpeed);
|
||||
|
||||
AnimationPlayer.Play("attack");
|
||||
})
|
||||
.Handle((in PlayerLogic.Output.ThrowItem output) =>
|
||||
{
|
||||
});
|
||||
|
||||
GameChunk.AddChunk(PlayerChunk);
|
||||
|
||||
PlayerLogic.Start();
|
||||
this.Provide();
|
||||
}
|
||||
|
||||
private void CollisionDetector_AreaEntered(Area3D area)
|
||||
{
|
||||
if (area.GetParent() is InventoryItem inventoryItem)
|
||||
{
|
||||
var isAdded = Inventory.TryAdd(inventoryItem);
|
||||
if (isAdded)
|
||||
{
|
||||
Game.AnnounceMessageOnMainScreen($"{inventoryItem.ItemName} picked up.");
|
||||
inventoryItem.QueueFree();
|
||||
}
|
||||
else
|
||||
Game.AnnounceMessageOnMainScreen($"Could not pick up {inventoryItem.ItemName}.");
|
||||
}
|
||||
if (area.GetParent() is DroppedItem droppedItem)
|
||||
{
|
||||
var isAdded = Inventory.TryAdd(droppedItem.Item);
|
||||
if (isAdded)
|
||||
{
|
||||
Game.AnnounceMessageOnMainScreen($"{droppedItem.Item.ItemName} picked up.");
|
||||
droppedItem.QueueFree();
|
||||
}
|
||||
else
|
||||
Game.AnnounceMessageOnMainScreen($"Could not pick up {droppedItem.Item.ItemName}.");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
SetPhysicsProcess(true);
|
||||
SwordSlashAnimation.Position = GetViewport().GetVisibleRect().Size / 2;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void Attack()
|
||||
{
|
||||
PlayerLogic.Input(new PlayerLogic.Input.Attack());
|
||||
}
|
||||
|
||||
public void ToggleInventory()
|
||||
{
|
||||
Game.ToggleInventory();
|
||||
}
|
||||
|
||||
public void ToggleMinimap()
|
||||
{
|
||||
Game.ToggleMinimap();
|
||||
}
|
||||
|
||||
public void PlayerPause()
|
||||
{
|
||||
Game.TogglePause();
|
||||
}
|
||||
|
||||
public IDungeonRoom GetCurrentRoom()
|
||||
{
|
||||
var rooms = Game.CurrentFloor.Rooms;
|
||||
var playersRoom = rooms.SingleOrDefault(x => x.IsPlayerInRoom);
|
||||
return playersRoom;
|
||||
}
|
||||
|
||||
public void RaiseHP(int amountToRaise)
|
||||
{
|
||||
Stats.SetMaximumHP(Stats.MaximumHP.Value + amountToRaise);
|
||||
Stats.SetCurrentHP(Stats.MaximumHP.Value);
|
||||
Game.AnnounceMessageOnInventoryScreen($"{amountToRaise}MAXHP Up.");
|
||||
}
|
||||
|
||||
public void HealHP(int amountToRestore)
|
||||
{
|
||||
Stats.SetCurrentHP(Stats.CurrentHP.Value + amountToRestore);
|
||||
var raiseString = amountToRestore == 1000 ? "MAX" : $"{amountToRestore}";
|
||||
Game.AnnounceMessageOnInventoryScreen($"{raiseString}HP Restored.");
|
||||
}
|
||||
|
||||
public void RaiseVT(int amountToRaise)
|
||||
{
|
||||
if (Stats.CurrentVT == Stats.MaximumVT)
|
||||
{
|
||||
Stats.SetMaximumVT(Stats.MaximumVT.Value + amountToRaise);
|
||||
Stats.SetCurrentVT(Stats.MaximumVT.Value);
|
||||
Game.AnnounceMessageOnInventoryScreen($"{amountToRaise}MAXVT Up.");
|
||||
}
|
||||
}
|
||||
|
||||
public void HealVT(int amountToRestore)
|
||||
{
|
||||
Stats.SetCurrentVT(Stats.CurrentVT.Value + amountToRestore);
|
||||
var raiseString = amountToRestore == 1000 ? "MAX" : $"{amountToRestore}";
|
||||
Game.AnnounceMessageOnInventoryScreen($"{raiseString}VT Restored.");
|
||||
}
|
||||
|
||||
public void ModifyBonusAttack(int amount)
|
||||
{
|
||||
Stats.SetBonusAttack(Stats.BonusAttack.Value + amount);
|
||||
}
|
||||
|
||||
public void ModifyBonusDefense(int amount)
|
||||
{
|
||||
Stats.SetBonusDefense(Stats.BonusDefense.Value + amount);
|
||||
}
|
||||
|
||||
public void ModifyMaximumHP(int amount)
|
||||
{
|
||||
Stats.SetMaximumHP(Stats.MaximumHP.Value + amount);
|
||||
}
|
||||
|
||||
public void ModifyMaximumVT(int amount)
|
||||
{
|
||||
Stats.SetMaximumVT(Stats.MaximumVT.Value + amount);
|
||||
}
|
||||
|
||||
public void ModifyBonusLuck(double amount)
|
||||
{
|
||||
Stats.SetLuck(Stats.Luck.Value + amount);
|
||||
}
|
||||
|
||||
public void Move(float delta)
|
||||
{
|
||||
var rawInput = GlobalInputVector;
|
||||
var strafeLeftInput = LeftStrafeInputVector;
|
||||
var strafeRightInput = RightStrafeInputVector;
|
||||
|
||||
var transform = Transform;
|
||||
transform.Basis = new Basis(Vector3.Up, Settings.RotationSpeed * -rawInput.X * delta) * transform.Basis;
|
||||
var moveDirection = new Vector3(strafeRightInput - strafeLeftInput, 0, rawInput.Z).Normalized();
|
||||
var velocity = Basis * moveDirection * Settings.MoveSpeed * Settings.Acceleration;
|
||||
_knockbackStrength = _knockbackStrength * 0.9f;
|
||||
Transform = Transform with { Basis = transform.Basis };
|
||||
Velocity = velocity + (_knockbackDirection * _knockbackStrength);
|
||||
MoveAndSlide();
|
||||
}
|
||||
|
||||
public void TeleportPlayer(Transform3D newTransform)
|
||||
{
|
||||
Transform = newTransform;
|
||||
}
|
||||
|
||||
public void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false)
|
||||
{
|
||||
if (Stats.CurrentHP.Value > 0)
|
||||
{
|
||||
damage = CalculateDefenseResistance(damage);
|
||||
if (isCriticalHit)
|
||||
damage *= 2;
|
||||
Stats.SetCurrentHP(Stats.CurrentHP.Value - (int)damage);
|
||||
}
|
||||
}
|
||||
|
||||
public void Knockback(float impulse)
|
||||
{
|
||||
_knockbackStrength = impulse;
|
||||
_knockbackDirection = GlobalBasis.Z.Normalized();
|
||||
}
|
||||
|
||||
public void GainExp(int expGained)
|
||||
{
|
||||
Stats.SetCurrentExp(Stats.CurrentExp.Value + expGained);
|
||||
}
|
||||
|
||||
public void LevelUp()
|
||||
{
|
||||
var nextLevel = Stats.CurrentLevel.Value + 1;
|
||||
var expToNextLevel = _expToNextLevel[nextLevel];
|
||||
var newCurrentExp = Mathf.Max(Stats.CurrentExp.Value - Stats.ExpToNextLevel.Value, 0);
|
||||
Stats.SetCurrentLevel(nextLevel);
|
||||
Stats.SetExpToNextLevel(expToNextLevel);
|
||||
Stats.SetCurrentExp(newCurrentExp);
|
||||
}
|
||||
|
||||
public void Die() => PlayerLogic.Input(new PlayerLogic.Input.Killed());
|
||||
|
||||
public override void _UnhandledInput(InputEvent @event)
|
||||
{
|
||||
if (@event.IsActionPressed(GameInputs.Inventory))
|
||||
ToggleInventory();
|
||||
|
||||
if (@event.IsActionPressed(GameInputs.MiniMap))
|
||||
ToggleMinimap();
|
||||
|
||||
if (@event.IsActionPressed(GameInputs.Pause))
|
||||
PlayerPause();
|
||||
|
||||
if (@event.IsActionPressed(GameInputs.Attack))
|
||||
Attack();
|
||||
}
|
||||
|
||||
public void OnPhysicsProcess(double delta)
|
||||
{
|
||||
PlayerLogic.Input(new PlayerLogic.Input.PhysicsTick(delta));
|
||||
PlayerLogic.Input(new PlayerLogic.Input.Moved(GlobalPosition, GlobalTransform));
|
||||
}
|
||||
|
||||
public void Equip(EquipableItem equipable)
|
||||
{
|
||||
if (equipable is Weapon weapon)
|
||||
{
|
||||
Unequip(_equippedWeapon.Value);
|
||||
weapon.IsEquipped = true;
|
||||
_equippedWeapon.OnNext(weapon);
|
||||
}
|
||||
else if (equipable is Armor armor)
|
||||
{
|
||||
Unequip(_equippedArmor.Value);
|
||||
armor.IsEquipped = true;
|
||||
_equippedArmor.OnNext(armor);
|
||||
}
|
||||
else if (equipable is Accessory accessory)
|
||||
{
|
||||
Unequip(_equippedAccessory.Value);
|
||||
accessory.IsEquipped = true;
|
||||
_equippedAccessory.OnNext(accessory);
|
||||
}
|
||||
else
|
||||
throw new NotImplementedException("Item type is not supported.");
|
||||
}
|
||||
|
||||
public void Unequip(EquipableItem equipable)
|
||||
{
|
||||
if (equipable is Weapon weapon)
|
||||
{
|
||||
weapon.IsEquipped = false;
|
||||
ModifyBonusAttack(-weapon.Damage);
|
||||
_equippedWeapon.OnNext(new Weapon());
|
||||
}
|
||||
else if (equipable is Armor armor)
|
||||
{
|
||||
armor.IsEquipped = false;
|
||||
ModifyBonusDefense(-armor.Defense);
|
||||
_equippedArmor.OnNext(new Armor());
|
||||
}
|
||||
else if (equipable is Accessory accessory)
|
||||
{
|
||||
accessory.IsEquipped = false;
|
||||
ModifyMaximumHP(-accessory.MaxHPUp);
|
||||
ModifyMaximumVT(-accessory.MaxVTUp);
|
||||
ModifyBonusAttack(-accessory.ATKUp);
|
||||
ModifyBonusDefense(-accessory.DEFUp);
|
||||
ModifyBonusLuck(-accessory.LuckUp);
|
||||
_equippedAccessory.OnNext(new Accessory());
|
||||
}
|
||||
else
|
||||
throw new NotImplementedException("Item type is not supported.");
|
||||
|
||||
if (equipable.ItemTag == ItemTag.BreaksOnChange)
|
||||
Inventory.Remove(equipable);
|
||||
}
|
||||
|
||||
private static Vector3 GlobalInputVector
|
||||
{
|
||||
get
|
||||
{
|
||||
var rawInput = Input.GetVector(GameInputs.MoveLeft, GameInputs.MoveRight, GameInputs.MoveUp, GameInputs.MoveDown);
|
||||
var input = new Vector3
|
||||
{
|
||||
X = rawInput.X,
|
||||
Z = rawInput.Y
|
||||
};
|
||||
return input with { Y = 0f };
|
||||
}
|
||||
}
|
||||
|
||||
private static float LeftStrafeInputVector
|
||||
{
|
||||
get
|
||||
{
|
||||
return Input.GetActionStrength(GameInputs.StrafeLeft);
|
||||
}
|
||||
}
|
||||
|
||||
private static float RightStrafeInputVector
|
||||
{
|
||||
get
|
||||
{
|
||||
return Input.GetActionStrength(GameInputs.StrafeRight);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowItem()
|
||||
{
|
||||
var itemScene = GD.Load<PackedScene>("res://src/items/throwable/ThrowableItem.tscn");
|
||||
var throwItem = itemScene.Instantiate<ThrowableItem>();
|
||||
GetTree().Root.AddChildEx(throwItem);
|
||||
throwItem.GlobalPosition = CurrentPosition + new Vector3(0, 3.5f, 0);
|
||||
throwItem.GlobalRotation = GlobalRotation;
|
||||
}
|
||||
|
||||
private void OnAnimationFinished(StringName animation)
|
||||
{
|
||||
GD.Print("Attack finished");
|
||||
PlayerLogic.Input(new PlayerLogic.Input.AttackAnimationFinished());
|
||||
}
|
||||
|
||||
private void OnExitTree()
|
||||
{
|
||||
PlayerLogic.Stop();
|
||||
PlayerBinding.Dispose();
|
||||
AnimationPlayer.AnimationFinished -= OnAnimationFinished;
|
||||
}
|
||||
|
||||
private void OnPlayerPositionUpdated(Vector3 globalPosition) => GlobalPosition = globalPosition;
|
||||
|
||||
private void OnHealthTimerTimeout()
|
||||
{
|
||||
if (Stats.CurrentHP.Value <= 0)
|
||||
return;
|
||||
|
||||
if (Stats.CurrentVT.Value > 0)
|
||||
{
|
||||
if (EquippedAccessory.Value.AccessoryTag == AccessoryTag.HalfVTConsumption)
|
||||
{
|
||||
reduceOnTick = !reduceOnTick;
|
||||
}
|
||||
Stats.SetCurrentHP(Stats.CurrentHP.Value + 1);
|
||||
if (reduceOnTick)
|
||||
Stats.SetCurrentVT(Stats.CurrentVT.Value - 1);
|
||||
}
|
||||
else
|
||||
Stats.SetCurrentHP(Stats.CurrentHP.Value - 1);
|
||||
}
|
||||
|
||||
private void EquippedWeapon_Sync(Weapon obj)
|
||||
{
|
||||
ModifyBonusAttack(obj.Damage);
|
||||
}
|
||||
|
||||
private void EquippedArmor_Sync(Armor obj)
|
||||
{
|
||||
ModifyBonusDefense(obj.Defense);
|
||||
}
|
||||
|
||||
private void EquippedAccessory_Sync(Accessory accessory)
|
||||
{
|
||||
ModifyMaximumHP(accessory.MaxHPUp);
|
||||
ModifyMaximumVT(accessory.MaxVTUp);
|
||||
ModifyBonusAttack(accessory.ATKUp);
|
||||
ModifyBonusDefense(accessory.DEFUp);
|
||||
ModifyBonusLuck(accessory.LuckUp);
|
||||
}
|
||||
|
||||
private void CurrentHP_Sync(int newHealth)
|
||||
{
|
||||
if (newHealth <= 0)
|
||||
Die();
|
||||
}
|
||||
|
||||
private void CurrentEXP_Sync(int newExp)
|
||||
{
|
||||
if (Stats.CurrentExp.Value >= Stats.ExpToNextLevel.Value)
|
||||
LevelUp();
|
||||
}
|
||||
|
||||
private double CalculateDefenseResistance(double incomingDamage)
|
||||
{
|
||||
return Mathf.Max(incomingDamage - Stats.CurrentDefense.Value - Stats.BonusDefense.Value, 0.0);
|
||||
}
|
||||
|
||||
private void Hitbox_AreaEntered(Area3D area)
|
||||
{
|
||||
var target = area.GetOwner();
|
||||
if (target is IEnemy enemy)
|
||||
HitEnemy(enemy);
|
||||
}
|
||||
|
||||
private void HitEnemy(IEnemy enemy)
|
||||
{
|
||||
var attackValue = Stats.CurrentAttack.Value + Stats.BonusAttack.Value;
|
||||
var ignoreElementalResistance = EquippedWeapon.Value.WeaponTag == WeaponTag.IgnoreAffinity;
|
||||
var isCriticalHit = BattleExtensions.IsCriticalHit(Stats.Luck.Value);
|
||||
var element = EquippedWeapon.Value.WeaponElement;
|
||||
|
||||
enemy.TakeDamage(
|
||||
attackValue * EquippedWeapon.Value.ElementalDamageBonus,
|
||||
element,
|
||||
isCriticalHit,
|
||||
false,
|
||||
ignoreElementalResistance);
|
||||
|
||||
if (EquippedWeapon.Value.WeaponTag == WeaponTag.Knockback)
|
||||
enemy.Knockback(0.3f, -CurrentBasis.Z.Normalized());
|
||||
}
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/player/Player.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/player/Player.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://yxmiqy7i0t7r
|
||||
566
Zennysoft.Game.Ma/src/player/Player.tscn
Normal file
566
Zennysoft.Game.Ma/src/player/Player.tscn
Normal file
File diff suppressed because one or more lines are too long
22
Zennysoft.Game.Ma/src/player/PlayerData.cs
Normal file
22
Zennysoft.Game.Ma/src/player/PlayerData.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.Serialization;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
[Meta, Id("player_data")]
|
||||
public partial record PlayerData
|
||||
{
|
||||
[Save("player_stats")]
|
||||
public required PlayerStats PlayerStats { get; init; }
|
||||
|
||||
[Save("player_inventory")]
|
||||
public required Inventory Inventory { get; init; }
|
||||
}
|
||||
|
||||
[Meta, Id("map_data")]
|
||||
public partial record MapData
|
||||
{
|
||||
[Save("floor_list")]
|
||||
public required List<string> FloorScenes { get; init; }
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/player/PlayerData.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/player/PlayerData.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b2nik7gefqiol
|
||||
43
Zennysoft.Game.Ma/src/player/PlayerStatResource.cs
Normal file
43
Zennysoft.Game.Ma/src/player/PlayerStatResource.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
[GlobalClass]
|
||||
public partial class PlayerStatResource : Resource
|
||||
{
|
||||
/// <summary>Rotation speed (quaternions?/sec).</summary>
|
||||
[Export(PropertyHint.Range, "0, 100, 0.1")]
|
||||
public float RotationSpeed { get; set; } = 12.0f;
|
||||
|
||||
/// <summary>Player speed (meters/sec).</summary>
|
||||
[Export(PropertyHint.Range, "0, 100, 0.1")]
|
||||
public float MoveSpeed { get; set; } = 8f;
|
||||
|
||||
/// <summary>Player speed (meters^2/sec).</summary>
|
||||
[Export(PropertyHint.Range, "0, 100, 0.1")]
|
||||
public float Acceleration { get; set; } = 4f;
|
||||
|
||||
[Export] public int CurrentHP { get; set; }
|
||||
[Export] public int MaximumHP { get; set; }
|
||||
|
||||
[Export] public int CurrentVT { get; set; }
|
||||
[Export] public int MaximumVT { get; set; }
|
||||
|
||||
[Export] public int CurrentExp { get; set; }
|
||||
[Export] public int ExpToNextLevel { get; set; }
|
||||
[Export] public int CurrentLevel { get; set; }
|
||||
|
||||
[Export] public int CurrentAttack { get; set; }
|
||||
[Export] public int BonusAttack { get; set; }
|
||||
|
||||
[Export] public int MaxAttack { get; set; }
|
||||
|
||||
[Export] public int CurrentDefense { get; set; }
|
||||
|
||||
[Export] public int BonusDefense { get; set; }
|
||||
|
||||
[Export] public int MaxDefense { get; set; }
|
||||
|
||||
[Export(PropertyHint.Range, "0, 1, 0.01")]
|
||||
public double Luck { get; set; }
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/player/PlayerStatResource.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/player/PlayerStatResource.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://s6ku2kyc4rbk
|
||||
152
Zennysoft.Game.Ma/src/player/PlayerStats.cs
Normal file
152
Zennysoft.Game.Ma/src/player/PlayerStats.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
using Chickensoft.Collections;
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.Serialization;
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
[Meta, Id("player_stats")]
|
||||
public partial record PlayerStats
|
||||
{
|
||||
[Save("currentHP")]
|
||||
public int CurrentHP { get; init; }
|
||||
[Save("maximumHP")]
|
||||
public int MaximumHP { get; init; }
|
||||
[Save("currentVT")]
|
||||
public int CurrentVT { get; init; }
|
||||
[Save("maximumVT")]
|
||||
public int MaximumVT { get; init; }
|
||||
[Save("currentExp")]
|
||||
public int CurrentExp { get; init; }
|
||||
[Save("currentLevel")]
|
||||
public int CurrentLevel { get; init; }
|
||||
[Save("currentAttack")]
|
||||
public int CurrentAttack { get; init; }
|
||||
[Save("bonusAttack")]
|
||||
public int BonusAttack { get; init; }
|
||||
[Save("maxAttack")]
|
||||
public int MaxAttack { get; init; }
|
||||
[Save("currentDefense")]
|
||||
public int CurrentDefense { get; init; }
|
||||
[Save("bonusDefense")]
|
||||
public int BonusDefense { get; init; }
|
||||
[Save("maxDefense")]
|
||||
public int MaxDefense { get; init; }
|
||||
[Save("expToNextLevel")]
|
||||
public int ExpToNextLevel { get; init; }
|
||||
[Save("luck")]
|
||||
public double Luck { get; init; }
|
||||
}
|
||||
|
||||
public class PlayerStatController
|
||||
{
|
||||
public void Init(PlayerStats playerStats)
|
||||
{
|
||||
_currentHP.OnNext(playerStats.CurrentHP);
|
||||
_maximumHP.OnNext(playerStats.MaximumHP);
|
||||
_currentVT.OnNext(playerStats.CurrentVT);
|
||||
_maximumVT.OnNext(playerStats.MaximumVT);
|
||||
_currentExp.OnNext(playerStats.CurrentExp);
|
||||
_currentLevel.OnNext(playerStats.CurrentLevel);
|
||||
_currentAttack.OnNext(playerStats.CurrentAttack);
|
||||
_bonusAttack.OnNext(playerStats.BonusAttack);
|
||||
_maxAttack.OnNext(playerStats.MaxAttack);
|
||||
_currentDefense.OnNext(playerStats.CurrentDefense);
|
||||
_bonusDefense.OnNext(playerStats.BonusDefense);
|
||||
_maxDefense.OnNext(playerStats.MaxDefense);
|
||||
_expToNextLevel.OnNext(playerStats.ExpToNextLevel);
|
||||
_luck.OnNext(playerStats.Luck);
|
||||
}
|
||||
|
||||
public IAutoProp<int> CurrentHP => _currentHP;
|
||||
public IAutoProp<int> MaximumHP => _maximumHP;
|
||||
public IAutoProp<int> CurrentVT => _currentVT;
|
||||
public IAutoProp<int> MaximumVT => _maximumVT;
|
||||
public IAutoProp<int> CurrentAttack => _currentAttack;
|
||||
public IAutoProp<int> MaxAttack => _maxAttack;
|
||||
public IAutoProp<int> BonusAttack => _bonusAttack;
|
||||
public IAutoProp<int> CurrentDefense => _currentDefense;
|
||||
public IAutoProp<int> MaxDefense => _maxDefense;
|
||||
public IAutoProp<int> BonusDefense => _bonusDefense;
|
||||
public IAutoProp<int> CurrentExp => _currentExp;
|
||||
public IAutoProp<int> ExpToNextLevel => _expToNextLevel;
|
||||
public IAutoProp<int> CurrentLevel => _currentLevel;
|
||||
public IAutoProp<double> Luck => _luck;
|
||||
|
||||
public void SetCurrentHP(int newValue)
|
||||
{
|
||||
var clampedValue = Mathf.Clamp(newValue, 0, MaximumHP.Value);
|
||||
_currentHP.OnNext(clampedValue);
|
||||
}
|
||||
public void SetMaximumHP(int newValue)
|
||||
{
|
||||
_maximumHP.OnNext(newValue);
|
||||
}
|
||||
public void SetCurrentVT(int newValue)
|
||||
{
|
||||
var clampedValue = Mathf.Clamp(newValue, 0, MaximumVT.Value);
|
||||
_currentVT.OnNext(clampedValue);
|
||||
}
|
||||
public void SetMaximumVT(int newValue)
|
||||
{
|
||||
_maximumVT.OnNext(newValue);
|
||||
}
|
||||
public void SetCurrentExp(int newValue)
|
||||
{
|
||||
_currentExp.OnNext(newValue);
|
||||
}
|
||||
public void SetCurrentLevel(int newValue)
|
||||
{
|
||||
_currentLevel.OnNext(newValue);
|
||||
}
|
||||
public void SetCurrentAttack(int newValue)
|
||||
{
|
||||
var clampedValue = Mathf.Clamp(newValue, 0, MaxAttack.Value);
|
||||
_currentAttack.OnNext(clampedValue);
|
||||
}
|
||||
public void SetBonusAttack(int newValue)
|
||||
{
|
||||
_bonusAttack.OnNext(newValue);
|
||||
}
|
||||
public void SetMaxAttack(int newValue)
|
||||
{
|
||||
_maxAttack.OnNext(newValue);
|
||||
}
|
||||
public void SetCurrentDefense(int newValue)
|
||||
{
|
||||
var clampedValue = Mathf.Clamp(newValue, 0, MaxDefense.Value);
|
||||
_currentDefense.OnNext(clampedValue);
|
||||
}
|
||||
public void SetBonusDefense(int newValue)
|
||||
{
|
||||
_bonusDefense.OnNext(newValue);
|
||||
}
|
||||
public void SetMaxDefense(int newValue)
|
||||
{
|
||||
_maxDefense.OnNext(newValue);
|
||||
}
|
||||
public void SetExpToNextLevel(int newValue)
|
||||
{
|
||||
_expToNextLevel.OnNext(newValue);
|
||||
}
|
||||
public void SetLuck(double newValue)
|
||||
{
|
||||
var clampedValue = Mathf.Clamp(newValue, 0, 1.0);
|
||||
_luck.OnNext(clampedValue);
|
||||
}
|
||||
|
||||
private readonly AutoProp<int> _currentHP = new(-1);
|
||||
private readonly AutoProp<int> _maximumHP = new(-1);
|
||||
private readonly AutoProp<int> _currentVT = new(-1);
|
||||
private readonly AutoProp<int> _maximumVT = new(-1);
|
||||
private readonly AutoProp<int> _currentExp = new(-1);
|
||||
private readonly AutoProp<int> _currentLevel = new(-1);
|
||||
private readonly AutoProp<int> _currentAttack = new(-1);
|
||||
private readonly AutoProp<int> _bonusAttack = new(-1);
|
||||
private readonly AutoProp<int> _maxAttack = new(-1);
|
||||
private readonly AutoProp<int> _currentDefense = new(-1);
|
||||
private readonly AutoProp<int> _bonusDefense = new(-1);
|
||||
private readonly AutoProp<int> _maxDefense = new(-1);
|
||||
private readonly AutoProp<int> _expToNextLevel = new(-1);
|
||||
private readonly AutoProp<double> _luck = new(-1);
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/player/PlayerStats.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/player/PlayerStats.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ds6nlnay5d6cv
|
||||
137
Zennysoft.Game.Ma/src/player/dont_look_in_here/player_model.tscn
Normal file
137
Zennysoft.Game.Ma/src/player/dont_look_in_here/player_model.tscn
Normal file
File diff suppressed because one or more lines are too long
BIN
Zennysoft.Game.Ma/src/player/dont_look_in_here/tendomaya.glb
Normal file
BIN
Zennysoft.Game.Ma/src/player/dont_look_in_here/tendomaya.glb
Normal file
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
[remap]
|
||||
|
||||
importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://d60ka3oda7au"
|
||||
path="res://.godot/imported/tendomaya.glb-f10208c626b86ebd9779207b611bbe24.scn"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/player/dont_look_in_here/tendomaya.glb"
|
||||
dest_files=["res://.godot/imported/tendomaya.glb-f10208c626b86ebd9779207b611bbe24.scn"]
|
||||
|
||||
[params]
|
||||
|
||||
nodes/root_type=""
|
||||
nodes/root_name=""
|
||||
nodes/apply_root_scale=true
|
||||
nodes/root_scale=1.0
|
||||
nodes/import_as_skeleton_bones=false
|
||||
nodes/use_node_type_suffixes=true
|
||||
meshes/ensure_tangents=true
|
||||
meshes/generate_lods=true
|
||||
meshes/create_shadow_meshes=true
|
||||
meshes/light_baking=1
|
||||
meshes/lightmap_texel_size=0.2
|
||||
meshes/force_disable_compression=false
|
||||
skins/use_named_skins=true
|
||||
animation/import=true
|
||||
animation/fps=30
|
||||
animation/trimming=false
|
||||
animation/remove_immutable_tracks=true
|
||||
animation/import_rest_as_RESET=false
|
||||
import_script/path=""
|
||||
_subresources={}
|
||||
gltf/naming_version=1
|
||||
gltf/embedded_image_handling=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,38 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dcf5vnogu2qpl"
|
||||
path.s3tc="res://.godot/imported/tendomaya_Diffuse Texture-Diffuse Texture.png-c133987a802d5d3b355e9b92080e5bbf.s3tc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
generator_parameters={
|
||||
"md5": "538abddaba633fa07d06288706267c48"
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/player/dont_look_in_here/tendomaya_Diffuse Texture-Diffuse Texture.png"
|
||||
dest_files=["res://.godot/imported/tendomaya_Diffuse Texture-Diffuse Texture.png-c133987a802d5d3b355e9b92080e5bbf.s3tc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 415 KiB |
@@ -0,0 +1,38 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://m6xsyhnt67sh"
|
||||
path.s3tc="res://.godot/imported/tendomaya_body0_tex00.png-2256e86fdf18d5c857533d2038fd1eb6.s3tc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
generator_parameters={
|
||||
"md5": "b25486677e476cae8eb50c6d6dc8ea8b"
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/player/dont_look_in_here/tendomaya_body0_tex00.png"
|
||||
dest_files=["res://.godot/imported/tendomaya_body0_tex00.png-2256e86fdf18d5c857533d2038fd1eb6.s3tc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
@@ -0,0 +1,38 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://qxq1jjr1cojo"
|
||||
path.s3tc="res://.godot/imported/tendomaya_face10_tex00.png-7cecce20e0644b630e61b58c3cca33f8.s3tc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
generator_parameters={
|
||||
"md5": "d4587d57094eebb71486d1ee6d26a975"
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/player/dont_look_in_here/tendomaya_face10_tex00.png"
|
||||
dest_files=["res://.godot/imported/tendomaya_face10_tex00.png-7cecce20e0644b630e61b58c3cca33f8.s3tc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://brr8uow0xte2o"
|
||||
path="res://.godot/imported/tendomaya_face20_tex00.png-b681d471a8f5b5fe143eb3e299e00cfc.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/player/dont_look_in_here/tendomaya_face20_tex00.png"
|
||||
dest_files=["res://.godot/imported/tendomaya_face20_tex00.png-b681d471a8f5b5fe143eb3e299e00cfc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
21
Zennysoft.Game.Ma/src/player/state/PlayerLogic.Input.cs
Normal file
21
Zennysoft.Game.Ma/src/player/state/PlayerLogic.Input.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public static class Input
|
||||
{
|
||||
public readonly record struct PhysicsTick(double Delta);
|
||||
|
||||
public readonly record struct Moved(Vector3 GlobalPosition, Transform3D GlobalTransform);
|
||||
|
||||
public readonly record struct Enable;
|
||||
|
||||
public readonly record struct Attack;
|
||||
|
||||
public readonly record struct AttackAnimationFinished;
|
||||
|
||||
public readonly record struct Killed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://ch6oc0relbray
|
||||
14
Zennysoft.Game.Ma/src/player/state/PlayerLogic.Output.cs
Normal file
14
Zennysoft.Game.Ma/src/player/state/PlayerLogic.Output.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public static class Output
|
||||
{
|
||||
public static class Animations
|
||||
{
|
||||
public readonly record struct Attack;
|
||||
}
|
||||
|
||||
public readonly record struct ThrowItem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cylnjf8jadgo6
|
||||
13
Zennysoft.Game.Ma/src/player/state/PlayerLogic.Settings.cs
Normal file
13
Zennysoft.Game.Ma/src/player/state/PlayerLogic.Settings.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public record Settings
|
||||
{
|
||||
public float MoveSpeed { get; set; }
|
||||
|
||||
public float RotationSpeed { get; set; }
|
||||
|
||||
public float Acceleration { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cmbt77ty7pmvc
|
||||
10
Zennysoft.Game.Ma/src/player/state/PlayerLogic.State.cs
Normal file
10
Zennysoft.Game.Ma/src/player/state/PlayerLogic.State.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
[Meta]
|
||||
public abstract partial record State : StateLogic<State>;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://c46w8aytsajoe
|
||||
13
Zennysoft.Game.Ma/src/player/state/PlayerLogic.cs
Normal file
13
Zennysoft.Game.Ma/src/player/state/PlayerLogic.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Chickensoft.LogicBlocks;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public interface IPlayerLogic : ILogicBlock<PlayerLogic.State>;
|
||||
|
||||
[Meta, Id("player_logic")]
|
||||
[LogicBlock(typeof(State), Diagram = true)]
|
||||
public partial class PlayerLogic : LogicBlock<PlayerLogic.State>, IPlayerLogic
|
||||
{
|
||||
public override Transition GetInitialState() => To<State.Idle>();
|
||||
}
|
||||
1
Zennysoft.Game.Ma/src/player/state/PlayerLogic.cs.uid
Normal file
1
Zennysoft.Game.Ma/src/player/state/PlayerLogic.cs.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://beqr05mbwbg3b
|
||||
20
Zennysoft.Game.Ma/src/player/state/PlayerLogic.g.puml
Normal file
20
Zennysoft.Game.Ma/src/player/state/PlayerLogic.g.puml
Normal file
@@ -0,0 +1,20 @@
|
||||
@startuml PlayerLogic
|
||||
state "PlayerLogic State" as Zennysoft_Game_Ma_PlayerLogic_State {
|
||||
state "Alive" as Zennysoft_Game_Ma_PlayerLogic_State_Alive {
|
||||
state "Attacking" as Zennysoft_Game_Ma_PlayerLogic_State_Attacking
|
||||
state "Idle" as Zennysoft_Game_Ma_PlayerLogic_State_Idle
|
||||
}
|
||||
state "Dead" as Zennysoft_Game_Ma_PlayerLogic_State_Dead
|
||||
state "Disabled" as Zennysoft_Game_Ma_PlayerLogic_State_Disabled
|
||||
}
|
||||
|
||||
Zennysoft_Game_Ma_PlayerLogic_State_Alive --> Zennysoft_Game_Ma_PlayerLogic_State_Alive : PhysicsTick
|
||||
Zennysoft_Game_Ma_PlayerLogic_State_Alive --> Zennysoft_Game_Ma_PlayerLogic_State_Dead : Killed
|
||||
Zennysoft_Game_Ma_PlayerLogic_State_Attacking --> Zennysoft_Game_Ma_PlayerLogic_State_Idle : AttackAnimationFinished
|
||||
Zennysoft_Game_Ma_PlayerLogic_State_Disabled --> Zennysoft_Game_Ma_PlayerLogic_State_Idle : Enable
|
||||
Zennysoft_Game_Ma_PlayerLogic_State_Idle --> Zennysoft_Game_Ma_PlayerLogic_State_Attacking : Attack
|
||||
|
||||
Zennysoft_Game_Ma_PlayerLogic_State_Idle : OnAttack → Attack
|
||||
|
||||
[*] --> Zennysoft_Game_Ma_PlayerLogic_State_Idle
|
||||
@enduml
|
||||
@@ -0,0 +1,18 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta]
|
||||
public partial record Attacking : Alive, IGet<Input.AttackAnimationFinished>
|
||||
{
|
||||
public Transition On(in Input.AttackAnimationFinished input)
|
||||
{
|
||||
return To<Idle>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dyrl0x5q3q5j7
|
||||
@@ -0,0 +1,22 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public abstract partial record State
|
||||
{
|
||||
[Meta, Id("player_logic_state_alive_idle")]
|
||||
public partial record Idle : Alive, IGet<Input.Attack>
|
||||
{
|
||||
|
||||
public virtual Transition On(in Input.Attack input)
|
||||
{
|
||||
GD.Print("Attacking...");
|
||||
Output(new Output.Animations.Attack());
|
||||
return To<Attacking>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://i0g8tve28n70
|
||||
@@ -0,0 +1,28 @@
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public partial record State
|
||||
{
|
||||
[Meta, Id("player_logic_alive")]
|
||||
public abstract partial record Alive : State, IGet<Input.PhysicsTick>, IGet<Input.Killed>
|
||||
{
|
||||
public virtual Transition On(in Input.PhysicsTick input)
|
||||
{
|
||||
var delta = input.Delta;
|
||||
var player = Get<IPlayer>();
|
||||
player.Move((float)delta);
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
public Transition On(in Input.Killed input)
|
||||
{
|
||||
GD.Print("Player died");
|
||||
return To<Dead>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://demor6ic4xcwn
|
||||
@@ -0,0 +1,12 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public abstract partial record State
|
||||
{
|
||||
[Meta, Id("player_logic_state_dead")]
|
||||
public partial record Dead : State;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bsxp82sus11pv
|
||||
@@ -0,0 +1,23 @@
|
||||
using Chickensoft.Introspection;
|
||||
|
||||
namespace Zennysoft.Game.Ma;
|
||||
|
||||
public partial class PlayerLogic
|
||||
{
|
||||
public abstract partial record State
|
||||
{
|
||||
[Meta, Id("player_logic_state_disabled")]
|
||||
public partial record Disabled : State, IGet<Input.Enable>
|
||||
{
|
||||
public Disabled()
|
||||
{
|
||||
OnAttach(() => Get<IAppRepo>().GameEntered += OnGameEntered);
|
||||
OnDetach(() => Get<IAppRepo>().GameEntered -= OnGameEntered);
|
||||
}
|
||||
|
||||
public Transition On(in Input.Enable input) => To<Idle>();
|
||||
|
||||
public void OnGameEntered() => Input(new Input.Enable());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://pbj8nbyp8iwr
|
||||
Reference in New Issue
Block a user