Refactor Enemy
This commit is contained in:
@@ -3,6 +3,10 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="src\enemy\enemy_types\NewFolder\**" />
|
||||
<EmbeddedResource Remove="src\enemy\enemy_types\NewFolder\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Chickensoft.AutoInject" Version="2.5.0" />
|
||||
<PackageReference Include="Chickensoft.GodotNodeInterfaces" Version="2.4.0" />
|
||||
|
||||
@@ -19,7 +19,6 @@ boot_splash/show_image=false
|
||||
|
||||
DialogueManager="*res://addons/dialogue_manager/dialogue_manager.gd"
|
||||
DialogueController="*res://src/game/DialogueController.cs"
|
||||
SettingsManager="*res://addons/deploy_to_steamos/SettingsManager.cs"
|
||||
|
||||
[dialogue_manager]
|
||||
|
||||
@@ -38,7 +37,7 @@ project/assembly_name="GameJamDungeon"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/SimpleDungeons/plugin.cfg", "res://addons/deploy_to_steamos/plugin.cfg", "res://addons/dialogue_manager/plugin.cfg")
|
||||
enabled=PackedStringArray("res://addons/SimpleDungeons/plugin.cfg", "res://addons/dialogue_manager/plugin.cfg")
|
||||
|
||||
[file_customization]
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
@startuml AppLogic
|
||||
state "AppLogic State" as GameJamDungeon_AppLogic_State {
|
||||
state "SetupGameScene" as GameJamDungeon_AppLogic_State_SetupGameScene
|
||||
state "MainMenu" as GameJamDungeon_AppLogic_State_MainMenu
|
||||
state "LoadingScreen" as GameJamDungeon_AppLogic_State_LoadingScreen
|
||||
state "InGame" as GameJamDungeon_AppLogic_State_InGame
|
||||
state "LoadingScreen" as GameJamDungeon_AppLogic_State_LoadingScreen
|
||||
state "MainMenu" as GameJamDungeon_AppLogic_State_MainMenu
|
||||
}
|
||||
|
||||
GameJamDungeon_AppLogic_State_InGame --> GameJamDungeon_AppLogic_State_MainMenu : GameOver
|
||||
|
||||
@@ -3,7 +3,6 @@ using Chickensoft.Collections;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
@@ -84,21 +83,21 @@ namespace GameJamDungeon
|
||||
|
||||
private void AttackBox_AreaEntered(Area3D area)
|
||||
{
|
||||
var bossHitDamage = DamageCalculator.CalculateEnemyAttackDamage(GameRepo.PlayerData.CurrentDefense.Value + GameRepo.PlayerData.BonusDefense,
|
||||
BossResource,
|
||||
GameRepo.PlayerData.Inventory.EquippedArmor.Value.ArmorStats,
|
||||
false);
|
||||
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - Mathf.RoundToInt(bossHitDamage));
|
||||
//var bossHitDamage = DamageCalculator.CalculateEnemyAttackDamage(GameRepo.PlayerData.CurrentDefense.Value + GameRepo.PlayerData.BonusDefense,
|
||||
// BossResource,
|
||||
// GameRepo.PlayerData.Inventory.EquippedArmor.Value.ArmorStats,
|
||||
// false);
|
||||
//GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - Mathf.RoundToInt(bossHitDamage));
|
||||
}
|
||||
|
||||
private void SecondaryAttackBox_AreaEntered(Area3D area)
|
||||
{
|
||||
var bossHitDamage = DamageCalculator.CalculateEnemyAttackDamage(GameRepo.PlayerData.CurrentDefense.Value + GameRepo.PlayerData.BonusDefense,
|
||||
BossResource,
|
||||
GameRepo.PlayerData.Inventory.EquippedArmor.Value.ArmorStats,
|
||||
false);
|
||||
var nerfDamage = bossHitDamage *= 0.25f;
|
||||
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - Mathf.RoundToInt(nerfDamage));
|
||||
//var bossHitDamage = DamageCalculator.CalculateEnemyAttackDamage(GameRepo.PlayerData.CurrentDefense.Value + GameRepo.PlayerData.BonusDefense,
|
||||
// BossResource,
|
||||
// GameRepo.PlayerData.Inventory.EquippedArmor.Value.ArmorStats,
|
||||
// false);
|
||||
//var nerfDamage = bossHitDamage *= 0.25f;
|
||||
//GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - Mathf.RoundToInt(nerfDamage));
|
||||
Game.Player.ApplyCentralImpulseToPlayer(GlobalBasis.Z.Normalized());
|
||||
}
|
||||
|
||||
@@ -118,9 +117,9 @@ namespace GameJamDungeon
|
||||
var roll = rng.Randf();
|
||||
if (roll <= GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.Luck)
|
||||
isCriticalHit = true;
|
||||
var damage = DamageCalculator.CalculateWeaponAttackDamage(GameRepo.PlayerData.CurrentAttack.Value + GameRepo.PlayerData.BonusAttack, BossResource, GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats, isCriticalHit);
|
||||
GD.Print($"Enemy Hit for {damage} damage.");
|
||||
BossLogic.Input(new BossLogic.Input.HitByPlayer(damage));
|
||||
//var damage = DamageCalculator.CalculateWeaponAttackDamage(GameRepo.PlayerData.CurrentAttack.Value + GameRepo.PlayerData.BonusAttack, BossResource, GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats, isCriticalHit);
|
||||
//GD.Print($"Enemy Hit for {damage} damage.");
|
||||
//BossLogic.Input(new BossLogic.Input.HitByPlayer(damage));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ public partial class DataViewer : Control
|
||||
|
||||
if (Input.IsActionJustPressed(GameInputs.Attack))
|
||||
{
|
||||
_currentModel.PlayAttackAnimation();
|
||||
_currentModel.PlayPrimaryAttackAnimation();
|
||||
}
|
||||
if (Input.IsActionJustPressed(GameInputs.Next))
|
||||
{
|
||||
|
||||
@@ -10,119 +10,123 @@ public partial class Enemy : RigidBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
{
|
||||
public override void _Notification(int what) => this.Notify(what);
|
||||
|
||||
public IEnemyLogic EnemyLogic { get; set; } = default!;
|
||||
private IEnemyLogic _enemyLogic { get; set; } = default!;
|
||||
|
||||
IEnemyLogic IProvide<IEnemyLogic>.Value() => EnemyLogic;
|
||||
IEnemyLogic IProvide<IEnemyLogic>.Value() => _enemyLogic;
|
||||
|
||||
public EnemyLogic.IBinding EnemyBinding { get; set; } = default!;
|
||||
|
||||
#region Dependencies
|
||||
|
||||
[Dependency] IGameRepo GameRepo => this.DependOn<IGameRepo>();
|
||||
|
||||
[Dependency] IGameEventDepot GameEventDepot => this.DependOn<IGameEventDepot>();
|
||||
#endregion
|
||||
|
||||
[Export]
|
||||
public EnemyStatResource EnemyStatResource { get; set; } = default!;
|
||||
#region Exports
|
||||
[Export] private EnemyStatResource _enemyStatResource { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
public static PackedScene CollisionDetectorScene => GD.Load<PackedScene>("res://src/enemy/CollisionDetector.tscn");
|
||||
#region Node Dependencies
|
||||
[Node] private NavigationAgent3D NavAgent { get; set; } = default!;
|
||||
|
||||
public static Area3D CollisionDetector { get; set; } = default!;
|
||||
[Node] private Area3D LineOfSight { get; set; } = default!;
|
||||
|
||||
public AutoProp<double> CurrentHP { get; set; }
|
||||
[Node] private Timer PatrolTimer { get; set; } = default!;
|
||||
|
||||
[Node] public NavigationAgent3D NavAgent { get; set; } = default!;
|
||||
[Node] private Timer AttackTimer { get; set; } = default!;
|
||||
|
||||
[Node] public Area3D LineOfSight { get; set; } = default!;
|
||||
[Node] private RayCast3D Raycast { get; set; } = default!;
|
||||
|
||||
[Node] public Timer PatrolTimer { get; set; } = default!;
|
||||
[Node] protected EnemyModelView EnemyModelView { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
[Node] public Timer AttackTimer { get; set; } = default!;
|
||||
public double CurrentHP => _currentHP.Value;
|
||||
|
||||
[Node] public RayCast3D Raycast { get; set; } = default!;
|
||||
|
||||
[Node] public EnemyModelView EnemyModelView { get; set; } = default!;
|
||||
private AutoProp<double> _currentHP { get; set; }
|
||||
|
||||
private float _knockbackStrength = 0.0f;
|
||||
|
||||
private Vector3 _knockbackDirection = Vector3.Zero;
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
EnemyLogic = new EnemyLogic();
|
||||
EnemyLogic.Set(EnemyStatResource);
|
||||
EnemyLogic.Set(this as IEnemy);
|
||||
EnemyLogic.Set(GameRepo);
|
||||
_enemyLogic = new EnemyLogic();
|
||||
_enemyLogic.Set(_enemyStatResource);
|
||||
_enemyLogic.Set(this as IEnemy);
|
||||
_enemyLogic.Set(GameRepo);
|
||||
}
|
||||
|
||||
public void OnReady()
|
||||
{
|
||||
SetPhysicsProcess(true);
|
||||
CollisionDetector = CollisionDetectorScene.Instantiate<Area3D>();
|
||||
CollisionDetector.AreaEntered += OnPlayerHitboxEntered;
|
||||
AddChild(CollisionDetector);
|
||||
EnemyModelView.Hitbox.AreaEntered += Hitbox_AreaEntered;
|
||||
}
|
||||
|
||||
private void Hitbox_AreaEntered(Area3D area)
|
||||
public void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false)
|
||||
{
|
||||
if (area.GetParent().GetParent() is IPlayer player)
|
||||
if (_currentHP.Value > 0)
|
||||
{
|
||||
var isCriticalHit = false;
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var roll = rng.Randf();
|
||||
if (roll <= EnemyStatResource.Luck)
|
||||
isCriticalHit = true;
|
||||
var damage = DamageCalculator.CalculateEnemyAttackDamage(
|
||||
GameRepo.PlayerData.CurrentDefense.Value + GameRepo.PlayerData.BonusDefense,
|
||||
EnemyStatResource,
|
||||
GameRepo.PlayerData.Inventory.EquippedArmor.Value.ArmorStats,
|
||||
isCriticalHit);
|
||||
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - Mathf.RoundToInt(damage));
|
||||
GD.Print($"Player hit for {damage} damage.");
|
||||
ApplyKnockback();
|
||||
|
||||
if (!ignoreElementalResistance)
|
||||
damage = CalculateElementalResistance(damage, elementType);
|
||||
if (!ignoreDefense)
|
||||
damage = CalculateDefenseResistance(damage);
|
||||
if (isCriticalHit)
|
||||
damage *= 2;
|
||||
GD.Print($"Enemy Hit for {damage} damage.");
|
||||
_currentHP.OnNext(_currentHP.Value - damage);
|
||||
GD.Print("Current HP: " + _currentHP.Value);
|
||||
EnemyModelView.PlayHitAnimation();
|
||||
_enemyLogic.Input(new EnemyLogic.Input.Alerted());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnResolved()
|
||||
public void MoveToLocation(Vector3 target, float delta)
|
||||
{
|
||||
EnemyBinding = EnemyLogic.Bind();
|
||||
NavAgent.TargetPosition = target;
|
||||
var targetPosition = NavAgent.GetNextPathPosition();
|
||||
|
||||
EnemyBinding
|
||||
.Handle((in EnemyLogic.Output.MovementComputed output) =>
|
||||
{
|
||||
var velocity = (targetPosition - GlobalTransform.Origin).Normalized() * 2f * delta;
|
||||
var lookAtDir = GlobalTransform.Origin - velocity;
|
||||
var lookAtPosition = new Vector3(lookAtDir.X, GlobalPosition.Y, lookAtDir.Z);
|
||||
if (GlobalPosition.DistanceTo(target) > 1.0f && !velocity.IsEqualApprox(Vector3.Zero) && !GlobalPosition.IsEqualApprox(lookAtPosition))
|
||||
LookAt(lookAtPosition);
|
||||
EnemyModelView.RotateModel(GlobalTransform.Basis, -GameRepo.PlayerGlobalTransform.Value.Basis.Z);
|
||||
_knockbackStrength = _knockbackStrength * 0.9f;
|
||||
MoveAndCollide(output.LinearVelocity + (_knockbackDirection * _knockbackStrength));
|
||||
})
|
||||
.Handle((in EnemyLogic.Output.HitByPlayer output) =>
|
||||
{
|
||||
EnemyModelView.PlayHitAnimation();
|
||||
// TODO: Make this an event to notify game that player hit someone
|
||||
if (GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.WeaponTags.Contains(WeaponTag.SelfDamage))
|
||||
GameRepo.PlayerData.SetCurrentHP(GameRepo.PlayerData.CurrentHP.Value - 5);
|
||||
if (GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.WeaponTags.Contains(WeaponTag.Knockback))
|
||||
{
|
||||
_knockbackDirection = -GameRepo.PlayerGlobalTransform.Value.Basis.Z.Normalized();
|
||||
_knockbackStrength = 0.3f;
|
||||
MoveAndCollide(velocity + (_knockbackDirection * _knockbackStrength));
|
||||
}
|
||||
})
|
||||
.Handle((in EnemyLogic.Output.Attack _) =>
|
||||
{
|
||||
EnemyModelView.PlayAttackAnimation();
|
||||
})
|
||||
.Handle((in EnemyLogic.Output.Defeated output) =>
|
||||
|
||||
public void Die()
|
||||
{
|
||||
_enemyLogic.Input(new EnemyLogic.Input.EnemyDefeated());
|
||||
EnemyModelView.PlayDeathAnimation();
|
||||
var tweener = GetTree().CreateTween();
|
||||
tweener.TweenInterval(1.0f);
|
||||
tweener.TweenCallback(Callable.From(QueueFree));
|
||||
GameEventDepot.OnEnemyDefeated(GlobalPosition, EnemyStatResource);
|
||||
GameEventDepot.OnEnemyDefeated(GlobalPosition, _enemyStatResource);
|
||||
}
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
EnemyBinding = _enemyLogic.Bind();
|
||||
|
||||
EnemyBinding
|
||||
.Handle((in EnemyLogic.Output.TakeAction _) =>
|
||||
{
|
||||
TakeAction();
|
||||
})
|
||||
.Handle((in EnemyLogic.Output.Defeated output) =>
|
||||
{
|
||||
Die();
|
||||
});
|
||||
|
||||
this.Provide();
|
||||
|
||||
EnemyLogic.Start();
|
||||
_enemyLogic.Start();
|
||||
|
||||
CurrentHP = new AutoProp<double>(EnemyStatResource.MaximumHP);
|
||||
CurrentHP.Sync += OnHPChanged;
|
||||
_currentHP = new AutoProp<double>(_enemyStatResource.MaximumHP);
|
||||
_currentHP.Sync += OnHPChanged;
|
||||
LineOfSight.BodyEntered += LineOfSight_BodyEntered;
|
||||
PatrolTimer.Timeout += OnPatrolTimeout;
|
||||
AttackTimer.Timeout += OnAttackTimeout;
|
||||
@@ -133,7 +137,7 @@ public partial class Enemy : RigidBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
|
||||
public void OnExitTree()
|
||||
{
|
||||
EnemyLogic.Stop();
|
||||
_enemyLogic.Stop();
|
||||
EnemyBinding.Dispose();
|
||||
}
|
||||
|
||||
@@ -142,32 +146,13 @@ public partial class Enemy : RigidBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var randomizedSpot = new Vector3(rng.RandfRange(-7.0f, 7.0f), 0, rng.RandfRange(-7.0f, 7.0f));
|
||||
EnemyLogic.Input(new EnemyLogic.Input.PatrolToRandomSpot(GlobalPosition + randomizedSpot));
|
||||
_enemyLogic.Input(new EnemyLogic.Input.PatrolToRandomSpot(GlobalPosition + randomizedSpot));
|
||||
PatrolTimer.WaitTime = rng.RandfRange(5.0f, 10.0f);
|
||||
}
|
||||
|
||||
public void OnPhysicsProcess(double delta)
|
||||
{
|
||||
EnemyLogic.Input(new EnemyLogic.Input.PhysicsTick(delta));
|
||||
}
|
||||
|
||||
public void OnPlayerHitboxEntered(Area3D body)
|
||||
{
|
||||
if (body is IHitbox hitBox)
|
||||
{
|
||||
if (CurrentHP.Value > 0)
|
||||
{
|
||||
var isCriticalHit = false;
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var roll = rng.Randf();
|
||||
if (roll <= GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.Luck)
|
||||
isCriticalHit = true;
|
||||
var damage = DamageCalculator.CalculateWeaponAttackDamage(GameRepo.PlayerData.CurrentAttack.Value + GameRepo.PlayerData.BonusAttack, EnemyStatResource, GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats, isCriticalHit);
|
||||
GD.Print($"Enemy Hit for {damage} damage.");
|
||||
EnemyLogic.Input(new EnemyLogic.Input.HitByPlayer(damage));
|
||||
}
|
||||
}
|
||||
_enemyLogic.Input(new EnemyLogic.Input.PhysicsTick(delta));
|
||||
}
|
||||
|
||||
private void OnAttackTimeout()
|
||||
@@ -177,7 +162,7 @@ public partial class Enemy : RigidBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
EnemyLogic.Input(new EnemyLogic.Input.AttackTimer());
|
||||
_enemyLogic.Input(new EnemyLogic.Input.AttackTimer());
|
||||
AttackTimer.Stop();
|
||||
AttackTimer.WaitTime = rng.RandfRange(2f, 5.0f);
|
||||
AttackTimer.Start();
|
||||
@@ -197,20 +182,49 @@ public partial class Enemy : RigidBody3D, IEnemy, IProvide<IEnemyLogic>
|
||||
if (collider is IPlayer player)
|
||||
{
|
||||
Raycast.DebugShapeCustomColor = Color.FromString("Purple", Colors.Purple);
|
||||
EnemyLogic.Input(new EnemyLogic.Input.Alerted());
|
||||
_enemyLogic.Input(new EnemyLogic.Input.Alerted());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyKnockback()
|
||||
{
|
||||
if (GameRepo.PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.WeaponTags.Contains(WeaponTag.Knockback))
|
||||
{
|
||||
_knockbackDirection = -GameRepo.PlayerGlobalTransform.Value.Basis.Z.Normalized();
|
||||
_knockbackStrength = 0.3f;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHPChanged(double newHP)
|
||||
{
|
||||
if (newHP <= 0)
|
||||
EnemyLogic.Input(new EnemyLogic.Input.EnemyDefeated());
|
||||
Die();
|
||||
}
|
||||
|
||||
private void DoNothing()
|
||||
private double CalculateElementalResistance(double incomingDamage, ElementType incomingElementType)
|
||||
{
|
||||
if (incomingElementType == ElementType.Aeolic)
|
||||
return Mathf.Max(incomingDamage - (incomingDamage * _enemyStatResource.AeolicResistance), 0.0);
|
||||
if (incomingElementType == ElementType.Hydric)
|
||||
return Mathf.Max(incomingDamage - (incomingDamage * _enemyStatResource.HydricResistance), 0.0);
|
||||
if (incomingElementType == ElementType.Igneous)
|
||||
return Mathf.Max(incomingDamage - (incomingDamage * _enemyStatResource.IgneousResistance), 0.0);
|
||||
if (incomingElementType == ElementType.Ferrum)
|
||||
return Mathf.Max(incomingDamage - (incomingDamage * _enemyStatResource.FerrumResistance), 0.0);
|
||||
if (incomingElementType == ElementType.Telluric)
|
||||
return Mathf.Max(incomingDamage - (incomingDamage * _enemyStatResource.TelluricResistance), 0.0);
|
||||
|
||||
return Mathf.Max(incomingDamage, 0.0);
|
||||
}
|
||||
|
||||
private double CalculateDefenseResistance(double incomingDamage)
|
||||
{
|
||||
return Mathf.Max(incomingDamage - _enemyStatResource.CurrentDefense, 0.0);
|
||||
}
|
||||
|
||||
public virtual void TakeAction()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,11 @@ using Godot;
|
||||
|
||||
public interface IEnemyModelView : INode3D
|
||||
{
|
||||
public void PlayAttackAnimation();
|
||||
public void PlayPrimaryAttackAnimation();
|
||||
|
||||
public void PlaySecondaryAttackAnimation();
|
||||
|
||||
public void PlayPrimarySkillAnimation();
|
||||
|
||||
public void PlayHitAnimation();
|
||||
public void PlayDeathAnimation();
|
||||
@@ -19,7 +23,9 @@ public interface IEnemyModelView : INode3D
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class EnemyModelView : Node3D, IEnemyModelView
|
||||
{
|
||||
private const string ATTACK = "attack";
|
||||
private const string PRIMARY_ATTACK = "primary_attack";
|
||||
private const string SECONDARY_ATTACK = "secondary_attack";
|
||||
private const string PRIMARY_SKILL = "primary_skill";
|
||||
private const string IDLE_FORWARD = "idle_front_walk";
|
||||
private const string IDLE_LEFT = "idle_left_walk";
|
||||
private const string IDLE_BACK = "idle_back_walk";
|
||||
@@ -43,9 +49,19 @@ public partial class EnemyModelView : Node3D, IEnemyModelView
|
||||
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Start(IDLE_FORWARD);
|
||||
}
|
||||
|
||||
public void PlayAttackAnimation()
|
||||
public void PlayPrimaryAttackAnimation()
|
||||
{
|
||||
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(ATTACK);
|
||||
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(PRIMARY_ATTACK);
|
||||
}
|
||||
|
||||
public void PlaySecondaryAttackAnimation()
|
||||
{
|
||||
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(SECONDARY_ATTACK);
|
||||
}
|
||||
|
||||
public void PlayPrimarySkillAnimation()
|
||||
{
|
||||
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(PRIMARY_SKILL);
|
||||
}
|
||||
|
||||
public void PlayHitAnimation()
|
||||
|
||||
@@ -45,19 +45,10 @@ namespace GameJamDungeon
|
||||
public double FerrumResistance { get; set; }
|
||||
|
||||
[Export]
|
||||
public double TelluricDamageBonus { get; set; }
|
||||
public ElementType SecondaryAttackElementalType { get; set; }
|
||||
|
||||
[Export]
|
||||
public double AeolicDamageBonus { get; set; }
|
||||
|
||||
[Export]
|
||||
public double BaseHydricDamageBonus { get; set; }
|
||||
|
||||
[Export]
|
||||
public double IgneousDamageBonus { get; set; }
|
||||
|
||||
[Export]
|
||||
public double FerrumDamageBonus { get; set; }
|
||||
public double SecondaryAttackElementalDamageBonus { get; set; } = 1.0;
|
||||
|
||||
[Export]
|
||||
public float DropsSoulGemChance { get; set; } = 0.75f;
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
using Chickensoft.Collections;
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using Godot;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
public interface IEnemy : IRigidBody3D
|
||||
public interface IEnemy
|
||||
{
|
||||
public IEnemyLogic EnemyLogic { get; }
|
||||
public void TakeAction();
|
||||
|
||||
public AutoProp<double> CurrentHP { get; set; }
|
||||
public void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false);
|
||||
|
||||
public EnemyStatResource EnemyStatResource { get; set; }
|
||||
public void MoveToLocation(Vector3 target, float delta);
|
||||
|
||||
public NavigationAgent3D NavAgent { get; set; }
|
||||
public void Die();
|
||||
|
||||
public Area3D LineOfSight { get; set; }
|
||||
|
||||
public Timer AttackTimer { get; set; }
|
||||
public double CurrentHP { get; }
|
||||
}
|
||||
|
||||
23
src/enemy/enemy_types/chariot/Chariot.cs
Normal file
23
src/enemy/enemy_types/chariot/Chariot.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Chariot : Enemy, IHasPrimaryAttack
|
||||
{
|
||||
[Export]
|
||||
public ElementType PrimaryAttackElementalType { get; set; } = ElementType.None;
|
||||
[Export]
|
||||
public double PrimaryAttackElementalDamageBonus { get; set; } = 1.0;
|
||||
|
||||
public override void TakeAction()
|
||||
{
|
||||
PrimaryAttack();
|
||||
}
|
||||
public void PrimaryAttack()
|
||||
{
|
||||
EnemyModelView.PlayPrimaryAttackAnimation();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
[gd_scene load_steps=137 format=3 uid="uid://dlw5cvutvypxn"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/enemy/Enemy.cs" id="1_t62lw"]
|
||||
[ext_resource type="Script" path="res://src/enemy/EnemyStatResource.cs" id="2_77bk6"]
|
||||
[ext_resource type="Script" path="res://src/hitbox/Hitbox.cs" id="3_lg405"]
|
||||
[ext_resource type="Script" path="res://src/enemy/enemy_types/chariot/Chariot.cs" id="1_hqeyd"]
|
||||
[ext_resource type="Script" uid="uid://dnkmr0eq1sij0" path="res://src/enemy/EnemyStatResource.cs" id="2_77bk6"]
|
||||
[ext_resource type="Script" uid="uid://6edayafleq8y" path="res://src/hitbox/Hitbox.cs" id="3_lg405"]
|
||||
[ext_resource type="Texture2D" uid="uid://c6fvuw1escea1" path="res://src/enemy/enemy_types/chariot/animations/Chariot Back Walk/Layer 1.png" id="4_fokm1"]
|
||||
[ext_resource type="Texture2D" uid="uid://drjnht11skb0l" path="res://src/enemy/enemy_types/chariot/animations/Chariot Front Walk/Layer 1.png" id="4_tav2y"]
|
||||
[ext_resource type="Texture2D" uid="uid://yl1m0fik4fab" path="res://src/enemy/enemy_types/chariot/animations/Chariot Back Walk/Layer 2.png" id="5_gp46b"]
|
||||
@@ -106,26 +106,25 @@
|
||||
[ext_resource type="Texture2D" uid="uid://b1qg8g32xpddx" path="res://src/enemy/enemy_types/chariot/animations/2nd Sprite Fabrics/2nd Sprite Fabrics/Layer 63.png" id="104_1k5tm"]
|
||||
[ext_resource type="Texture2D" uid="uid://upyfmmm6ksmo" path="res://src/enemy/enemy_types/chariot/animations/2nd Sprite Fabrics/2nd Sprite Fabrics/Layer 50.png" id="105_s26ni"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_rxw8v"]
|
||||
[sub_resource type="Resource" id="Resource_dvne1"]
|
||||
script = ExtResource("2_77bk6")
|
||||
CurrentHP = 45.0
|
||||
MaximumHP = 45.0
|
||||
CurrentAttack = 20
|
||||
CurrentDefense = 10
|
||||
MaxAttack = 20
|
||||
MaxDefense = 10
|
||||
CurrentHP = 50.0
|
||||
MaximumHP = 50.0
|
||||
CurrentAttack = 5
|
||||
CurrentDefense = 5
|
||||
MaxAttack = 5
|
||||
MaxDefense = 5
|
||||
ExpFromDefeat = 15
|
||||
Luck = 0.05
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
TelluricDamageBonus = 0.0
|
||||
AeolicDamageBonus = 0.0
|
||||
BaseHydricDamageBonus = 0.0
|
||||
IgneousDamageBonus = 0.0
|
||||
FerrumDamageBonus = 0.0
|
||||
DropsSoulGemChance = 0.9
|
||||
SecondaryAttackElementalType = 0
|
||||
SecondaryAttackElementalDamageBonus = 1.0
|
||||
DropsSoulGemChance = 0.75
|
||||
metadata/_custom_type_script = ExtResource("2_77bk6")
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_cwfph"]
|
||||
radius = 1.0
|
||||
@@ -492,23 +491,6 @@ tracks/0/keys = {
|
||||
"values": [true]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_ruc6s"]
|
||||
resource_name = "attack"
|
||||
length = 0.750008
|
||||
step = 0.0833333
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Hitbox/CollisionShape3D:disabled")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.25, 0.666666),
|
||||
"transitions": PackedFloat32Array(1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [true, false, true]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_1tda5"]
|
||||
resource_name = "idle_back_walk"
|
||||
length = 1.25001
|
||||
@@ -527,17 +509,31 @@ length = 1.25001
|
||||
loop_mode = 1
|
||||
step = 0.0833333
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_6tj5r"]
|
||||
_data = {
|
||||
"RESET": SubResource("Animation_ch8ic"),
|
||||
"attack": SubResource("Animation_ruc6s"),
|
||||
"idle_back_walk": SubResource("Animation_1tda5"),
|
||||
"idle_front_walk": SubResource("Animation_31nry"),
|
||||
"idle_left_walk": SubResource("Animation_1870e")
|
||||
[sub_resource type="Animation" id="Animation_ruc6s"]
|
||||
resource_name = "attack"
|
||||
length = 0.750008
|
||||
step = 0.0833333
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Hitbox/CollisionShape3D:disabled")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.25, 0.666666),
|
||||
"transitions": PackedFloat32Array(1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [true, false, true]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_erbrx"]
|
||||
animation = &"attack"
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_6tj5r"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_ch8ic"),
|
||||
&"idle_back_walk": SubResource("Animation_1tda5"),
|
||||
&"idle_front_walk": SubResource("Animation_31nry"),
|
||||
&"idle_left_walk": SubResource("Animation_1870e"),
|
||||
&"primary_attack": SubResource("Animation_ruc6s")
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_o0tmb"]
|
||||
animation = &"idle_back_walk"
|
||||
@@ -548,6 +544,9 @@ animation = &"idle_front_walk"
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_dvj10"]
|
||||
animation = &"idle_left_walk"
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_erbrx"]
|
||||
animation = &"attack"
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_vljb2"]
|
||||
advance_mode = 2
|
||||
|
||||
@@ -588,15 +587,15 @@ switch_mode = 2
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_acrfn"]
|
||||
states/End/position = Vector2(1464, 100)
|
||||
states/attack/node = SubResource("AnimationNodeAnimation_erbrx")
|
||||
states/attack/position = Vector2(1024, 92.9474)
|
||||
states/idle_back_walk/node = SubResource("AnimationNodeAnimation_o0tmb")
|
||||
states/idle_back_walk/position = Vector2(491, 92.9474)
|
||||
states/idle_front_walk/node = SubResource("AnimationNodeAnimation_a6s5c")
|
||||
states/idle_front_walk/position = Vector2(331, -12)
|
||||
states/idle_left_walk/node = SubResource("AnimationNodeAnimation_dvj10")
|
||||
states/idle_left_walk/position = Vector2(331, 196.947)
|
||||
transitions = ["Start", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_vljb2"), "idle_front_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_3xv6a"), "idle_left_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_0h1op"), "idle_front_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_361b7"), "idle_back_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_wftla"), "idle_back_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_gqqkl"), "idle_left_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_5cj36"), "idle_front_walk", "attack", SubResource("AnimationNodeStateMachineTransition_4t05h"), "attack", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_8hgxu"), "attack", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_fq2yw"), "attack", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_yqm0k"), "idle_back_walk", "attack", SubResource("AnimationNodeStateMachineTransition_bmy1k"), "idle_left_walk", "attack", SubResource("AnimationNodeStateMachineTransition_mxl7w")]
|
||||
states/primary_attack/node = SubResource("AnimationNodeAnimation_erbrx")
|
||||
states/primary_attack/position = Vector2(1024, 92.9474)
|
||||
transitions = ["Start", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_vljb2"), "idle_front_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_3xv6a"), "idle_left_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_0h1op"), "idle_front_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_361b7"), "idle_back_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_wftla"), "idle_back_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_gqqkl"), "idle_left_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_5cj36"), "idle_front_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_4t05h"), "primary_attack", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_8hgxu"), "primary_attack", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_fq2yw"), "primary_attack", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_yqm0k"), "idle_back_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_bmy1k"), "idle_left_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_mxl7w")]
|
||||
graph_offset = Vector2(-190, -62.0526)
|
||||
|
||||
[node name="Chariot" type="RigidBody3D"]
|
||||
@@ -608,8 +607,8 @@ axis_lock_linear_y = true
|
||||
axis_lock_angular_x = true
|
||||
contact_monitor = true
|
||||
max_contacts_reported = 1
|
||||
script = ExtResource("1_t62lw")
|
||||
EnemyStatResource = SubResource("Resource_rxw8v")
|
||||
script = ExtResource("1_hqeyd")
|
||||
_enemyStatResource = SubResource("Resource_dvne1")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
|
||||
@@ -690,7 +689,7 @@ offset = Vector2(250, 250)
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
libraries = {
|
||||
"": SubResource("AnimationLibrary_6tj5r")
|
||||
&"": SubResource("AnimationLibrary_6tj5r")
|
||||
}
|
||||
|
||||
[node name="AnimationTree" type="AnimationTree" parent="."]
|
||||
|
||||
38
src/enemy/enemy_types/filth_eater/FilthEater.cs
Normal file
38
src/enemy/enemy_types/filth_eater/FilthEater.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class FilthEater : Enemy, IHasPrimaryAttack, IHasSecondaryAttack
|
||||
{
|
||||
[Export]
|
||||
public ElementType PrimaryAttackElementalType { get; set; } = ElementType.None;
|
||||
[Export]
|
||||
public double PrimaryAttackElementalDamageBonus { get; set; } = 1.0;
|
||||
|
||||
[Export]
|
||||
public ElementType SecondaryAttackElementalType { get; set; } = ElementType.None;
|
||||
[Export]
|
||||
public double SecondaryAttackElementalDamageBonus { get; set; } = 1.0;
|
||||
|
||||
public override void TakeAction()
|
||||
{
|
||||
var rng = new RandomNumberGenerator();
|
||||
var options = new List<Action>() { PrimaryAttack, SecondaryAttack };
|
||||
var selection = rng.RandWeighted([0.875f, 0.125f]);
|
||||
options[(int)selection].Invoke();
|
||||
}
|
||||
public void PrimaryAttack()
|
||||
{
|
||||
EnemyModelView.PlayPrimaryAttackAnimation();
|
||||
}
|
||||
|
||||
public void SecondaryAttack()
|
||||
{
|
||||
EnemyModelView.PlaySecondaryAttackAnimation();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
[gd_scene load_steps=120 format=3 uid="uid://cvk007twac22c"]
|
||||
[gd_scene load_steps=127 format=3 uid="uid://cvk007twac22c"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/enemy/Enemy.cs" id="1_a8er3"]
|
||||
[ext_resource type="Script" path="res://src/enemy/EnemyStatResource.cs" id="2_mqiog"]
|
||||
[ext_resource type="Script" path="res://src/hitbox/Hitbox.cs" id="3_ipypc"]
|
||||
[ext_resource type="Script" path="res://src/enemy/enemy_types/filth_eater/FilthEater.cs" id="1_fyc13"]
|
||||
[ext_resource type="Script" uid="uid://dnkmr0eq1sij0" path="res://src/enemy/EnemyStatResource.cs" id="2_mqiog"]
|
||||
[ext_resource type="Script" uid="uid://6edayafleq8y" path="res://src/hitbox/Hitbox.cs" id="3_ipypc"]
|
||||
[ext_resource type="Texture2D" uid="uid://cx1wk7n77hdpu" path="res://src/enemy/enemy_types/filth_eater/animations/WALK BACK/Layer 1.png" id="4_ag3g0"]
|
||||
[ext_resource type="Texture2D" uid="uid://bv4du7bb3m6ug" path="res://src/enemy/enemy_types/filth_eater/animations/SWIPE/Layer 1.png" id="4_qpdqy"]
|
||||
[ext_resource type="Texture2D" uid="uid://bdl6xn7wskn2r" path="res://src/enemy/enemy_types/filth_eater/animations/WALK BACK/Layer 2.png" id="5_881nf"]
|
||||
@@ -89,26 +89,27 @@
|
||||
[ext_resource type="Texture2D" uid="uid://d32ej6fsx53io" path="res://src/enemy/enemy_types/filth_eater/animations/TELLERIC ATTACK/Layer 39.png" id="57_o526l"]
|
||||
[ext_resource type="Texture2D" uid="uid://cy5dacfrmsxwe" path="res://src/enemy/enemy_types/filth_eater/animations/TELLERIC ATTACK/Layer 40.png" id="58_4tgv5"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_rxw8v"]
|
||||
[sub_resource type="Resource" id="Resource_0y048"]
|
||||
script = ExtResource("2_mqiog")
|
||||
CurrentHP = 45.0
|
||||
MaximumHP = 45.0
|
||||
CurrentAttack = 20
|
||||
CurrentDefense = 10
|
||||
MaxAttack = 20
|
||||
MaxDefense = 10
|
||||
CurrentHP = 50.0
|
||||
MaximumHP = 50.0
|
||||
CurrentAttack = 5
|
||||
CurrentDefense = 5
|
||||
MaxAttack = 5
|
||||
MaxDefense = 5
|
||||
ExpFromDefeat = 15
|
||||
Luck = 0.05
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
TelluricDamageBonus = 0.0
|
||||
AeolicDamageBonus = 0.0
|
||||
BaseHydricDamageBonus = 0.0
|
||||
IgneousDamageBonus = 0.0
|
||||
FerrumDamageBonus = 0.0
|
||||
DropsSoulGemChance = 0.9
|
||||
PrimaryAttackElementalType = 0
|
||||
PrimaryAttackElementalDamageBonus = 1.0
|
||||
SecondaryAttackElementalType = 2
|
||||
SecondaryAttackElementalDamageBonus = 1.15
|
||||
DropsSoulGemChance = 0.75
|
||||
metadata/_custom_type_script = ExtResource("2_mqiog")
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_cwfph"]
|
||||
radius = 1.0
|
||||
@@ -445,6 +446,24 @@ tracks/2/keys = {
|
||||
"values": [0]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_1tda5"]
|
||||
resource_name = "idle_back_walk"
|
||||
length = 1.25001
|
||||
loop_mode = 1
|
||||
step = 0.0833333
|
||||
|
||||
[sub_resource type="Animation" id="Animation_31nry"]
|
||||
resource_name = "idle_front_walk"
|
||||
length = 1.25001
|
||||
loop_mode = 1
|
||||
step = 0.0833333
|
||||
|
||||
[sub_resource type="Animation" id="Animation_1870e"]
|
||||
resource_name = "idle_left_walk"
|
||||
length = 1.25001
|
||||
loop_mode = 1
|
||||
step = 0.0833333
|
||||
|
||||
[sub_resource type="Animation" id="Animation_ruc6s"]
|
||||
resource_name = "attack"
|
||||
length = 0.750008
|
||||
@@ -490,37 +509,16 @@ tracks/1/keys = {
|
||||
"values": [0]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_1tda5"]
|
||||
resource_name = "idle_back_walk"
|
||||
length = 1.25001
|
||||
loop_mode = 1
|
||||
step = 0.0833333
|
||||
|
||||
[sub_resource type="Animation" id="Animation_31nry"]
|
||||
resource_name = "idle_front_walk"
|
||||
length = 1.25001
|
||||
loop_mode = 1
|
||||
step = 0.0833333
|
||||
|
||||
[sub_resource type="Animation" id="Animation_1870e"]
|
||||
resource_name = "idle_left_walk"
|
||||
length = 1.25001
|
||||
loop_mode = 1
|
||||
step = 0.0833333
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_6tj5r"]
|
||||
_data = {
|
||||
"RESET": SubResource("Animation_ch8ic"),
|
||||
"attack": SubResource("Animation_ruc6s"),
|
||||
"attack2": SubResource("Animation_wwl4v"),
|
||||
"idle_back_walk": SubResource("Animation_1tda5"),
|
||||
"idle_front_walk": SubResource("Animation_31nry"),
|
||||
"idle_left_walk": SubResource("Animation_1870e")
|
||||
&"RESET": SubResource("Animation_ch8ic"),
|
||||
&"idle_back_walk": SubResource("Animation_1tda5"),
|
||||
&"idle_front_walk": SubResource("Animation_31nry"),
|
||||
&"idle_left_walk": SubResource("Animation_1870e"),
|
||||
&"primary_attack": SubResource("Animation_ruc6s"),
|
||||
&"secondary_attack": SubResource("Animation_wwl4v")
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_erbrx"]
|
||||
animation = &"attack"
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_o0tmb"]
|
||||
animation = &"idle_back_walk"
|
||||
|
||||
@@ -530,6 +528,12 @@ animation = &"idle_front_walk"
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_dvj10"]
|
||||
animation = &"idle_left_walk"
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_erbrx"]
|
||||
animation = &"primary_attack"
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_fyc13"]
|
||||
animation = &"secondary_attack"
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_vljb2"]
|
||||
advance_mode = 2
|
||||
|
||||
@@ -568,17 +572,37 @@ switch_mode = 2
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_mxl7w"]
|
||||
switch_mode = 2
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_0y048"]
|
||||
switch_mode = 2
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_uhpql"]
|
||||
switch_mode = 2
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_l7m4y"]
|
||||
switch_mode = 2
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_464kr"]
|
||||
switch_mode = 2
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_45of7"]
|
||||
switch_mode = 2
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_c482n"]
|
||||
switch_mode = 2
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_acrfn"]
|
||||
states/End/position = Vector2(1464, 100)
|
||||
states/attack/node = SubResource("AnimationNodeAnimation_erbrx")
|
||||
states/attack/position = Vector2(1024, 92.9474)
|
||||
states/idle_back_walk/node = SubResource("AnimationNodeAnimation_o0tmb")
|
||||
states/idle_back_walk/position = Vector2(491, 92.9474)
|
||||
states/idle_back_walk/position = Vector2(519, 75.9474)
|
||||
states/idle_front_walk/node = SubResource("AnimationNodeAnimation_a6s5c")
|
||||
states/idle_front_walk/position = Vector2(331, -12)
|
||||
states/idle_left_walk/node = SubResource("AnimationNodeAnimation_dvj10")
|
||||
states/idle_left_walk/position = Vector2(331, 196.947)
|
||||
transitions = ["Start", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_vljb2"), "idle_front_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_3xv6a"), "idle_left_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_0h1op"), "idle_front_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_361b7"), "idle_back_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_wftla"), "idle_back_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_gqqkl"), "idle_left_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_5cj36"), "idle_front_walk", "attack", SubResource("AnimationNodeStateMachineTransition_4t05h"), "attack", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_8hgxu"), "attack", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_fq2yw"), "attack", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_yqm0k"), "idle_back_walk", "attack", SubResource("AnimationNodeStateMachineTransition_bmy1k"), "idle_left_walk", "attack", SubResource("AnimationNodeStateMachineTransition_mxl7w")]
|
||||
states/primary_attack/node = SubResource("AnimationNodeAnimation_erbrx")
|
||||
states/primary_attack/position = Vector2(1067, 33.9474)
|
||||
states/secondary_attack/node = SubResource("AnimationNodeAnimation_fyc13")
|
||||
states/secondary_attack/position = Vector2(1057, 151.947)
|
||||
transitions = ["Start", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_vljb2"), "idle_front_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_3xv6a"), "idle_left_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_0h1op"), "idle_front_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_361b7"), "idle_back_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_wftla"), "idle_back_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_gqqkl"), "idle_left_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_5cj36"), "idle_front_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_4t05h"), "primary_attack", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_8hgxu"), "primary_attack", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_fq2yw"), "primary_attack", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_yqm0k"), "idle_back_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_bmy1k"), "idle_left_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_mxl7w"), "idle_back_walk", "secondary_attack", SubResource("AnimationNodeStateMachineTransition_0y048"), "idle_left_walk", "secondary_attack", SubResource("AnimationNodeStateMachineTransition_uhpql"), "idle_front_walk", "secondary_attack", SubResource("AnimationNodeStateMachineTransition_l7m4y"), "secondary_attack", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_464kr"), "secondary_attack", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_45of7"), "secondary_attack", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_c482n")]
|
||||
graph_offset = Vector2(-121, -17.0526)
|
||||
|
||||
[node name="FilthEater" type="RigidBody3D"]
|
||||
@@ -590,8 +614,8 @@ axis_lock_linear_y = true
|
||||
axis_lock_angular_x = true
|
||||
contact_monitor = true
|
||||
max_contacts_reported = 1
|
||||
script = ExtResource("1_a8er3")
|
||||
EnemyStatResource = SubResource("Resource_rxw8v")
|
||||
script = ExtResource("1_fyc13")
|
||||
_enemyStatResource = SubResource("Resource_0y048")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
|
||||
@@ -662,7 +686,7 @@ offset = Vector2(150, 150)
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
libraries = {
|
||||
"": SubResource("AnimationLibrary_6tj5r")
|
||||
&"": SubResource("AnimationLibrary_6tj5r")
|
||||
}
|
||||
|
||||
[node name="AnimationTree" type="AnimationTree" parent="."]
|
||||
|
||||
23
src/enemy/enemy_types/michael/Michael.cs
Normal file
23
src/enemy/enemy_types/michael/Michael.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Michael : Enemy, IHasPrimaryAttack
|
||||
{
|
||||
[Export]
|
||||
public ElementType PrimaryAttackElementalType { get; set; } = ElementType.None;
|
||||
[Export]
|
||||
public double PrimaryAttackElementalDamageBonus { get; set; } = 1.0;
|
||||
|
||||
public override void TakeAction()
|
||||
{
|
||||
PrimaryAttack();
|
||||
}
|
||||
public void PrimaryAttack()
|
||||
{
|
||||
EnemyModelView.PlayPrimaryAttackAnimation();
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,8 @@
|
||||
[gd_scene load_steps=7 format=3 uid="uid://b0gwivt7cw7nd"]
|
||||
[gd_scene load_steps=5 format=3 uid="uid://b0gwivt7cw7nd"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://2d34jler3rmv" path="res://src/enemy/Enemy.cs" id="1_a6wro"]
|
||||
[ext_resource type="Script" uid="uid://dnkmr0eq1sij0" path="res://src/enemy/EnemyStatResource.cs" id="2_x4pjh"]
|
||||
[ext_resource type="Script" path="res://src/enemy/enemy_types/michael/Michael.cs" id="1_wfjxm"]
|
||||
[ext_resource type="PackedScene" uid="uid://bjg8wyvp8q6oc" path="res://src/enemy/enemy_types/michael/MichaelModelView.tscn" id="3_wrps7"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_k2g1o"]
|
||||
script = ExtResource("2_x4pjh")
|
||||
CurrentHP = 45.0
|
||||
MaximumHP = 45.0
|
||||
CurrentAttack = 20
|
||||
CurrentDefense = 11
|
||||
MaxAttack = 20
|
||||
MaxDefense = 11
|
||||
ExpFromDefeat = 10
|
||||
Luck = 0.05
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
TelluricDamageBonus = 0.0
|
||||
AeolicDamageBonus = 0.0
|
||||
BaseHydricDamageBonus = 0.0
|
||||
IgneousDamageBonus = 0.0
|
||||
FerrumDamageBonus = 0.0
|
||||
DropsSoulGemChance = 0.75
|
||||
|
||||
[sub_resource type="CylinderShape3D" id="CylinderShape3D_jbgmx"]
|
||||
height = 5.0
|
||||
radius = 1.0
|
||||
@@ -40,8 +17,7 @@ collision_layer = 10
|
||||
collision_mask = 11
|
||||
axis_lock_linear_y = true
|
||||
axis_lock_angular_x = true
|
||||
script = ExtResource("1_a6wro")
|
||||
EnemyStatResource = SubResource("Resource_k2g1o")
|
||||
script = ExtResource("1_wfjxm")
|
||||
|
||||
[node name="LineOfSight" type="Area3D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[gd_scene load_steps=101 format=3 uid="uid://bjg8wyvp8q6oc"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/enemy/EnemyModelView.cs" id="1_iajg3"]
|
||||
[ext_resource type="Script" uid="uid://chymnqdw7hibn" path="res://src/enemy/EnemyModelView.cs" id="1_iajg3"]
|
||||
[ext_resource type="Texture2D" uid="uid://clpqh2pyqljkn" path="res://src/enemy/enemy_types/michael/animations/IDLE_WALK/BACK/Michael_Walk_Idle_Back (1).png" id="2_3g180"]
|
||||
[ext_resource type="Resource" uid="uid://6d7ivtna8dqb" path="res://src/enemy/enemy_types/michael/MichaelLoreInfo.tres" id="2_fssmb"]
|
||||
[ext_resource type="Texture2D" uid="uid://b0dec8ak2bo5t" path="res://src/enemy/enemy_types/michael/animations/IDLE_WALK/BACK/Michael_Walk_Idle_Back (2).png" id="3_fssmb"]
|
||||
@@ -71,7 +71,7 @@
|
||||
[ext_resource type="Texture2D" uid="uid://vxphbifafq0q" path="res://src/enemy/enemy_types/michael/animations/IDLE_WALK/LEFT SIDE/Michael_IdleWalk_Left (21).png" id="68_msiau"]
|
||||
[ext_resource type="Texture2D" uid="uid://7r30bjydumon" path="res://src/enemy/enemy_types/michael/animations/IDLE_WALK/LEFT SIDE/Michael_IdleWalk_Left (22).png" id="69_lec8c"]
|
||||
[ext_resource type="Texture2D" uid="uid://djspx2smexhme" path="res://src/enemy/enemy_types/michael/animations/IDLE_WALK/LEFT SIDE/Michael_IdleWalk_Left (23).png" id="70_f0jo7"]
|
||||
[ext_resource type="Script" path="res://src/hitbox/Hitbox.cs" id="71_ul4dn"]
|
||||
[ext_resource type="Script" uid="uid://6edayafleq8y" path="res://src/hitbox/Hitbox.cs" id="71_ul4dn"]
|
||||
|
||||
[sub_resource type="ViewportTexture" id="ViewportTexture_v7t0v"]
|
||||
viewport_path = NodePath("Sprite/SubViewport")
|
||||
@@ -345,47 +345,6 @@ tracks/2/keys = {
|
||||
"values": [&"idle_front_walk"]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_0k3e8"]
|
||||
resource_name = "attack"
|
||||
length = 0.416668
|
||||
step = 0.0166667
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Hitbox/CollisionShape3D:disabled")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.0333333, 0.3),
|
||||
"transitions": PackedFloat32Array(1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [true, false, true]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("Sprite/SubViewport/AnimatedSprite:animation")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [&"idle_front_walk"]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("Sprite/SubViewport/AnimatedSprite:frame")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0, 0.0166667, 0.0333334, 0.0500001, 0.0666668, 0.0833335, 0.1, 0.116667, 0.133334, 0.15, 0.166667, 0.183334, 0.2, 0.216667, 0.233334, 0.25, 0.266667, 0.283334, 0.300001, 0.316667, 0.333334, 0.350001, 0.366667),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_ppbeh"]
|
||||
resource_name = "idle_back_walk"
|
||||
length = 1.91667
|
||||
@@ -476,18 +435,56 @@ tracks/1/keys = {
|
||||
"values": [&"idle_left_walk"]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_0k3e8"]
|
||||
resource_name = "attack"
|
||||
length = 0.416668
|
||||
step = 0.0166667
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Hitbox/CollisionShape3D:disabled")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0, 0.0333333, 0.3),
|
||||
"transitions": PackedFloat32Array(1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [true, false, true]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("Sprite/SubViewport/AnimatedSprite:animation")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [&"idle_front_walk"]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("Sprite/SubViewport/AnimatedSprite:frame")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0, 0.0166667, 0.0333334, 0.0500001, 0.0666668, 0.0833335, 0.1, 0.116667, 0.133334, 0.15, 0.166667, 0.183334, 0.2, 0.216667, 0.233334, 0.25, 0.266667, 0.283334, 0.300001, 0.316667, 0.333334, 0.350001, 0.366667),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_346xs"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_41ppy"),
|
||||
&"attack": SubResource("Animation_0k3e8"),
|
||||
&"idle_back_walk": SubResource("Animation_ppbeh"),
|
||||
&"idle_front_walk": SubResource("Animation_3dffb"),
|
||||
&"idle_left_walk": SubResource("Animation_0qxqf")
|
||||
&"idle_left_walk": SubResource("Animation_0qxqf"),
|
||||
&"primary_attack": SubResource("Animation_0k3e8")
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_erbrx"]
|
||||
animation = &"attack"
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_o0tmb"]
|
||||
animation = &"idle_back_walk"
|
||||
|
||||
@@ -497,6 +494,9 @@ animation = &"idle_front_walk"
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_dvj10"]
|
||||
animation = &"idle_left_walk"
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_erbrx"]
|
||||
animation = &"primary_attack"
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_vljb2"]
|
||||
advance_mode = 2
|
||||
|
||||
@@ -537,15 +537,15 @@ switch_mode = 2
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_r23qr"]
|
||||
states/End/position = Vector2(1464, 100)
|
||||
states/attack/node = SubResource("AnimationNodeAnimation_erbrx")
|
||||
states/attack/position = Vector2(1151, 86.9474)
|
||||
states/idle_back_walk/node = SubResource("AnimationNodeAnimation_o0tmb")
|
||||
states/idle_back_walk/position = Vector2(490, 92.9474)
|
||||
states/idle_front_walk/node = SubResource("AnimationNodeAnimation_a6s5c")
|
||||
states/idle_front_walk/position = Vector2(331, -12)
|
||||
states/idle_left_walk/node = SubResource("AnimationNodeAnimation_dvj10")
|
||||
states/idle_left_walk/position = Vector2(331, 196.947)
|
||||
transitions = ["Start", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_vljb2"), "idle_front_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_3xv6a"), "idle_left_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_0h1op"), "idle_front_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_361b7"), "idle_back_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_wftla"), "idle_back_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_gqqkl"), "idle_left_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_5cj36"), "idle_front_walk", "attack", SubResource("AnimationNodeStateMachineTransition_4t05h"), "attack", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_8hgxu"), "attack", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_fq2yw"), "attack", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_yqm0k"), "idle_back_walk", "attack", SubResource("AnimationNodeStateMachineTransition_bmy1k"), "idle_left_walk", "attack", SubResource("AnimationNodeStateMachineTransition_mxl7w")]
|
||||
states/primary_attack/node = SubResource("AnimationNodeAnimation_erbrx")
|
||||
states/primary_attack/position = Vector2(1151, 86.9474)
|
||||
transitions = ["Start", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_vljb2"), "idle_front_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_3xv6a"), "idle_left_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_0h1op"), "idle_front_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_361b7"), "idle_back_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_wftla"), "idle_back_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_gqqkl"), "idle_left_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_5cj36"), "idle_front_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_4t05h"), "primary_attack", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_8hgxu"), "primary_attack", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_fq2yw"), "primary_attack", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_yqm0k"), "idle_back_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_bmy1k"), "idle_left_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_mxl7w")]
|
||||
graph_offset = Vector2(-190, -62.0526)
|
||||
|
||||
[node name="EnemyModelView" type="Node3D"]
|
||||
|
||||
23
src/enemy/enemy_types/sproingy/Sproingy.cs
Normal file
23
src/enemy/enemy_types/sproingy/Sproingy.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using Chickensoft.AutoInject;
|
||||
using Chickensoft.Introspection;
|
||||
using Godot;
|
||||
|
||||
namespace GameJamDungeon;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class Sproingy : Enemy, IHasPrimaryAttack
|
||||
{
|
||||
[Export]
|
||||
public ElementType PrimaryAttackElementalType { get; set; } = ElementType.None;
|
||||
[Export]
|
||||
public double PrimaryAttackElementalDamageBonus { get; set; } = 1.0;
|
||||
|
||||
public override void TakeAction()
|
||||
{
|
||||
PrimaryAttack();
|
||||
}
|
||||
public void PrimaryAttack()
|
||||
{
|
||||
EnemyModelView.PlayPrimaryAttackAnimation();
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,8 @@
|
||||
[gd_scene load_steps=7 format=3 uid="uid://bksq62muhk3h5"]
|
||||
[gd_scene load_steps=5 format=3 uid="uid://bksq62muhk3h5"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://2d34jler3rmv" path="res://src/enemy/Enemy.cs" id="1_7tinp"]
|
||||
[ext_resource type="Script" uid="uid://dnkmr0eq1sij0" path="res://src/enemy/EnemyStatResource.cs" id="2_j3knd"]
|
||||
[ext_resource type="Script" path="res://src/enemy/enemy_types/sproingy/Sproingy.cs" id="1_ldo22"]
|
||||
[ext_resource type="PackedScene" uid="uid://bli0t0d6ommvi" path="res://src/enemy/enemy_types/sproingy/SproingyModelView.tscn" id="4_o3b7p"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_rxw8v"]
|
||||
script = ExtResource("2_j3knd")
|
||||
CurrentHP = 45.0
|
||||
MaximumHP = 45.0
|
||||
CurrentAttack = 20
|
||||
CurrentDefense = 10
|
||||
MaxAttack = 20
|
||||
MaxDefense = 10
|
||||
ExpFromDefeat = 8
|
||||
Luck = 0.05
|
||||
TelluricResistance = 0.0
|
||||
AeolicResistance = 0.0
|
||||
HydricResistance = 0.0
|
||||
IgneousResistance = 0.0
|
||||
FerrumResistance = 0.0
|
||||
TelluricDamageBonus = 0.0
|
||||
AeolicDamageBonus = 0.0
|
||||
BaseHydricDamageBonus = 0.0
|
||||
IgneousDamageBonus = 0.0
|
||||
FerrumDamageBonus = 0.0
|
||||
DropsSoulGemChance = 0.9
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_cwfph"]
|
||||
radius = 0.226425
|
||||
height = 2.02807
|
||||
@@ -43,8 +20,7 @@ axis_lock_linear_y = true
|
||||
axis_lock_angular_x = true
|
||||
contact_monitor = true
|
||||
max_contacts_reported = 1
|
||||
script = ExtResource("1_7tinp")
|
||||
EnemyStatResource = SubResource("Resource_rxw8v")
|
||||
script = ExtResource("1_ldo22")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[gd_scene load_steps=86 format=3 uid="uid://bli0t0d6ommvi"]
|
||||
|
||||
[ext_resource type="Script" path="res://src/enemy/EnemyModelView.cs" id="1_0vbio"]
|
||||
[ext_resource type="Script" uid="uid://chymnqdw7hibn" path="res://src/enemy/EnemyModelView.cs" id="1_0vbio"]
|
||||
[ext_resource type="Texture2D" uid="uid://dd0ia6isdqg61" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 1.png" id="1_pbx41"]
|
||||
[ext_resource type="Texture2D" uid="uid://bs4ico5ouo5d3" path="res://src/enemy/enemy_types/sproingy/animations/ATTACK/Layer 2.png" id="2_0vbio"]
|
||||
[ext_resource type="Resource" uid="uid://bctxs1jlkhgmc" path="res://src/enemy/enemy_types/sproingy/SproingyLoreInfo.tres" id="2_53wuj"]
|
||||
@@ -57,7 +57,7 @@
|
||||
[ext_resource type="Texture2D" uid="uid://b3gndmrlrvexy" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_SIDE/Layer 13.png" id="53_nr2vc"]
|
||||
[ext_resource type="Texture2D" uid="uid://b1cmx8l4ia3fv" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_SIDE/Layer 14.png" id="54_jdvn0"]
|
||||
[ext_resource type="Texture2D" uid="uid://c7t4626rox02s" path="res://src/enemy/enemy_types/sproingy/animations/IDLE_WALK_SIDE/Layer 15.png" id="55_2eqor"]
|
||||
[ext_resource type="Script" path="res://src/hitbox/Hitbox.cs" id="57_lae8t"]
|
||||
[ext_resource type="Script" uid="uid://6edayafleq8y" path="res://src/hitbox/Hitbox.cs" id="57_lae8t"]
|
||||
|
||||
[sub_resource type="ViewportTexture" id="ViewportTexture_h1kaf"]
|
||||
viewport_path = NodePath("Sprite3D/SubViewport")
|
||||
@@ -281,35 +281,6 @@ tracks/1/keys = {
|
||||
"values": [0]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_ruc6s"]
|
||||
resource_name = "attack"
|
||||
length = 0.750008
|
||||
step = 0.0833333
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:animation")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [&"attack"]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:frame")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0, 0.0833333, 0.166667, 0.25, 0.333333, 0.416667, 0.5, 0.583333, 0.666666, 0.75),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 0,
|
||||
"values": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_1tda5"]
|
||||
resource_name = "idle_back_walk"
|
||||
length = 1.16667
|
||||
@@ -400,18 +371,44 @@ tracks/1/keys = {
|
||||
"values": [&"idle_left_walk"]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_ruc6s"]
|
||||
resource_name = "attack"
|
||||
length = 0.750008
|
||||
step = 0.0833333
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:animation")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 0,
|
||||
"values": [&"attack"]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("Sprite3D/SubViewport/AnimatedSprite:frame")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0, 0.0833333, 0.166667, 0.25, 0.333333, 0.416667, 0.5, 0.583333, 0.666666, 0.75),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 0,
|
||||
"values": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_6tj5r"]
|
||||
_data = {
|
||||
&"RESET": SubResource("Animation_ch8ic"),
|
||||
&"attack": SubResource("Animation_ruc6s"),
|
||||
&"idle_back_walk": SubResource("Animation_1tda5"),
|
||||
&"idle_front_walk": SubResource("Animation_31nry"),
|
||||
&"idle_left_walk": SubResource("Animation_1870e")
|
||||
&"idle_left_walk": SubResource("Animation_1870e"),
|
||||
&"primary_attack": SubResource("Animation_ruc6s")
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_erbrx"]
|
||||
animation = &"attack"
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_o0tmb"]
|
||||
animation = &"idle_back_walk"
|
||||
|
||||
@@ -421,6 +418,9 @@ animation = &"idle_front_walk"
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_dvj10"]
|
||||
animation = &"idle_left_walk"
|
||||
|
||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_erbrx"]
|
||||
animation = &"primary_attack"
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachineTransition" id="AnimationNodeStateMachineTransition_vljb2"]
|
||||
advance_mode = 2
|
||||
|
||||
@@ -461,15 +461,15 @@ switch_mode = 2
|
||||
|
||||
[sub_resource type="AnimationNodeStateMachine" id="AnimationNodeStateMachine_d5bmw"]
|
||||
states/End/position = Vector2(1464, 100)
|
||||
states/attack/node = SubResource("AnimationNodeAnimation_erbrx")
|
||||
states/attack/position = Vector2(1024, 92.9474)
|
||||
states/idle_back_walk/node = SubResource("AnimationNodeAnimation_o0tmb")
|
||||
states/idle_back_walk/position = Vector2(491, 92.9474)
|
||||
states/idle_front_walk/node = SubResource("AnimationNodeAnimation_a6s5c")
|
||||
states/idle_front_walk/position = Vector2(331, -12)
|
||||
states/idle_left_walk/node = SubResource("AnimationNodeAnimation_dvj10")
|
||||
states/idle_left_walk/position = Vector2(331, 196.947)
|
||||
transitions = ["Start", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_vljb2"), "idle_front_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_3xv6a"), "idle_left_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_0h1op"), "idle_front_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_361b7"), "idle_back_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_wftla"), "idle_back_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_gqqkl"), "idle_left_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_5cj36"), "idle_front_walk", "attack", SubResource("AnimationNodeStateMachineTransition_4t05h"), "attack", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_8hgxu"), "attack", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_fq2yw"), "attack", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_yqm0k"), "idle_back_walk", "attack", SubResource("AnimationNodeStateMachineTransition_bmy1k"), "idle_left_walk", "attack", SubResource("AnimationNodeStateMachineTransition_mxl7w")]
|
||||
states/primary_attack/node = SubResource("AnimationNodeAnimation_erbrx")
|
||||
states/primary_attack/position = Vector2(1024, 92.9474)
|
||||
transitions = ["Start", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_vljb2"), "idle_front_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_3xv6a"), "idle_left_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_0h1op"), "idle_front_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_361b7"), "idle_back_walk", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_wftla"), "idle_back_walk", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_gqqkl"), "idle_left_walk", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_5cj36"), "idle_front_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_4t05h"), "primary_attack", "idle_front_walk", SubResource("AnimationNodeStateMachineTransition_8hgxu"), "primary_attack", "idle_back_walk", SubResource("AnimationNodeStateMachineTransition_fq2yw"), "primary_attack", "idle_left_walk", SubResource("AnimationNodeStateMachineTransition_yqm0k"), "idle_back_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_bmy1k"), "idle_left_walk", "primary_attack", SubResource("AnimationNodeStateMachineTransition_mxl7w")]
|
||||
graph_offset = Vector2(46.1163, -62.0526)
|
||||
|
||||
[node name="EnemyModelView" type="Node3D"]
|
||||
|
||||
@@ -13,8 +13,6 @@ namespace GameJamDungeon
|
||||
|
||||
public readonly record struct PhysicsTick(double Delta);
|
||||
|
||||
public readonly record struct HitByPlayer(double Damage);
|
||||
|
||||
public readonly record struct EnemyDefeated();
|
||||
|
||||
public readonly record struct PatrolToRandomSpot(Vector3 PatrolTarget);
|
||||
|
||||
@@ -10,9 +10,7 @@ namespace GameJamDungeon
|
||||
|
||||
public readonly record struct MovementComputed(Vector3 LinearVelocity);
|
||||
|
||||
public readonly record struct HitByPlayer(double CurrentHP);
|
||||
|
||||
public readonly record struct Attack();
|
||||
public readonly record struct TakeAction();
|
||||
|
||||
public readonly record struct Defeated();
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
@startuml EnemyLogic
|
||||
state "EnemyLogic State" as GameJamDungeon_EnemyLogic_State {
|
||||
state "Defeated" as GameJamDungeon_EnemyLogic_State_Defeated
|
||||
state "Alive" as GameJamDungeon_EnemyLogic_State_Alive {
|
||||
state "FollowPlayer" as GameJamDungeon_EnemyLogic_State_FollowPlayer
|
||||
state "Idle" as GameJamDungeon_EnemyLogic_State_Idle
|
||||
}
|
||||
state "Defeated" as GameJamDungeon_EnemyLogic_State_Defeated
|
||||
}
|
||||
|
||||
GameJamDungeon_EnemyLogic_State_Alive --> GameJamDungeon_EnemyLogic_State_Alive : AttackTimer
|
||||
GameJamDungeon_EnemyLogic_State_Alive --> GameJamDungeon_EnemyLogic_State_Alive : HitByPlayer
|
||||
GameJamDungeon_EnemyLogic_State_Alive --> GameJamDungeon_EnemyLogic_State_Defeated : EnemyDefeated
|
||||
GameJamDungeon_EnemyLogic_State_FollowPlayer --> GameJamDungeon_EnemyLogic_State_FollowPlayer : PhysicsTick
|
||||
GameJamDungeon_EnemyLogic_State_FollowPlayer --> GameJamDungeon_EnemyLogic_State_Idle : LostPlayer
|
||||
@@ -16,11 +15,8 @@ GameJamDungeon_EnemyLogic_State_Idle --> GameJamDungeon_EnemyLogic_State_FollowP
|
||||
GameJamDungeon_EnemyLogic_State_Idle --> GameJamDungeon_EnemyLogic_State_Idle : PatrolToRandomSpot
|
||||
GameJamDungeon_EnemyLogic_State_Idle --> GameJamDungeon_EnemyLogic_State_Idle : PhysicsTick
|
||||
|
||||
GameJamDungeon_EnemyLogic_State_Alive : OnAttackTimer → Attack
|
||||
GameJamDungeon_EnemyLogic_State_Alive : OnAttackTimer → TakeAction
|
||||
GameJamDungeon_EnemyLogic_State_Alive : OnEnemyDefeated → Defeated
|
||||
GameJamDungeon_EnemyLogic_State_Alive : OnHitByPlayer → HitByPlayer
|
||||
GameJamDungeon_EnemyLogic_State_FollowPlayer : OnPhysicsTick → MovementComputed
|
||||
GameJamDungeon_EnemyLogic_State_Idle : OnPhysicsTick → MovementComputed
|
||||
|
||||
[*] --> GameJamDungeon_EnemyLogic_State_Idle
|
||||
@enduml
|
||||
@@ -8,23 +8,11 @@ namespace GameJamDungeon
|
||||
public partial record State
|
||||
{
|
||||
[Meta, Id("enemy_logic_state_alive")]
|
||||
public abstract partial record Alive : State, IGet<Input.HitByPlayer>, IGet<Input.AttackTimer>, IGet<Input.EnemyDefeated>
|
||||
public abstract partial record Alive : State, IGet<Input.AttackTimer>, IGet<Input.EnemyDefeated>
|
||||
{
|
||||
public Transition On(in Input.HitByPlayer input)
|
||||
{
|
||||
var enemy = Get<IEnemy>();
|
||||
enemy.CurrentHP.OnNext(enemy.CurrentHP.Value - input.Damage);
|
||||
GD.Print("Current HP: " + enemy.CurrentHP.Value);
|
||||
Output(new Output.HitByPlayer());
|
||||
|
||||
Input(new Input.Alerted());
|
||||
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
public Transition On(in Input.AttackTimer input)
|
||||
{
|
||||
Output(new Output.Attack());
|
||||
Output(new Output.TakeAction());
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
|
||||
@@ -16,16 +16,7 @@ namespace GameJamDungeon
|
||||
var enemy = Get<IEnemy>();
|
||||
var gameRepo = Get<IGameRepo>();
|
||||
var target = gameRepo.PlayerGlobalPosition.Value;
|
||||
enemy.NavAgent.TargetPosition = target;
|
||||
var targetPosition = enemy.NavAgent.GetNextPathPosition();
|
||||
|
||||
var velocity = (targetPosition - enemy.GlobalTransform.Origin).Normalized() * 2f * (float)delta;
|
||||
var lookAtDir = enemy.GlobalTransform.Origin - velocity;
|
||||
var lookAtPosition = new Vector3(lookAtDir.X, enemy.GlobalPosition.Y, lookAtDir.Z);
|
||||
if (enemy.GlobalPosition.DistanceTo(target) > 1.0f && !velocity.IsEqualApprox(Vector3.Zero) && !enemy.GlobalPosition.IsEqualApprox(lookAtPosition))
|
||||
enemy.LookAt(lookAtPosition);
|
||||
|
||||
Output(new Output.MovementComputed(velocity));
|
||||
enemy.MoveToLocation(target, (float)delta);
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ public partial class EnemyLogic
|
||||
[Meta, Id("enemy_logic_state_idle")]
|
||||
public partial record Idle : Alive, IGet<Input.Alerted>, IGet<Input.PhysicsTick>, IGet<Input.PatrolToRandomSpot>
|
||||
{
|
||||
private Vector3 _patrolTarget { get; set; }
|
||||
public Transition On(in Input.Alerted _)
|
||||
{
|
||||
return To<FollowPlayer>();
|
||||
@@ -19,22 +20,13 @@ public partial class EnemyLogic
|
||||
{
|
||||
var delta = input.Delta;
|
||||
var enemy = Get<IEnemy>();
|
||||
var targetPosition = enemy.NavAgent.GetNextPathPosition();
|
||||
var velocity = (targetPosition - enemy.GlobalPosition).Normalized() * 1.0f * (float)delta;
|
||||
var lookAtDir = enemy.GlobalTransform.Origin - velocity;
|
||||
|
||||
var lookAtPosition = new Vector3(lookAtDir.X, enemy.GlobalPosition.Y, lookAtDir.Z);
|
||||
if (enemy.GlobalPosition.DistanceTo(targetPosition) > 1.0f && !velocity.IsEqualApprox(Vector3.Zero) && !enemy.GlobalPosition.IsEqualApprox(lookAtPosition))
|
||||
enemy.LookAt(lookAtPosition);
|
||||
|
||||
Output(new Output.MovementComputed(velocity));
|
||||
enemy.MoveToLocation(_patrolTarget, (float)delta);
|
||||
return ToSelf();
|
||||
}
|
||||
|
||||
public Transition On(in Input.PatrolToRandomSpot input)
|
||||
{
|
||||
var enemy = Get<IEnemy>();
|
||||
enemy.NavAgent.TargetPosition = input.PatrolTarget;
|
||||
_patrolTarget = input.PatrolTarget;
|
||||
return ToSelf();
|
||||
}
|
||||
}
|
||||
|
||||
12
src/game/ElementType.cs
Normal file
12
src/game/ElementType.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public enum ElementType
|
||||
{
|
||||
None,
|
||||
Aeolic,
|
||||
Telluric,
|
||||
Hydric,
|
||||
Igneous,
|
||||
Ferrum
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
@startuml GameLogic
|
||||
state "GameLogic State" as GameJamDungeon_GameLogic_State {
|
||||
state "Quit" as GameJamDungeon_GameLogic_State_Quit
|
||||
state "GameStarted" as GameJamDungeon_GameLogic_State_GameStarted
|
||||
state "Playing" as GameJamDungeon_GameLogic_State_Playing {
|
||||
state "AskForTeleport" as GameJamDungeon_GameLogic_State_AskForTeleport
|
||||
state "FloorClearedDecisionState" as GameJamDungeon_GameLogic_State_FloorClearedDecisionState
|
||||
state "InventoryOpened" as GameJamDungeon_GameLogic_State_InventoryOpened
|
||||
state "MinimapOpen" as GameJamDungeon_GameLogic_State_MinimapOpen
|
||||
state "Paused" as GameJamDungeon_GameLogic_State_Paused
|
||||
state "FloorClearedDecisionState" as GameJamDungeon_GameLogic_State_FloorClearedDecisionState
|
||||
state "AskForTeleport" as GameJamDungeon_GameLogic_State_AskForTeleport
|
||||
state "InventoryOpened" as GameJamDungeon_GameLogic_State_InventoryOpened
|
||||
state "Resuming" as GameJamDungeon_GameLogic_State_Resuming
|
||||
}
|
||||
state "GameStarted" as GameJamDungeon_GameLogic_State_GameStarted
|
||||
state "Quit" as GameJamDungeon_GameLogic_State_Quit
|
||||
}
|
||||
|
||||
GameJamDungeon_GameLogic_State_AskForTeleport --> GameJamDungeon_GameLogic_State_FloorClearedDecisionState : FloorExitReached
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Chickensoft.GodotNodeInterfaces;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public interface IHitbox : IArea3D
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@ using Chickensoft.Introspection;
|
||||
using GameJamDungeon;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
[Meta(typeof(IAutoNode))]
|
||||
public partial class ThrowableItem : Node3D, IUsableItem
|
||||
@@ -27,23 +26,10 @@ public partial class ThrowableItem : Node3D, IUsableItem
|
||||
|
||||
[Node] public Area3D Pickup { get; set; } = default!;
|
||||
|
||||
private ThrowableItemTag[] _affinityTypes;
|
||||
|
||||
private int _affinityIndex = 0;
|
||||
|
||||
public void OnResolved()
|
||||
{
|
||||
Sprite.Texture = ThrowableItemInfo.Texture;
|
||||
Pickup.BodyEntered += OnEntered;
|
||||
_affinityTypes =
|
||||
[
|
||||
ThrowableItemTag.InflictBaseDamage,
|
||||
ThrowableItemTag.InflictHydricDamage,
|
||||
ThrowableItemTag.InflictIgneousDamage,
|
||||
ThrowableItemTag.InflictTelluricDamage,
|
||||
ThrowableItemTag.InflictAeolicDamage,
|
||||
ThrowableItemTag.InflictFerrumDamage
|
||||
];
|
||||
}
|
||||
|
||||
public void Use()
|
||||
@@ -62,13 +48,12 @@ public partial class ThrowableItem : Node3D, IUsableItem
|
||||
|
||||
private void ChangeAffinity()
|
||||
{
|
||||
ThrowableItemInfo.ThrowableItemTags.Remove(_affinityTypes[_affinityIndex]);
|
||||
_affinityIndex = (_affinityIndex + 1) % (_affinityTypes.Length);
|
||||
ThrowableItemInfo.ThrowableItemTags.Add(_affinityTypes[_affinityIndex]);
|
||||
var maximumElements = Enum.GetNames(typeof(ElementType)).Length;
|
||||
ThrowableItemInfo.ElementType = ThrowableItemInfo.ElementType + 1 % maximumElements;
|
||||
|
||||
// TODO: Make this an inventory animation to cycle through elements.
|
||||
ThrowableItemInfo.Description =
|
||||
$"{GetDescription(_affinityTypes[_affinityIndex])} when thrown." +
|
||||
$"Inflicts {ThrowableItemInfo.ElementType} damage when thrown." +
|
||||
$"{System.Environment.NewLine}Use item to change Affinity.";
|
||||
}
|
||||
|
||||
@@ -78,19 +63,4 @@ public partial class ThrowableItem : Node3D, IUsableItem
|
||||
if (isAdded)
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
private static string GetDescription(ThrowableItemTag enumValue)
|
||||
{
|
||||
var field = enumValue.GetType().GetField(enumValue.ToString());
|
||||
if (field == null)
|
||||
return enumValue.ToString();
|
||||
|
||||
var attributes = field.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||
if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attribute)
|
||||
{
|
||||
return attribute.Description;
|
||||
}
|
||||
|
||||
return enumValue.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
[sub_resource type="Resource" id="Resource_b0s4k"]
|
||||
script = ExtResource("2_8h2lx")
|
||||
ThrowableItemTags = Array[int]([])
|
||||
ElementType = 0
|
||||
UsableItemTags = Array[int]([])
|
||||
Name = ""
|
||||
Description = ""
|
||||
|
||||
@@ -8,6 +8,9 @@ public partial class ThrowableItemStats : InventoryItemStats
|
||||
[Export]
|
||||
public Godot.Collections.Array<ThrowableItemTag> ThrowableItemTags { get; set; } = new Godot.Collections.Array<ThrowableItemTag>();
|
||||
|
||||
[Export]
|
||||
public ElementType ElementType { get; set; } = ElementType.None;
|
||||
|
||||
[Export]
|
||||
public Godot.Collections.Array<UsableItemTag> UsableItemTags { get; set; } = new Godot.Collections.Array<UsableItemTag>();
|
||||
}
|
||||
|
||||
@@ -2,18 +2,6 @@
|
||||
|
||||
public enum ThrowableItemTag
|
||||
{
|
||||
[Description("Inflicts basic damage")]
|
||||
InflictBaseDamage,
|
||||
[Description("Inflicts Telluric damage")]
|
||||
InflictTelluricDamage,
|
||||
[Description("Inflicts Aeolic damage")]
|
||||
InflictAeolicDamage,
|
||||
[Description("Inflicts Hydric damage")]
|
||||
InflictHydricDamage,
|
||||
[Description("Inflicts Igneous damage")]
|
||||
InflictIgneousDamage,
|
||||
[Description("Inflicts Ferrum damage")]
|
||||
InflictFerrumDamage,
|
||||
LowerTargetTo1HP,
|
||||
CanChangeAffinity
|
||||
}
|
||||
|
||||
@@ -38,14 +38,16 @@ public partial class ThrownItem : RigidBody3D
|
||||
|
||||
private void CalculateEffect(IEnemy enemy)
|
||||
{
|
||||
enemy.EnemyLogic.Input(new EnemyLogic.Input.HitByPlayer(ThrownItemStats.ThrowDamage));
|
||||
|
||||
if (ThrownItemStats is ThrowableItemStats throwableItemStats)
|
||||
{
|
||||
if (throwableItemStats.ThrowableItemTags.Contains(ThrowableItemTag.LowerTargetTo1HP))
|
||||
enemy.EnemyLogic.Input(new EnemyLogic.Input.HitByPlayer(enemy.CurrentHP.Value - 1));
|
||||
enemy.EnemyLogic.Input(new EnemyLogic.Input.HitByPlayer(DamageCalculator.CalculateThrownItemDamage(throwableItemStats.ThrowDamage, enemy.EnemyStatResource, throwableItemStats)));
|
||||
|
||||
enemy.TakeDamage(enemy.CurrentHP - 1, ElementType.None, false, true, true);
|
||||
else
|
||||
enemy.TakeDamage(throwableItemStats.ThrowDamage, throwableItemStats.ElementType);
|
||||
}
|
||||
else
|
||||
{
|
||||
enemy.TakeDamage(ThrownItemStats.ThrowDamage, ElementType.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,19 +14,10 @@ public partial class WeaponStats : InventoryItemStats
|
||||
public double AttackSpeed { get; set; } = 1;
|
||||
|
||||
[Export]
|
||||
public double TelluricDamageBonus { get; set; } = 0;
|
||||
public ElementType WeaponElement { get; set; } = ElementType.None;
|
||||
|
||||
[Export]
|
||||
public double AeolicDamageBonus { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
public double BaseHydricDamageBonus { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
public double IgneousDamageBonus { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
public double FerrumDamageBonus { get; set; } = 0;
|
||||
public double ElementalDamageBonus { get; set; } = 1.0;
|
||||
|
||||
[Export]
|
||||
public Godot.Collections.Array<WeaponTag> WeaponTags { get; set; } = new Godot.Collections.Array<WeaponTag>();
|
||||
|
||||
@@ -9,8 +9,6 @@ namespace GameJamDungeon
|
||||
{
|
||||
public interface IPlayer : ICharacterBody3D, IKillable
|
||||
{
|
||||
PlayerLogic PlayerLogic { get; }
|
||||
|
||||
public Vector3 GetGlobalInputVector();
|
||||
|
||||
public float GetLeftStrafeInputVector();
|
||||
@@ -33,6 +31,13 @@ namespace GameJamDungeon
|
||||
|
||||
PlayerLogic IProvide<PlayerLogic>.Value() => PlayerLogic;
|
||||
|
||||
public PlayerLogic.Settings Settings { get; set; } = default!;
|
||||
|
||||
private PlayerLogic PlayerLogic { get; set; } = default!;
|
||||
|
||||
private PlayerLogic.IBinding PlayerBinding { get; set; } = default!;
|
||||
|
||||
#region Dependencies
|
||||
[Dependency]
|
||||
public IAppRepo AppRepo => this.DependOn<IAppRepo>();
|
||||
|
||||
@@ -41,14 +46,18 @@ namespace GameJamDungeon
|
||||
|
||||
[Dependency]
|
||||
public ISaveChunk<GameData> GameChunk => this.DependOn<ISaveChunk<GameData>>();
|
||||
#endregion
|
||||
|
||||
#region Event Signals
|
||||
[Signal]
|
||||
public delegate void InventoryButtonPressedEventHandler();
|
||||
[Signal]
|
||||
public delegate void MinimapButtonHeldEventHandler();
|
||||
[Signal]
|
||||
public delegate void PauseButtonPressedEventHandler();
|
||||
#endregion
|
||||
|
||||
#region Exports
|
||||
[Export]
|
||||
public PlayerStatResource PlayerStatResource { get; set; } = default!;
|
||||
|
||||
@@ -56,22 +65,17 @@ namespace GameJamDungeon
|
||||
private WeaponStats _defaultWeapon { get; set; } = default!;
|
||||
[Export]
|
||||
private ArmorStats _defaultArmor { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
public PlayerLogic.Settings Settings { get; set; } = default!;
|
||||
#region Node Dependencies
|
||||
[Node] private IAnimationPlayer AnimationPlayer { get; set; } = default!;
|
||||
|
||||
public PlayerLogic PlayerLogic { get; set; } = default!;
|
||||
[Node] private AnimatedSprite2D SwordSlashAnimation { get; set; } = default!;
|
||||
|
||||
public PlayerLogic.IBinding PlayerBinding { get; set; } = default!;
|
||||
[Node] private IHitbox Hitbox { get; set; } = default!;
|
||||
|
||||
[Node] public IAnimationPlayer AnimationPlayer { get; set; } = default!;
|
||||
|
||||
[Node] public AnimatedSprite2D SwordSlashAnimation { get; set; } = default!;
|
||||
|
||||
[Node] public IHitbox Hitbox { get; set; } = default!;
|
||||
|
||||
[Node] public Timer HealthTimer { get; set; } = default!;
|
||||
|
||||
[Node] public IArea3D CollisionDetector { get; set; } = default!;
|
||||
[Node] private Timer HealthTimer { get; set; } = default!;
|
||||
#endregion
|
||||
|
||||
private PlayerData PlayerData { get; set; } = default!;
|
||||
|
||||
@@ -177,8 +181,16 @@ namespace GameJamDungeon
|
||||
GlobalPosition = GameRepo.PlayerGlobalPosition.Value;
|
||||
GameRepo.PlayerGlobalPosition.Sync += PlayerGlobalPosition_Sync;
|
||||
HealthTimer.Timeout += OnHealthTimerTimeout;
|
||||
CollisionDetector.BodyEntered += CollisionDetector_BodyEntered;
|
||||
PlayerData.Inventory.AccessoryUnequipped += Inventory_AccessoryUnequipped;
|
||||
Hitbox.AreaEntered += Hitbox_AreaEntered;
|
||||
}
|
||||
|
||||
private void Hitbox_AreaEntered(Area3D area)
|
||||
{
|
||||
var enemy = Hitbox.GetParent<IEnemy>();
|
||||
enemy.TakeDamage((PlayerStatResource.CurrentAttack + PlayerStatResource.BonusAttack) * PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.ElementalDamageBonus,
|
||||
PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.WeaponElement,
|
||||
ignoreElementalResistance: PlayerData.Inventory.EquippedWeapon.Value.WeaponStats.WeaponTags.Contains(WeaponTag.IgnoreAffinity));
|
||||
}
|
||||
|
||||
public void OnReady()
|
||||
@@ -319,24 +331,6 @@ namespace GameJamDungeon
|
||||
PlayerData.SetLuck(PlayerData.Luck.Value - unequippedAccessory.LUCKUp);
|
||||
}
|
||||
|
||||
private void CollisionDetector_BodyEntered(Node3D body)
|
||||
{
|
||||
if (body is IHitbox hitBox)
|
||||
{
|
||||
var enemy = hitBox.GetParent<IEnemy>();
|
||||
var isCriticalHit = false;
|
||||
var rng = new RandomNumberGenerator();
|
||||
rng.Randomize();
|
||||
var roll = rng.Randf();
|
||||
if (roll <= enemy.EnemyStatResource.Luck)
|
||||
isCriticalHit = true;
|
||||
var damage = DamageCalculator.CalculateEnemyAttackDamage(PlayerData.CurrentDefense.Value + PlayerData.BonusDefense, enemy.EnemyStatResource, GameRepo.PlayerData.Inventory.EquippedArmor.Value.ArmorStats, isCriticalHit);
|
||||
PlayerData.SetCurrentHP(PlayerData.CurrentHP.Value - Mathf.RoundToInt(damage));
|
||||
GD.Print($"Player hit for {damage} damage.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void CurrentHP_Sync(int newHealth)
|
||||
{
|
||||
if (newHealth <= 0)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
@startuml PlayerLogic
|
||||
state "PlayerLogic State" as GameJamDungeon_PlayerLogic_State {
|
||||
state "Disabled" as GameJamDungeon_PlayerLogic_State_Disabled
|
||||
state "Dead" as GameJamDungeon_PlayerLogic_State_Dead
|
||||
state "Alive" as GameJamDungeon_PlayerLogic_State_Alive {
|
||||
state "Attacking" as GameJamDungeon_PlayerLogic_State_Attacking
|
||||
state "Idle" as GameJamDungeon_PlayerLogic_State_Idle
|
||||
}
|
||||
state "Dead" as GameJamDungeon_PlayerLogic_State_Dead
|
||||
state "Disabled" as GameJamDungeon_PlayerLogic_State_Disabled
|
||||
}
|
||||
|
||||
GameJamDungeon_PlayerLogic_State_Alive --> GameJamDungeon_PlayerLogic_State_Alive : Moved
|
||||
|
||||
23
src/system/IHasPrimaryAttack.cs
Normal file
23
src/system/IHasPrimaryAttack.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace GameJamDungeon
|
||||
{
|
||||
public interface IHasPrimaryAttack
|
||||
{
|
||||
public ElementType PrimaryAttackElementalType { set; }
|
||||
public double PrimaryAttackElementalDamageBonus { set; }
|
||||
|
||||
public void PrimaryAttack();
|
||||
}
|
||||
|
||||
public interface IHasSecondaryAttack
|
||||
{
|
||||
public ElementType SecondaryAttackElementalType { set; }
|
||||
public double SecondaryAttackElementalDamageBonus { set; }
|
||||
|
||||
public void SecondaryAttack();
|
||||
}
|
||||
|
||||
public interface IHasPrimarySkill
|
||||
{
|
||||
public void PrimarySkill();
|
||||
}
|
||||
}
|
||||
@@ -4,68 +4,10 @@ namespace GameJamDungeon
|
||||
{
|
||||
public static class DamageCalculator
|
||||
{
|
||||
public static double CalculateWeaponAttackDamage(int totalAttack, EnemyStatResource enemyStatResource, WeaponStats weapon, bool isCriticalHit)
|
||||
public static double CalculateWeaponAttackDamage(int totalAttack, WeaponStats weapon)
|
||||
{
|
||||
var hydricResistance = enemyStatResource.HydricResistance;
|
||||
var igneousResistance = enemyStatResource.IgneousResistance;
|
||||
var telluricResistance = enemyStatResource.TelluricResistance;
|
||||
var aeolicResistance = enemyStatResource.AeolicResistance;
|
||||
var ferrumResistance = enemyStatResource.FerrumResistance;
|
||||
|
||||
if (weapon.WeaponTags.Contains(WeaponTag.IgnoreAffinity))
|
||||
{
|
||||
hydricResistance = 0;
|
||||
igneousResistance = 0;
|
||||
telluricResistance = 0;
|
||||
aeolicResistance = 0;
|
||||
ferrumResistance = 0;
|
||||
}
|
||||
|
||||
var elementADamage = (weapon.BaseHydricDamageBonus > 0 ? weapon.BaseHydricDamageBonus - hydricResistance : 0) / 100;
|
||||
var elementBDamage = (weapon.IgneousDamageBonus > 0 ? weapon.IgneousDamageBonus - igneousResistance : 0) / 100;
|
||||
var elementCDamage = (weapon.TelluricDamageBonus > 0 ? weapon.TelluricDamageBonus - telluricResistance : 0) / 100;
|
||||
var elementDDamage = (weapon.AeolicDamageBonus > 0 ? weapon.AeolicDamageBonus - aeolicResistance : 0) / 100;
|
||||
var elementEDamage = (weapon.FerrumDamageBonus > 0 ? weapon.FerrumDamageBonus - ferrumResistance : 0) / 100;
|
||||
var elementalBonusDamage = totalAttack + (totalAttack * elementADamage) + (totalAttack * elementBDamage) + (totalAttack * elementCDamage) + (totalAttack * elementDDamage) + (totalAttack * elementEDamage);
|
||||
var calculatedDamage = elementalBonusDamage - enemyStatResource.CurrentDefense;
|
||||
|
||||
if (isCriticalHit)
|
||||
calculatedDamage *= 2;
|
||||
|
||||
return Mathf.Max(calculatedDamage, 0.0);
|
||||
}
|
||||
|
||||
public static double CalculateEnemyAttackDamage(int playerTotalDefense, EnemyStatResource enemyStatResource, ArmorStats armor, bool isCriticalHit)
|
||||
{
|
||||
var totalAttack = enemyStatResource.CurrentAttack;
|
||||
var elementADamage = (enemyStatResource.BaseHydricDamageBonus > 0 ? enemyStatResource.BaseHydricDamageBonus - armor.HydricResistance : 0) / 100;
|
||||
var elementBDamage = (enemyStatResource.IgneousDamageBonus > 0 ? enemyStatResource.IgneousDamageBonus - armor.IgneousResistance : 0) / 100;
|
||||
var elementCDamage = (enemyStatResource.TelluricDamageBonus > 0 ? enemyStatResource.TelluricDamageBonus - armor.TelluricResistance : 0) / 100;
|
||||
var elementDDamage = (enemyStatResource.AeolicDamageBonus > 0 ? enemyStatResource.AeolicDamageBonus - armor.AeolicResistance : 0) / 100;
|
||||
var elementEDamage = (enemyStatResource.FerrumDamageBonus > 0 ? enemyStatResource.FerrumDamageBonus - armor.FerrumResistance : 0) / 100;
|
||||
var elementalBonusDamage = totalAttack + (totalAttack * elementADamage) + (totalAttack * elementBDamage) + (totalAttack * elementCDamage) + (totalAttack * elementDDamage) + (totalAttack * elementEDamage);
|
||||
var calculatedDamage = elementalBonusDamage - playerTotalDefense - (armor != null ? armor.Defense : 0);
|
||||
|
||||
if (isCriticalHit)
|
||||
calculatedDamage *= 2;
|
||||
|
||||
return Mathf.Max(calculatedDamage, 0.0);
|
||||
}
|
||||
|
||||
public static double CalculateThrownItemDamage(int baseThrowDamage, EnemyStatResource enemyStatResource, ThrowableItemStats throwableItemStats)
|
||||
{
|
||||
if (throwableItemStats.ThrowableItemTags.Contains(ThrowableItemTag.InflictAeolicDamage))
|
||||
return Mathf.Max(baseThrowDamage * enemyStatResource.AeolicResistance, 0.0);
|
||||
if (throwableItemStats.ThrowableItemTags.Contains(ThrowableItemTag.InflictFerrumDamage))
|
||||
return Mathf.Max(baseThrowDamage * enemyStatResource.FerrumResistance, 0.0);
|
||||
if (throwableItemStats.ThrowableItemTags.Contains(ThrowableItemTag.InflictHydricDamage))
|
||||
return Mathf.Max(baseThrowDamage * enemyStatResource.HydricResistance, 0.0);
|
||||
if (throwableItemStats.ThrowableItemTags.Contains(ThrowableItemTag.InflictIgneousDamage))
|
||||
return Mathf.Max(baseThrowDamage * enemyStatResource.IgneousResistance, 0.0);
|
||||
if (throwableItemStats.ThrowableItemTags.Contains(ThrowableItemTag.InflictTelluricDamage))
|
||||
return Mathf.Max(baseThrowDamage * enemyStatResource.TelluricResistance, 0.0);
|
||||
|
||||
return Mathf.Max(baseThrowDamage, 0.0);
|
||||
var totalDamage = totalAttack * weapon.ElementalDamageBonus;
|
||||
return Mathf.Max(totalDamage, 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user