item-info wip
parent
ae5767e1fd
commit
f0a33b0c77
|
@ -159,7 +159,8 @@ namespace SupaLidlGame.Characters
|
|||
return;
|
||||
}
|
||||
|
||||
if (Inventory.SelectedItem is Weapon weapon)
|
||||
// TODO: support for offhand items
|
||||
if (Inventory.PrimaryItem is Weapon weapon)
|
||||
{
|
||||
weapon.Use();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ namespace SupaLidlGame.Characters
|
|||
{
|
||||
public override void _Ready()
|
||||
{
|
||||
Inventory.SelectedItem = Inventory.GetNode<Items.Item>("Sword");
|
||||
//Inventory.SelectedItem = Inventory.GetNode<Items.Item>("Sword");
|
||||
Inventory.SelectFirstItem();
|
||||
base._Ready();
|
||||
}
|
||||
|
||||
|
|
|
@ -165,7 +165,6 @@ y_sort_enabled = true
|
|||
script = ExtResource("7_43gq8")
|
||||
|
||||
[node name="Sword" parent="Inventory" instance=ExtResource("8_s3c8r")]
|
||||
Knockback = 40.0
|
||||
|
||||
[node name="FlashAnimation" type="AnimationPlayer" parent="."]
|
||||
libraries = {
|
||||
|
|
|
@ -288,7 +288,8 @@ namespace SupaLidlGame.Characters
|
|||
|
||||
if (Target.LengthSquared() < 1024)
|
||||
{
|
||||
if (Inventory.SelectedItem is Weapon weapon)
|
||||
// TODO: offhand items
|
||||
if (Inventory.PrimaryItem is Weapon weapon)
|
||||
{
|
||||
UseCurrentItem();
|
||||
}
|
||||
|
|
|
@ -61,5 +61,19 @@ namespace SupaLidlGame.Characters
|
|||
GD.Print("died");
|
||||
//base.Die();
|
||||
}
|
||||
|
||||
public bool IsUsingAnyWeapon()
|
||||
{
|
||||
bool checkItem(Items.Item item)
|
||||
{
|
||||
if (item is Items.Weapon weapon)
|
||||
{
|
||||
return weapon.IsUsing;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return checkItem(Inventory.PrimaryItem) ||
|
||||
checkItem(Inventory.OffhandItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
[ext_resource type="PackedScene" uid="uid://cl56eadpklnbo" path="res://Utils/PlayerCamera.tscn" id="4_ym125"]
|
||||
[ext_resource type="Script" path="res://Characters/States/PlayerMoveState.cs" id="5_tx5rw"]
|
||||
[ext_resource type="Script" path="res://Characters/States/PlayerRollState.cs" id="6_6bgrj"]
|
||||
[ext_resource type="PackedScene" uid="uid://d72ehtv1ks0e" path="res://Items/Weapons/Sword.tscn" id="7_4rxuv"]
|
||||
[ext_resource type="Script" path="res://Items/Inventory.cs" id="7_xyenu"]
|
||||
[ext_resource type="PackedScene" uid="uid://cjgxyhgcyvsv7" path="res://BoundingBoxes/Hurtbox.tscn" id="9_avyu4"]
|
||||
[ext_resource type="AudioStream" uid="uid://njun3e6v4854" path="res://Assets/Sounds/hurt.wav" id="12_h0x0g"]
|
||||
|
@ -86,6 +85,69 @@ size = Vector2(16, 8)
|
|||
[sub_resource type="LabelSettings" id="LabelSettings_q5h1n"]
|
||||
font_size = 24
|
||||
|
||||
[sub_resource type="CSharpScript" id="CSharpScript_rcje3"]
|
||||
script/source = "using Godot;
|
||||
using SupaLidlGame.Characters;
|
||||
|
||||
namespace SupaLidlGame.Items
|
||||
{
|
||||
public partial class ItemInfo : Resource
|
||||
{
|
||||
[Export]
|
||||
public string ItemName { get; set; } = \"Item Name\";
|
||||
|
||||
[Export]
|
||||
public string Description { get; set; } = \"Item description.\";
|
||||
|
||||
[Export]
|
||||
public bool CanStack { get; set; } = false;
|
||||
|
||||
[Export]
|
||||
public int Count { get; set; } = 1;
|
||||
|
||||
[Export]
|
||||
public bool IsOneHanded { get; set; } = false;
|
||||
|
||||
[Export]
|
||||
public Character CharacterOwner { get; set; } = null;
|
||||
|
||||
[Export]
|
||||
public Texture2D Texture { get; set; }
|
||||
|
||||
[Export]
|
||||
public string ScenePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this item can directly stack with other items
|
||||
/// </summary>
|
||||
public virtual bool StacksWith(ItemInfo itemInfo)
|
||||
{
|
||||
if (!CanStack)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ItemName != itemInfo.ItemName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// several more conditions may be added soon
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Item InstantiateItem(string name = \"Primary\")
|
||||
{
|
||||
var scene = ResourceLoader.Load<PackedScene>(ScenePath);
|
||||
var instance = scene.Instantiate<Item>();
|
||||
instance.Name = name;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
"
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_cjk6b"]
|
||||
size = Vector2(16, 24)
|
||||
|
||||
|
@ -193,8 +255,7 @@ horizontal_alignment = 1
|
|||
y_sort_enabled = true
|
||||
position = Vector2(0, 2)
|
||||
script = ExtResource("7_xyenu")
|
||||
|
||||
[node name="Sword" parent="Inventory" instance=ExtResource("7_4rxuv")]
|
||||
Items = Array[Resource]([SubResource("CSharpScript_rcje3")])
|
||||
|
||||
[node name="Hurtbox" parent="." instance=ExtResource("9_avyu4")]
|
||||
Faction = 1
|
||||
|
|
|
@ -9,11 +9,11 @@ namespace SupaLidlGame.Characters.State
|
|||
|
||||
public override CharacterState Enter(CharacterState previousState)
|
||||
{
|
||||
if (Character.Inventory.SelectedItem is Weapon weapon)
|
||||
if (Character.Inventory.PrimaryItem is Weapon weapon)
|
||||
{
|
||||
_attackTime = weapon.UseTime;
|
||||
_attackTime = weapon.Info.UseTime;
|
||||
weapon.Visible = true;
|
||||
Character.Inventory.SelectedItem.Use();
|
||||
Character.Inventory.PrimaryItem.Use();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -24,12 +24,12 @@ namespace SupaLidlGame.Characters.State
|
|||
|
||||
public override void Exit(CharacterState nextState)
|
||||
{
|
||||
if (Character.Inventory.SelectedItem is null)
|
||||
if (Character.Inventory.PrimaryItem is null)
|
||||
{
|
||||
|
||||
}
|
||||
Character.Inventory.SelectedItem.Deuse();
|
||||
if (Character.Inventory.SelectedItem is Weapon weapon)
|
||||
Character.Inventory.PrimaryItem.Deuse();
|
||||
if (Character.Inventory.PrimaryItem is Weapon weapon)
|
||||
{
|
||||
//weapon.Visible = false;
|
||||
}
|
||||
|
|
|
@ -29,14 +29,7 @@ namespace SupaLidlGame.Characters.State
|
|||
{
|
||||
if (@event.IsActionPressed("roll"))
|
||||
{
|
||||
if (Character.Inventory.SelectedItem is Weapon weapon)
|
||||
{
|
||||
if (!weapon.IsUsing)
|
||||
{
|
||||
return RollState;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!_player.IsUsingAnyWeapon())
|
||||
{
|
||||
return RollState;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@ namespace SupaLidlGame.Characters.State
|
|||
#if DEBUG
|
||||
if (@event.IsActionPressed("equip"))
|
||||
{
|
||||
Character.Inventory.SelectedItem = Character.Inventory.GetNode<Items.Item>("Sword");
|
||||
//Character.Inventory.SelectedItem = Character.Inventory.GetNode<Items.Item>("Sword");
|
||||
//Character.Inventory.SelectedItem = Character.
|
||||
Character.Inventory.SelectFirstItem();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -29,7 +31,7 @@ namespace SupaLidlGame.Characters.State
|
|||
"ui_up", "ui_down");
|
||||
Vector2 mousePos = Character.GetGlobalMousePosition();
|
||||
Vector2 dirToMouse = Character.GlobalPosition.DirectionTo(mousePos);
|
||||
if (Character.Inventory.SelectedItem is Weapon weapon)
|
||||
if (Character.Inventory.PrimaryItem is Weapon weapon)
|
||||
{
|
||||
if (!weapon.IsUsing)
|
||||
{
|
||||
|
@ -39,7 +41,7 @@ namespace SupaLidlGame.Characters.State
|
|||
|
||||
if (Godot.Input.IsActionPressed("attack1"))
|
||||
{
|
||||
if (Character.Inventory.SelectedItem is not null)
|
||||
if (Character.Inventory.PrimaryItem is not null)
|
||||
{
|
||||
Character.UseCurrentItem();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
using Godot;
|
||||
|
||||
namespace SupaLidlGame.Extensions
|
||||
{
|
||||
public static class ResourceExtensions
|
||||
{
|
||||
public static string GetFileName(this Resource resource)
|
||||
{
|
||||
return resource.ResourcePath.GetFile();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,39 +8,96 @@ namespace SupaLidlGame.Items
|
|||
{
|
||||
public Character Character { get; private set; }
|
||||
|
||||
public List<Item> Items { get; private set; } = new List<Item>();
|
||||
[Export]
|
||||
public Godot.Collections.Array<ItemInfo> Items { get; private set; }
|
||||
|
||||
[Export]
|
||||
public ItemInfo Test { get; set; }
|
||||
|
||||
public const int MaxCapacity = 32;
|
||||
|
||||
private Item _selectedItem;
|
||||
private Item _primaryItem;
|
||||
|
||||
private Item _offhandItem;
|
||||
|
||||
public Item SelectedItem
|
||||
public Item PrimaryItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set => EquipItem(value, ref _selectedItem);
|
||||
get => _primaryItem;
|
||||
private set => _primaryItem = value;
|
||||
}
|
||||
|
||||
public Item OffhandItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set => EquipItem(value, ref _offhandItem);
|
||||
get => _offhandItem;
|
||||
private set => _offhandItem = value;
|
||||
}
|
||||
|
||||
private bool EquipItem(Item item, ref Item slot)
|
||||
public Inventory()
|
||||
{
|
||||
if (item is not null && item.IsOneHanded)
|
||||
{
|
||||
// we can not equip this if either hand is occupied by
|
||||
// two-handed item
|
||||
Items = new Godot.Collections.Array<ItemInfo>();
|
||||
}
|
||||
|
||||
if (_selectedItem is not null && !_selectedItem.IsOneHanded)
|
||||
public bool EquipItem(ItemInfo info, bool offhand = false)
|
||||
{
|
||||
if (UnequipItem() == info)
|
||||
{
|
||||
// if the item that was unequipped was our item, then we stop
|
||||
return true;
|
||||
}
|
||||
|
||||
var idx = Items.IndexOf(info);
|
||||
|
||||
if (idx < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_offhandItem is not null && !_offhandItem.IsOneHanded)
|
||||
ItemInfo item = Items[idx];
|
||||
|
||||
string name = offhand ? "Offhand" : "Primary";
|
||||
PrimaryItem = item.InstantiateItem(name);
|
||||
PrimaryItem.Equip(Character);
|
||||
PrimaryItem.CharacterOwner = Character;
|
||||
//PrimaryItem.CharacterOwner
|
||||
AddChild(PrimaryItem);
|
||||
return true;
|
||||
}
|
||||
|
||||
public ItemInfo UnequipItem(bool offhand = false)
|
||||
{
|
||||
Item item;
|
||||
if (!offhand)
|
||||
{
|
||||
item = Character.Inventory.GetNode<Item>("Primary");
|
||||
}
|
||||
else
|
||||
{
|
||||
item = Character.Inventory.GetNode<Item>("Offhand");
|
||||
}
|
||||
|
||||
if (item is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
item.QueueFree();
|
||||
return item.Info;
|
||||
}
|
||||
|
||||
/*
|
||||
private bool EquipItem(Item item, ref Item slot)
|
||||
{
|
||||
if (item is not null && item.Info.IsOneHanded)
|
||||
{
|
||||
// we can not equip this if either hand is occupied by
|
||||
// two-handed item
|
||||
|
||||
if (_selectedItem is not null && !_selectedItem.Info.IsOneHanded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_offhandItem is not null && !_offhandItem.Info.IsOneHanded)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -66,39 +123,59 @@ namespace SupaLidlGame.Items
|
|||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
public Item AddItem(Item item)
|
||||
public ItemInfo AddItem(ItemInfo info)
|
||||
{
|
||||
if (Items.Count >= MaxCapacity)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
item.CharacterOwner = Character;
|
||||
item.Visible = false;
|
||||
Items.Add(item);
|
||||
return item;
|
||||
info.CharacterOwner = Character;
|
||||
//item.Visible = false;
|
||||
Items.Add(info);
|
||||
return info;
|
||||
}
|
||||
|
||||
public Item DropItem(Item item)
|
||||
public Item DropItem(ItemInfo item)
|
||||
{
|
||||
item.CharacterOwner = null;
|
||||
item.Visible = true;
|
||||
var e = SelectedItem = item;
|
||||
//item.Visible = true;
|
||||
//var e = SelectedItem = item;
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Character = GetParent<Character>();
|
||||
EnsureChildrenItems();
|
||||
base._Ready();
|
||||
}
|
||||
|
||||
private void EnsureChildrenItems()
|
||||
{
|
||||
foreach (Node child in GetChildren())
|
||||
{
|
||||
if (child is Item item)
|
||||
{
|
||||
AddItem(item);
|
||||
GD.Print(item.Info.Count);
|
||||
if (Items.IndexOf(item.Info) < 0)
|
||||
{
|
||||
AddItem(item.Info);
|
||||
PrimaryItem = item;
|
||||
}
|
||||
}
|
||||
base._Ready();
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectFirstItem()
|
||||
{
|
||||
EnsureChildrenItems();
|
||||
if (Items.Count > 0)
|
||||
{
|
||||
EquipItem(Items[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,17 +6,7 @@ namespace SupaLidlGame.Items
|
|||
public abstract partial class Item : Node2D
|
||||
{
|
||||
[Export]
|
||||
public string ItemName { get; set; }
|
||||
|
||||
[Export]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Export]
|
||||
public bool CanStack { get; set; } = false;
|
||||
|
||||
public int Count { get; set; } = 1;
|
||||
|
||||
public bool IsOneHanded { get; set; } = false;
|
||||
public ItemInfo Info { get; set; }
|
||||
|
||||
public Character CharacterOwner { get; set; }
|
||||
|
||||
|
@ -25,12 +15,12 @@ namespace SupaLidlGame.Items
|
|||
/// </summary>
|
||||
public virtual bool StacksWith(Item item)
|
||||
{
|
||||
if (!CanStack)
|
||||
if (!Info.CanStack)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ItemName != item.ItemName)
|
||||
if (Info.ItemName != item.Info.ItemName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
namespace SupaLidlGame
|
||||
{
|
||||
public class ItemDatabase
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
using Godot;
|
||||
using SupaLidlGame.Characters;
|
||||
using MonoCustomResourceRegistry;
|
||||
|
||||
namespace SupaLidlGame.Items
|
||||
{
|
||||
[RegisteredType(nameof(ItemInfo))]
|
||||
public partial class ItemInfo : Resource
|
||||
{
|
||||
[Export]
|
||||
public string ItemName { get; set; } = "Item Name";
|
||||
|
||||
[Export]
|
||||
public string Description { get; set; } = "Item description.";
|
||||
|
||||
[Export]
|
||||
public bool CanStack { get; set; } = false;
|
||||
|
||||
[Export]
|
||||
public int Count { get; set; } = 1;
|
||||
|
||||
[Export]
|
||||
public bool IsOneHanded { get; set; } = false;
|
||||
|
||||
[Export]
|
||||
public Character CharacterOwner { get; set; } = null;
|
||||
|
||||
[Export]
|
||||
public Texture2D Texture { get; set; }
|
||||
|
||||
[Export]
|
||||
public string ScenePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this item can directly stack with other items
|
||||
/// </summary>
|
||||
public virtual bool StacksWith(ItemInfo itemInfo)
|
||||
{
|
||||
if (!CanStack)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ItemName != itemInfo.ItemName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// several more conditions may be added soon
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Item InstantiateItem(string name = "Primary")
|
||||
{
|
||||
var scene = ResourceLoader.Load<PackedScene>(ScenePath);
|
||||
var instance = scene.Instantiate<Item>();
|
||||
instance.Name = name;
|
||||
instance.Info = this;
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using Godot;
|
||||
|
||||
namespace SupaLidlGame.Items.Weapons
|
||||
{
|
||||
public partial class MeleeInfo : WeaponInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The time frame in seconds for which the weapon will deal damage.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The value of <c>AttackTime</c> should be less than the
|
||||
/// value of <c>UseTime</c>
|
||||
/// </remarks>
|
||||
[Export]
|
||||
public double AttackTime { get; set; } = 0;
|
||||
}
|
||||
}
|
|
@ -10,30 +10,7 @@ namespace SupaLidlGame.Items
|
|||
|
||||
public bool IsUsing => RemainingUseTime > 0;
|
||||
|
||||
/// <summary>
|
||||
/// How much damage in HP that this weapon deals.
|
||||
/// </summary>
|
||||
[Export]
|
||||
public float Damage { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The time in seconds it takes for this weapon to become available
|
||||
/// again after using.
|
||||
/// </summary>
|
||||
[Export]
|
||||
public double UseTime { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The magnitude of the knockback force of the weapon.
|
||||
/// </summary>
|
||||
[Export]
|
||||
public float Knockback { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The initial velocity of any projectile the weapon may spawn.
|
||||
/// </summary>
|
||||
[Export]
|
||||
public float InitialVelocity { get; set; } = 0;
|
||||
public new WeaponInfo Info => base.Info as WeaponInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the weapon can parry other weapons and is
|
||||
|
@ -51,6 +28,7 @@ namespace SupaLidlGame.Items
|
|||
|
||||
public override void Equip(Character character)
|
||||
{
|
||||
GD.Print("Equipped by " + character.Name);
|
||||
Character = character;
|
||||
}
|
||||
|
||||
|
@ -61,7 +39,7 @@ namespace SupaLidlGame.Items
|
|||
|
||||
public override void Use()
|
||||
{
|
||||
RemainingUseTime = UseTime;
|
||||
RemainingUseTime = Info.UseTime;
|
||||
}
|
||||
|
||||
public override void Deuse()
|
||||
|
@ -84,7 +62,7 @@ namespace SupaLidlGame.Items
|
|||
{
|
||||
if (box is Hurtbox hurtbox)
|
||||
{
|
||||
hurtbox.InflictDamage(Damage, Character, Knockback);
|
||||
hurtbox.InflictDamage(Info.Damage, Character, Info.Knockback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
using Godot;
|
||||
|
||||
namespace SupaLidlGame.Items
|
||||
{
|
||||
public partial class WeaponInfo : ItemInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// How much damage in HP that this weapon deals.
|
||||
/// </summary>
|
||||
[Export]
|
||||
public float Damage { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The time in seconds it takes for this weapon to become available
|
||||
/// again after using.
|
||||
/// </summary>
|
||||
[Export]
|
||||
public double UseTime { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The magnitude of the knockback force of the weapon.
|
||||
/// </summary>
|
||||
[Export]
|
||||
public float Knockback { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The initial velocity of any projectile the weapon may spawn.
|
||||
/// </summary>
|
||||
[Export]
|
||||
public float InitialVelocity { get; set; } = 0;
|
||||
|
||||
}
|
||||
}
|
|
@ -15,16 +15,6 @@ namespace SupaLidlGame.Items.Weapons
|
|||
[Export]
|
||||
public AnimationPlayer AnimationPlayer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The time frame in seconds for which the weapon will deal damage.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The value of <c>AttackTime</c> should be less than the
|
||||
/// value of <c>UseTime</c>
|
||||
/// </remarks>
|
||||
[Export]
|
||||
public double AttackTime { get; set; } = 0;
|
||||
|
||||
[Export]
|
||||
public CpuParticles2D ParryParticles { get; set; }
|
||||
|
||||
|
@ -103,7 +93,7 @@ namespace SupaLidlGame.Items.Weapons
|
|||
|
||||
public override void _Ready()
|
||||
{
|
||||
Hitbox.Damage = Damage;
|
||||
Hitbox.Damage = Info.Damage;
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
|
@ -123,7 +113,10 @@ namespace SupaLidlGame.Items.Weapons
|
|||
GD.Print("processing hit");
|
||||
if (box is Hurtbox hurtbox)
|
||||
{
|
||||
hurtbox.InflictDamage(Damage, Character, Knockback);
|
||||
hurtbox.InflictDamage(
|
||||
Info.Damage,
|
||||
Character,
|
||||
Info.Knockback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,10 +158,13 @@ namespace SupaLidlGame.Items.Weapons
|
|||
{
|
||||
if (hurt.GetParent() is Character c)
|
||||
{
|
||||
var item = c.Inventory.SelectedItem;
|
||||
if (item is Weapon w)
|
||||
if (c.Inventory.PrimaryItem is Weapon primary)
|
||||
{
|
||||
AttemptParry(w);
|
||||
AttemptParry(primary);
|
||||
}
|
||||
if (c.Inventory.OffhandItem is Weapon offhand)
|
||||
{
|
||||
AttemptParry(offhand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
[gd_resource type="Resource" load_steps=2 format=3 uid="uid://dbqk11m54e72e"]
|
||||
|
||||
[ext_resource type="Script" path="res://Items/MeleeInfo.cs" id="1_w5yvw"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_w5yvw")
|
||||
AttackTime = 0.1
|
||||
Damage = 20.0
|
||||
UseTime = 0.8
|
||||
Knockback = 80.0
|
||||
InitialVelocity = 0.0
|
||||
ItemName = "Sword"
|
||||
Description = "A basic sword."
|
||||
CanStack = false
|
||||
Count = 1
|
||||
IsOneHanded = false
|
||||
ScenePath = ""
|
|
@ -1,6 +1,7 @@
|
|||
[gd_scene load_steps=20 format=3 uid="uid://d72ehtv1ks0e"]
|
||||
[gd_scene load_steps=21 format=3 uid="uid://d72ehtv1ks0e"]
|
||||
|
||||
[ext_resource type="Script" path="res://Items/Weapons/Sword.cs" id="1_mlo73"]
|
||||
[ext_resource type="Resource" uid="uid://dbqk11m54e72e" path="res://Items/Weapons/Sword.tres" id="2_5vlf6"]
|
||||
[ext_resource type="Texture2D" uid="uid://dt6u8p4h6g7le" path="res://Assets/Sprites/knife.png" id="2_rnfo4"]
|
||||
[ext_resource type="PackedScene" uid="uid://du5vhccg75nrq" path="res://BoundingBoxes/Hitbox.tscn" id="3_up3ob"]
|
||||
[ext_resource type="PackedScene" uid="uid://cojxmcin13ihm" path="res://Utils/Trail.tscn" id="4_pt6lq"]
|
||||
|
@ -302,13 +303,8 @@ position = Vector2(2, 0)
|
|||
script = ExtResource("1_mlo73")
|
||||
Hitbox = NodePath("Hitbox")
|
||||
AnimationPlayer = NodePath("AnimationPlayer")
|
||||
AttackTime = 0.1
|
||||
ParryParticles = NodePath("Anchor/Sprite2D/ParryParticles")
|
||||
Damage = 20.0
|
||||
UseTime = 0.8
|
||||
Knockback = 80.0
|
||||
ItemName = "Sword"
|
||||
Description = "A basic sword."
|
||||
Info = ExtResource("2_5vlf6")
|
||||
|
||||
[node name="Anchor" type="Node2D" parent="."]
|
||||
y_sort_enabled = true
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
using Godot;
|
||||
|
||||
namespace SupaLidlGame.Utils
|
||||
{
|
||||
public class AudioBuilder
|
||||
{
|
||||
private AudioStreamPlayer2D _audio;
|
||||
|
||||
public AudioBuilder(AudioStreamPlayer2D baseAudio)
|
||||
{
|
||||
_audio = baseAudio;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
using Godot;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
// Originally written by wmigor
|
||||
// Edited by Atlinx to recursively search for files.
|
||||
// Edited by bls220 to update for Godot 4.0
|
||||
// wmigor's Public Repo: https://github.com/wmigor/godot-mono-custom-resource-register
|
||||
namespace MonoCustomResourceRegistry
|
||||
{
|
||||
#if TOOLS
|
||||
[Tool]
|
||||
public partial class Plugin : EditorPlugin
|
||||
{
|
||||
// We're not going to hijack the Mono Build button since it actually takes time to build
|
||||
// and we can't be sure how long that is. I guess we have to leave refreshing to the user for now.
|
||||
// There isn't any automation we can do to fix that.
|
||||
// private Button MonoBuildButton => GetNode<Button>("/root/EditorNode/@@580/@@581/@@589/@@590/Button");
|
||||
private readonly List<string> customTypes = new List<string>();
|
||||
private Button? refreshButton;
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
refreshButton = new Button();
|
||||
refreshButton.Text = "CCR";
|
||||
|
||||
AddControlToContainer(CustomControlContainer.Toolbar, refreshButton);
|
||||
refreshButton.Icon = GetEditorInterface().GetBaseControl().GetThemeIcon("Reload", "EditorIcons");
|
||||
refreshButton.Pressed += OnRefreshPressed;
|
||||
|
||||
Settings.Init();
|
||||
RefreshCustomClasses();
|
||||
GD.PushWarning("You may change any setting for MonoCustomResourceRegistry in Project -> ProjectSettings -> General -> MonoCustomResourceRegistry");
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
UnregisterCustomClasses();
|
||||
RemoveControlFromContainer(CustomControlContainer.Toolbar, refreshButton);
|
||||
refreshButton?.QueueFree();
|
||||
}
|
||||
|
||||
public void RefreshCustomClasses()
|
||||
{
|
||||
GD.Print("\nRefreshing Registered Resources...");
|
||||
UnregisterCustomClasses();
|
||||
RegisterCustomClasses();
|
||||
}
|
||||
|
||||
private void RegisterCustomClasses()
|
||||
{
|
||||
customTypes.Clear();
|
||||
|
||||
foreach (Type type in GetCustomRegisteredTypes())
|
||||
if (type.IsSubclassOf(typeof(Resource)))
|
||||
AddRegisteredType(type, nameof(Resource));
|
||||
else
|
||||
AddRegisteredType(type, nameof(Node));
|
||||
}
|
||||
|
||||
private void AddRegisteredType(Type type, string defaultBaseTypeName)
|
||||
{
|
||||
RegisteredTypeAttribute? attribute = Attribute.GetCustomAttribute(type, typeof(RegisteredTypeAttribute)) as RegisteredTypeAttribute;
|
||||
string? path = FindClassPath(type);
|
||||
if (path == null && !FileAccess.FileExists(path))
|
||||
return;
|
||||
Script script = GD.Load<Script>(path);
|
||||
if (script == null)
|
||||
return;
|
||||
string baseType = defaultBaseTypeName;
|
||||
if (attribute is not null && attribute.baseType != "")
|
||||
baseType = attribute.baseType;
|
||||
ImageTexture? icon = null;
|
||||
if (attribute is not null && attribute.iconPath != "")
|
||||
{
|
||||
if (FileAccess.FileExists(attribute.iconPath))
|
||||
{
|
||||
Texture2D rawIcon = ResourceLoader.Load<Texture2D>(attribute.iconPath);
|
||||
if (rawIcon != null)
|
||||
{
|
||||
Image image = rawIcon.GetImage();
|
||||
int length = (int)Mathf.Round(16 * GetEditorInterface().GetEditorScale());
|
||||
image.Resize(length, length);
|
||||
icon = ImageTexture.CreateFromImage(image);
|
||||
}
|
||||
else
|
||||
GD.PushError($"Could not load the icon for the registered type \"{type.FullName}\" at path \"{path}\".");
|
||||
}
|
||||
else
|
||||
GD.PushError($"The icon path of \"{path}\" for the registered type \"{type.FullName}\" does not exist.");
|
||||
}
|
||||
AddCustomType($"{Settings.ClassPrefix}{type.Name}", baseType, script, icon);
|
||||
customTypes.Add($"{Settings.ClassPrefix}{type.Name}");
|
||||
GD.Print($"Registered custom type: {type.Name} -> {path}");
|
||||
}
|
||||
|
||||
private static string? FindClassPath(Type type)
|
||||
{
|
||||
switch (Settings.SearchType)
|
||||
{
|
||||
case Settings.ResourceSearchType.Recursive:
|
||||
return FindClassPathRecursive(type);
|
||||
case Settings.ResourceSearchType.Namespace:
|
||||
return FindClassPathNamespace(type);
|
||||
default:
|
||||
throw new Exception($"ResourceSearchType {Settings.SearchType} not implemented!");
|
||||
}
|
||||
}
|
||||
|
||||
private static string? FindClassPathNamespace(Type type)
|
||||
{
|
||||
foreach (string dir in Settings.ResourceScriptDirectories)
|
||||
{
|
||||
StringBuilder builder = new(dir);
|
||||
if (!dir.EndsWith('/'))
|
||||
{
|
||||
builder.Append('/');
|
||||
}
|
||||
if (type.Namespace is not null)
|
||||
{
|
||||
builder
|
||||
.Append(type.Namespace.Replace(".", "/"))
|
||||
.Append('/');
|
||||
}
|
||||
builder
|
||||
.Append(type.Name)
|
||||
.Append(".cs");
|
||||
string filePath = builder.ToString();
|
||||
if (FileAccess.FileExists(filePath))
|
||||
return filePath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string? FindClassPathRecursive(Type type)
|
||||
{
|
||||
foreach (string directory in Settings.ResourceScriptDirectories)
|
||||
{
|
||||
string? fileFound = FindClassPathRecursiveHelper(type, directory);
|
||||
if (fileFound != null)
|
||||
return fileFound;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string? FindClassPathRecursiveHelper(Type type, string directory)
|
||||
{
|
||||
var dir = DirAccess.Open(directory);
|
||||
|
||||
if (DirAccess.GetOpenError() == Error.Ok)
|
||||
{
|
||||
dir.ListDirBegin();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var fileOrDirName = dir.GetNext();
|
||||
|
||||
// Skips hidden files like .
|
||||
if (fileOrDirName == "")
|
||||
break;
|
||||
else if (fileOrDirName.StartsWith("."))
|
||||
continue;
|
||||
else if (dir.CurrentIsDir())
|
||||
{
|
||||
string? foundFilePath = FindClassPathRecursiveHelper(type, dir.GetCurrentDir() + "/" + fileOrDirName);
|
||||
if (foundFilePath != null)
|
||||
{
|
||||
dir.ListDirEnd();
|
||||
return foundFilePath;
|
||||
}
|
||||
}
|
||||
else if (fileOrDirName == $"{type.Name}.cs")
|
||||
return dir.GetCurrentDir() + "/" + fileOrDirName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> GetCustomRegisteredTypes()
|
||||
{
|
||||
var assembly = Assembly.GetAssembly(typeof(Plugin));
|
||||
return assembly?.GetTypes().Where(t => !t.IsAbstract
|
||||
&& Attribute.IsDefined(t, typeof(RegisteredTypeAttribute))
|
||||
&& (t.IsSubclassOf(typeof(Node)) || t.IsSubclassOf(typeof(Resource)))
|
||||
) ?? Enumerable.Empty<Type>();
|
||||
}
|
||||
|
||||
private void UnregisterCustomClasses()
|
||||
{
|
||||
foreach (var script in customTypes)
|
||||
{
|
||||
RemoveCustomType(script);
|
||||
GD.Print($"Unregister custom resource: {script}");
|
||||
}
|
||||
|
||||
customTypes.Clear();
|
||||
}
|
||||
|
||||
private void OnRefreshPressed()
|
||||
{
|
||||
RefreshCustomClasses();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace MonoCustomResourceRegistry
|
||||
{
|
||||
[AttributeUsage(System.AttributeTargets.Class)]
|
||||
public partial class RegisteredTypeAttribute : System.Attribute
|
||||
{
|
||||
public string name;
|
||||
public string iconPath;
|
||||
public string baseType;
|
||||
|
||||
public RegisteredTypeAttribute(string name, string iconPath = "", string baseType = "")
|
||||
{
|
||||
this.name = name;
|
||||
this.iconPath = iconPath;
|
||||
this.baseType = baseType;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using Godot;
|
||||
using Godot.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace MonoCustomResourceRegistry
|
||||
{
|
||||
public static class Settings
|
||||
{
|
||||
public enum ResourceSearchType
|
||||
{
|
||||
Recursive = 0,
|
||||
Namespace = 1,
|
||||
}
|
||||
|
||||
public static string ClassPrefix => GetSettings(nameof(ClassPrefix)).AsString();
|
||||
public static ResourceSearchType SearchType => (ResourceSearchType)GetSettings(nameof(SearchType)).AsInt32();
|
||||
public static ReadOnlyCollection<string> ResourceScriptDirectories
|
||||
{
|
||||
get
|
||||
{
|
||||
Array array = (Array)GetSettings(nameof(ResourceScriptDirectories)) ?? new Array();
|
||||
return new(array.Select(v => v.AsString()).ToList());
|
||||
}
|
||||
}
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
AddSetting(nameof(ClassPrefix), Variant.Type.String, "");
|
||||
AddSetting(nameof(SearchType), Variant.Type.Int, ResourceSearchType.Recursive, PropertyHint.Enum, "Recursive,Namespace");
|
||||
AddSetting(nameof(ResourceScriptDirectories), Variant.Type.Array, new Array<string>(new string[] { "res://" }));
|
||||
}
|
||||
|
||||
private static Variant GetSettings(string title)
|
||||
{
|
||||
return ProjectSettings.GetSetting($"{nameof(MonoCustomResourceRegistry)}/{title}");
|
||||
}
|
||||
|
||||
private static void AddSetting<T>(string title, Variant.Type type, T value, PropertyHint hint = PropertyHint.None, string hintString = "")
|
||||
{
|
||||
title = SettingPath(title);
|
||||
if (!ProjectSettings.HasSetting(title))
|
||||
ProjectSettings.SetSetting(title, Variant.From(value));
|
||||
var info = new Dictionary
|
||||
{
|
||||
["name"] = title,
|
||||
["type"] = Variant.From(type),
|
||||
["hint"] = Variant.From(hint),
|
||||
["hint_string"] = hintString,
|
||||
};
|
||||
ProjectSettings.AddPropertyInfo(info);
|
||||
GD.Print("Successfully added property: " + title);
|
||||
}
|
||||
|
||||
private static string SettingPath(string title) => $"{nameof(MonoCustomResourceRegistry)}/{title}";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
[plugin]
|
||||
|
||||
name="Mono Custom Resource Registry"
|
||||
description="Registers custom C# resources for Godot"
|
||||
author="Atlinx, wmigor, rob-mur"
|
||||
version="3.0.0"
|
||||
script="Plugin.cs"
|
|
@ -8,6 +8,12 @@
|
|||
|
||||
config_version=5
|
||||
|
||||
[MonoCustomResourceRegistry]
|
||||
|
||||
ClassPrefix=""
|
||||
SearchType=0
|
||||
ResourceScriptDirectories=["res://"]
|
||||
|
||||
[application]
|
||||
|
||||
config/name="SupaLidlGame"
|
||||
|
@ -19,6 +25,10 @@ config/icon="res://icon.svg"
|
|||
|
||||
project/assembly_name="SupaLidlGame"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/MonoCustomResourceRegistry/plugin.cfg")
|
||||
|
||||
[input]
|
||||
|
||||
ui_left={
|
||||
|
|
Loading…
Reference in New Issue