Basic projectile implementation (put sample version in FilthEaterModelView)

This commit is contained in:
2025-10-23 18:50:05 -07:00
parent bc161a58b3
commit f5360adbf1
36 changed files with 1124 additions and 106 deletions

View File

@@ -22,10 +22,10 @@ public partial class DungeonFloorLayout : LayoutType
public Callable PopulateMapList => Callable.From(() => PopulateDictionary(SetType));
[Export]
public Dictionary<string, float> LayoutWithSpawnRate { get; private set; }
public Dictionary<string, float> LayoutWithSpawnRate;
[Export]
public Dictionary<EnemyType, float> EnemySpawnRates { get; set; } = default!;
public Dictionary<EnemyType, float> EnemySpawnRates;
private string _floorPath = "res://src/map/dungeon/floors/";
private DungeonFloorSetType _setType;

View File

@@ -10,21 +10,14 @@ public class DefenseComponent : IDefenseComponent
public IAutoProp<int> MaximumDefense => _maximumDefense;
public IAutoProp<int> BonusDefense => _bonusDefense;
private readonly AutoProp<int> _currentDefense;
private readonly AutoProp<int> _maximumDefense;
private readonly AutoProp<int> _bonusDefense;
public int TotalDefense => CurrentDefense.Value + BonusDefense.Value;
public DefenseComponent(int defenseValue)
{
_maximumDefense = new AutoProp<int>(defenseValue);
_currentDefense = new AutoProp<int>(defenseValue);
_bonusDefense = new AutoProp<int>(0);
}
public void Restore(int restoreAmount)
@@ -50,14 +43,4 @@ public class DefenseComponent : IDefenseComponent
_maximumDefense.OnNext(raiseAmount);
Restore(raiseAmount);
}
public void RaiseBonusDefense(int raiseAmount)
{
_bonusDefense.OnNext(_bonusDefense.Value + raiseAmount);
}
public void ResetBonusDefense()
{
_bonusDefense.OnNext(0);
}
}

View File

@@ -1,5 +1,6 @@
using Chickensoft.Collections;
using Zennysoft.Ma.Adapter;
using Zennysoft.Ma.Adapter.Entity;
namespace Zennysoft.Game.Ma;
public class EquipmentComponent : IEquipmentComponent
@@ -26,6 +27,8 @@ public class EquipmentComponent : IEquipmentComponent
public int BonusLuck => _equippedWeapon.Value.BonusLuck + _equippedArmor.Value.BonusLuck + _equippedAccessory.Value.BonusLuck;
public ElementalResistanceSet ElementalResistance => _equippedWeapon.Value.ElementalResistance + _equippedArmor.Value.ElementalResistance + _equippedAccessory.Value.ElementalResistance;
public EquipmentComponent()
{
_equippedWeapon = new AutoProp<EquipableItem>(new Weapon());

View File

@@ -150,5 +150,11 @@ public partial class App : Node, IApp
AppLogic.Stop();
AppBinding.Dispose();
AppRepo.Dispose();
MainMenu.NewGame -= OnNewGame;
MainMenu.LoadGame -= OnLoadGame;
MainMenu.EnemyViewer -= OnEnemyViewer;
MainMenu.Quit -= OnQuit;
_loadedScene.Changed -= OnGameLoaded;
}
}

View File

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

View File

@@ -95,7 +95,7 @@ public partial class BossTypeA : Enemy, IHaveEngagePlayerBehavior, IHaveFollowBe
{
var target = area.GetOwner();
if (target is IPlayer player)
player.TakeDamage(new AttackData(AttackComponent.TotalAttack, PrimaryAttackElementalType));
player.TakeDamage(new AttackData(AttackComponent.CurrentAttack.Value, PrimaryAttackElementalType));
}
public void StartFight()
@@ -142,5 +142,9 @@ public partial class BossTypeA : Enemy, IHaveEngagePlayerBehavior, IHaveFollowBe
public override void _ExitTree()
{
FollowBehavior.OnVelocityComputed -= OnVelocityComputed;
EngagePlayerBehavior.TakeAction -= PerformAction;
PlayerDetector.BodyEntered -= PlayerDetector_BodyEntered;
PlayerDetector.BodyExited -= PlayerDetector_BodyExited;
}
}

View File

@@ -150,6 +150,9 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
{
_enemyLogic.Stop();
EnemyBinding.Dispose();
HealthComponent.HealthReachedZero -= Die;
HealthComponent.DamageTaken -= TakeHit;
EnemyModelView.HitPlayer -= EnemyModelView_HitPlayer;
}
public virtual void MoveEnemyToNewRoom(IDungeonRoom newRoom)
@@ -182,6 +185,6 @@ public abstract partial class Enemy : CharacterBody3D, IEnemy, IProvide<IEnemyLo
private void EnemyModelView_HitPlayer(object sender, System.EventArgs e)
{
_player.TakeDamage(new AttackData(AttackComponent.TotalAttack, ElementType.None));
_player.TakeDamage(new AttackData(AttackComponent.CurrentAttack.Value, ElementType.None));
}
}

View File

@@ -67,7 +67,7 @@ public abstract partial class Enemy2D : Enemy
{
var collider = Raycast.GetCollider();
if (collider is IPlayer)
_enemyLogic.Input(new EnemyLogic.Input.Follow());
_enemyLogic.Input(new EnemyLogic.Input.Attack());
}
}
}

View File

@@ -2,6 +2,7 @@
using Chickensoft.Introspection;
using Godot;
using System;
using System.Linq;
namespace Zennysoft.Game.Ma;

View File

@@ -60,4 +60,12 @@ public partial class EngagePlayerBehavior : Node, IEngagePlayerBehavior
rng.Randomize();
return rng.RandfRange(min, max);
}
public void OnExitTree()
{
_actionTimer.Stop();
_acquireTargetTimer.Stop();
_actionTimer.Timeout -= OnAttackTimeout;
_acquireTargetTimer.Timeout -= OnAcquireTargetTimeout;
}
}

View File

@@ -58,4 +58,10 @@ public partial class FollowBehavior : Node3D, IBehavior
var velocity = parent.GlobalPosition.DirectionTo(nextVelocity) * (float)_followSpeed * (float)delta;
EmitSignal(SignalName.OnVelocityComputed, velocity);
}
public void OnExitTree()
{
_thinkTimer.Stop();
_thinkTimer.Timeout -= OnTimeout;
}
}

View File

@@ -88,4 +88,11 @@ public partial class PatrolBehavior : Node3D, IBehavior
}
private void PatrolTimer_Timeout() => SetPatrolTarget();
public void OnExitTree()
{
_patrolTimer.Stop();
_patrolTimer.Timeout -= PatrolTimer_Timeout;
_navigationAgent.WaypointReached -= NavigationAgent_WaypointReached;
}
}

View File

@@ -30,4 +30,14 @@ public partial class Sproingy : Enemy2D, IHavePatrolBehavior, IHaveEngagePlayerB
PlayerDetector.BodyExited += PlayerDetector_BodyExited;
SetPhysicsProcess(true);
}
public override void _ExitTree()
{
PatrolBehavior.OnVelocityComputed -= OnVelocityComputed;
FollowBehavior.OnVelocityComputed -= OnVelocityComputed;
EngagePlayerBehavior.TakeAction -= EngagePlayerBehavior_TakeAction;
EngagePlayerBehavior.AcquireTarget -= EngagePlayerBehavior_AcquireTarget;
PlayerDetector.BodyEntered -= PlayerDetector_BodyEntered;
PlayerDetector.BodyExited -= PlayerDetector_BodyExited;
}
}

View File

@@ -23,11 +23,23 @@ public partial class FilthEater : Enemy2D, IHavePatrolBehavior, IHaveEngagePlaye
PatrolBehavior.HomePosition = GlobalPosition;
PatrolBehavior.OnVelocityComputed += OnVelocityComputed;
FollowBehavior.OnVelocityComputed += OnVelocityComputed;
EngagePlayerBehavior.TakeAction += EngagePlayerBehavior_TakeAction;
EngagePlayerBehavior.TakeAction += PerformAction;
EngagePlayerBehavior.AcquireTarget += EngagePlayerBehavior_AcquireTarget;
_enemyLogic.Input(new EnemyLogic.Input.Patrol());
PlayerDetector.BodyEntered += PlayerDetector_BodyEntered;
PlayerDetector.BodyExited += PlayerDetector_BodyExited;
SetPhysicsProcess(true);
}
public override void PerformAction() => EnemyModelView.PlaySecondaryAttackAnimation();
public override void _ExitTree()
{
PatrolBehavior.OnVelocityComputed -= OnVelocityComputed;
FollowBehavior.OnVelocityComputed -= OnVelocityComputed;
EngagePlayerBehavior.TakeAction -= EngagePlayerBehavior_TakeAction;
EngagePlayerBehavior.AcquireTarget -= EngagePlayerBehavior_AcquireTarget;
PlayerDetector.BodyEntered -= PlayerDetector_BodyEntered;
PlayerDetector.BodyExited -= PlayerDetector_BodyExited;
}
}

View File

@@ -24,6 +24,8 @@ Description = "This guy grosses me out."
metadata/_custom_type_script = ExtResource("4_5eid5")
[sub_resource type="CylinderShape3D" id="CylinderShape3D_qbmfg"]
height = 1.5
radius = 3.0
[node name="FilthEater" type="CharacterBody3D"]
process_mode = 1
@@ -71,6 +73,7 @@ collision_layer = 0
collision_mask = 34
[node name="CollisionShape3D" type="CollisionShape3D" parent="PlayerDetector"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.179932, 0)
shape = SubResource("CylinderShape3D_qbmfg")
[node name="Components" type="Node3D" parent="."]

View File

@@ -1,8 +1,9 @@
[gd_scene load_steps=302 format=3 uid="uid://bup8c4x1na3aw"]
[gd_scene load_steps=354 format=3 uid="uid://bup8c4x1na3aw"]
[ext_resource type="Script" uid="uid://cvr1qimxpignl" path="res://src/enemy/EnemyModelView2D.cs" id="1_718m1"]
[ext_resource type="Script" uid="uid://dlsgyx4i1jmp3" path="res://src/enemy/EnemyLoreInfo.cs" id="2_krqul"]
[ext_resource type="Texture2D" uid="uid://bdar3daydbkge" path="res://src/enemy/enemy_types/03. filth_eater/animations/SWIPE/Layer 1.png" id="2_vpn42"]
[ext_resource type="Script" uid="uid://ctshiyffvt4y5" path="res://src/system/AttackDataResource.cs" id="3_4h5gj"]
[ext_resource type="Texture2D" uid="uid://o214hr614jit" path="res://src/enemy/enemy_types/03. filth_eater/animations/SWIPE/Layer 2.png" id="3_7tggm"]
[ext_resource type="Texture2D" uid="uid://hyipatqsvukp" path="res://src/enemy/enemy_types/03. filth_eater/animations/SWIPE/Layer 3.png" id="4_usgpm"]
[ext_resource type="Texture2D" uid="uid://sgj8yf8vsocq" path="res://src/enemy/enemy_types/03. filth_eater/animations/SWIPE/Layer 4.png" id="5_ovibr"]
@@ -197,6 +198,8 @@
[ext_resource type="AnimationNodeStateMachine" uid="uid://cbq8xog50cjjy" path="res://src/enemy/animation_state_machines/PrimaryAttackStateMachine.tres" id="195_5cwnl"]
[ext_resource type="AnimationNodeStateMachine" uid="uid://clybvwx3itfeo" path="res://src/enemy/animation_state_machines/SecondaryAttackStateMachine.tres" id="196_e0gee"]
[ext_resource type="AnimationNodeStateMachine" uid="uid://cy2ngl55c0rws" path="res://src/enemy/animation_state_machines/WalkingStateMachine.tres" id="197_mno7m"]
[ext_resource type="Texture2D" uid="uid://wqjql5n24h1l" path="res://src/vfx/Enemy/BLUE_FLAME.png" id="198_mno7m"]
[ext_resource type="Script" uid="uid://cqm6u7qa8japr" path="res://src/system/Projectile.cs" id="199_4h5gj"]
[sub_resource type="Resource" id="Resource_pyy2h"]
script = ExtResource("2_krqul")
@@ -204,6 +207,12 @@ Name = "Filth Eater"
Description = "yuck"
metadata/_custom_type_script = "uid://dlsgyx4i1jmp3"
[sub_resource type="Resource" id="Resource_e5pq0"]
script = ExtResource("3_4h5gj")
Damage = 10
ElementType = 0
metadata/_custom_type_script = "uid://ctshiyffvt4y5"
[sub_resource type="ViewportTexture" id="ViewportTexture_7tggm"]
viewport_path = NodePath("Sprite3D/SubViewportContainer/SubViewport")
@@ -1582,40 +1591,38 @@ tracks/1/keys = {
"update": 0,
"values": [0, 39]
}
tracks/2/type = "value"
tracks/2/type = "animation"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Hitbox/CollisionShape3D:disabled")
tracks/2/path = NodePath("attack VFX/attack VFX animplayer")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 1.75453, 2.16781),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 1,
"values": [true, false, true]
}
tracks/3/type = "animation"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("attack VFX/attack VFX animplayer")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"clips": PackedStringArray("[stop]", "attack", "[stop]"),
"times": PackedFloat32Array(0, 0.833333, 3.16667)
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("OmniLight3D:light_energy")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("OmniLight3D:light_energy")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0.833333, 1.91667, 2, 2.16667),
"transitions": PackedFloat32Array(1, 1, 1, 1),
"update": 0,
"values": [0.0, 10.0, 500.0, 0.0]
}
tracks/4/type = "animation"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("Attack Objects/Projectile1/Bullet/AnimationPlayer")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"clips": PackedStringArray("Fire"),
"times": PackedFloat32Array(1.91667)
}
[sub_resource type="Animation" id="Animation_7a6is"]
resource_name = "secondary_attack_back"
@@ -2341,10 +2348,420 @@ _data = {
&"attack": SubResource("Animation_nmlvd")
}
[sub_resource type="Resource" id="Resource_mno7m"]
script = ExtResource("3_4h5gj")
Damage = 7
ElementType = 4
metadata/_custom_type_script = "uid://ctshiyffvt4y5"
[sub_resource type="AtlasTexture" id="AtlasTexture_xrn7e"]
atlas = ExtResource("198_mno7m")
region = Rect2(1024, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_8qeb2"]
atlas = ExtResource("198_mno7m")
region = Rect2(1536, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_q8n6h"]
atlas = ExtResource("198_mno7m")
region = Rect2(2048, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_brbcy"]
atlas = ExtResource("198_mno7m")
region = Rect2(2560, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_dftoy"]
atlas = ExtResource("198_mno7m")
region = Rect2(3072, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_8u0x2"]
atlas = ExtResource("198_mno7m")
region = Rect2(3584, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_fqqmc"]
atlas = ExtResource("198_mno7m")
region = Rect2(4096, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_b1lif"]
atlas = ExtResource("198_mno7m")
region = Rect2(4608, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_f7ayv"]
atlas = ExtResource("198_mno7m")
region = Rect2(5120, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_2y7ln"]
atlas = ExtResource("198_mno7m")
region = Rect2(5632, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_311ch"]
atlas = ExtResource("198_mno7m")
region = Rect2(6144, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_60ajf"]
atlas = ExtResource("198_mno7m")
region = Rect2(6656, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_qcv8t"]
atlas = ExtResource("198_mno7m")
region = Rect2(7168, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ym3vo"]
atlas = ExtResource("198_mno7m")
region = Rect2(7680, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_5fqo7"]
atlas = ExtResource("198_mno7m")
region = Rect2(8192, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_w2bwt"]
atlas = ExtResource("198_mno7m")
region = Rect2(8704, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_qm55s"]
atlas = ExtResource("198_mno7m")
region = Rect2(9216, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_rdrim"]
atlas = ExtResource("198_mno7m")
region = Rect2(9728, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_kli1f"]
atlas = ExtResource("198_mno7m")
region = Rect2(10240, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_dif4r"]
atlas = ExtResource("198_mno7m")
region = Rect2(10752, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_4mwd1"]
atlas = ExtResource("198_mno7m")
region = Rect2(11264, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_npl5k"]
atlas = ExtResource("198_mno7m")
region = Rect2(11776, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_obbx1"]
atlas = ExtResource("198_mno7m")
region = Rect2(12288, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_4o8yi"]
atlas = ExtResource("198_mno7m")
region = Rect2(12800, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_kk4df"]
atlas = ExtResource("198_mno7m")
region = Rect2(13312, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_a212s"]
atlas = ExtResource("198_mno7m")
region = Rect2(13824, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ddop6"]
atlas = ExtResource("198_mno7m")
region = Rect2(14336, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_bsamt"]
atlas = ExtResource("198_mno7m")
region = Rect2(14848, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_lcs75"]
atlas = ExtResource("198_mno7m")
region = Rect2(15360, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_sv0jq"]
atlas = ExtResource("198_mno7m")
region = Rect2(15872, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ap565"]
atlas = ExtResource("198_mno7m")
region = Rect2(0, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_x7xwk"]
atlas = ExtResource("198_mno7m")
region = Rect2(512, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_gf7y0"]
atlas = ExtResource("198_mno7m")
region = Rect2(1024, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_n3cae"]
atlas = ExtResource("198_mno7m")
region = Rect2(1536, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_s3abf"]
atlas = ExtResource("198_mno7m")
region = Rect2(2048, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ldl6g"]
atlas = ExtResource("198_mno7m")
region = Rect2(2560, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ysnl1"]
atlas = ExtResource("198_mno7m")
region = Rect2(3072, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_l6jiv"]
atlas = ExtResource("198_mno7m")
region = Rect2(3584, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ra6k7"]
atlas = ExtResource("198_mno7m")
region = Rect2(4096, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_chxxr"]
atlas = ExtResource("198_mno7m")
region = Rect2(4608, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_1cxo4"]
atlas = ExtResource("198_mno7m")
region = Rect2(5120, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_sx8e2"]
atlas = ExtResource("198_mno7m")
region = Rect2(5632, 502, 512, 502)
[sub_resource type="SpriteFrames" id="SpriteFrames_brsyt"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_xrn7e")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_8qeb2")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_q8n6h")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_brbcy")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_dftoy")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_8u0x2")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_fqqmc")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_b1lif")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_f7ayv")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_2y7ln")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_311ch")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_60ajf")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_qcv8t")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ym3vo")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_5fqo7")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_w2bwt")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_qm55s")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_rdrim")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_kli1f")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_dif4r")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_4mwd1")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_npl5k")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_obbx1")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_4o8yi")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_kk4df")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_a212s")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ddop6")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_bsamt")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_lcs75")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_sv0jq")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ap565")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_x7xwk")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_gf7y0")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_n3cae")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_s3abf")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ldl6g")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ysnl1")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_l6jiv")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ra6k7")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_chxxr")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_1cxo4")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_sx8e2")
}],
"loop": true,
"name": &"default",
"speed": 24.0
}]
[sub_resource type="SphereShape3D" id="SphereShape3D_kct8n"]
[sub_resource type="Animation" id="Animation_8qeb2"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("..:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../ProjectileHitbox:monitoring")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath(".:visible")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
[sub_resource type="Animation" id="Animation_xrn7e"]
resource_name = "fire"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("..:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, 0, 10)]
}
tracks/1/type = "audio"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../AudioStreamPlayer3D")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"clips": [{
"end_offset": 0.0,
"start_offset": 0.0,
"stream": null
}],
"times": PackedFloat32Array(0.0333333)
}
tracks/1/use_blend = true
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("../ProjectileHitbox:monitoring")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.0333333, 1),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 1,
"values": [false, true, false]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath(".:visible")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.0333333, 1),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 1,
"values": [false, true, false]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_q8n6h"]
_data = {
&"Fire": SubResource("Animation_xrn7e"),
&"RESET": SubResource("Animation_8qeb2")
}
[node name="EnemyModelView" type="Node3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.97683, 0)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0)
script = ExtResource("1_718m1")
EnemyLoreInfo = SubResource("Resource_pyy2h")
AttackData = SubResource("Resource_e5pq0")
[node name="Sprite3D" type="Sprite3D" parent="."]
transform = Transform3D(1.5, 0, 0, 0, 1.5, 0, 0, 0, 1.5, 0, 0.0862446, 0)
@@ -2411,3 +2828,36 @@ libraries = {
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.546972)
light_color = Color(0.837456, 0.93601, 0.775258, 1)
omni_attenuation = 0.2
[node name="Attack Objects" type="Node3D" parent="."]
[node name="Projectile1" type="Node3D" parent="Attack Objects"]
script = ExtResource("199_4h5gj")
AttackData = SubResource("Resource_mno7m")
[node name="Bullet" type="Node3D" parent="Attack Objects/Projectile1"]
[node name="AnimatedSprite3D" type="AnimatedSprite3D" parent="Attack Objects/Projectile1/Bullet"]
visible = false
offset = Vector2(0, 150)
billboard = 1
sprite_frames = SubResource("SpriteFrames_brsyt")
autoplay = "default"
frame_progress = 0.79063
[node name="ProjectileHitbox" type="Area3D" parent="Attack Objects/Projectile1/Bullet"]
unique_name_in_owner = true
collision_layer = 0
collision_mask = 64
monitoring = false
[node name="CollisionShape3D" type="CollisionShape3D" parent="Attack Objects/Projectile1/Bullet/ProjectileHitbox"]
shape = SubResource("SphereShape3D_kct8n")
[node name="AudioStreamPlayer3D" type="AudioStreamPlayer3D" parent="Attack Objects/Projectile1/Bullet"]
[node name="AnimationPlayer" type="AnimationPlayer" parent="Attack Objects/Projectile1/Bullet"]
root_node = NodePath("../AnimatedSprite3D")
libraries = {
&"": SubResource("AnimationLibrary_q8n6h")
}

View File

@@ -21,8 +21,8 @@ public partial class EnemyLogic
OnDetach(() =>
{
var enemy = Get<IEnemy>();
if (enemy is IHaveFollowBehavior patrolEnemy)
patrolEnemy.FollowBehavior.StopFollow();
if (enemy is IHaveFollowBehavior followEnemy)
followEnemy.FollowBehavior.StopFollow();
});
}

View File

@@ -503,4 +503,20 @@ public partial class Game : Node3D, IGame
private void OnQuit()
{
}
public void OnExitTree()
{
InGameUI.UseTeleportPrompt.TeleportToNextFloor -= UseTeleportPrompt_TeleportToNextFloor;
InGameUI.UseTeleportPrompt.CloseTeleportPrompt -= UseTeleportPrompt_CloseTeleportPrompt;
FloorClearMenu.GoToNextFloor -= FloorClearMenu_GoToNextFloor;
FloorClearMenu.SaveAndExit -= FloorClearMenu_SaveAndExit;
FloorClearMenu.TransitionCompleted -= FloorClearMenu_TransitionCompleted;
GameRepo.RestorativePickedUp -= GameEventDepot_RestorativePickedUp;
DeathMenu.NewGame -= OnContinueGame;
DeathMenu.QuitGame -= OnQuit;
GameRepo.IsPaused.Sync -= IsPaused_Sync;
}
}

View File

@@ -155,7 +155,6 @@ public class EffectService
var currentWeapon = (Weapon)_player.EquipmentComponent.EquippedWeapon.Value;
currentWeapon.IncreaseWeaponAttack(1);
_player.AttackComponent.RaiseBonusAttack(1);
}
public void RaiseCurrentArmorDefense()
@@ -165,7 +164,6 @@ public class EffectService
var currentArmor = (Armor)_player.EquipmentComponent.EquippedArmor.Value;
currentArmor.IncreaseArmorDefense(1);
_player.DefenseComponent.RaiseBonusDefense(1);
}
public void RaiseLevel() => _player.LevelUp();

View File

@@ -1,7 +1,6 @@
using Chickensoft.Introspection;
using Chickensoft.Serialization;
using Godot;
using Zennysoft.Game.Implementation;
using Zennysoft.Ma.Adapter;
namespace Zennysoft.Game.Ma;
@@ -24,11 +23,26 @@ public abstract partial class InventoryItemStats : Resource
[Export]
[Save("armor_defense")]
public int Defense { get; set; } = 0;
public int BonusDefense { get; set; } = 0;
[Export]
[Save("weapon_luck")]
public double Luck { get; set; } = 0.05;
public double BonusLuck { get; set; } = 0.05;
[Export]
public int AeolicResistance { get; set; } = 0;
[Export]
public int TelluricResistance { get; set; } = 0;
[Export]
public int HydricResistance { get; set; } = 0;
[Export]
public int IgneousResistance { get; set; } = 0;
[Export]
public int FerrumResistance { get; set; } = 0;
[Export(PropertyHint.Range, "0, 25, 0.1")]
public float ThrowSpeed { get; set; } = 12.0f;

View File

@@ -45,7 +45,8 @@ public partial class ItemDatabase : Node
var armorInfo = GD.Load<ArmorStats>($"res://src/items/armor/resources/{armor}");
var armorScene = ResourceLoader.Load<PackedScene>("res://src/items/armor/Armor.tscn").Instantiate<Armor>();
armorScene.Stats = armorInfo;
database.Add(armorScene);
if (!database.Contains(armorScene))
database.Add(armorScene);
}
foreach (var weapon in weaponResources)
@@ -53,6 +54,8 @@ public partial class ItemDatabase : Node
var weaponInfo = GD.Load<WeaponStats>($"res://src/items/weapons/resources/{weapon}");
var weaponScene = ResourceLoader.Load<PackedScene>("res://src/items/weapons/Weapon.tscn").Instantiate<Weapon>();
weaponScene.Stats = weaponInfo;
if (!database.Contains(weaponScene))
database.Add(weaponScene);
database.Add(weaponScene);
}
@@ -61,6 +64,8 @@ public partial class ItemDatabase : Node
var accessoryInfo = GD.Load<AccessoryStats>($"res://src/items/accessory/resources/{accessory}");
var accessoryScene = ResourceLoader.Load<PackedScene>("res://src/items/accessory/Accessory.tscn").Instantiate<Accessory>();
accessoryScene.Stats = accessoryInfo;
if (!database.Contains(accessoryScene))
database.Add(accessoryScene);
database.Add(accessoryScene);
}
@@ -69,6 +74,8 @@ public partial class ItemDatabase : Node
var throwableItemInfo = GD.Load<ThrowableItemStats>($"res://src/items/throwable/resources/{throwable}");
var throwableItemScene = ResourceLoader.Load<PackedScene>("res://src/items/throwable/ThrowableItem.tscn").Instantiate<ThrowableItem>();
throwableItemScene.Stats = throwableItemInfo;
if (!database.Contains(throwableItemScene))
database.Add(throwableItemScene);
database.Add(throwableItemScene);
}
@@ -77,6 +84,8 @@ public partial class ItemDatabase : Node
var consumableItemInfo = GD.Load<ConsumableItemStats>($"res://src/items/consumable/resources/{consumable}");
var consumableItemScene = ResourceLoader.Load<PackedScene>("res://src/items/consumable/ConsumableItem.tscn").Instantiate<ConsumableItem>();
consumableItemScene.Stats = consumableItemInfo;
if (!database.Contains(consumableItemScene))
database.Add(consumableItemScene);
database.Add(consumableItemScene);
}
@@ -85,6 +94,8 @@ public partial class ItemDatabase : Node
var effectItemInfo = GD.Load<EffectItemStats>($"res://src/items/effect/resources/{effectItem}");
var effectItemScene = ResourceLoader.Load<PackedScene>("res://src/items/effect/EffectItem.tscn").Instantiate<EffectItem>();
effectItemScene.Stats = effectItemInfo;
if (!database.Contains(effectItemScene))
database.Add(effectItemScene);
database.Add(effectItemScene);
}

View File

@@ -3,6 +3,7 @@ using Chickensoft.Introspection;
using Chickensoft.Serialization;
using Godot;
using Zennysoft.Ma.Adapter;
using Zennysoft.Ma.Adapter.Entity;
namespace Zennysoft.Game.Ma;
@@ -27,6 +28,8 @@ public partial class Accessory : EquipableItem
public override float ThrowSpeed => Stats.ThrowSpeed;
public override ElementalResistanceSet ElementalResistance => new ElementalResistanceSet(Stats.AeolicResistance, Stats.HydricResistance, Stats.IgneousResistance, Stats.FerrumResistance, Stats.TelluricResistance);
public AccessoryTag AccessoryTag => Stats.AccessoryTag;
public override ItemTag ItemTag => Stats.ItemTag;

View File

@@ -3,6 +3,7 @@ using Chickensoft.Introspection;
using Chickensoft.Serialization;
using Godot;
using Zennysoft.Ma.Adapter;
using Zennysoft.Ma.Adapter.Entity;
namespace Zennysoft.Game.Ma;
@@ -28,10 +29,12 @@ public partial class Armor : EquipableItem
public override float ThrowSpeed => Stats.ThrowSpeed;
public override int BonusDefense => Stats.Defense + _bonusDefense;
public override int BonusDefense => Stats.BonusDefense + _bonusDefense;
private int _bonusDefense { get; set; } = 0;
public override ElementalResistanceSet ElementalResistance => new ElementalResistanceSet(Stats.AeolicResistance, Stats.HydricResistance, Stats.IgneousResistance, Stats.FerrumResistance, Stats.TelluricResistance);
public void IncreaseArmorDefense(int bonus) => _bonusDefense += bonus;
public override ItemTag ItemTag => Stats.ItemTag;

View File

@@ -3,6 +3,7 @@ using Chickensoft.Introspection;
using Chickensoft.Serialization;
using Godot;
using Zennysoft.Ma.Adapter;
using Zennysoft.Ma.Adapter.Entity;
namespace Zennysoft.Game.Ma;
@@ -28,7 +29,7 @@ public partial class Weapon : EquipableItem
public override float ThrowSpeed => Stats.ThrowSpeed;
public double Luck => Stats.Luck;
public double Luck => Stats.BonusLuck;
public double AttackSpeed => Stats.AttackSpeed;
@@ -38,6 +39,8 @@ public partial class Weapon : EquipableItem
public ElementType WeaponElement => Stats.WeaponElement;
public override ElementalResistanceSet ElementalResistance => new ElementalResistanceSet(Stats.AeolicResistance, Stats.HydricResistance, Stats.IgneousResistance, Stats.FerrumResistance, Stats.TelluricResistance);
public void IncreaseWeaponAttack(int bonus) => _extraDamage += bonus;
public override int BonusAttack { get => Stats.BonusAttack + _extraDamage; }

View File

@@ -78,12 +78,6 @@ unique_name_in_owner = true
[node name="Floor01 (Press Populate Map Data Button to load floor from SetAFloors folder)" type="Node" parent="MapOrder"]
script = ExtResource("3_v14r0")
LayoutWithSpawnRate = Dictionary[String, float]({
"SetAFloors/test_floor.tscn": 1.0
})
EnemySpawnRates = {
0: 1.0
}
metadata/_custom_type_script = "uid://ci7o3nn4mdo8o"
[node name="Overworld (Add SpecialFloorLayout node for special floors and pick the FloorName from the list)" type="Node" parent="MapOrder"]
@@ -92,13 +86,8 @@ metadata/_custom_type_script = "uid://cabvj6s31iucg"
[node name="Altar (Arrange order of nodes to change default load order)" type="Node" parent="MapOrder"]
script = ExtResource("2_00xd7")
FloorName = 1
metadata/_custom_type_script = "uid://cabvj6s31iucg"
[node name="Floor02 (Add DungeonFloorLayout node for regular dungeon floors)" type="Node" parent="MapOrder"]
script = ExtResource("3_v14r0")
LayoutWithSpawnRate = Dictionary[String, float]({})
EnemySpawnRates = {
0: 1.0
}
metadata/_custom_type_script = "uid://ci7o3nn4mdo8o"

View File

@@ -20,41 +20,41 @@ public partial class DungeonFloor : Node3D, IDungeonFloor
public void InitializeDungeon()
{
Rooms = [];
Rooms = FindAllDungeonRooms([.. GetChildren()], Rooms);
_playerSpawnPoint = RandomizePlayerSpawnPoint();
Rooms = [];
Rooms = FindAllDungeonRooms([.. GetChildren()], Rooms);
_playerSpawnPoint = RandomizePlayerSpawnPoint();
}
public void SpawnEnemies(Godot.Collections.Dictionary<EnemyType, float> enemyInfo)
{
var monsterRooms = Rooms.OfType<MonsterRoom>();
foreach (var room in monsterRooms)
room.SpawnEnemies(enemyInfo);
var monsterRooms = Rooms.OfType<MonsterRoom>();
foreach (var room in monsterRooms)
room.SpawnEnemies(enemyInfo);
}
public Transform3D GetPlayerSpawnPoint() => new Transform3D(_playerSpawnPoint.Basis, new Vector3(_playerSpawnPoint.Origin.X, 0f, _playerSpawnPoint.Origin.Z));
private Transform3D RandomizePlayerSpawnPoint()
{
var randomSpawnLocations = Rooms
.OfType<MonsterRoom>()
.Select(x => x.PlayerSpawn);
var godotCollection = new Godot.Collections.Array<Marker3D>(randomSpawnLocations);
var result = godotCollection.PickRandom();
return result.GlobalTransform;
var randomSpawnLocations = Rooms
.OfType<MonsterRoom>()
.Select(x => x.PlayerSpawn);
var godotCollection = new Godot.Collections.Array<Marker3D>(randomSpawnLocations);
var result = godotCollection.PickRandom();
return result.GlobalTransform;
}
private static ImmutableList<IDungeonRoom> FindAllDungeonRooms(List<Node> nodesToSearch, ImmutableList<IDungeonRoom> roomsFound)
{
if (nodesToSearch.Count == 0)
return roomsFound;
if (nodesToSearch.Count == 0)
return roomsFound;
foreach (var node in nodesToSearch)
{
if (node is IDungeonRoom dungeonRoom)
roomsFound = roomsFound.Add(dungeonRoom);
}
foreach (var node in nodesToSearch)
{
if (node is IDungeonRoom dungeonRoom)
roomsFound = roomsFound.Add(dungeonRoom);
}
return FindAllDungeonRooms([.. nodesToSearch.SelectMany(x => x.GetChildren())], roomsFound);
return FindAllDungeonRooms([.. nodesToSearch.SelectMany(x => x.GetChildren())], roomsFound);
}
}

View File

@@ -65,4 +65,10 @@ public abstract partial class DungeonRoom : Node3D, IDungeonRoom
_playerDiscoveredRoom = true;
_minimap.Show();
}
public void OnExitTree()
{
_room.BodyEntered -= Room_BodyEntered;
_room.BodyExited -= Room_BodyExited;
}
}

View File

@@ -208,7 +208,7 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
public void TakeDamage(AttackData damage)
{
var damageReceived = DamageCalculator.CalculateDamage(damage, DefenseComponent.TotalDefense, ((Armor)EquipmentComponent.EquippedArmor.Value).Stats.ElementalResistanceSet);
var damageReceived = DamageCalculator.CalculateDamage(damage, DefenseComponent.CurrentDefense.Value + EquipmentComponent.BonusDefense, EquipmentComponent.ElementalResistance);
HealthComponent.Damage(damageReceived);
}
@@ -322,6 +322,10 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
{
PlayerLogic.Stop();
PlayerBinding.Dispose();
Hitbox.AreaEntered -= Hitbox_AreaEntered;
CollisionDetector.AreaEntered -= CollisionDetector_AreaEntered;
HealthComponent.HealthReachedZero -= Die;
HealthTimer.Timeout -= OnHealthTimerTimeout;
}
private void Move(float delta)
@@ -370,14 +374,14 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<ISaveChunk<Play
var ignoreElementalResistance = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreAffinity;
var ignoreDefense = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponTag == WeaponTag.IgnoreDefense;
var isCriticalHit = BattleExtensions.IsCriticalHit(LuckComponent.Luck.Value + EquipmentComponent.BonusLuck);
var totalDamage = AttackComponent.TotalAttack + EquipmentComponent.BonusAttack;
var totalDamage = AttackComponent.CurrentAttack.Value + EquipmentComponent.BonusAttack;
var element = (EquipmentComponent.EquippedWeapon.Value as Weapon).WeaponElement;
if (isCriticalHit)
totalDamage += (int)(totalDamage * 0.5f);
var baseAttack = new AttackData(totalDamage, element, ignoreDefense, ignoreElementalResistance);
var damageDealt = DamageCalculator.CalculateDamage(baseAttack, enemy.DefenseComponent.TotalDefense, ElementalResistanceSet.None);
var damageDealt = DamageCalculator.CalculateDamage(baseAttack, enemy.DefenseComponent.CurrentDefense.Value, ElementalResistanceSet.None);
enemy.HealthComponent.Damage(damageDealt);
if (((Weapon)EquipmentComponent.EquippedWeapon.Value).WeaponTag == WeaponTag.Knockback && enemy is IKnockbackable knockbackable)

View File

@@ -0,0 +1,35 @@
using Chickensoft.AutoInject;
using Chickensoft.Introspection;
using Godot;
using System.Linq;
using Zennysoft.Game.Ma;
using Zennysoft.Ma.Adapter;
[Meta(typeof(IAutoNode))]
public partial class Projectile : Node3D
{
public override void _Notification(int what) => this.Notify(what);
[Dependency] protected IPlayer _player => this.DependOn(() => GetParent().GetChildren().OfType<IPlayer>().Single());
[Node] public Area3D ProjectileHitbox { get; set; }
[Node] public AnimationPlayer AnimationPlayer { get; set; }
[Export] public AttackDataResource AttackData { get; set; }
public void OnReady()
{
ProjectileHitbox.AreaEntered += Hitbox_AreaEntered;
}
public void Fire()
{
AnimationPlayer.Play("Fire");
}
private void Hitbox_AreaEntered(Area3D area)
{
_player.TakeDamage(new AttackData(AttackData.Damage, AttackData.ElementType));
}
}

View File

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

View File

@@ -0,0 +1,438 @@
[gd_scene load_steps=50 format=3 uid="uid://36h8dl0tpmga"]
[ext_resource type="Script" uid="uid://cqm6u7qa8japr" path="res://src/system/Projectile.cs" id="1_0hjuy"]
[ext_resource type="Texture2D" uid="uid://wqjql5n24h1l" path="res://src/vfx/Enemy/BLUE_FLAME.png" id="2_hwc8p"]
[sub_resource type="AtlasTexture" id="AtlasTexture_xrn7e"]
atlas = ExtResource("2_hwc8p")
region = Rect2(1024, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_8qeb2"]
atlas = ExtResource("2_hwc8p")
region = Rect2(1536, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_q8n6h"]
atlas = ExtResource("2_hwc8p")
region = Rect2(2048, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_brbcy"]
atlas = ExtResource("2_hwc8p")
region = Rect2(2560, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_dftoy"]
atlas = ExtResource("2_hwc8p")
region = Rect2(3072, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_8u0x2"]
atlas = ExtResource("2_hwc8p")
region = Rect2(3584, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_fqqmc"]
atlas = ExtResource("2_hwc8p")
region = Rect2(4096, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_b1lif"]
atlas = ExtResource("2_hwc8p")
region = Rect2(4608, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_f7ayv"]
atlas = ExtResource("2_hwc8p")
region = Rect2(5120, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_2y7ln"]
atlas = ExtResource("2_hwc8p")
region = Rect2(5632, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_311ch"]
atlas = ExtResource("2_hwc8p")
region = Rect2(6144, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_60ajf"]
atlas = ExtResource("2_hwc8p")
region = Rect2(6656, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_qcv8t"]
atlas = ExtResource("2_hwc8p")
region = Rect2(7168, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ym3vo"]
atlas = ExtResource("2_hwc8p")
region = Rect2(7680, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_5fqo7"]
atlas = ExtResource("2_hwc8p")
region = Rect2(8192, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_w2bwt"]
atlas = ExtResource("2_hwc8p")
region = Rect2(8704, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_qm55s"]
atlas = ExtResource("2_hwc8p")
region = Rect2(9216, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_rdrim"]
atlas = ExtResource("2_hwc8p")
region = Rect2(9728, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_kli1f"]
atlas = ExtResource("2_hwc8p")
region = Rect2(10240, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_dif4r"]
atlas = ExtResource("2_hwc8p")
region = Rect2(10752, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_4mwd1"]
atlas = ExtResource("2_hwc8p")
region = Rect2(11264, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_npl5k"]
atlas = ExtResource("2_hwc8p")
region = Rect2(11776, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_obbx1"]
atlas = ExtResource("2_hwc8p")
region = Rect2(12288, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_4o8yi"]
atlas = ExtResource("2_hwc8p")
region = Rect2(12800, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_kk4df"]
atlas = ExtResource("2_hwc8p")
region = Rect2(13312, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_a212s"]
atlas = ExtResource("2_hwc8p")
region = Rect2(13824, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ddop6"]
atlas = ExtResource("2_hwc8p")
region = Rect2(14336, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_bsamt"]
atlas = ExtResource("2_hwc8p")
region = Rect2(14848, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_lcs75"]
atlas = ExtResource("2_hwc8p")
region = Rect2(15360, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_sv0jq"]
atlas = ExtResource("2_hwc8p")
region = Rect2(15872, 0, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ap565"]
atlas = ExtResource("2_hwc8p")
region = Rect2(0, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_x7xwk"]
atlas = ExtResource("2_hwc8p")
region = Rect2(512, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_gf7y0"]
atlas = ExtResource("2_hwc8p")
region = Rect2(1024, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_n3cae"]
atlas = ExtResource("2_hwc8p")
region = Rect2(1536, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_s3abf"]
atlas = ExtResource("2_hwc8p")
region = Rect2(2048, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ldl6g"]
atlas = ExtResource("2_hwc8p")
region = Rect2(2560, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ysnl1"]
atlas = ExtResource("2_hwc8p")
region = Rect2(3072, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_l6jiv"]
atlas = ExtResource("2_hwc8p")
region = Rect2(3584, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_ra6k7"]
atlas = ExtResource("2_hwc8p")
region = Rect2(4096, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_chxxr"]
atlas = ExtResource("2_hwc8p")
region = Rect2(4608, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_1cxo4"]
atlas = ExtResource("2_hwc8p")
region = Rect2(5120, 502, 512, 502)
[sub_resource type="AtlasTexture" id="AtlasTexture_sx8e2"]
atlas = ExtResource("2_hwc8p")
region = Rect2(5632, 502, 512, 502)
[sub_resource type="SpriteFrames" id="SpriteFrames_brsyt"]
animations = [{
"frames": [{
"duration": 1.0,
"texture": SubResource("AtlasTexture_xrn7e")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_8qeb2")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_q8n6h")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_brbcy")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_dftoy")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_8u0x2")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_fqqmc")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_b1lif")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_f7ayv")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_2y7ln")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_311ch")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_60ajf")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_qcv8t")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ym3vo")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_5fqo7")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_w2bwt")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_qm55s")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_rdrim")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_kli1f")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_dif4r")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_4mwd1")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_npl5k")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_obbx1")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_4o8yi")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_kk4df")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_a212s")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ddop6")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_bsamt")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_lcs75")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_sv0jq")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ap565")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_x7xwk")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_gf7y0")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_n3cae")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_s3abf")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ldl6g")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ysnl1")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_l6jiv")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_ra6k7")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_chxxr")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_1cxo4")
}, {
"duration": 1.0,
"texture": SubResource("AtlasTexture_sx8e2")
}],
"loop": true,
"name": &"default",
"speed": 24.0
}]
[sub_resource type="SphereShape3D" id="SphereShape3D_kct8n"]
[sub_resource type="Animation" id="Animation_8qeb2"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("..:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../ProjectileHitbox:monitoring")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath(".:visible")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
[sub_resource type="Animation" id="Animation_xrn7e"]
resource_name = "fire"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("..:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, 0, 10)]
}
tracks/1/type = "audio"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../AudioStreamPlayer3D")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"clips": [{
"end_offset": 0.0,
"start_offset": 0.0,
"stream": null
}],
"times": PackedFloat32Array(0.0333333)
}
tracks/1/use_blend = true
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("../ProjectileHitbox:monitoring")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.0333333, 1),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 1,
"values": [false, true, false]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath(".:visible")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.0333333, 1),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 1,
"values": [false, true, false]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_q8n6h"]
_data = {
&"Fire": SubResource("Animation_xrn7e"),
&"RESET": SubResource("Animation_8qeb2")
}
[node name="Projectile" type="Node3D"]
script = ExtResource("1_0hjuy")
[node name="Bullet" type="Node3D" parent="."]
[node name="AnimatedSprite3D" type="AnimatedSprite3D" parent="Bullet"]
visible = false
offset = Vector2(0, 150)
billboard = 1
sprite_frames = SubResource("SpriteFrames_brsyt")
autoplay = "default"
frame_progress = 0.79063
[node name="ProjectileHitbox" type="Area3D" parent="Bullet"]
unique_name_in_owner = true
collision_layer = 0
collision_mask = 64
monitoring = false
[node name="CollisionShape3D" type="CollisionShape3D" parent="Bullet/ProjectileHitbox"]
shape = SubResource("SphereShape3D_kct8n")
[node name="AudioStreamPlayer3D" type="AudioStreamPlayer3D" parent="Bullet"]
[node name="AnimationPlayer" type="AnimationPlayer" parent="Bullet"]
unique_name_in_owner = true
root_node = NodePath("../AnimatedSprite3D")
libraries = {
&"": SubResource("AnimationLibrary_q8n6h")
}