Demon wall implementation (attack data, takes damage, dies, etc) but mostly placeholders
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
using Godot;
|
||||||
|
using Zennysoft.Ma.Adapter.Entity;
|
||||||
|
|
||||||
|
namespace Zennysoft.Ma.Adapter
|
||||||
|
{
|
||||||
|
public class DamageCalculator : IDamageCalculator
|
||||||
|
{
|
||||||
|
public double CalculateDamage(double damage,
|
||||||
|
ElementType elementType,
|
||||||
|
double defense,
|
||||||
|
ElementalResistanceSet elementalResistanceSet,
|
||||||
|
bool isCriticalHit = false,
|
||||||
|
bool ignoreDefense = false,
|
||||||
|
bool ignoreElementalResistance = false)
|
||||||
|
{
|
||||||
|
var calculatedDamage = damage;
|
||||||
|
if (!ignoreElementalResistance)
|
||||||
|
calculatedDamage = CalculateElementalResistance(calculatedDamage, elementType, elementalResistanceSet);
|
||||||
|
if (!ignoreDefense)
|
||||||
|
calculatedDamage = CalculateDefenseResistance(calculatedDamage, defense);
|
||||||
|
if (isCriticalHit)
|
||||||
|
calculatedDamage *= 2;
|
||||||
|
|
||||||
|
return calculatedDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double CalculateDefenseResistance(double incomingDamage, double defense)
|
||||||
|
{
|
||||||
|
return Mathf.Max(incomingDamage - defense, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double CalculateElementalResistance(
|
||||||
|
double incomingDamage,
|
||||||
|
ElementType incomingElementType,
|
||||||
|
ElementalResistanceSet elementalResistanceSet)
|
||||||
|
{
|
||||||
|
var resistance = elementalResistanceSet.ElementalResistance[incomingElementType];
|
||||||
|
return Mathf.Max(incomingDamage - (incomingDamage * resistance), 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IDamageCalculator
|
||||||
|
{
|
||||||
|
public double CalculateDamage(double damage,
|
||||||
|
ElementType elementType,
|
||||||
|
double defense,
|
||||||
|
ElementalResistanceSet elementalResistanceSet,
|
||||||
|
bool isCriticalHit = false,
|
||||||
|
bool ignoreDefense = false,
|
||||||
|
bool ignoreElementalResistance = false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace Zennysoft.Ma.Adapter.Entity
|
||||||
|
{
|
||||||
|
public record ElementalResistanceSet
|
||||||
|
{
|
||||||
|
public Dictionary<ElementType, double> ElementalResistance { get; }
|
||||||
|
|
||||||
|
public ElementalResistanceSet(double aeolicResistance, double hydricResistance, double igneousResistance, double ferrumResistance, double telluricResistance)
|
||||||
|
{
|
||||||
|
ElementalResistance = new Dictionary<ElementType, double>
|
||||||
|
{
|
||||||
|
{ ElementType.None, 0 },
|
||||||
|
{ ElementType.Aeolic, aeolicResistance },
|
||||||
|
{ ElementType.Hydric, hydricResistance },
|
||||||
|
{ ElementType.Igneous, igneousResistance },
|
||||||
|
{ ElementType.Ferrum, ferrumResistance },
|
||||||
|
{ ElementType.Telluric, telluricResistance },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
using Chickensoft.Collections;
|
using Chickensoft.Introspection;
|
||||||
using Chickensoft.Introspection;
|
|
||||||
using Chickensoft.Serialization;
|
using Chickensoft.Serialization;
|
||||||
using Godot;
|
|
||||||
|
|
||||||
namespace Zennysoft.Game.Ma;
|
namespace Zennysoft.Game.Ma;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public partial class BossTypeA : Enemy, IHasPrimaryAttack, IHasSecondaryAttack,
|
|||||||
|
|
||||||
public double SecondaryAttackElementalDamageBonus { get; set; } = 1.0;
|
public double SecondaryAttackElementalDamageBonus { get; set; } = 1.0;
|
||||||
|
|
||||||
[Node] public new EnemyModelView3D _enemyModelView { get; set; }
|
[Node] public new BossTypeAEnemyModelView _enemyModelView { get; set; }
|
||||||
|
|
||||||
[Node] public CollisionShape3D EnemyHitbox { get; set; } = default!;
|
[Node] public CollisionShape3D EnemyHitbox { get; set; } = default!;
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
|
|||||||
|
|
||||||
private Vector3 _knockbackDirection = Vector3.Zero;
|
private Vector3 _knockbackDirection = Vector3.Zero;
|
||||||
|
|
||||||
|
private IDamageCalculator _damageCalculator;
|
||||||
|
|
||||||
#region Godot methods
|
#region Godot methods
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
@@ -59,6 +61,7 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
|
|||||||
_enemyLogic.Set(_enemyStatResource);
|
_enemyLogic.Set(_enemyStatResource);
|
||||||
_enemyLogic.Set(this as IEnemy);
|
_enemyLogic.Set(this as IEnemy);
|
||||||
_enemyLogic.Set(_player);
|
_enemyLogic.Set(_player);
|
||||||
|
_damageCalculator = new DamageCalculator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnResolved()
|
public void OnResolved()
|
||||||
@@ -118,12 +121,13 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
|
|||||||
{
|
{
|
||||||
if (CurrentHP.Value > 0)
|
if (CurrentHP.Value > 0)
|
||||||
{
|
{
|
||||||
if (!ignoreElementalResistance)
|
_damageCalculator.CalculateDamage(damage,
|
||||||
damage = CalculateElementalResistance(damage, elementType);
|
elementType,
|
||||||
if (!ignoreDefense)
|
_player.Stats.CurrentDefense.Value + _player.Stats.BonusDefense.Value,
|
||||||
damage = CalculateDefenseResistance(damage);
|
_enemyStatResource.ElementalResistance,
|
||||||
if (isCriticalHit)
|
isCriticalHit,
|
||||||
damage *= 2;
|
ignoreDefense,
|
||||||
|
ignoreElementalResistance);
|
||||||
GD.Print($"Enemy Hit for {damage} damage.");
|
GD.Print($"Enemy Hit for {damage} damage.");
|
||||||
CurrentHP.OnNext(CurrentHP.Value - damage);
|
CurrentHP.OnNext(CurrentHP.Value - damage);
|
||||||
GD.Print("Current HP: " + CurrentHP.Value);
|
GD.Print("Current HP: " + CurrentHP.Value);
|
||||||
@@ -151,7 +155,7 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
|
|||||||
_enemyLogic.Input(new EnemyLogic.Input.EnemyDefeated());
|
_enemyLogic.Input(new EnemyLogic.Input.EnemyDefeated());
|
||||||
_collisionShape.SetDeferred("disabled", true);
|
_collisionShape.SetDeferred("disabled", true);
|
||||||
_enemyModelView.PlayDeathAnimation();
|
_enemyModelView.PlayDeathAnimation();
|
||||||
var tweener = GetTree().CreateTween();
|
var tweener = CreateTween();
|
||||||
tweener.TweenInterval(1.0f);
|
tweener.TweenInterval(1.0f);
|
||||||
tweener.TweenCallback(Callable.From(QueueFree));
|
tweener.TweenCallback(Callable.From(QueueFree));
|
||||||
Game.EnemyDefeated(GlobalPosition, _enemyStatResource);
|
Game.EnemyDefeated(GlobalPosition, _enemyStatResource);
|
||||||
@@ -238,22 +242,6 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
|
|||||||
Die();
|
Die();
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
private double CalculateDefenseResistance(double incomingDamage)
|
||||||
{
|
{
|
||||||
return Mathf.Max(incomingDamage - _enemyStatResource.CurrentDefense, 0.0);
|
return Mathf.Max(incomingDamage - _enemyStatResource.CurrentDefense, 0.0);
|
||||||
|
|||||||
@@ -24,14 +24,8 @@ public partial class EnemyModelView3D : Node3D, IEnemyModelView
|
|||||||
|
|
||||||
[Node] public AnimationTree AnimationTree { get; set; } = default!;
|
[Node] public AnimationTree AnimationTree { get; set; } = default!;
|
||||||
|
|
||||||
[Node] public IHitbox Hitbox { get; set; } = default!;
|
|
||||||
|
|
||||||
[Node] public MeshInstance3D MeshInstance { get; set; } = default!;
|
[Node] public MeshInstance3D MeshInstance { get; set; } = default!;
|
||||||
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PlayPrimaryAttackAnimation()
|
public void PlayPrimaryAttackAnimation()
|
||||||
{
|
{
|
||||||
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(PRIMARY_ATTACK);
|
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(PRIMARY_ATTACK);
|
||||||
@@ -49,7 +43,7 @@ public partial class EnemyModelView3D : Node3D, IEnemyModelView
|
|||||||
|
|
||||||
public void PlayHitAnimation()
|
public void PlayHitAnimation()
|
||||||
{
|
{
|
||||||
var tweener = GetTree().CreateTween();
|
var tweener = CreateTween();
|
||||||
ChangeMaterial();
|
ChangeMaterial();
|
||||||
tweener.TweenMethod(Callable.From((float x) => SetTransparency(x)), 0.0f, 0.5f, 0.3f);
|
tweener.TweenMethod(Callable.From((float x) => SetTransparency(x)), 0.0f, 0.5f, 0.3f);
|
||||||
tweener.TweenCallback(Callable.From(ClearDamageEffect));
|
tweener.TweenCallback(Callable.From(ClearDamageEffect));
|
||||||
@@ -58,7 +52,7 @@ public partial class EnemyModelView3D : Node3D, IEnemyModelView
|
|||||||
public void PlayDeathAnimation()
|
public void PlayDeathAnimation()
|
||||||
{
|
{
|
||||||
LoadShader("res://src/enemy/EnemyDie.tres");
|
LoadShader("res://src/enemy/EnemyDie.tres");
|
||||||
var tweener = GetTree().CreateTween();
|
var tweener = CreateTween();
|
||||||
tweener.TweenMethod(Callable.From((float x) => SetTransparency(x)), 0.0f, 1.0f, 0.8f);
|
tweener.TweenMethod(Callable.From((float x) => SetTransparency(x)), 0.0f, 1.0f, 0.8f);
|
||||||
tweener.TweenCallback(Callable.From(QueueFree));
|
tweener.TweenCallback(Callable.From(QueueFree));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
|
using Zennysoft.Ma.Adapter.Entity;
|
||||||
|
|
||||||
namespace Zennysoft.Game.Ma;
|
namespace Zennysoft.Game.Ma;
|
||||||
|
|
||||||
@@ -30,19 +31,21 @@ public partial class EnemyStatResource : Resource
|
|||||||
public double Luck { get; set; } = 0.05f;
|
public double Luck { get; set; } = 0.05f;
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public double TelluricResistance { get; set; }
|
private double _telluricResistance { get; set; }
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public double AeolicResistance { get; set; }
|
private double _aeolicResistance { get; set; }
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public double HydricResistance { get; set; }
|
private double _hydricResistance { get; set; }
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public double IgneousResistance { get; set; }
|
private double _igneousResistance { get; set; }
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public double FerrumResistance { get; set; }
|
private double _ferrumResistance { get; set; }
|
||||||
|
|
||||||
|
public ElementalResistanceSet ElementalResistance => new ElementalResistanceSet(_aeolicResistance, _hydricResistance, _igneousResistance, _ferrumResistance, _telluricResistance);
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public float DropsSoulGemChance { get; set; } = 0.75f;
|
public float DropsSoulGemChance { get; set; } = 0.75f;
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ MaxAttack = 15
|
|||||||
MaxDefense = 0
|
MaxDefense = 0
|
||||||
ExpFromDefeat = 5
|
ExpFromDefeat = 5
|
||||||
Luck = 0.05
|
Luck = 0.05
|
||||||
TelluricResistance = 0.0
|
_telluricResistance = 0.0
|
||||||
AeolicResistance = 0.0
|
_aeolicResistance = 0.0
|
||||||
HydricResistance = 0.0
|
_hydricResistance = 0.0
|
||||||
IgneousResistance = 0.0
|
_igneousResistance = 0.0
|
||||||
FerrumResistance = 0.0
|
_ferrumResistance = 0.0
|
||||||
DropsSoulGemChance = 0.75
|
DropsSoulGemChance = 0.75
|
||||||
metadata/_custom_type_script = ExtResource("2_wrps7")
|
metadata/_custom_type_script = ExtResource("2_wrps7")
|
||||||
|
|
||||||
|
|||||||
@@ -2,30 +2,6 @@
|
|||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_ttkyx"]
|
[sub_resource type="Animation" id="Animation_ttkyx"]
|
||||||
length = 0.001
|
length = 0.001
|
||||||
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),
|
|
||||||
"transitions": PackedFloat32Array(1),
|
|
||||||
"update": 1,
|
|
||||||
"values": [true]
|
|
||||||
}
|
|
||||||
tracks/1/type = "value"
|
|
||||||
tracks/1/imported = false
|
|
||||||
tracks/1/enabled = true
|
|
||||||
tracks/1/path = NodePath("Hitbox/CollisionShape3D:disabled")
|
|
||||||
tracks/1/interp = 1
|
|
||||||
tracks/1/loop_wrap = true
|
|
||||||
tracks/1/keys = {
|
|
||||||
"times": PackedFloat32Array(0),
|
|
||||||
"transitions": PackedFloat32Array(1),
|
|
||||||
"update": 0,
|
|
||||||
"values": [true]
|
|
||||||
}
|
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_sfyuh"]
|
[sub_resource type="Animation" id="Animation_sfyuh"]
|
||||||
resource_name = "idle"
|
resource_name = "idle"
|
||||||
@@ -594,18 +570,6 @@ tracks/39/path = NodePath("Armature/Skeleton3D:heelIK_R")
|
|||||||
tracks/39/interp = 0
|
tracks/39/interp = 0
|
||||||
tracks/39/loop_wrap = true
|
tracks/39/loop_wrap = true
|
||||||
tracks/39/keys = PackedFloat32Array(0, 1, -0.456756, -0.539878, 0.539587, 0.456893)
|
tracks/39/keys = PackedFloat32Array(0, 1, -0.456756, -0.539878, 0.539587, 0.456893)
|
||||||
tracks/40/type = "value"
|
|
||||||
tracks/40/imported = false
|
|
||||||
tracks/40/enabled = true
|
|
||||||
tracks/40/path = NodePath("Hitbox/CollisionShape3D:disabled")
|
|
||||||
tracks/40/interp = 1
|
|
||||||
tracks/40/loop_wrap = true
|
|
||||||
tracks/40/keys = {
|
|
||||||
"times": PackedFloat32Array(0, 0.1, 0.2),
|
|
||||||
"transitions": PackedFloat32Array(1, 1, 1),
|
|
||||||
"update": 1,
|
|
||||||
"values": [true, false, true]
|
|
||||||
}
|
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_fdnqs"]
|
[sub_resource type="Animation" id="Animation_fdnqs"]
|
||||||
resource_name = "SHIELD BASH"
|
resource_name = "SHIELD BASH"
|
||||||
@@ -890,18 +854,6 @@ tracks/39/path = NodePath("Armature/Skeleton3D:heelIK_R")
|
|||||||
tracks/39/interp = 0
|
tracks/39/interp = 0
|
||||||
tracks/39/loop_wrap = true
|
tracks/39/loop_wrap = true
|
||||||
tracks/39/keys = PackedFloat32Array(0, 1, -0.456756, -0.539878, 0.539587, 0.456893)
|
tracks/39/keys = PackedFloat32Array(0, 1, -0.456756, -0.539878, 0.539587, 0.456893)
|
||||||
tracks/40/type = "value"
|
|
||||||
tracks/40/imported = false
|
|
||||||
tracks/40/enabled = true
|
|
||||||
tracks/40/path = NodePath("Hitbox/CollisionShape3D:disabled")
|
|
||||||
tracks/40/interp = 1
|
|
||||||
tracks/40/loop_wrap = true
|
|
||||||
tracks/40/keys = {
|
|
||||||
"times": PackedFloat32Array(0, 0.533333, 0.633333),
|
|
||||||
"transitions": PackedFloat32Array(1, 1, 1),
|
|
||||||
"update": 0,
|
|
||||||
"values": [true, false, true]
|
|
||||||
}
|
|
||||||
|
|
||||||
[sub_resource type="Animation" id="Animation_ui3ue"]
|
[sub_resource type="Animation" id="Animation_ui3ue"]
|
||||||
resource_name = "WALK"
|
resource_name = "WALK"
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ MaxAttack = 0
|
|||||||
MaxDefense = 0
|
MaxDefense = 0
|
||||||
ExpFromDefeat = 0
|
ExpFromDefeat = 0
|
||||||
Luck = 0.05
|
Luck = 0.05
|
||||||
TelluricResistance = 0.0
|
_telluricResistance = 0.0
|
||||||
AeolicResistance = 0.0
|
_aeolicResistance = 0.0
|
||||||
HydricResistance = 0.0
|
_hydricResistance = 0.0
|
||||||
IgneousResistance = 0.0
|
_igneousResistance = 0.0
|
||||||
FerrumResistance = 0.0
|
_ferrumResistance = 0.0
|
||||||
DropsSoulGemChance = 0.75
|
DropsSoulGemChance = 0.75
|
||||||
metadata/_custom_type_script = "uid://dnkmr0eq1sij0"
|
metadata/_custom_type_script = "uid://dnkmr0eq1sij0"
|
||||||
|
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ bones/0/name = "spine1"
|
|||||||
bones/0/parent = -1
|
bones/0/parent = -1
|
||||||
bones/0/rest = Transform3D(1.49012e-06, 0.00846654, -0.999964, 2.93367e-08, 0.999964, 0.00846654, 1, -4.23752e-08, 1.49012e-06, 0.000155807, -0.00105953, -2.01735)
|
bones/0/rest = Transform3D(1.49012e-06, 0.00846654, -0.999964, 2.93367e-08, 0.999964, 0.00846654, 1, -4.23752e-08, 1.49012e-06, 0.000155807, -0.00105953, -2.01735)
|
||||||
bones/0/enabled = true
|
bones/0/enabled = true
|
||||||
bones/0/position = Vector3(-0.260278, -1.0541, -1.96767)
|
bones/0/position = Vector3(-0.259488, -0.96383, -1.97376)
|
||||||
bones/0/rotation = Quaternion(0.0915277, -0.692111, -0.0341586, 0.715149)
|
bones/0/rotation = Quaternion(0.0915277, -0.692111, -0.0341586, 0.715149)
|
||||||
bones/0/scale = Vector3(1, 1, 1)
|
bones/0/scale = Vector3(1, 1, 1)
|
||||||
bones/1/name = "spine0"
|
bones/1/name = "spine0"
|
||||||
@@ -243,7 +243,7 @@ bones/6/parent = 5
|
|||||||
bones/6/rest = Transform3D(0.0598389, 0.98531, 0.15995, -0.975271, 0.0235553, 0.219755, 0.212759, -0.169144, 0.962353, 3.65078e-07, 1.40318, 0)
|
bones/6/rest = Transform3D(0.0598389, 0.98531, 0.15995, -0.975271, 0.0235553, 0.219755, 0.212759, -0.169144, 0.962353, 3.65078e-07, 1.40318, 0)
|
||||||
bones/6/enabled = true
|
bones/6/enabled = true
|
||||||
bones/6/position = Vector3(3.65078e-07, 1.40318, 0)
|
bones/6/position = Vector3(3.65078e-07, 1.40318, 0)
|
||||||
bones/6/rotation = Quaternion(-0.0474983, -0.294201, -0.744151, 0.597854)
|
bones/6/rotation = Quaternion(-0.0697867, -0.302352, -0.744713, 0.59086)
|
||||||
bones/6/scale = Vector3(1, 1, 1)
|
bones/6/scale = Vector3(1, 1, 1)
|
||||||
bones/7/name = "Bone.007"
|
bones/7/name = "Bone.007"
|
||||||
bones/7/parent = 6
|
bones/7/parent = 6
|
||||||
@@ -278,7 +278,7 @@ bones/11/parent = 1
|
|||||||
bones/11/rest = Transform3D(0.981457, 0.0769315, -0.175568, 0.18837, -0.217537, 0.957703, 0.035485, -0.973015, -0.227995, -1.09896e-07, 3.84743, -2.10479e-07)
|
bones/11/rest = Transform3D(0.981457, 0.0769315, -0.175568, 0.18837, -0.217537, 0.957703, 0.035485, -0.973015, -0.227995, -1.09896e-07, 3.84743, -2.10479e-07)
|
||||||
bones/11/enabled = true
|
bones/11/enabled = true
|
||||||
bones/11/position = Vector3(-1.09896e-07, 3.84743, -2.10479e-07)
|
bones/11/position = Vector3(-1.09896e-07, 3.84743, -2.10479e-07)
|
||||||
bones/11/rotation = Quaternion(-0.779754, -0.0572995, 0.0817541, 0.618075)
|
bones/11/rotation = Quaternion(-0.784729, -0.0616535, 0.0718257, 0.612568)
|
||||||
bones/11/scale = Vector3(1, 0.999999, 1)
|
bones/11/scale = Vector3(1, 0.999999, 1)
|
||||||
bones/12/name = "arm2_L"
|
bones/12/name = "arm2_L"
|
||||||
bones/12/parent = 11
|
bones/12/parent = 11
|
||||||
@@ -306,7 +306,7 @@ bones/15/parent = 1
|
|||||||
bones/15/rest = Transform3D(-0.98213, 0.0512573, -0.181089, -0.187541, -0.185921, 0.964501, 0.0157694, 0.981227, 0.192212, 0.00107862, 3.8461, -0.0821097)
|
bones/15/rest = Transform3D(-0.98213, 0.0512573, -0.181089, -0.187541, -0.185921, 0.964501, 0.0157694, 0.981227, 0.192212, 0.00107862, 3.8461, -0.0821097)
|
||||||
bones/15/enabled = true
|
bones/15/enabled = true
|
||||||
bones/15/position = Vector3(0.00107886, 3.8461, -0.0821095)
|
bones/15/position = Vector3(0.00107886, 3.8461, -0.0821095)
|
||||||
bones/15/rotation = Quaternion(-0.215469, 0.745349, 0.613517, -0.147056)
|
bones/15/rotation = Quaternion(-0.210671, 0.737877, 0.621635, -0.157245)
|
||||||
bones/15/scale = Vector3(1, 1, 1)
|
bones/15/scale = Vector3(1, 1, 1)
|
||||||
bones/16/name = "arm2_R"
|
bones/16/name = "arm2_R"
|
||||||
bones/16/parent = 15
|
bones/16/parent = 15
|
||||||
@@ -333,22 +333,22 @@ bones/19/name = "hip_L"
|
|||||||
bones/19/parent = -1
|
bones/19/parent = -1
|
||||||
bones/19/rest = Transform3D(0.138486, 0.897208, 0.419333, -0.129033, -0.403458, 0.905854, 0.981923, -0.179556, 0.059896, 0.000155807, -0.00105953, -2.01735)
|
bones/19/rest = Transform3D(0.138486, 0.897208, 0.419333, -0.129033, -0.403458, 0.905854, 0.981923, -0.179556, 0.059896, 0.000155807, -0.00105953, -2.01735)
|
||||||
bones/19/enabled = true
|
bones/19/enabled = true
|
||||||
bones/19/position = Vector3(-0.381736, -1.20058, -1.71562)
|
bones/19/position = Vector3(-0.309033, -1.1318, -1.95517)
|
||||||
bones/19/rotation = Quaternion(0.627802, 0.292645, 0.544916, -0.472536)
|
bones/19/rotation = Quaternion(0.612762, 0.310855, 0.569327, -0.451397)
|
||||||
bones/19/scale = Vector3(1, 1, 1)
|
bones/19/scale = Vector3(1, 1, 1)
|
||||||
bones/20/name = "leg1_L"
|
bones/20/name = "leg1_L"
|
||||||
bones/20/parent = 19
|
bones/20/parent = 19
|
||||||
bones/20/rest = Transform3D(0.945603, 0.113405, 0.304916, -0.324072, 0.410457, 0.852351, -0.0284943, -0.9048, 0.424881, 2.08616e-07, 2.00996, -7.1153e-07)
|
bones/20/rest = Transform3D(0.945603, 0.113405, 0.304916, -0.324072, 0.410457, 0.852351, -0.0284943, -0.9048, 0.424881, 2.08616e-07, 2.00996, -7.1153e-07)
|
||||||
bones/20/enabled = true
|
bones/20/enabled = true
|
||||||
bones/20/position = Vector3(2.08616e-07, 2.00996, -7.1153e-07)
|
bones/20/position = Vector3(2.08616e-07, 2.00996, -7.1153e-07)
|
||||||
bones/20/rotation = Quaternion(-0.327961, -0.422555, -0.300918, 0.789517)
|
bones/20/rotation = Quaternion(-0.312233, -0.440038, -0.274881, 0.795813)
|
||||||
bones/20/scale = Vector3(1, 0.999999, 1)
|
bones/20/scale = Vector3(1, 0.999999, 1)
|
||||||
bones/21/name = "leg2_L"
|
bones/21/name = "leg2_L"
|
||||||
bones/21/parent = 20
|
bones/21/parent = 20
|
||||||
bones/21/rest = Transform3D(0.990336, -0.138679, 0.00180777, 0.138628, 0.990193, 0.0173138, -0.00419111, -0.0168959, 0.999848, 5.96046e-08, 5.85994, -5.23403e-07)
|
bones/21/rest = Transform3D(0.990336, -0.138679, 0.00180777, 0.138628, 0.990193, 0.0173138, -0.00419111, -0.0168959, 0.999848, 5.96046e-08, 5.85994, -5.23403e-07)
|
||||||
bones/21/enabled = true
|
bones/21/enabled = true
|
||||||
bones/21/position = Vector3(5.96046e-08, 5.85994, -5.23403e-07)
|
bones/21/position = Vector3(5.96046e-08, 5.85994, -5.23403e-07)
|
||||||
bones/21/rotation = Quaternion(-0.0604978, 0.00129835, 0.489732, 0.869771)
|
bones/21/rotation = Quaternion(-0.0601745, 0.00130057, 0.487115, 0.871261)
|
||||||
bones/21/scale = Vector3(1, 1, 1)
|
bones/21/scale = Vector3(1, 1, 1)
|
||||||
bones/22/name = "foot1_L"
|
bones/22/name = "foot1_L"
|
||||||
bones/22/parent = 21
|
bones/22/parent = 21
|
||||||
@@ -382,7 +382,7 @@ bones/26/name = "hip_R"
|
|||||||
bones/26/parent = -1
|
bones/26/parent = -1
|
||||||
bones/26/rest = Transform3D(0.138486, -0.897208, -0.419333, 0.129033, -0.403458, 0.905854, -0.981923, -0.179556, 0.059896, -0.000155807, -0.00105953, -2.01735)
|
bones/26/rest = Transform3D(0.138486, -0.897208, -0.419333, 0.129033, -0.403458, 0.905854, -0.981923, -0.179556, 0.059896, -0.000155807, -0.00105953, -2.01735)
|
||||||
bones/26/enabled = true
|
bones/26/enabled = true
|
||||||
bones/26/position = Vector3(-0.0213137, -1.11395, -2.01918)
|
bones/26/position = Vector3(-0.235011, -1.11395, -2.01773)
|
||||||
bones/26/rotation = Quaternion(0.608697, -0.3155, -0.575514, -0.445793)
|
bones/26/rotation = Quaternion(0.608697, -0.3155, -0.575514, -0.445793)
|
||||||
bones/26/scale = Vector3(1, 1, 1)
|
bones/26/scale = Vector3(1, 1, 1)
|
||||||
bones/27/name = "leg1_R"
|
bones/27/name = "leg1_R"
|
||||||
@@ -390,14 +390,14 @@ bones/27/parent = 26
|
|||||||
bones/27/rest = Transform3D(0.945603, -0.113405, -0.304916, 0.324072, 0.410457, 0.852351, 0.0284943, -0.9048, 0.424881, -9.54606e-09, 2.00996, -3.52971e-07)
|
bones/27/rest = Transform3D(0.945603, -0.113405, -0.304916, 0.324072, 0.410457, 0.852351, 0.0284943, -0.9048, 0.424881, -9.54606e-09, 2.00996, -3.52971e-07)
|
||||||
bones/27/enabled = true
|
bones/27/enabled = true
|
||||||
bones/27/position = Vector3(-9.54606e-09, 2.00996, -3.52971e-07)
|
bones/27/position = Vector3(-9.54606e-09, 2.00996, -3.52971e-07)
|
||||||
bones/27/rotation = Quaternion(-0.202201, 0.424694, 0.137914, 0.871625)
|
bones/27/rotation = Quaternion(-0.207711, 0.421647, 0.141893, 0.871169)
|
||||||
bones/27/scale = Vector3(1, 0.999999, 1)
|
bones/27/scale = Vector3(1, 0.999999, 1)
|
||||||
bones/28/name = "leg2_R"
|
bones/28/name = "leg2_R"
|
||||||
bones/28/parent = 27
|
bones/28/parent = 27
|
||||||
bones/28/rest = Transform3D(0.990336, 0.138679, -0.00180777, -0.138628, 0.990193, 0.0173138, 0.00419111, -0.0168959, 0.999848, 4.51691e-08, 5.85994, -3.72529e-09)
|
bones/28/rest = Transform3D(0.990336, 0.138679, -0.00180777, -0.138628, 0.990193, 0.0173138, 0.00419111, -0.0168959, 0.999848, 4.51691e-08, 5.85994, -3.72529e-09)
|
||||||
bones/28/enabled = true
|
bones/28/enabled = true
|
||||||
bones/28/position = Vector3(4.51691e-08, 5.85994, -3.72529e-09)
|
bones/28/position = Vector3(4.51691e-08, 5.85994, -3.72529e-09)
|
||||||
bones/28/rotation = Quaternion(-0.0627787, -0.00116448, -0.501219, 0.863039)
|
bones/28/rotation = Quaternion(-0.0640421, -0.00115636, -0.511308, 0.857007)
|
||||||
bones/28/scale = Vector3(1, 1, 1)
|
bones/28/scale = Vector3(1, 1, 1)
|
||||||
bones/29/name = "foot1_R"
|
bones/29/name = "foot1_R"
|
||||||
bones/29/parent = 28
|
bones/29/parent = 28
|
||||||
@@ -429,7 +429,7 @@ bones/32/rotation = Quaternion(0.456756, 0.539878, -0.539587, -0.456893)
|
|||||||
bones/32/scale = Vector3(1, 1, 1)
|
bones/32/scale = Vector3(1, 1, 1)
|
||||||
|
|
||||||
[node name="BoneAttachment3D" type="BoneAttachment3D" parent="Armature/Skeleton3D"]
|
[node name="BoneAttachment3D" type="BoneAttachment3D" parent="Armature/Skeleton3D"]
|
||||||
transform = Transform3D(-0.266252, -0.0359368, -0.963233, -0.333724, -0.934064, 0.127095, -0.904288, 0.355294, 0.236703, -1.68949, 8.19963, 4.95696)
|
transform = Transform3D(-0.291816, -0.0758791, -0.95346, -0.329798, -0.927733, 0.174769, -0.897817, 0.36545, 0.245702, -1.66649, 8.30024, 4.94846)
|
||||||
bone_name = "TOP OF SKULL"
|
bone_name = "TOP OF SKULL"
|
||||||
bone_idx = 8
|
bone_idx = 8
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,26 +1,7 @@
|
|||||||
[gd_scene load_steps=11 format=3 uid="uid://dxrgfh28wj5su"]
|
[gd_scene load_steps=10 format=3 uid="uid://dxrgfh28wj5su"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://vgvrmwsrwakf" path="res://src/enemy/enemy_types/16. demon wall/DemonWallArm.cs" id="1_fhrhk"]
|
[ext_resource type="Script" uid="uid://vgvrmwsrwakf" path="res://src/enemy/enemy_types/16. demon wall/DemonWallArm.cs" id="1_fhrhk"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dafhaya5sejdj" path="res://src/enemy/enemy_types/16. demon wall/model/ARM3.glb" id="1_wuuwb"]
|
[ext_resource type="PackedScene" uid="uid://dafhaya5sejdj" path="res://src/enemy/enemy_types/16. demon wall/model/ARM3.glb" id="1_wuuwb"]
|
||||||
[ext_resource type="Script" uid="uid://dnkmr0eq1sij0" path="res://src/enemy/EnemyStatResource.cs" id="2_afuej"]
|
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_gcbec"]
|
|
||||||
script = ExtResource("2_afuej")
|
|
||||||
CurrentHP = 20.0
|
|
||||||
MaximumHP = 20
|
|
||||||
CurrentAttack = 0
|
|
||||||
CurrentDefense = 0
|
|
||||||
MaxAttack = 0
|
|
||||||
MaxDefense = 0
|
|
||||||
ExpFromDefeat = 0
|
|
||||||
Luck = 0.05
|
|
||||||
TelluricResistance = 0.0
|
|
||||||
AeolicResistance = 0.0
|
|
||||||
HydricResistance = 0.0
|
|
||||||
IgneousResistance = 0.0
|
|
||||||
FerrumResistance = 0.0
|
|
||||||
DropsSoulGemChance = 0.0
|
|
||||||
metadata/_custom_type_script = "uid://dnkmr0eq1sij0"
|
|
||||||
|
|
||||||
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_bpd8u"]
|
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_bpd8u"]
|
||||||
animation = &"ARM 3 WALL CALL"
|
animation = &"ARM 3 WALL CALL"
|
||||||
@@ -46,11 +27,10 @@ states/idle/node = SubResource("AnimationNodeAnimation_ccv8a")
|
|||||||
states/idle/position = Vector2(339, 112)
|
states/idle/position = Vector2(339, 112)
|
||||||
transitions = ["Start", "idle", SubResource("AnimationNodeStateMachineTransition_sjgs2"), "idle", "attack", SubResource("AnimationNodeStateMachineTransition_p21h7"), "attack", "idle", SubResource("AnimationNodeStateMachineTransition_1weac")]
|
transitions = ["Start", "idle", SubResource("AnimationNodeStateMachineTransition_sjgs2"), "idle", "attack", SubResource("AnimationNodeStateMachineTransition_p21h7"), "attack", "idle", SubResource("AnimationNodeStateMachineTransition_1weac")]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_fhrhk"]
|
||||||
|
|
||||||
[node name="Arm3" type="Node3D"]
|
[node name="Arm3" type="Node3D"]
|
||||||
script = ExtResource("1_fhrhk")
|
script = ExtResource("1_fhrhk")
|
||||||
_enemyStatResource = SubResource("Resource_gcbec")
|
|
||||||
PrimaryAttackElementalType = null
|
|
||||||
PrimaryAttackElementalDamageBonus = null
|
|
||||||
|
|
||||||
[node name="ARM3" parent="." instance=ExtResource("1_wuuwb")]
|
[node name="ARM3" parent="." instance=ExtResource("1_wuuwb")]
|
||||||
|
|
||||||
@@ -59,3 +39,12 @@ unique_name_in_owner = true
|
|||||||
root_node = NodePath("%AnimationTree/..")
|
root_node = NodePath("%AnimationTree/..")
|
||||||
tree_root = SubResource("AnimationNodeStateMachine_fhrhk")
|
tree_root = SubResource("AnimationNodeStateMachine_fhrhk")
|
||||||
anim_player = NodePath("../AnimationPlayer")
|
anim_player = NodePath("../AnimationPlayer")
|
||||||
|
|
||||||
|
[node name="Hitbox" type="Area3D" parent="ARM3"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 0
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="ARM3/Hitbox"]
|
||||||
|
shape = SubResource("BoxShape3D_fhrhk")
|
||||||
|
disabled = true
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1,4 +1,5 @@
|
|||||||
using Chickensoft.AutoInject;
|
using Chickensoft.AutoInject;
|
||||||
|
using Chickensoft.Collections;
|
||||||
using Chickensoft.Introspection;
|
using Chickensoft.Introspection;
|
||||||
using Godot;
|
using Godot;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -7,7 +8,7 @@ using Zennysoft.Ma.Adapter;
|
|||||||
namespace Zennysoft.Game.Ma;
|
namespace Zennysoft.Game.Ma;
|
||||||
|
|
||||||
[Meta(typeof(IAutoNode))]
|
[Meta(typeof(IAutoNode))]
|
||||||
public partial class DemonWall : CharacterBody3D
|
public partial class DemonWall : CharacterBody3D, IEnemy
|
||||||
{
|
{
|
||||||
public override void _Notification(int what) => this.Notify(what);
|
public override void _Notification(int what) => this.Notify(what);
|
||||||
|
|
||||||
@@ -15,89 +16,87 @@ public partial class DemonWall : CharacterBody3D
|
|||||||
|
|
||||||
[Export] protected EnemyStatResource _enemyStatResource { get; set; } = default!;
|
[Export] protected EnemyStatResource _enemyStatResource { get; set; } = default!;
|
||||||
|
|
||||||
[Node] private DemonWallArm _arm3 { get; set; } = default!;
|
[Node] public DemonWallModelView EnemyModelView { get; set; } = default!;
|
||||||
|
|
||||||
[Node] public Node3D LeftArms { get; set; } = default!;
|
public AutoProp<double> CurrentHP { get; private set; }
|
||||||
|
|
||||||
[Node] public Node3D RightArms { get; set; } = default!;
|
|
||||||
|
|
||||||
[Node] public MeshInstance3D Eye { get; set; } = default!;
|
|
||||||
|
|
||||||
[Node] private Node3D _rotation { get; set; } = default!;
|
|
||||||
|
|
||||||
[Node] private AnimatableBody3D _opposingWall { get; set; } = default!;
|
|
||||||
|
|
||||||
[Export] private double _maximumWallMoveAmount = 24;
|
[Export] private double _maximumWallMoveAmount = 24;
|
||||||
|
|
||||||
private Timer _attackTimer;
|
private Timer _attackTimer;
|
||||||
|
|
||||||
public void OnPhysicsProcess(double delta)
|
private IDamageCalculator _damageCalculator;
|
||||||
|
|
||||||
|
public void OnReady()
|
||||||
{
|
{
|
||||||
var direction = GlobalPosition.DirectionTo(_player.CurrentPosition).Normalized();
|
CurrentHP = new AutoProp<double>(_enemyStatResource.MaximumHP);
|
||||||
var rotationAngle = GetRotationAngle();
|
_attackTimer = new Timer { WaitTime = 5f };
|
||||||
RotateToPlayer(rotationAngle);
|
_attackTimer.Timeout += AttackTimer_Timeout;
|
||||||
|
AddChild(_attackTimer);
|
||||||
|
_damageCalculator = new DamageCalculator();
|
||||||
|
CurrentHP.Sync += CurrentHP_Sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RotateToPlayer(float rotationAngle)
|
private void CurrentHP_Sync(double newHP)
|
||||||
{
|
{
|
||||||
var tweener = GetTree().CreateTween();
|
if (newHP <= 0)
|
||||||
tweener.TweenMethod(Callable.From((float x) => RotateTowardsPlayer(x)), Eye.Rotation.Y, rotationAngle, 1f);
|
Die();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Activate()
|
public void Activate()
|
||||||
{
|
{
|
||||||
_opposingWall.Show();
|
EnemyModelView.Activate();
|
||||||
var collisionShape = _opposingWall.GetChildren().OfType<CollisionShape3D>().Single();
|
|
||||||
collisionShape.SetDeferred(CollisionShape3D.PropertyName.Disabled, false);
|
|
||||||
|
|
||||||
_attackTimer = new Timer { WaitTime = 5f };
|
|
||||||
_attackTimer.Timeout += AttackTimer_Timeout;
|
|
||||||
AddChild(_attackTimer);
|
|
||||||
SetPhysicsProcess(true);
|
SetPhysicsProcess(true);
|
||||||
_attackTimer.Start();
|
StartAttackTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AttackTimer_Timeout()
|
private void AttackTimer_Timeout()
|
||||||
{
|
{
|
||||||
var rng = new RandomNumberGenerator();
|
TakeAction();
|
||||||
rng.Randomize();
|
|
||||||
|
|
||||||
var leftArms = new Godot.Collections.Array<DemonWallArm>(LeftArms.GetChildren().Cast<DemonWallArm>());
|
|
||||||
var rightArms = new Godot.Collections.Array<DemonWallArm>(RightArms.GetChildren().Cast<DemonWallArm>());
|
|
||||||
|
|
||||||
var leftArm = leftArms.PickRandom();
|
|
||||||
var rightArm = rightArms.PickRandom();
|
|
||||||
|
|
||||||
leftArm.PrimaryAttack();
|
|
||||||
rightArm.PrimaryAttack();
|
|
||||||
|
|
||||||
if (leftArm == _arm3 && _opposingWall.Position.Z > -_maximumWallMoveAmount)
|
|
||||||
MoveWall();
|
|
||||||
}
|
|
||||||
|
|
||||||
private float GetRotationAngle()
|
|
||||||
{
|
|
||||||
var target = new Vector3(_player.CurrentPosition.X, Position.Y, _player.CurrentPosition.Z);
|
|
||||||
_rotation.LookAt(target, Vector3.Up, true);
|
|
||||||
_rotation.RotateY(Rotation.Y);
|
|
||||||
return _rotation.Rotation.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MoveWall()
|
|
||||||
{
|
|
||||||
var tweener = GetTree().CreateTween();
|
|
||||||
tweener.TweenMethod(Callable.From((float x) => MoveWallTowardsPlayer(x)), _opposingWall.Position.Z, _opposingWall.Position.Z - 2, 3f);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RotateTowardsPlayer(float angle) => Eye.Rotation = new Vector3(Eye.Rotation.X, angle, Eye.Rotation.Z);
|
|
||||||
|
|
||||||
private void MoveWallTowardsPlayer(float moveAmount)
|
|
||||||
{
|
|
||||||
_opposingWall.Position = new Vector3(_opposingWall.Position.X, _opposingWall.Position.Y, moveAmount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnExitTree()
|
public void OnExitTree()
|
||||||
{
|
{
|
||||||
_attackTimer.Timeout -= AttackTimer_Timeout;
|
_attackTimer.Timeout -= AttackTimer_Timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TakeAction()
|
||||||
|
{
|
||||||
|
EnemyModelView.Attack(_maximumWallMoveAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Move(Vector3 velocity) => throw new System.NotImplementedException();
|
||||||
|
|
||||||
|
public void TakeDamage(double damage, ElementType elementType = ElementType.None, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false)
|
||||||
|
{
|
||||||
|
var damageTaken = _damageCalculator.CalculateDamage(
|
||||||
|
damage,
|
||||||
|
elementType,
|
||||||
|
_enemyStatResource.CurrentDefense,
|
||||||
|
_enemyStatResource.ElementalResistance,
|
||||||
|
isCriticalHit,
|
||||||
|
ignoreDefense,
|
||||||
|
ignoreElementalResistance);
|
||||||
|
|
||||||
|
CurrentHP.OnNext(CurrentHP.Value - damageTaken);
|
||||||
|
GD.Print($"Demon Wall HP Left: {CurrentHP.Value}");
|
||||||
|
EnemyModelView.PlayHitAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Knockback(float impulse, Vector3 direction) => throw new System.NotImplementedException();
|
||||||
|
public void SetCurrentHP(int newHP) => throw new System.NotImplementedException();
|
||||||
|
public int GetMaximumHP() => _enemyStatResource.MaximumHP;
|
||||||
|
public void StartAttackTimer() => _attackTimer.Start();
|
||||||
|
public void StopAttackTimer() => _attackTimer.Stop();
|
||||||
|
public void SetTarget(Vector3 target) => throw new System.NotImplementedException();
|
||||||
|
public void SetEnemyGlobalPosition(Vector3 target) => throw new System.NotImplementedException();
|
||||||
|
public Vector3 GetEnemyGlobalPosition() => throw new System.NotImplementedException();
|
||||||
|
public IDungeonRoom GetCurrentRoom() => throw new System.NotImplementedException();
|
||||||
|
|
||||||
|
public async void Die()
|
||||||
|
{
|
||||||
|
CurrentHP.OnCompleted();
|
||||||
|
EnemyModelView.PlayDeathAnimation();
|
||||||
|
await ToSignal(GetTree().CreateTimer(0.8f), "timeout");
|
||||||
|
CallDeferred(MethodName.QueueFree);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,7 @@
|
|||||||
using Chickensoft.AutoInject;
|
using Chickensoft.AutoInject;
|
||||||
using Chickensoft.Introspection;
|
using Chickensoft.Introspection;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
using System.Linq;
|
||||||
using Zennysoft.Ma.Adapter;
|
using Zennysoft.Ma.Adapter;
|
||||||
|
|
||||||
namespace Zennysoft.Game.Ma;
|
namespace Zennysoft.Game.Ma;
|
||||||
@@ -16,13 +17,29 @@ public partial class DemonWallArm : Node3D
|
|||||||
private const string PARAMETERS_PLAYBACK = "parameters/playback";
|
private const string PARAMETERS_PLAYBACK = "parameters/playback";
|
||||||
private const string ATTACK = "attack";
|
private const string ATTACK = "attack";
|
||||||
|
|
||||||
|
[Dependency] protected IPlayer _player => this.DependOn(() => GetParent().GetChildren().OfType<IPlayer>().Single());
|
||||||
|
|
||||||
[Node] public AnimationTree AnimationTree { get; set; } = default!;
|
[Node] public AnimationTree AnimationTree { get; set; } = default!;
|
||||||
|
|
||||||
[Export] protected EnemyStatResource _enemyStatResource { get; set; } = default!;
|
[Node] public Area3D Hitbox { get; set; } = default!;
|
||||||
|
|
||||||
|
[Export] public double Damage { get; set; } = 15;
|
||||||
|
|
||||||
[Export] public ElementType PrimaryAttackElementalType { get; set; } = ElementType.None;
|
[Export] public ElementType PrimaryAttackElementalType { get; set; } = ElementType.None;
|
||||||
|
|
||||||
[Export] public double PrimaryAttackElementalDamageBonus { get; set; } = 1.0f;
|
[Export] public double PrimaryAttackElementalDamageBonus { get; set; } = 1.0f;
|
||||||
|
|
||||||
public void PrimaryAttack() => AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(ATTACK);
|
public void PrimaryAttack() => AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(ATTACK);
|
||||||
|
|
||||||
|
public void OnReady()
|
||||||
|
{
|
||||||
|
Hitbox.AreaEntered += Hitbox_AreaEntered;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Hitbox_AreaEntered(Area3D area)
|
||||||
|
{
|
||||||
|
var target = area.GetOwner();
|
||||||
|
if (target is IPlayer player)
|
||||||
|
player.TakeDamage(Damage * PrimaryAttackElementalDamageBonus, PrimaryAttackElementalType, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
using Chickensoft.AutoInject;
|
||||||
|
using Chickensoft.Introspection;
|
||||||
|
using Godot;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Zennysoft.Ma.Adapter;
|
||||||
|
|
||||||
|
namespace Zennysoft.Game.Ma;
|
||||||
|
|
||||||
|
[Meta(typeof(IAutoNode))]
|
||||||
|
public partial class DemonWallModelView : EnemyModelView3D
|
||||||
|
{
|
||||||
|
public override void _Notification(int what) => this.Notify(what);
|
||||||
|
|
||||||
|
[Dependency] protected IPlayer _player => this.DependOn(() => GetParent().GetChildren().OfType<IPlayer>().Single());
|
||||||
|
|
||||||
|
[Node] public Node3D LeftArms { get; set; } = default!;
|
||||||
|
|
||||||
|
[Node] public Node3D RightArms { get; set; } = default!;
|
||||||
|
|
||||||
|
[Node] public MeshInstance3D Eye { get; set; } = default!;
|
||||||
|
|
||||||
|
[Node] private Node3D _rotation { get; set; } = default!;
|
||||||
|
|
||||||
|
[Node] private AnimatableBody3D _opposingWall { get; set; } = default!;
|
||||||
|
|
||||||
|
public void Activate()
|
||||||
|
{
|
||||||
|
_opposingWall.Show();
|
||||||
|
var collisionShape = _opposingWall.GetChildren().OfType<CollisionShape3D>().Single();
|
||||||
|
collisionShape.SetDeferred(CollisionShape3D.PropertyName.Disabled, false);
|
||||||
|
SetPhysicsProcess(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnPhysicsProcess(double delta)
|
||||||
|
{
|
||||||
|
var direction = GlobalPosition.DirectionTo(_player.CurrentPosition).Normalized();
|
||||||
|
var rotationAngle = GetRotationAngle(_rotation);
|
||||||
|
RotateToPlayer(Eye, rotationAngle, 1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RotateToPlayer(Node3D rotateObject, float rotationAngle, float timeInSeconds)
|
||||||
|
{
|
||||||
|
var tweener = CreateTween();
|
||||||
|
tweener.TweenMethod(Callable.From((float x) => RotateTowardsPlayer(rotateObject, x)), rotateObject.Rotation.Y, rotationAngle, timeInSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void Attack(double maximumWallMoveAmount)
|
||||||
|
{
|
||||||
|
var rng = new RandomNumberGenerator();
|
||||||
|
rng.Randomize();
|
||||||
|
|
||||||
|
var leftArms = new Godot.Collections.Array<DemonWallArm>(LeftArms.GetChildren().Cast<DemonWallArm>());
|
||||||
|
var rightArms = new Godot.Collections.Array<DemonWallArm>(RightArms.GetChildren().Cast<DemonWallArm>());
|
||||||
|
|
||||||
|
var leftArm = leftArms.PickRandom();
|
||||||
|
var rightArm = rightArms.PickRandom();
|
||||||
|
|
||||||
|
leftArm.PrimaryAttack();
|
||||||
|
rightArm.PrimaryAttack();
|
||||||
|
|
||||||
|
var arm1 = GetNode<DemonWallArm>("%Arm1");
|
||||||
|
var arm2 = GetNode<DemonWallArm>("%Arm2");
|
||||||
|
var arm7 = GetNode<DemonWallArm>("%Arm2");
|
||||||
|
|
||||||
|
if (leftArm == arm1)
|
||||||
|
await AimAtPlayer(arm1, 2.1);
|
||||||
|
if (leftArm == arm2)
|
||||||
|
await AimAtPlayer(arm2, 1.5);
|
||||||
|
if (leftArm == GetNode<DemonWallArm>("%Arm3") && _opposingWall.Position.Z > -maximumWallMoveAmount)
|
||||||
|
MoveWall();
|
||||||
|
if (rightArm == arm7)
|
||||||
|
await AimAtPlayer(arm7, 2.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AimAtPlayer(DemonWallArm arm, double animationLengthInSeconds)
|
||||||
|
{
|
||||||
|
var rotationAngle = GetRotationAngle(arm.GetNode<Node3D>("%Rotation"));
|
||||||
|
RotateToPlayer(arm.GetNode<Node3D>("%Pivot"), rotationAngle, 0.3f);
|
||||||
|
await ToSignal(GetTree().CreateTimer(animationLengthInSeconds), "timeout");
|
||||||
|
RotateToPlayer(arm.GetNode<Node3D>("%Pivot"), 0, 0.3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void MoveWall()
|
||||||
|
{
|
||||||
|
await ToSignal(GetTree().CreateTimer(1.5f), "timeout");
|
||||||
|
var tweener = CreateTween();
|
||||||
|
tweener.TweenMethod(Callable.From((float x) => MoveWallTowardsPlayer(x)), _opposingWall.Position.Z, _opposingWall.Position.Z - 2, 3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MoveWallTowardsPlayer(float moveAmount)
|
||||||
|
{
|
||||||
|
_opposingWall.Position = new Vector3(_opposingWall.Position.X, _opposingWall.Position.Y, moveAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetRotationAngle(Node3D rotationNode)
|
||||||
|
{
|
||||||
|
var target = new Vector3(_player.CurrentPosition.X, Position.Y, _player.CurrentPosition.Z);
|
||||||
|
rotationNode.LookAt(target, Vector3.Up, true);
|
||||||
|
rotationNode.RotateY(Rotation.Y);
|
||||||
|
return rotationNode.Rotation.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RotateTowardsPlayer(Node3D rotationNode, float angle) => rotationNode.Rotation = new Vector3(rotationNode.Rotation.X, angle, rotationNode.Rotation.Z);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://d3cvsxlaohuqy
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
|||||||
|
using Chickensoft.AutoInject;
|
||||||
|
using Chickensoft.Introspection;
|
||||||
|
|
||||||
|
namespace Zennysoft.Game.Ma;
|
||||||
|
[Meta(typeof(IAutoNode))]
|
||||||
|
public partial class BossTypeAEnemyModelView : EnemyModelView3D
|
||||||
|
{
|
||||||
|
public override void _Notification(int what) => this.Notify(what);
|
||||||
|
|
||||||
|
[Node] public IHitbox Hitbox { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bvcfww5827g74
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Chickensoft.Introspection;
|
using Chickensoft.Introspection;
|
||||||
using Chickensoft.Serialization;
|
using Chickensoft.Serialization;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
using Zennysoft.Ma.Adapter.Entity;
|
||||||
|
|
||||||
namespace Zennysoft.Game.Ma;
|
namespace Zennysoft.Game.Ma;
|
||||||
|
|
||||||
@@ -22,21 +23,23 @@ public partial class ArmorStats : InventoryItemStats
|
|||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
[Save("armor_telluric_resistance")]
|
[Save("armor_telluric_resistance")]
|
||||||
public double TelluricResistance { get; set; } = 0;
|
private double _telluricResistance { get; set; } = 0;
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
[Save("armor_aeolic_resistance")]
|
[Save("armor_aeolic_resistance")]
|
||||||
public double AeolicResistance { get; set; } = 0;
|
private double _aeolicResistance { get; set; } = 0;
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
[Save("armor_hydric_resistance")]
|
[Save("armor_hydric_resistance")]
|
||||||
public double HydricResistance { get; set; } = 0;
|
private double _hydricResistance { get; set; } = 0;
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
[Save("armor_igneous_resistance")]
|
[Save("armor_igneous_resistance")]
|
||||||
public double IgneousResistance { get; set; } = 0;
|
private double _igneousResistance { get; set; } = 0;
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
[Save("armor_ferrum_resistance")]
|
[Save("armor_ferrum_resistance")]
|
||||||
public double FerrumResistance { get; set; } = 0;
|
private double _ferrumResistance { get; set; } = 0;
|
||||||
|
|
||||||
|
public ElementalResistanceSet ElementalResistanceSet => new ElementalResistanceSet(_aeolicResistance, _hydricResistance, _igneousResistance, _ferrumResistance, _telluricResistance);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1946,3 +1946,4 @@ shape = SubResource("BoxShape3D_bxvob")
|
|||||||
[node name="DemonWall" parent="." instance=ExtResource("25_k2q0o")]
|
[node name="DemonWall" parent="." instance=ExtResource("25_k2q0o")]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 21.2936, 55.334)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 21.2936, 55.334)
|
||||||
|
_maximumWallMoveAmount = 24.0
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Godot;
|
|||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
using SimpleInjector;
|
using SimpleInjector;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using Zennysoft.Ma.Adapter;
|
using Zennysoft.Ma.Adapter;
|
||||||
|
|
||||||
namespace Zennysoft.Game.Ma;
|
namespace Zennysoft.Game.Ma;
|
||||||
@@ -96,6 +95,8 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
|
|||||||
|
|
||||||
private Dictionary<int, int> _expToNextLevel;
|
private Dictionary<int, int> _expToNextLevel;
|
||||||
|
|
||||||
|
private IDamageCalculator _damageCalculator;
|
||||||
|
|
||||||
#region Initialization
|
#region Initialization
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
@@ -110,6 +111,7 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
|
|||||||
{ 7, 417 },
|
{ 7, 417 },
|
||||||
{ 8, 609 }
|
{ 8, 609 }
|
||||||
};
|
};
|
||||||
|
_damageCalculator = new DamageCalculator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Setup()
|
public void Setup()
|
||||||
@@ -147,10 +149,14 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
|
|||||||
PlayerLogic.Set(Stats);
|
PlayerLogic.Set(Stats);
|
||||||
PlayerLogic.Set(_gameRepo);
|
PlayerLogic.Set(_gameRepo);
|
||||||
|
|
||||||
var defaultWeapon = new Weapon();
|
var defaultWeapon = new Weapon
|
||||||
defaultWeapon.Stats = _defaultWeapon;
|
{
|
||||||
var defaultArmor = new Armor();
|
Stats = _defaultWeapon
|
||||||
defaultArmor.Stats = _defaultArmor;
|
};
|
||||||
|
var defaultArmor = new Armor
|
||||||
|
{
|
||||||
|
Stats = _defaultArmor
|
||||||
|
};
|
||||||
Inventory.TryAdd(defaultWeapon);
|
Inventory.TryAdd(defaultWeapon);
|
||||||
Inventory.TryAdd(defaultArmor);
|
Inventory.TryAdd(defaultArmor);
|
||||||
|
|
||||||
@@ -330,9 +336,7 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
|
|||||||
{
|
{
|
||||||
if (Stats.CurrentHP.Value > 0)
|
if (Stats.CurrentHP.Value > 0)
|
||||||
{
|
{
|
||||||
damage = CalculateDefenseResistance(damage);
|
_damageCalculator.CalculateDamage(damage, elementType, Stats.CurrentDefense.Value + Stats.BonusDefense.Value, ((Armor)_equippedArmor.Value).Stats.ElementalResistanceSet);
|
||||||
if (isCriticalHit)
|
|
||||||
damage *= 2;
|
|
||||||
Stats.SetCurrentHP(Stats.CurrentHP.Value - (int)damage);
|
Stats.SetCurrentHP(Stats.CurrentHP.Value - (int)damage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -537,11 +541,6 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
|
|||||||
LevelUp();
|
LevelUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
private double CalculateDefenseResistance(double incomingDamage)
|
|
||||||
{
|
|
||||||
return Mathf.Max(incomingDamage - Stats.CurrentDefense.Value - Stats.BonusDefense.Value, 0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Hitbox_AreaEntered(Area3D area)
|
private void Hitbox_AreaEntered(Area3D area)
|
||||||
{
|
{
|
||||||
var target = area.GetOwner();
|
var target = area.GetOwner();
|
||||||
|
|||||||
Reference in New Issue
Block a user