Revamp boss logic

This commit is contained in:
2025-03-18 00:12:36 -07:00
parent f50eaa1847
commit 13e2ef90c8
84 changed files with 2547 additions and 3655 deletions

View File

@@ -30,6 +30,8 @@
<PackageReference Include="Zeroconf" Version="3.7.16" /> <PackageReference Include="Zeroconf" Version="3.7.16" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="src\enemy\enemy_types\14. horse_head\" />
<Folder Include="src\enemy\enemy_types\15. ox_face\" />
<Folder Include="src\ui\dialogue\" /> <Folder Include="src\ui\dialogue\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,163 +0,0 @@
using Chickensoft.AutoInject;
using Chickensoft.Collections;
using Chickensoft.GodotNodeInterfaces;
using Chickensoft.Introspection;
using Godot;
using Zennysoft.Ma.Adapter;
namespace Zennysoft.Game.Ma;
public interface IBoss : ICharacterBody3D
{
public void Activate();
public void TakeDamage(double damage, ElementType elementType = ElementType.None, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false);
public void MoveToLocation(Vector3 target, float delta);
public void StartAttackTimer();
public void StopAttackTimer();
public double CurrentHP { get; }
public AutoProp<bool> IsDefeated { get; }
}
[Meta(typeof(IAutoNode))]
public partial class Boss : CharacterBody3D, IBoss, IProvide<IBossLogic>
{
public override void _Notification(int what) => this.Notify(what);
public double CurrentHP => _currentHP.Value;
public AutoProp<bool> IsDefeated { get; set; }
private AutoProp<double> _currentHP { get; set; }
#region Autoinject
protected IBossLogic _bossLogic { get; set; } = default!;
IBossLogic IProvide<IBossLogic>.Value() => _bossLogic;
public BossLogic.IBinding BossBinding { get; set; } = default!;
#endregion
#region Export
[Export] private EnemyStatResource _bossStatResource { get; set; } = default!;
#endregion
#region Dependencies
[Dependency] private IPlayer _player => this.DependOn<IPlayer>();
#endregion
#region Nodes
[Node] private AnimationTree _animationTree { get; set; } = default!;
[Node] private Timer _attackTimer { get; set; } = default!;
[Node] private AnimationPlayer _hitAnimation { get; set; } = default!;
[Node] private Area3D _hitbox { get; set; } = default!;
[Node] private Area3D _attackBox { get; set; } = default!;
[Node] private Area3D _secondaryAttackBox { get; set; } = default!;
#endregion
public void Setup()
{
_bossLogic = new BossLogic();
_bossLogic.Set(this as IBoss);
_bossLogic.Set(_player);
SetPhysicsProcess(false);
Hide();
}
public void OnResolved()
{
BossBinding = _bossLogic.Bind();
BossBinding
.Handle((in BossLogic.Output.Defeated output) =>
{
_hitAnimation.Play("Defeated");
});
this.Provide();
_bossLogic.Start();
_currentHP = new AutoProp<double>(_bossStatResource.MaximumHP);
_currentHP.Sync += OnHPChanged;
_attackTimer.Timeout += AttackTimer_Timeout;
}
public void Activate()
{
_bossLogic.Input(new BossLogic.Input.Activate());
}
public void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false)
{
if (_currentHP.Value > 0)
{
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);
if (_currentHP.Value <= 0)
return;
//EnemyModelView.PlayHitAnimation();
}
}
public void MoveToLocation(Vector3 target, float delta) => throw new System.NotImplementedException();
public void StartAttackTimer() => _attackTimer.Start();
public void StopAttackTimer() => _attackTimer.Stop();
private void AttackTimer_Timeout() => _bossLogic.Input(new BossLogic.Input.AttackTimer());
public virtual void TakeAction()
{
}
public void OnPhysicsProcess(double delta)
{
_bossLogic.Input(new BossLogic.Input.PhysicsTick(delta));
MoveAndSlide();
}
private void OnHPChanged(double newHP)
{
if (newHP <= 0)
_bossLogic.Input(new BossLogic.Input.BossDefeated());
}
private double CalculateElementalResistance(double incomingDamage, ElementType incomingElementType)
{
if (incomingElementType == ElementType.Aeolic)
return Mathf.Max(incomingDamage - (incomingDamage * _bossStatResource.AeolicResistance), 0.0);
if (incomingElementType == ElementType.Hydric)
return Mathf.Max(incomingDamage - (incomingDamage * _bossStatResource.HydricResistance), 0.0);
if (incomingElementType == ElementType.Igneous)
return Mathf.Max(incomingDamage - (incomingDamage * _bossStatResource.IgneousResistance), 0.0);
if (incomingElementType == ElementType.Ferrum)
return Mathf.Max(incomingDamage - (incomingDamage * _bossStatResource.FerrumResistance), 0.0);
if (incomingElementType == ElementType.Telluric)
return Mathf.Max(incomingDamage - (incomingDamage * _bossStatResource.TelluricResistance), 0.0);
return Mathf.Max(incomingDamage, 0.0);
}
private double CalculateDefenseResistance(double incomingDamage)
{
return Mathf.Max(incomingDamage - _bossStatResource.CurrentDefense, 0.0);
}
}

View File

@@ -1 +0,0 @@
uid://dwpswg0xufxa7

View File

@@ -1,19 +0,0 @@
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
public static class Input
{
public readonly record struct Activate;
public readonly record struct PhysicsTick(double Delta);
public readonly record struct StopMoving;
public readonly record struct AttackTimer;
public readonly record struct StartAttacking;
public readonly record struct BossDefeated;
}
}

View File

@@ -1 +0,0 @@
uid://cc1wadksmbq6h

View File

@@ -1,17 +0,0 @@
using Godot;
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
public static class Output
{
public readonly record struct MoveTowardsPlayer(Vector3 TargetPosition);
public readonly record struct MovementComputed(Vector3 LinearVelocity);
public readonly record struct TakeAction;
public readonly record struct Defeated;
}
}

View File

@@ -1 +0,0 @@
uid://c7r8l4w4nwd8x

View File

@@ -1,15 +0,0 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
[Meta]
public abstract partial record State : StateLogic<State>
{
protected State()
{
}
}
}

View File

@@ -1 +0,0 @@
uid://ds1hjuenunrht

View File

@@ -1,13 +0,0 @@
using Chickensoft.Introspection;
using Chickensoft.LogicBlocks;
namespace Zennysoft.Game.Ma;
public interface IBossLogic : ILogicBlock<BossLogic.State>;
[Meta, Id("boss_logic")]
[LogicBlock(typeof(State), Diagram = true)]
public partial class BossLogic : LogicBlock<BossLogic.State>, IBossLogic
{
public override Transition GetInitialState() => To<State.Unactivated>();
}

View File

@@ -1 +0,0 @@
uid://dnpj001c3iabh

View File

@@ -1,29 +0,0 @@
@startuml BossLogic
state "BossLogic State" as GameJamDungeon_BossLogic_State {
state "Defeated" as GameJamDungeon_BossLogic_State_Defeated
state "Alive" as GameJamDungeon_BossLogic_State_Alive {
state "Idle" as GameJamDungeon_BossLogic_State_Idle
state "EngagePlayer" as GameJamDungeon_BossLogic_State_EngagePlayer
state "ApproachPlayer" as GameJamDungeon_BossLogic_State_ApproachPlayer
state "Activated" as GameJamDungeon_BossLogic_State_Activated {
state "Attacking" as GameJamDungeon_BossLogic_State_Attacking
state "FollowPlayer" as GameJamDungeon_BossLogic_State_FollowPlayer
}
}
}
GameJamDungeon_BossLogic_State_Alive --> GameJamDungeon_BossLogic_State_Defeated : BossDefeated
GameJamDungeon_BossLogic_State_ApproachPlayer --> GameJamDungeon_BossLogic_State_ApproachPlayer : PhysicsTick
GameJamDungeon_BossLogic_State_ApproachPlayer --> GameJamDungeon_BossLogic_State_EngagePlayer : PhysicsTick
GameJamDungeon_BossLogic_State_EngagePlayer --> GameJamDungeon_BossLogic_State_ApproachPlayer : PhysicsTick
GameJamDungeon_BossLogic_State_EngagePlayer --> GameJamDungeon_BossLogic_State_EngagePlayer : PhysicsTick
GameJamDungeon_BossLogic_State_EngagePlayer --> GameJamDungeon_BossLogic_State_EngagePlayer : PrimaryAttack
GameJamDungeon_BossLogic_State_EngagePlayer --> GameJamDungeon_BossLogic_State_EngagePlayer : SecondaryAttack
GameJamDungeon_BossLogic_State_FollowPlayer --> GameJamDungeon_BossLogic_State_FollowPlayer : PhysicsTick
GameJamDungeon_BossLogic_State_Idle --> GameJamDungeon_BossLogic_State_ApproachPlayer : Activate
GameJamDungeon_BossLogic_State : On() → Defeated
GameJamDungeon_BossLogic_State_Alive : OnBossDefeated → Defeated
[*] --> GameJamDungeon_BossLogic_State_Idle
@enduml

View File

@@ -1,14 +0,0 @@
using Chickensoft.Introspection;
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
public partial record State
{
[Meta, Id("boss_logic_state_activated")]
public partial record Activated : Alive
{
}
}
}

View File

@@ -1 +0,0 @@
uid://dk60nmw42pm82

View File

@@ -1,37 +0,0 @@
using Chickensoft.Introspection;
using Godot;
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
public partial record State
{
[Meta, Id("boss_logic_state_alive")]
public abstract partial record Alive : State, IGet<Input.BossDefeated>, IGet<Input.AttackTimer>, IGet<Input.StopMoving>, IGet<Input.StartAttacking>
{
}
public Transition On(in Input.AttackTimer input)
{
Output(new Output.TakeAction());
return To<Attacking>();
}
public Transition On(in Input.BossDefeated input)
{
Output(new Output.Defeated());
return To<Defeated>();
}
public Transition On(in Input.StopMoving input)
{
return To<Idle>();
}
public Transition On(in Input.StartAttacking input)
{
return To<Attacking>();
}
}
}

View File

@@ -1 +0,0 @@
uid://bbwhocehdcsbt

View File

@@ -1,34 +0,0 @@
using Chickensoft.Introspection;
using Godot;
using Zennysoft.Ma.Adapter;
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
public partial record State
{
[Meta, Id("boss_logic_state_approach_player")]
public partial record ApproachPlayer : Alive, IGet<Input.PhysicsTick>
{
public Transition On(in Input.PhysicsTick input)
{
var boss = Get<IBoss>();
var player = Get<IPlayer>();
var delta = (float)input.Delta;
var playerPosition = new Vector3(player.CurrentPosition.X, boss.GlobalPosition.Y, player.CurrentPosition.Z);
if (boss.GlobalPosition.DistanceTo(player.CurrentPosition) <= 5.0f)
return To<EngagePlayer>();
var moveToward = boss.GlobalPosition.MoveToward(playerPosition, (float)delta * 3f);
boss.GlobalPosition = moveToward;
var targetDirection = boss.GlobalPosition - player.CurrentPosition;
boss.GlobalRotation = new Vector3(boss.GlobalRotation.X, Mathf.LerpAngle(boss.GlobalRotation.Y, Mathf.Atan2(-targetDirection.X, -targetDirection.Z), delta * 3f), boss.GlobalRotation.Z);
return ToSelf();
}
}
}
}

View File

@@ -1,19 +0,0 @@
using Chickensoft.Introspection;
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
public partial record State
{
[Meta, Id("boss_logic_state_attacking")]
public partial record Attacking : Activated, IGet<Input.StopMoving>
{
public Attacking()
{
OnAttach(() => Get<IEnemy>().StartAttackTimer());
OnDetach(() => Get<IEnemy>().StopAttackTimer());
}
}
}
}

View File

@@ -1 +0,0 @@
uid://crsw8t5nr4ots

View File

@@ -1,14 +0,0 @@
using Chickensoft.Introspection;
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
public partial record State
{
[Meta, Id("boss_logic_state_defeated")]
public partial record Defeated : State
{
}
}
}

View File

@@ -1 +0,0 @@
uid://beymhvkyuay4h

View File

@@ -1,32 +0,0 @@
using Chickensoft.Introspection;
using Godot;
using Zennysoft.Ma.Adapter;
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
public partial record State
{
[Meta, Id("boss_logic_state_engage_player")]
public partial record EngagePlayer : Alive, IGet<Input.PhysicsTick>
{
public EngagePlayer()
{
}
public Transition On(in Input.PhysicsTick input)
{
var boss = Get<IBoss>();
var player = Get<IPlayer>();
var delta = (float)input.Delta;
var targetDirection = boss.GlobalPosition - player.CurrentPosition;
boss.GlobalRotation = new Vector3(boss.GlobalRotation.X, Mathf.LerpAngle(boss.GlobalRotation.Y, Mathf.Atan2(-targetDirection.X, -targetDirection.Z), delta * 3f), boss.GlobalRotation.Z);
if (boss.GlobalPosition.DistanceTo(player.CurrentPosition) > 5.0f)
return To<ApproachPlayer>();
return ToSelf();
}
}
}
}

View File

@@ -1,23 +0,0 @@
using Chickensoft.Introspection;
using Zennysoft.Ma.Adapter;
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
public partial record State
{
[Meta, Id("boss_logic_state_followplayer")]
public partial record FollowPlayer : Activated, IGet<Input.PhysicsTick>
{
public Transition On(in Input.PhysicsTick input)
{
var enemy = Get<IEnemy>();
var player = Get<IPlayer>();
var target = player.CurrentPosition;
enemy.SetTarget(target);
return ToSelf();
}
}
}
}

View File

@@ -1,28 +0,0 @@
using Chickensoft.Introspection;
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
public partial record State
{
[Meta, Id("boss_logic_state_idle")]
public partial record Idle : Alive, IGet<Input.Activate>
{
public Idle()
{
OnDetach(() =>
{
var boss = Get<IBoss>();
boss.SetPhysicsProcess(true);
boss.Show();
}
);
}
public Transition On(in Input.Activate input)
{
return To<ApproachPlayer>();
}
}
}
}

View File

@@ -1 +0,0 @@
uid://h4f0q5o6nolw

View File

@@ -1,18 +0,0 @@
using Chickensoft.Introspection;
namespace Zennysoft.Game.Ma;
public partial class BossLogic
{
public partial record State
{
[Meta, Id("boss_logic_state_unactivated")]
public partial record Unactivated : State, IGet<Input.Activate>
{
public Transition On(in Input.Activate input)
{
return To<Activated>();
}
}
}
}

View File

@@ -1,59 +0,0 @@
[gd_resource type="ShaderMaterial" load_steps=2 format=3 uid="uid://cf3an7cx1vjm6"]
[sub_resource type="Shader" id="Shader_veoq4"]
code = "// NOTE: Shader automatically converted from Godot Engine 4.4.dev1.mono's StandardMaterial3D.
shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_burley, specular_schlick_ggx;
uniform vec4 albedo : source_color;
uniform sampler2D texture_albedo : source_color, filter_linear_mipmap, repeat_enable;
uniform float point_size : hint_range(0.1, 128.0, 0.1);
uniform float roughness : hint_range(0.0, 1.0);
uniform sampler2D texture_metallic : hint_default_white, filter_linear_mipmap, repeat_enable;
uniform vec4 metallic_texture_channel;
uniform sampler2D texture_roughness : hint_roughness_r, filter_linear_mipmap, repeat_enable;
uniform float specular : hint_range(0.0, 1.0, 0.01);
uniform float metallic : hint_range(0.0, 1.0, 0.01);
uniform vec3 uv1_scale;
uniform vec3 uv1_offset;
uniform vec3 uv2_scale;
uniform vec3 uv2_offset;
void vertex() {
UV = UV * uv1_scale.xy + uv1_offset.xy;
}
void fragment() {
vec2 base_uv = UV;
vec4 albedo_tex = texture(texture_albedo, base_uv);
ALBEDO = albedo.rgb * albedo_tex.rgb;
float metallic_tex = dot(texture(texture_metallic, base_uv), metallic_texture_channel);
METALLIC = metallic_tex * metallic;
SPECULAR = specular;
vec4 roughness_texture_channel = vec4(1.0, 0.0, 0.0, 0.0);
float roughness_tex = dot(texture(texture_roughness, base_uv), roughness_texture_channel);
ROUGHNESS = roughness_tex * roughness;
ALPHA *= albedo.a * albedo_tex.a;
}
"
[resource]
render_priority = 0
shader = SubResource("Shader_veoq4")
shader_parameter/albedo = Color(0.784314, 0, 0, 0.00784314)
shader_parameter/point_size = 1.0
shader_parameter/roughness = 1.0
shader_parameter/metallic_texture_channel = Vector4(0, 0, 0, 0)
shader_parameter/specular = 0.5
shader_parameter/metallic = 0.0
shader_parameter/uv1_scale = Vector3(1, 1, 1)
shader_parameter/uv1_offset = Vector3(0, 0, 0)
shader_parameter/uv2_scale = Vector3(1, 1, 1)
shader_parameter/uv2_offset = Vector3(0, 0, 0)

View File

@@ -0,0 +1,134 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
using System.Collections.Generic;
using System;
using Zennysoft.Ma.Adapter;
namespace Zennysoft.Game.Ma;
[Meta(typeof(IAutoNode))]
public partial class BossTypeA : Enemy, IHasPrimaryAttack, IHasSecondaryAttack, ICanActivate
{
public override void _Notification(int what) => this.Notify(what);
[Export]
public ElementType PrimaryAttackElementalType { get; set; } = ElementType.None;
[Export]
public double PrimaryAttackElementalDamageBonus { get; set; } = 1.0;
public ElementType SecondaryAttackElementalType { get; set; } = ElementType.None;
public double SecondaryAttackElementalDamageBonus { get; set; } = 1.0;
[Node] public new EnemyModelView3D _enemyModelView { get; set; }
[Node] public CollisionShape3D EnemyHitbox { get; set; } = default!;
private Vector3 _target;
public void OnReady()
{
_target = GlobalPosition;
SetPhysicsProcess(true);
_enemyModelView.Hitbox.AreaEntered += Hitbox_AreaEntered;
_attackTimer.Start();
}
public void OnPhysicsProcess(double delta)
{
_enemyLogic.Input(new EnemyLogic.Input.PhysicsTick(delta));
if (_enemyLogic.Value is not EnemyLogic.State.Activated)
return;
if (_enemyLogic.Value is EnemyLogic.State.FollowPlayer && GlobalPosition.DistanceTo(_player.CurrentPosition) < 5f)
_enemyLogic.Input(new EnemyLogic.Input.StartAttacking());
if (_enemyLogic.Value is EnemyLogic.State.Attacking && GlobalPosition.DistanceTo(_player.CurrentPosition) > 5f)
_enemyLogic.Input(new EnemyLogic.Input.Alerted());
var direction = (_target - GlobalPosition).Normalized();
LookAt(direction);
if (_enemyLogic.Value is EnemyLogic.State.FollowPlayer)
{
Velocity = direction * _movementSpeed;
MoveAndSlide();
_enemyModelView.PlayWalkAnimation();
}
else
{
_enemyModelView.PlayIdleAnimation();
}
}
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();
}
public override void StartAttackTimer()
{
_attackTimer.Timeout += OnAttackTimeout;
}
public override void StopAttackTimer()
{
_attackTimer.Timeout -= OnAttackTimeout;
}
public override void SetTarget(Vector3 target) => _target = target;
private void Hitbox_AreaEntered(Area3D area)
{
var target = area.GetOwner();
if (target is IPlayer player)
{
var damage = _enemyStatResource.CurrentAttack * PrimaryAttackElementalDamageBonus;
player.TakeDamage(damage, PrimaryAttackElementalType, BattleExtensions.IsCriticalHit(_enemyStatResource.Luck));
}
}
public void Activate()
{
Show();
_enemyLogic.Input(new EnemyLogic.Input.Alerted());
EnemyHitbox.SetDeferred(CollisionShape3D.PropertyName.Disabled, false);
}
private void OnAttackTimeout()
{
if (GlobalPosition.DistanceTo(_player.CurrentPosition) > 5f)
{
_enemyLogic.Input(new EnemyLogic.Input.Alerted());
return;
}
var rng = new RandomNumberGenerator();
rng.Randomize();
_enemyLogic.Input(new EnemyLogic.Input.AttackTimer());
_attackTimer.Stop();
_attackTimer.WaitTime = rng.RandfRange(2f, 5.0f);
_attackTimer.Start();
}
public override void _ExitTree()
{
CurrentHP.OnCompleted();
StopAttackTimer();
_enemyModelView.Hitbox.AreaEntered -= Hitbox_AreaEntered;
}
}

View File

@@ -0,0 +1 @@
uid://dveonnhcxcp08

View File

@@ -31,7 +31,7 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
[Export] protected EnemyStatResource _enemyStatResource { get; set; } = default!; [Export] protected EnemyStatResource _enemyStatResource { get; set; } = default!;
[Export] [Export]
private float _movementSpeed = 2f; protected float _movementSpeed = 2f;
#endregion #endregion
#region Node Dependencies #region Node Dependencies
@@ -39,16 +39,14 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
[Node] private Area3D _lineOfSight { get; set; } = default!; [Node] private Area3D _lineOfSight { get; set; } = default!;
[Node] private Timer _attackTimer { get; set; } = default!; [Node] protected Timer _attackTimer { get; set; } = default!;
[Node] private RayCast3D _raycast { get; set; } = default!; [Node] private RayCast3D _raycast { get; set; } = default!;
[Node] protected IEnemyModelView _enemyModelView { get; set; } = default!; [Node] protected IEnemyModelView _enemyModelView { get; set; } = default!;
#endregion #endregion
public double CurrentHP => _currentHP.Value; public AutoProp<double> CurrentHP { get; set; }
private AutoProp<double> _currentHP { get; set; }
private float _knockbackStrength = 0.0f; private float _knockbackStrength = 0.0f;
@@ -80,14 +78,14 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
_enemyLogic.Start(); _enemyLogic.Start();
_currentHP = new AutoProp<double>(_enemyStatResource.MaximumHP); CurrentHP = new AutoProp<double>(_enemyStatResource.MaximumHP);
_currentHP.Sync += OnHPChanged; CurrentHP.Sync += OnHPChanged;
_lineOfSight.BodyEntered += LineOfSight_BodyEntered; _lineOfSight.BodyEntered += LineOfSight_BodyEntered;
} }
public override void _PhysicsProcess(double delta) public override void _PhysicsProcess(double delta)
{ {
if (CurrentHP <= 0) if (CurrentHP.Value <= 0)
return; return;
var lookDir = GlobalPosition + Velocity; var lookDir = GlobalPosition + Velocity;
@@ -118,7 +116,7 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
public virtual void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false) public virtual void TakeDamage(double damage, ElementType elementType, bool isCriticalHit = false, bool ignoreDefense = false, bool ignoreElementalResistance = false)
{ {
if (_currentHP.Value > 0) if (CurrentHP.Value > 0)
{ {
if (!ignoreElementalResistance) if (!ignoreElementalResistance)
damage = CalculateElementalResistance(damage, elementType); damage = CalculateElementalResistance(damage, elementType);
@@ -127,10 +125,10 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
if (isCriticalHit) if (isCriticalHit)
damage *= 2; damage *= 2;
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);
if (_currentHP.Value <= 0) if (CurrentHP.Value <= 0)
return; return;
_enemyModelView.PlayHitAnimation(); _enemyModelView.PlayHitAnimation();
@@ -149,7 +147,7 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
public void Die() public void Die()
{ {
_currentHP.OnNext(0); CurrentHP.OnNext(0);
_enemyLogic.Input(new EnemyLogic.Input.EnemyDefeated()); _enemyLogic.Input(new EnemyLogic.Input.EnemyDefeated());
_collisionShape.SetDeferred("disabled", true); _collisionShape.SetDeferred("disabled", true);
_enemyModelView.PlayDeathAnimation(); _enemyModelView.PlayDeathAnimation();
@@ -161,7 +159,7 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
public void SetCurrentHP(int targetHP) public void SetCurrentHP(int targetHP)
{ {
_currentHP.OnNext(targetHP); CurrentHP.OnNext(targetHP);
} }
public int GetMaximumHP() public int GetMaximumHP()
@@ -169,12 +167,12 @@ public partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLogic>
return _enemyStatResource.MaximumHP; return _enemyStatResource.MaximumHP;
} }
public void StartAttackTimer() public virtual void StartAttackTimer()
{ {
_attackTimer.Timeout += OnAttackTimeout; _attackTimer.Timeout += OnAttackTimeout;
} }
public void StopAttackTimer() public virtual void StopAttackTimer()
{ {
_attackTimer.Timeout -= OnAttackTimeout; _attackTimer.Timeout -= OnAttackTimeout;
} }

View File

@@ -1,4 +1,4 @@
using Chickensoft.AutoInject; using Chickensoft.AutoInject;
using Chickensoft.Introspection; using Chickensoft.Introspection;
using Godot; using Godot;
@@ -10,12 +10,8 @@ public partial class EnemyModelView3D : Node3D, IEnemyModelView
private const string PRIMARY_ATTACK = "primary_attack"; private const string PRIMARY_ATTACK = "primary_attack";
private const string SECONDARY_ATTACK = "secondary_attack"; private const string SECONDARY_ATTACK = "secondary_attack";
private const string PRIMARY_SKILL = "primary_skill"; private const string PRIMARY_SKILL = "primary_skill";
private const string IDLE_FORWARD = "idle_front"; private const string WALK = "walk";
private const string IDLE_LEFT = "idle_left"; private const string IDLE = "idle";
private const string IDLE_BACK = "idle_back";
private const string IDLE_FORWARD_WALK = "idle_front_walk";
private const string IDLE_LEFT_WALK = "idle_left_walk";
private const string IDLE_BACK_WALK = "idle_back_walk";
private const string TAKE_DAMAGE = "take_damage"; private const string TAKE_DAMAGE = "take_damage";
private const string DEFEATED = "defeated"; private const string DEFEATED = "defeated";
private const string PARAMETERS_PLAYBACK = "parameters/playback"; private const string PARAMETERS_PLAYBACK = "parameters/playback";
@@ -24,34 +20,48 @@ public partial class EnemyModelView3D : Node3D, IEnemyModelView
[Export] public EnemyLoreInfo EnemyLoreInfo { get; set; } = default!; [Export] public EnemyLoreInfo EnemyLoreInfo { get; set; } = default!;
[Node] private MeshInstance3D _meshInstance { get; set; } = default!;
[Node] private AnimationPlayer _animationPlayer { get; set; } = default!; [Node] private AnimationPlayer _animationPlayer { get; set; } = default!;
[Node] public AnimationTree AnimationTree { get; set; } = default!;
[Node] public IHitbox Hitbox { get; set; } = default!;
public void Setup() public void Setup()
{ {
} }
public void PlayPrimaryAttackAnimation() public void PlayPrimaryAttackAnimation()
{ {
_animationPlayer.Play(PRIMARY_ATTACK); AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(PRIMARY_ATTACK);
} }
public void PlaySecondaryAttackAnimation() public void PlaySecondaryAttackAnimation()
{ {
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(SECONDARY_ATTACK);
} }
public void PlayPrimarySkillAnimation() public void PlayPrimarySkillAnimation()
{ {
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(PRIMARY_SKILL);
} }
public void PlayHitAnimation() public void PlayHitAnimation()
{ {
_animationPlayer.Play(TAKE_DAMAGE); _animationPlayer.Play(TAKE_DAMAGE);
} }
public void PlayDeathAnimation() public void PlayDeathAnimation()
{ {
_animationPlayer.Play(DEFEATED); _animationPlayer.Play(DEFEATED);
}
public void PlayWalkAnimation()
{
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(WALK);
}
public void PlayIdleAnimation()
{
AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().Travel(IDLE);
} }
} }

View File

@@ -0,0 +1,6 @@
namespace Zennysoft.Game.Ma;
public interface ICanActivate
{
public void Activate();
}

View File

@@ -0,0 +1 @@
uid://btxdf6ncxkk02

View File

@@ -1,4 +1,5 @@
using Godot; using Chickensoft.Collections;
using Godot;
using Zennysoft.Game.Abstractions; using Zennysoft.Game.Abstractions;
using Zennysoft.Ma.Adapter; using Zennysoft.Ma.Adapter;
@@ -14,7 +15,7 @@ public interface IEnemy : IKillable
public void Knockback(float impulse, Vector3 direction); public void Knockback(float impulse, Vector3 direction);
public double CurrentHP { get; } public AutoProp<double> CurrentHP { get; }
public void SetCurrentHP(int newHP); public void SetCurrentHP(int newHP);

View File

@@ -7,7 +7,7 @@ using Zennysoft.Ma.Adapter;
namespace Zennysoft.Game.Ma; namespace Zennysoft.Game.Ma;
[Meta(typeof(IAutoNode))] [Meta(typeof(IAutoNode))]
public partial class Chinthe : Enemy, IHasPrimaryAttack, ICanPatrol public partial class Chinthe : Enemy, IHasPrimaryAttack, ICanPatrol, ICanActivate
{ {
public override void _Notification(int what) => this.Notify(what); public override void _Notification(int what) => this.Notify(what);
@@ -24,72 +24,72 @@ public partial class Chinthe : Enemy, IHasPrimaryAttack, ICanPatrol
public void OnReady() public void OnReady()
{ {
SetPhysicsProcess(true); SetPhysicsProcess(true);
EnemyModelView.Hitbox.AreaEntered += Hitbox_AreaEntered; EnemyModelView.Hitbox.AreaEntered += Hitbox_AreaEntered;
} }
public void OnPhysicsProcess(double delta) public void OnPhysicsProcess(double delta)
{ {
_enemyLogic.Input(new EnemyLogic.Input.PhysicsTick(delta)); _enemyLogic.Input(new EnemyLogic.Input.PhysicsTick(delta));
if (_enemyLogic.Value is not EnemyLogic.State.Activated) if (_enemyLogic.Value is not EnemyLogic.State.Activated)
return; return;
if (_enemyLogic.Value is EnemyLogic.State.FollowPlayer && GlobalPosition.DistanceTo(_player.CurrentPosition) < 2.5f) if (_enemyLogic.Value is EnemyLogic.State.FollowPlayer && GlobalPosition.DistanceTo(_player.CurrentPosition) < 2.5f)
_enemyLogic.Input(new EnemyLogic.Input.StartAttacking()); _enemyLogic.Input(new EnemyLogic.Input.StartAttacking());
if (_enemyLogic.Value is EnemyLogic.State.FollowPlayer && GlobalPosition.DistanceTo(_player.CurrentPosition) > 45f) if (_enemyLogic.Value is EnemyLogic.State.FollowPlayer && GlobalPosition.DistanceTo(_player.CurrentPosition) > 45f)
_enemyLogic.Input(new EnemyLogic.Input.LostPlayer()); _enemyLogic.Input(new EnemyLogic.Input.LostPlayer());
if (_enemyLogic.Value is EnemyLogic.State.Attacking && GlobalPosition.DistanceTo(_player.CurrentPosition) > 2.5f) if (_enemyLogic.Value is EnemyLogic.State.Attacking && GlobalPosition.DistanceTo(_player.CurrentPosition) > 2.5f)
_enemyLogic.Input(new EnemyLogic.Input.Alerted()); _enemyLogic.Input(new EnemyLogic.Input.Alerted());
_navigationAgentClient.CalculateVelocity(GlobalPosition, EnemyModelView.CanMove); _navigationAgentClient.CalculateVelocity(GlobalPosition, EnemyModelView.CanMove);
base._PhysicsProcess(delta); base._PhysicsProcess(delta);
} }
public override void TakeAction() public override void TakeAction()
{ {
PrimaryAttack(); PrimaryAttack();
} }
public void PrimaryAttack() public void PrimaryAttack()
{ {
_enemyModelView.PlayPrimaryAttackAnimation(); _enemyModelView.PlayPrimaryAttackAnimation();
} }
public override void SetTarget(Vector3 target) => _navigationAgentClient.SetTarget(target); public override void SetTarget(Vector3 target) => _navigationAgentClient.SetTarget(target);
public void Patrol() public void Patrol()
{ {
var rng = new RandomNumberGenerator(); var rng = new RandomNumberGenerator();
rng.Randomize(); rng.Randomize();
var randomizedSpot = new Vector3(rng.RandfRange(-5.0f, 5.0f), 0, rng.RandfRange(-5.0f, 5.0f)); var randomizedSpot = new Vector3(rng.RandfRange(-5.0f, 5.0f), 0, rng.RandfRange(-5.0f, 5.0f));
_enemyLogic.Input(new EnemyLogic.Input.PatrolToRandomSpot(GlobalPosition + randomizedSpot)); _enemyLogic.Input(new EnemyLogic.Input.PatrolToRandomSpot(GlobalPosition + randomizedSpot));
_enemyLogic.Input(new EnemyLogic.Input.StartPatrol()); _enemyLogic.Input(new EnemyLogic.Input.StartPatrol());
} }
public void Activate() public void Activate()
{ {
if (EnemyModelView.AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().GetCurrentNode().ToString().Contains("front")) if (EnemyModelView.AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().GetCurrentNode().ToString().Contains("front"))
EnemyModelView.PlayActivateFrontAnimation(); EnemyModelView.PlayActivateFrontAnimation();
if (EnemyModelView.AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().GetCurrentNode().ToString().Contains("left")) if (EnemyModelView.AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().GetCurrentNode().ToString().Contains("left"))
EnemyModelView.PlayActivateLeftAnimation(); EnemyModelView.PlayActivateLeftAnimation();
if (EnemyModelView.AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().GetCurrentNode().ToString().Contains("back")) if (EnemyModelView.AnimationTree.Get(PARAMETERS_PLAYBACK).As<AnimationNodeStateMachinePlayback>().GetCurrentNode().ToString().Contains("back"))
EnemyModelView.PlayActivateBackAnimation(); EnemyModelView.PlayActivateBackAnimation();
} }
public void Teleport() public void Teleport()
{ {
EnemyModelView.PlayTeleportAnimation(); EnemyModelView.PlayTeleportAnimation();
} }
private void Hitbox_AreaEntered(Area3D area) private void Hitbox_AreaEntered(Area3D area)
{ {
var target = area.GetOwner(); var target = area.GetOwner();
if (target is IPlayer player) if (target is IPlayer player)
{ {
var damage = _enemyStatResource.CurrentAttack * PrimaryAttackElementalDamageBonus; var damage = _enemyStatResource.CurrentAttack * PrimaryAttackElementalDamageBonus;
player.TakeDamage(damage, PrimaryAttackElementalType, BattleExtensions.IsCriticalHit(_enemyStatResource.Luck)); player.TakeDamage(damage, PrimaryAttackElementalType, BattleExtensions.IsCriticalHit(_enemyStatResource.Luck));
} }
} }
} }

View File

@@ -3,7 +3,7 @@
[ext_resource type="Texture2D" uid="uid://cvst7yhbw0sxt" path="res://src/enemy/enemy_types/10. Eden Pillar/model/PILLAR EXPORT 1_ENEMY_PILLAR_TEXTURE2.jpg" id="1_1kpl1"] [ext_resource type="Texture2D" uid="uid://cvst7yhbw0sxt" path="res://src/enemy/enemy_types/10. Eden Pillar/model/PILLAR EXPORT 1_ENEMY_PILLAR_TEXTURE2.jpg" id="1_1kpl1"]
[ext_resource type="Script" uid="uid://ckv5dmrw6pvn6" path="res://src/enemy/EnemyModelView3D.cs" id="1_11eq8"] [ext_resource type="Script" uid="uid://ckv5dmrw6pvn6" path="res://src/enemy/EnemyModelView3D.cs" id="1_11eq8"]
[ext_resource type="Texture2D" uid="uid://bnbveonobhyhc" path="res://src/enemy/enemy_types/10. Eden Pillar/model/PILLAR EXPORT 1_cannon_edge.png" id="2_11eq8"] [ext_resource type="Texture2D" uid="uid://bnbveonobhyhc" path="res://src/enemy/enemy_types/10. Eden Pillar/model/PILLAR EXPORT 1_cannon_edge.png" id="2_11eq8"]
[ext_resource type="Material" uid="uid://brwu51ylevbmg" path="res://src/enemy/enemy_types/14. horse_head/BossHit.tres" id="2_xf2ga"] [ext_resource type="Material" uid="uid://brwu51ylevbmg" path="res://src/enemy/enemy_types/14. horse_head/animation/BossHit.tres" id="2_xf2ga"]
[ext_resource type="Texture2D" uid="uid://by7k6crx6fmpv" path="res://src/enemy/enemy_types/10. Eden Pillar/model/PILLAR EXPORT 1_floral_single_tile.jpg" id="3_oxjs8"] [ext_resource type="Texture2D" uid="uid://by7k6crx6fmpv" path="res://src/enemy/enemy_types/10. Eden Pillar/model/PILLAR EXPORT 1_floral_single_tile.jpg" id="3_oxjs8"]
[ext_resource type="Texture2D" uid="uid://cc1tenm6p3pca" path="res://src/enemy/enemy_types/10. Eden Pillar/model/PILLAR EXPORT 1_ENEMY_PILLAR_TEXTURE.jpg" id="4_xf2ga"] [ext_resource type="Texture2D" uid="uid://cc1tenm6p3pca" path="res://src/enemy/enemy_types/10. Eden Pillar/model/PILLAR EXPORT 1_ENEMY_PILLAR_TEXTURE.jpg" id="4_xf2ga"]
[ext_resource type="Texture2D" uid="uid://bydfevqfagpq8" path="res://src/enemy/enemy_types/10. Eden Pillar/model/PILLAR EXPORT 1_concrete_0025_height_1k.png" id="5_qhmtu"] [ext_resource type="Texture2D" uid="uid://bydfevqfagpq8" path="res://src/enemy/enemy_types/10. Eden Pillar/model/PILLAR EXPORT 1_concrete_0025_height_1k.png" id="5_qhmtu"]

View File

@@ -0,0 +1 @@
uid://clt3sfgb5m3xq

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +0,0 @@
using Godot;
namespace Zennysoft.Game.Ma;
public partial class HorseHead : Node3D
{
}

View File

@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://8yaqqojv4nuv"] [gd_scene load_steps=2 format=3 uid="uid://8yaqqojv4nuv"]
[ext_resource type="PackedScene" uid="uid://c4uus6q6c4ocg" path="res://src/enemy/enemy_types/14. horse_head/Horse Head 1.0 STATUE.glb" id="1_ktvqd"] [ext_resource type="PackedScene" uid="uid://c4uus6q6c4ocg" path="res://src/enemy/enemy_types/14. horse_head/animation/Horse Head 1.0 STATUE.glb" id="1_ktvqd"]
[node name="Node3D" type="Node3D"] [node name="Node3D" type="Node3D"]

View File

@@ -4,12 +4,12 @@ importer="scene"
importer_version=1 importer_version=1
type="PackedScene" type="PackedScene"
uid="uid://cvqaccot8ltrf" uid="uid://cvqaccot8ltrf"
path="res://.godot/imported/HORSE-FACE 1.1.glb-a095bfe8da5727e267e8a8185cd8aaee.scn" path="res://.godot/imported/HORSE-FACE 1.1.glb-8c0ac9d603554b32a1666de9bd9b1814.scn"
[deps] [deps]
source_file="res://src/enemy/enemy_types/14. horse_head/HORSE-FACE 1.1.glb" source_file="res://src/enemy/enemy_types/14. horse_head/animation/HORSE-FACE 1.1.glb"
dest_files=["res://.godot/imported/HORSE-FACE 1.1.glb-a095bfe8da5727e267e8a8185cd8aaee.scn"] dest_files=["res://.godot/imported/HORSE-FACE 1.1.glb-8c0ac9d603554b32a1666de9bd9b1814.scn"]
[params] [params]

View File

@@ -3,7 +3,7 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://csj3kjwyn3s2u" uid="uid://csj3kjwyn3s2u"
path="res://.godot/imported/HORSE-FACE 1_Metal054C_1K-JPG_Color.jpg-dd3ebefab63cbbf56a2e0e52b75bc691.ctex" path="res://.godot/imported/HORSE-FACE 1_Metal054C_1K-JPG_Color.jpg-1f1a8445de0bb81a567077e5aec18194.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
@@ -13,8 +13,8 @@ generator_parameters={
[deps] [deps]
source_file="res://src/enemy/enemy_types/14. horse_head/HORSE-FACE 1_Metal054C_1K-JPG_Color.jpg" source_file="res://src/enemy/enemy_types/14. horse_head/animation/HORSE-FACE 1_Metal054C_1K-JPG_Color.jpg"
dest_files=["res://.godot/imported/HORSE-FACE 1_Metal054C_1K-JPG_Color.jpg-dd3ebefab63cbbf56a2e0e52b75bc691.ctex"] dest_files=["res://.godot/imported/HORSE-FACE 1_Metal054C_1K-JPG_Color.jpg-1f1a8445de0bb81a567077e5aec18194.ctex"]
[params] [params]

View File

@@ -3,7 +3,7 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://dd7ocxanos2o7" uid="uid://dd7ocxanos2o7"
path="res://.godot/imported/HORSE-FACE 1_Metal054C_1K-JPG_Displacement.jpg-5771feccb31b5f0e73720e8a3e7a5725.ctex" path="res://.godot/imported/HORSE-FACE 1_Metal054C_1K-JPG_Displacement.jpg-386dacafcbff768209a8a638cefcea95.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
@@ -13,8 +13,8 @@ generator_parameters={
[deps] [deps]
source_file="res://src/enemy/enemy_types/14. horse_head/HORSE-FACE 1_Metal054C_1K-JPG_Displacement.jpg" source_file="res://src/enemy/enemy_types/14. horse_head/animation/HORSE-FACE 1_Metal054C_1K-JPG_Displacement.jpg"
dest_files=["res://.godot/imported/HORSE-FACE 1_Metal054C_1K-JPG_Displacement.jpg-5771feccb31b5f0e73720e8a3e7a5725.ctex"] dest_files=["res://.godot/imported/HORSE-FACE 1_Metal054C_1K-JPG_Displacement.jpg-386dacafcbff768209a8a638cefcea95.ctex"]
[params] [params]

View File

@@ -4,12 +4,12 @@ importer="scene"
importer_version=1 importer_version=1
type="PackedScene" type="PackedScene"
uid="uid://c4uus6q6c4ocg" uid="uid://c4uus6q6c4ocg"
path="res://.godot/imported/Horse Head 1.0 STATUE.glb-e0c74b4195e0fc27f4658130960774ea.scn" path="res://.godot/imported/Horse Head 1.0 STATUE.glb-0ffebc243c4ceff8865a777101feadec.scn"
[deps] [deps]
source_file="res://src/enemy/enemy_types/14. horse_head/Horse Head 1.0 STATUE.glb" source_file="res://src/enemy/enemy_types/14. horse_head/animation/Horse Head 1.0 STATUE.glb"
dest_files=["res://.godot/imported/Horse Head 1.0 STATUE.glb-e0c74b4195e0fc27f4658130960774ea.scn"] dest_files=["res://.godot/imported/Horse Head 1.0 STATUE.glb-0ffebc243c4ceff8865a777101feadec.scn"]
[params] [params]

View File

@@ -8,7 +8,7 @@ valid=false
[deps] [deps]
source_file="res://src/enemy/enemy_types/14. horse_head/Horse Head 1.0 WALK.glb" source_file="res://src/enemy/enemy_types/14. horse_head/animation/Horse Head 1.0 WALK.glb"
[params] [params]

View File

@@ -4,12 +4,12 @@ importer="scene"
importer_version=1 importer_version=1
type="PackedScene" type="PackedScene"
uid="uid://b8xs07d4ycm3s" uid="uid://b8xs07d4ycm3s"
path="res://.godot/imported/Horse Head 1.0.glb-17c7ea9ea5d193e3a003f25b69f74650.scn" path="res://.godot/imported/Horse Head 1.0.glb-1e71651be336a86299c334b8540d0758.scn"
[deps] [deps]
source_file="res://src/enemy/enemy_types/14. horse_head/Horse Head 1.0.glb" source_file="res://src/enemy/enemy_types/14. horse_head/animation/Horse Head 1.0.glb"
dest_files=["res://.godot/imported/Horse Head 1.0.glb-17c7ea9ea5d193e3a003f25b69f74650.scn"] dest_files=["res://.godot/imported/Horse Head 1.0.glb-1e71651be336a86299c334b8540d0758.scn"]
[params] [params]

View File

@@ -3,7 +3,7 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://2e4cp477ex0t" uid="uid://2e4cp477ex0t"
path="res://.godot/imported/Horse Head 1_Metal054C_1K-JPG_Color.jpg-309c20056c641a0bf0fe6eabcff04ca0.ctex" path="res://.godot/imported/Horse Head 1_Metal054C_1K-JPG_Color.jpg-0c0531e87bbeff5b38eafc2808887dbf.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
@@ -13,8 +13,8 @@ generator_parameters={
[deps] [deps]
source_file="res://src/enemy/enemy_types/14. horse_head/Horse Head 1_Metal054C_1K-JPG_Color.jpg" source_file="res://src/enemy/enemy_types/14. horse_head/animation/Horse Head 1_Metal054C_1K-JPG_Color.jpg"
dest_files=["res://.godot/imported/Horse Head 1_Metal054C_1K-JPG_Color.jpg-309c20056c641a0bf0fe6eabcff04ca0.ctex"] dest_files=["res://.godot/imported/Horse Head 1_Metal054C_1K-JPG_Color.jpg-0c0531e87bbeff5b38eafc2808887dbf.ctex"]
[params] [params]

View File

@@ -3,7 +3,7 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://kdnitbg4n87p" uid="uid://kdnitbg4n87p"
path="res://.godot/imported/Horse Head 1_Metal054C_1K-JPG_Displacement.jpg-22bf3780ddcc88b6230d35aebd896c20.ctex" path="res://.godot/imported/Horse Head 1_Metal054C_1K-JPG_Displacement.jpg-0a8cfa8420b016a4333949db03bcf0e5.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
@@ -13,8 +13,8 @@ generator_parameters={
[deps] [deps]
source_file="res://src/enemy/enemy_types/14. horse_head/Horse Head 1_Metal054C_1K-JPG_Displacement.jpg" source_file="res://src/enemy/enemy_types/14. horse_head/animation/Horse Head 1_Metal054C_1K-JPG_Displacement.jpg"
dest_files=["res://.godot/imported/Horse Head 1_Metal054C_1K-JPG_Displacement.jpg-22bf3780ddcc88b6230d35aebd896c20.ctex"] dest_files=["res://.godot/imported/Horse Head 1_Metal054C_1K-JPG_Displacement.jpg-0a8cfa8420b016a4333949db03bcf0e5.ctex"]
[params] [params]

View File

@@ -3,15 +3,15 @@
importer="texture" importer="texture"
type="CompressedTexture2D" type="CompressedTexture2D"
uid="uid://bv60n7epxktw5" uid="uid://bv60n7epxktw5"
path="res://.godot/imported/Metal054C_1K-JPG_NormalDX.jpg-1cf1bfec87fee44ad90f8f8942ca9cd1.ctex" path="res://.godot/imported/Metal054C_1K-JPG_NormalDX.jpg-8f619f53486c72857b0b0ce2b4ae98bd.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
[deps] [deps]
source_file="res://src/enemy/enemy_types/14. horse_head/Metal054C_1K-JPG_NormalDX.jpg" source_file="res://src/enemy/enemy_types/14. horse_head/animation/Metal054C_1K-JPG_NormalDX.jpg"
dest_files=["res://.godot/imported/Metal054C_1K-JPG_NormalDX.jpg-1cf1bfec87fee44ad90f8f8942ca9cd1.ctex"] dest_files=["res://.godot/imported/Metal054C_1K-JPG_NormalDX.jpg-8f619f53486c72857b0b0ce2b4ae98bd.ctex"]
[params] [params]

View File

@@ -1,57 +0,0 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
using Zennysoft.Ma.Adapter;
namespace Zennysoft.Game.Ma;
[Meta(typeof(IAutoNode))]
public partial class OxFace : Node3D
{
public override void _Notification(int what) => this.Notify(what);
[Node] public AnimationTree AnimationTree { get; set; } = default!;
[Dependency] public IPlayer Player => this.DependOn<IPlayer>();
[Node] public Timer AttackTimer { get; set; } = default!;
private bool isInRange = false;
public void Setup()
{
SetPhysicsProcess(false);
}
public void EngagePlayer()
{
SetPhysicsProcess(true);
Visible = true;
AttackTimer.Timeout += AttackTimer_Timeout;
AttackTimer.Start();
}
private void AttackTimer_Timeout()
{
AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel("SPEAR");
}
public override void _PhysicsProcess(double delta)
{
var playerPosition = new Vector3(Player.CurrentPosition.X, GlobalPosition.Y, Player.CurrentPosition.Z);
var targetDirection = GlobalPosition - Player.CurrentPosition;
GlobalRotation = new Vector3(GlobalRotation.X, Mathf.LerpAngle(GlobalRotation.Y, Mathf.Atan2(-targetDirection.X, -targetDirection.Z), (float)delta * 3f), GlobalRotation.Z);
if (GlobalPosition.DistanceTo(Player.CurrentPosition) > 5.0f)
{
isInRange = false;
var moveToward = GlobalPosition.MoveToward(playerPosition, (float)delta * 3f);
GlobalPosition = moveToward;
AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel("WALK");
}
else if (!isInRange)
{
isInRange = true;
AnimationTree.Get("parameters/playback").As<AnimationNodeStateMachinePlayback>().Travel("IDLE");
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -98,7 +98,7 @@ public class EffectService
var currentEnemies = currentRoom.EnemiesInRoom; var currentEnemies = currentRoom.EnemiesInRoom;
var hpToAbsorb = 0.0; var hpToAbsorb = 0.0;
foreach (var enemy in currentEnemies) foreach (var enemy in currentEnemies)
hpToAbsorb += enemy.CurrentHP * 0.05; hpToAbsorb += enemy.CurrentHP.Value * 0.05;
_player.Stats.SetCurrentHP(_player.Stats.CurrentHP.Value + (int)hpToAbsorb); _player.Stats.SetCurrentHP(_player.Stats.CurrentHP.Value + (int)hpToAbsorb);
GD.Print("HP to absorb: " + hpToAbsorb); GD.Print("HP to absorb: " + hpToAbsorb);
} }

View File

@@ -31,8 +31,12 @@ public partial class ThrownItem : RigidBody3D
private void ThrownItem_BodyEntered(Node body) private void ThrownItem_BodyEntered(Node body)
{ {
if (body is IEnemy enemy) if (body is IEnemy enemy)
{
CalculateEffect(enemy); CalculateEffect(enemy);
QueueFree(); QueueFree();
}
else if (ItemThatIsThrown is ThrowableItem)
QueueFree();
} }
public void Throw(EffectService effectService) public void Throw(EffectService effectService)
@@ -85,7 +89,7 @@ public partial class ThrownItem : RigidBody3D
switch (throwableItem.ThrowableItemTag) switch (throwableItem.ThrowableItemTag)
{ {
case ThrowableItemTag.LowerTargetTo1HP: case ThrowableItemTag.LowerTargetTo1HP:
enemy.TakeDamage(enemy.CurrentHP - 1, ignoreDefense: true, ignoreElementalResistance: true); enemy.TakeDamage(enemy.CurrentHP.Value - 1, ignoreDefense: true, ignoreElementalResistance: true);
break; break;
case ThrowableItemTag.TeleportToRandomLocation: case ThrowableItemTag.TeleportToRandomLocation:
_effectService.TeleportToRandomRoom(enemy); _effectService.TeleportToRandomRoom(enemy);
@@ -99,6 +103,6 @@ public partial class ThrownItem : RigidBody3D
} }
} }
else else
enemy.TakeDamage(((InventoryItem)ItemThatIsThrown).ThrowDamage); enemy.TakeDamage(ItemThatIsThrown.ThrowDamage);
} }
} }

View File

@@ -10,8 +10,8 @@ size = Vector3(0.46632, 0.507293, 0.586082)
viewport_path = NodePath("Sprite3D/SubViewportContainer/SubViewport") viewport_path = NodePath("Sprite3D/SubViewportContainer/SubViewport")
[node name="Hitbox" type="RigidBody3D"] [node name="Hitbox" type="RigidBody3D"]
collision_layer = 1040 collision_layer = 3072
collision_mask = 25 collision_mask = 2049
mass = 0.1 mass = 0.1
gravity_scale = 0.2 gravity_scale = 0.2
contact_monitor = true contact_monitor = true

View File

@@ -1,8 +1,9 @@
[gd_scene load_steps=12 format=3 uid="uid://by67pn7fdsg1m"] [gd_scene load_steps=13 format=3 uid="uid://by67pn7fdsg1m"]
[ext_resource type="Script" uid="uid://14e8mu48ed4" path="res://src/map/Map.cs" id="1_bw70o"] [ext_resource type="Script" uid="uid://14e8mu48ed4" path="res://src/map/Map.cs" id="1_bw70o"]
[ext_resource type="PackedScene" uid="uid://dl6h1djc27ddl" path="res://src/map/dungeon/floors/Floor00.tscn" id="2_0m8h8"] [ext_resource type="PackedScene" uid="uid://dl6h1djc27ddl" path="res://src/map/dungeon/floors/Floor00.tscn" id="2_0m8h8"]
[ext_resource type="PackedScene" uid="uid://bc1sp6xwe0j65" path="res://src/map/dungeon/floors/Floor01.tscn" id="2_merfv"] [ext_resource type="PackedScene" uid="uid://bc1sp6xwe0j65" path="res://src/map/dungeon/floors/Floor01.tscn" id="2_merfv"]
[ext_resource type="PackedScene" uid="uid://g28xmp6cn16h" path="res://src/map/dungeon/floors/Floor10.tscn" id="3_caf7v"]
[ext_resource type="PackedScene" uid="uid://dmiqwmivkjgmq" path="res://src/map/dungeon/floors/Floor02.tscn" id="4_8y0oy"] [ext_resource type="PackedScene" uid="uid://dmiqwmivkjgmq" path="res://src/map/dungeon/floors/Floor02.tscn" id="4_8y0oy"]
[ext_resource type="PackedScene" uid="uid://dl1scvkp8r5sw" path="res://src/map/dungeon/floors/Floor03.tscn" id="5_uag72"] [ext_resource type="PackedScene" uid="uid://dl1scvkp8r5sw" path="res://src/map/dungeon/floors/Floor03.tscn" id="5_uag72"]
[ext_resource type="PackedScene" uid="uid://cikq7vuorlpbl" path="res://src/map/dungeon/floors/Floor04.tscn" id="6_55rmo"] [ext_resource type="PackedScene" uid="uid://cikq7vuorlpbl" path="res://src/map/dungeon/floors/Floor04.tscn" id="6_55rmo"]
@@ -14,6 +15,6 @@
[node name="Map" type="Node3D"] [node name="Map" type="Node3D"]
script = ExtResource("1_bw70o") script = ExtResource("1_bw70o")
_floors = Array[PackedScene]([ExtResource("2_0m8h8"), ExtResource("11_y74f3"), ExtResource("2_merfv"), ExtResource("4_8y0oy"), ExtResource("5_uag72"), ExtResource("6_55rmo"), ExtResource("7_f6kwn"), ExtResource("8_ne2vg"), ExtResource("9_abpbr"), ExtResource("10_caf7v")]) _floors = Array[PackedScene]([ExtResource("2_0m8h8"), ExtResource("3_caf7v"), ExtResource("11_y74f3"), ExtResource("2_merfv"), ExtResource("4_8y0oy"), ExtResource("5_uag72"), ExtResource("6_55rmo"), ExtResource("7_f6kwn"), ExtResource("8_ne2vg"), ExtResource("9_abpbr"), ExtResource("10_caf7v")])
[node name="WorldEnvironment" type="WorldEnvironment" parent="."] [node name="WorldEnvironment" type="WorldEnvironment" parent="."]

View File

@@ -10,18 +10,16 @@ public partial class BossFloor : Node3D, IDungeonFloor
{ {
public override void _Notification(int what) => this.Notify(what); public override void _Notification(int what) => this.Notify(what);
private BossRoomA BossRoom; [Node] private BossRoomA BossFloorA { get; set; } = default!;
public ImmutableList<IDungeonRoom> Rooms => []; public ImmutableList<IDungeonRoom> Rooms => [];
public void InitializeDungeon() public void InitializeDungeon()
{ {
var bossRoomScene = GD.Load<PackedScene>($"res://src/map/dungeon/scenes/BossRoom.tscn"); FloorIsLoaded = true;
BossRoom = bossRoomScene.Instantiate<BossRoomA>();
FloorIsLoaded = true;
} }
public bool FloorIsLoaded { get; set; } public bool FloorIsLoaded { get; set; }
public Transform3D GetPlayerSpawnPoint() => BossRoom.PlayerSpawn.GlobalTransform; public Transform3D GetPlayerSpawnPoint() => BossFloorA.PlayerSpawn.GlobalTransform;
} }

View File

@@ -1,4 +1,4 @@
using Chickensoft.AutoInject; using Chickensoft.AutoInject;
using Chickensoft.Introspection; using Chickensoft.Introspection;
using Godot; using Godot;
@@ -9,28 +9,37 @@ public partial class BossRoomA : Node3D, IBossRoom
{ {
public override void _Notification(int what) => this.Notify(what); public override void _Notification(int what) => this.Notify(what);
[Dependency] public IGame Game => this.DependOn<IGame>();
[Node] public Marker3D PlayerSpawn { get; set; } = default!; [Node] public Marker3D PlayerSpawn { get; set; } = default!;
[Node] public Node3D HorseHeadStatue { get; set; } = default!; [Node] public Node3D HorseHeadStatue { get; set; } = default!;
[Node] public Node3D OxFaceStatue { get; set; } = default!; [Node] public Node3D OxFaceStatue { get; set; } = default!;
[Node] public Boss OxFace { get; set; } = default!; [Node] public BossTypeA OxFace { get; set; } = default!;
[Node] public Boss HorseFace { get; set; } = default!; [Node] public BossTypeA HorseFace { get; set; } = default!;
[Node] public Area3D ActivateTrap { get; set; } = default!; [Node] public Area3D ActivateTrap { get; set; } = default!;
[Node] public Node3D GateCollision { get; set; } = default!; [Node] public Node3D GateCollision { get; set; } = default!;
[Node] private Area3D _exit { get; set; } = default!;
public void Setup() public void Setup()
{ {
ActivateTrap.BodyEntered += ActivateTrap_BodyEntered; ActivateTrap.BodyEntered += ActivateTrap_BodyEntered;
OxFace.IsDefeated.Sync += BossStatusUpdate; OxFace.CurrentHP.Sync += BossStatusUpdate;
HorseFace.IsDefeated.Sync += BossStatusUpdate; HorseFace.CurrentHP.Sync += BossStatusUpdate;
_exit.AreaEntered += Exit_AreaEntered;
} }
private void ActivateTrap_BodyEntered(Node3D body) => StartBossFight(); private void ActivateTrap_BodyEntered(Node3D body)
{
ActivateTrap.BodyEntered -= ActivateTrap_BodyEntered;
StartBossFight();
}
public void StartBossFight() public void StartBossFight()
{ {
@@ -45,9 +54,14 @@ public partial class BossRoomA : Node3D, IBossRoom
GateCollision.CallDeferred(MethodName.QueueFree); GateCollision.CallDeferred(MethodName.QueueFree);
} }
private void BossStatusUpdate(bool obj) private void BossStatusUpdate(double hp)
{ {
if (OxFace.IsDefeated.Value && HorseFace.IsDefeated.Value) if (OxFace.CurrentHP.Value <= 0 && HorseFace.CurrentHP.Value <= 0)
OnBossFightEnded(); OnBossFightEnded();
} }
public void ExitReached()
=> Game.FloorExitReached();
private void Exit_AreaEntered(Area3D area) => ExitReached();
} }

View File

@@ -12,7 +12,6 @@ public partial class ExitRoom : DungeonRoom
[Dependency] public IGame Game => this.DependOn<IGame>(); [Dependency] public IGame Game => this.DependOn<IGame>();
[Node] private Area3D _exit { get; set; } = default!; [Node] private Area3D _exit { get; set; } = default!;
[Node] private Area3D _room { get; set; } = default!;
public override void _Ready() public override void _Ready()
{ {

View File

@@ -6,4 +6,5 @@
[node name="Floor10" type="Node3D"] [node name="Floor10" type="Node3D"]
script = ExtResource("1_0xjxw") script = ExtResource("1_0xjxw")
[node name="Boss Floor A" parent="." instance=ExtResource("2_rbjfi")] [node name="BossFloorA" parent="." instance=ExtResource("2_rbjfi")]
unique_name_in_owner = true

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=132 format=4 uid="uid://5ja3qxn8h7iw"] [gd_scene load_steps=134 format=4 uid="uid://5ja3qxn8h7iw"]
[ext_resource type="Script" uid="uid://tqyybt313web" path="res://src/map/dungeon/code/BossRoomA.cs" id="1_0h3lb"] [ext_resource type="Script" uid="uid://tqyybt313web" path="res://src/map/dungeon/code/BossRoomA.cs" id="1_0h3lb"]
[ext_resource type="Texture2D" uid="uid://vjbe1lg810gh" path="res://src/map/dungeon/models/Set A/15. Boss Floor A/15_A1_BOSS FLOOR A_VER_swirled_column.png" id="2_06eum"] [ext_resource type="Texture2D" uid="uid://vjbe1lg810gh" path="res://src/map/dungeon/models/Set A/15. Boss Floor A/15_A1_BOSS FLOOR A_VER_swirled_column.png" id="2_06eum"]
@@ -758,6 +758,9 @@ _surfaces = [{
blend_shape_mode = 0 blend_shape_mode = 0
shadow_mesh = SubResource("ArrayMesh_d6sdf") shadow_mesh = SubResource("ArrayMesh_d6sdf")
[sub_resource type="BoxShape3D" id="BoxShape3D_01whq"]
size = Vector3(3.42822, 1.92615, 1.85886)
[sub_resource type="ArrayMesh" id="ArrayMesh_2xh7e"] [sub_resource type="ArrayMesh" id="ArrayMesh_2xh7e"]
_surfaces = [{ _surfaces = [{
"aabb": AABB(-10.8214, -29.365, -6.19888e-06, 21.6429, 58.73, 1.14441e-05), "aabb": AABB(-10.8214, -29.365, -6.19888e-06, 21.6429, 58.73, 1.14441e-05),
@@ -1594,7 +1597,10 @@ size = Vector3(44.8284, 85.1827, 35.0648)
size = Vector3(23.3561, 85.1827, 86.7729) size = Vector3(23.3561, 85.1827, 86.7729)
[sub_resource type="BoxShape3D" id="BoxShape3D_2y86l"] [sub_resource type="BoxShape3D" id="BoxShape3D_2y86l"]
size = Vector3(57.711, 85.1827, 121.41) size = Vector3(24.4394, 85.1827, 121.41)
[sub_resource type="BoxShape3D" id="BoxShape3D_blf77"]
size = Vector3(59.626, 85.1827, 51.1984)
[sub_resource type="BoxShape3D" id="BoxShape3D_ukub6"] [sub_resource type="BoxShape3D" id="BoxShape3D_ukub6"]
size = Vector3(11.6031, 85.1827, 18.5975) size = Vector3(11.6031, 85.1827, 18.5975)
@@ -1662,12 +1668,12 @@ data = PackedVector3Array(-1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1,
[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_1txpk"] [sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_1txpk"]
data = PackedVector3Array(-1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1) data = PackedVector3Array(-1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1)
[sub_resource type="BoxShape3D" id="BoxShape3D_01whq"]
size = Vector3(3.42822, 1.92615, 1.85886)
[sub_resource type="BoxShape3D" id="BoxShape3D_pkvyy"] [sub_resource type="BoxShape3D" id="BoxShape3D_pkvyy"]
size = Vector3(6.25977, 15.6429, 37.6357) size = Vector3(6.25977, 15.6429, 37.6357)
[sub_resource type="BoxShape3D" id="BoxShape3D_1qa0g"]
size = Vector3(12.4734, 10.2039, 7.09571)
[node name="Boss Floor A" type="Node3D"] [node name="Boss Floor A" type="Node3D"]
script = ExtResource("1_0h3lb") script = ExtResource("1_0h3lb")
@@ -1678,6 +1684,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.135796, -15.9299, 0)
[node name="COLLISION 2" type="MeshInstance3D" parent="Model/15_A1_BOSS FLOOR A_VER_2"] [node name="COLLISION 2" type="MeshInstance3D" parent="Model/15_A1_BOSS FLOOR A_VER_2"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -88.3533, 14.402, -0.620708) transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -88.3533, 14.402, -0.620708)
visible = false
mesh = SubResource("ArrayMesh_dyjpi") mesh = SubResource("ArrayMesh_dyjpi")
skeleton = NodePath("") skeleton = NodePath("")
@@ -1688,11 +1695,13 @@ skeleton = NodePath("")
[node name="COLLISION 3" type="MeshInstance3D" parent="Model/15_A1_BOSS FLOOR A_VER_2"] [node name="COLLISION 3" type="MeshInstance3D" parent="Model/15_A1_BOSS FLOOR A_VER_2"]
transform = Transform3D(19.342, 0, 0, 0, 3.58, 0, 0, 0, 4.493, -118.368, 16.3753, 28.1552) transform = Transform3D(19.342, 0, 0, 0, 3.58, 0, 0, 0, 4.493, -118.368, 16.3753, 28.1552)
visible = false
mesh = SubResource("ArrayMesh_tyise") mesh = SubResource("ArrayMesh_tyise")
skeleton = NodePath("") skeleton = NodePath("")
[node name="COLLISION" type="MeshInstance3D" parent="Model/15_A1_BOSS FLOOR A_VER_2"] [node name="COLLISION" type="MeshInstance3D" parent="Model/15_A1_BOSS FLOOR A_VER_2"]
transform = Transform3D(19.342, 0, 0, 0, 3.12, 0, 0, 0, 4.493, -118.368, 16.0099, 6.55423) transform = Transform3D(19.342, 0, 0, 0, 3.12, 0, 0, 0, 4.493, -118.368, 16.0099, 6.55423)
visible = false
mesh = SubResource("ArrayMesh_tyise") mesh = SubResource("ArrayMesh_tyise")
skeleton = NodePath("") skeleton = NodePath("")
@@ -1702,6 +1711,13 @@ transform = Transform3D(0.816274, 0, 0, 0, 1.99383, 0, 0, 0, 1.99383, -145.76, 1
mesh = SubResource("ArrayMesh_xlsos") mesh = SubResource("ArrayMesh_xlsos")
skeleton = NodePath("") skeleton = NodePath("")
[node name="StaticBody3D6" type="StaticBody3D" parent="Model/15_A1_BOSS FLOOR A_VER_2/GateCollision"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.000244141, 2.08616e-07, 0)
[node name="CollisionShape3D" type="CollisionShape3D" parent="Model/15_A1_BOSS FLOOR A_VER_2/GateCollision/StaticBody3D6"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.337311, 0.0641477, -0.00570393)
shape = SubResource("BoxShape3D_01whq")
[node name="BOSS FLOOR_001" type="MeshInstance3D" parent="Model/15_A1_BOSS FLOOR A_VER_2"] [node name="BOSS FLOOR_001" type="MeshInstance3D" parent="Model/15_A1_BOSS FLOOR A_VER_2"]
transform = Transform3D(-0.188597, 0, -3.10851e-08, 0, 0.0695013, 0, 5.62062e-08, 0, -0.104304, -81.6436, 15.2955, 15.4911) transform = Transform3D(-0.188597, 0, -3.10851e-08, 0, 0.0695013, 0, 5.62062e-08, 0, -0.104304, -81.6436, 15.2955, 15.4911)
mesh = SubResource("ArrayMesh_31d0h") mesh = SubResource("ArrayMesh_31d0h")
@@ -1822,9 +1838,13 @@ transform = Transform3D(1, 0, -4.26326e-14, 0, 1, 0, 3.41061e-13, 0, 1, -66.351,
shape = SubResource("BoxShape3D_0u7qe") shape = SubResource("BoxShape3D_0u7qe")
[node name="CollisionShape3D7" type="CollisionShape3D" parent="Collision/StaticBody3D3"] [node name="CollisionShape3D7" type="CollisionShape3D" parent="Collision/StaticBody3D3"]
transform = Transform3D(1, 0, -4.26326e-14, 0, 1, 0, 3.41061e-13, 0, 1, -26.3376, -8.11585, 60.0398) transform = Transform3D(1, 0, 1.84741e-12, 0, 1, 0, 4.54747e-13, 0, 1, -9.70184, 2.74369, 60.0398)
shape = SubResource("BoxShape3D_2y86l") shape = SubResource("BoxShape3D_2y86l")
[node name="CollisionShape3D29" type="CollisionShape3D" parent="Collision/StaticBody3D3"]
transform = Transform3D(1, 0, 6.03961e-12, 0, 1, 0, 4.54747e-13, 0, 1, -27.2952, 2.74369, 24.934)
shape = SubResource("BoxShape3D_blf77")
[node name="CollisionShape3D8" type="CollisionShape3D" parent="Collision/StaticBody3D3"] [node name="CollisionShape3D8" type="CollisionShape3D" parent="Collision/StaticBody3D3"]
transform = Transform3D(1, 0, -4.26326e-14, 0, 1, 0, 3.41061e-13, 0, 1, 191.381, -8.11585, 25.5622) transform = Transform3D(1, 0, -4.26326e-14, 0, 1, 0, 3.41061e-13, 0, 1, 191.381, -8.11585, 25.5622)
shape = SubResource("BoxShape3D_ukub6") shape = SubResource("BoxShape3D_ukub6")
@@ -1917,20 +1937,13 @@ transform = Transform3D(19.342, 0, 0, 0, 3.12, 0, 0, 0, 4.493, -118.232, 0.07999
[node name="CollisionShape3D" type="CollisionShape3D" parent="Collision/StaticBody3D5"] [node name="CollisionShape3D" type="CollisionShape3D" parent="Collision/StaticBody3D5"]
shape = SubResource("ConcavePolygonShape3D_1txpk") shape = SubResource("ConcavePolygonShape3D_1txpk")
[node name="StaticBody3D6" type="StaticBody3D" parent="Collision"]
transform = Transform3D(0.816274, 0, 0, 0, 1.99383, 0, 0, 0, 1.99383, -145.624, -0.6323, 17.4223)
[node name="CollisionShape3D" type="CollisionShape3D" parent="Collision/StaticBody3D6"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.337311, 0.0641477, -0.00570393)
shape = SubResource("BoxShape3D_01whq")
[node name="Doors" type="Node3D" parent="."] [node name="Doors" type="Node3D" parent="."]
[node name="Spawn Points" type="Node3D" parent="."] [node name="Spawn Points" type="Node3D" parent="."]
[node name="PlayerSpawn" type="Marker3D" parent="Spawn Points"] [node name="PlayerSpawn" type="Marker3D" parent="Spawn Points"]
unique_name_in_owner = true unique_name_in_owner = true
transform = Transform3D(-4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, -53.747, -2.58899, 17.731) transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -53.747, -2.5101, 17.731)
[node name="ItemDatabase" parent="Spawn Points" instance=ExtResource("23_gov56")] [node name="ItemDatabase" parent="Spawn Points" instance=ExtResource("23_gov56")]
unique_name_in_owner = true unique_name_in_owner = true
@@ -1957,7 +1970,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -102.157, -2.30863, 13.0139)
[node name="HorseFace" parent="Room" instance=ExtResource("25_a482y")] [node name="HorseFace" parent="Room" instance=ExtResource("25_a482y")]
unique_name_in_owner = true unique_name_in_owner = true
transform = Transform3D(0.15, 0, 0, 0, 0.15, 0, 0, 0, 0.15, -102.157, -2.30863, 13.0139) transform = Transform3D(0.15, 0, 0, 0, 0.15, 0, 0, 0, 0.15, -102.157, -0.510939, 13.0139)
visible = false visible = false
[node name="OxFaceStatue" parent="Room" instance=ExtResource("26_futcf")] [node name="OxFaceStatue" parent="Room" instance=ExtResource("26_futcf")]
@@ -1966,7 +1979,17 @@ transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, -101.5
[node name="OxFace" parent="Room" instance=ExtResource("27_g6y6v")] [node name="OxFace" parent="Room" instance=ExtResource("27_g6y6v")]
unique_name_in_owner = true unique_name_in_owner = true
transform = Transform3D(-0.15, 0, -2.26494e-08, 0, 0.15, 0, 2.26494e-08, 0, -0.15, -101.703, -2.44182, 22.0955) transform = Transform3D(-0.15, 0, -2.26494e-08, 0, 0.15, 0, 2.26494e-08, 0, -0.15, -101.703, -0.479859, 22.0955)
visible = false visible = false
[node name="Exit" type="Area3D" parent="Room"]
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -250.02, -7.44633, 15.2627)
collision_layer = 256
collision_mask = 256
[node name="CollisionShape3D" type="CollisionShape3D" parent="Room/Exit"]
transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 1.59105, 7.59621, 2.59402)
shape = SubResource("BoxShape3D_1qa0g")
[node name="Minimap" type="Node3D" parent="."] [node name="Minimap" type="Node3D" parent="."]