Add inventory system
This commit is contained in:
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"godotTools.editorPath.godot4": "/var/lib/flatpak/app/org.godotengine.Godot/current/active/export/bin/org.godotengine.Godot",
|
"godotTools.editorPath.godot4": "/var/lib/flatpak/app/org.godotengine.Godot/current/active/export/bin/org.godotengine.Godot",
|
||||||
|
"terminal.integrated.tabs.enabled": false,
|
||||||
"editor.insertSpaces": false,
|
"editor.insertSpaces": false,
|
||||||
"editor.tabSize": 4,
|
"editor.tabSize": 4
|
||||||
"terminal.integrated.tabs.enabled": false
|
|
||||||
}
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
[gd_scene load_steps=8 format=3 uid="uid://yhtpoum3eek7"]
|
[gd_scene load_steps=8 format=3 uid="uid://yhtpoum3eek7"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/RosaController.gd" id="1_3g383"]
|
[ext_resource type="Script" path="res://scripts/Entities/RosaController.gd" id="1_3g383"]
|
||||||
[ext_resource type="Script" path="res://scripts/RosaCamera.gd" id="2_tr66j"]
|
[ext_resource type="Script" path="res://scripts/Entities/RosaCamera.gd" id="2_tr66j"]
|
||||||
[ext_resource type="Shader" path="res://shaders/NPC Shader.gdshader" id="3_j5vis"]
|
[ext_resource type="Shader" path="res://shaders/NPC Shader.gdshader" id="3_j5vis"]
|
||||||
[ext_resource type="Texture2D" uid="uid://i34vweii6joy" path="res://textures/rosa.png" id="4_qdjyy"]
|
[ext_resource type="Texture2D" uid="uid://i34vweii6joy" path="res://textures/rosa.png" id="4_qdjyy"]
|
||||||
|
|
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene load_steps=7 format=3 uid="uid://dr4b2pmsknuhc"]
|
[gd_scene load_steps=7 format=3 uid="uid://dr4b2pmsknuhc"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/TestNPCController.gd" id="1_61g2d"]
|
[ext_resource type="Script" path="res://scripts/Entities/TestNPCController.gd" id="1_61g2d"]
|
||||||
[ext_resource type="Shader" path="res://shaders/NPC Shader.gdshader" id="1_xgcv1"]
|
[ext_resource type="Shader" path="res://shaders/NPC Shader.gdshader" id="1_xgcv1"]
|
||||||
[ext_resource type="Texture2D" uid="uid://i34vweii6joy" path="res://textures/rosa.png" id="2_shls4"]
|
[ext_resource type="Texture2D" uid="uid://i34vweii6joy" path="res://textures/rosa.png" id="2_shls4"]
|
||||||
|
|
14
scenes/MapBounds.tscn
Normal file
14
scenes/MapBounds.tscn
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://cy4r0tp2htivb"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/MapBounds.gd" id="1_43dqt"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_ep4u2"]
|
||||||
|
|
||||||
|
[node name="MapBounds" type="Area3D"]
|
||||||
|
script = ExtResource("1_43dqt")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("BoxShape3D_ep4u2")
|
||||||
|
|
||||||
|
[connection signal="body_entered" from="." to="." method="_on_body_entered"]
|
||||||
|
[connection signal="body_exited" from="." to="." method="_on_body_exited"]
|
6
scenes/Systems.tscn
Normal file
6
scenes/Systems.tscn
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://iibqlagufwhm"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/Systems/Systems.gd" id="1_uen2c"]
|
||||||
|
|
||||||
|
[node name="Systems" type="Node3D"]
|
||||||
|
script = ExtResource("1_uen2c")
|
@@ -1,8 +1,10 @@
|
|||||||
[gd_scene load_steps=7 format=3 uid="uid://bdrpqtbwvtivd"]
|
[gd_scene load_steps=9 format=3 uid="uid://bdrpqtbwvtivd"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://yhtpoum3eek7" path="res://scenes/NPC/Rosa.tscn" id="1_3u2u0"]
|
[ext_resource type="PackedScene" uid="uid://yhtpoum3eek7" path="res://scenes/Entities/Rosa.tscn" id="1_3u2u0"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dr4b2pmsknuhc" path="res://scenes/NPC/TestNPC.tscn" id="2_6f3lj"]
|
[ext_resource type="PackedScene" uid="uid://iibqlagufwhm" path="res://scenes/Systems.tscn" id="1_3x3uf"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dr4b2pmsknuhc" path="res://scenes/Entities/TestNPC.tscn" id="2_6f3lj"]
|
||||||
[ext_resource type="PackedScene" uid="uid://7wjfo6u4dp3h" path="res://scenes/Maps/test.tscn" id="4_18e1y"]
|
[ext_resource type="PackedScene" uid="uid://7wjfo6u4dp3h" path="res://scenes/Maps/test.tscn" id="4_18e1y"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cy4r0tp2htivb" path="res://scenes/MapBounds.tscn" id="4_gv7tl"]
|
||||||
|
|
||||||
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_1b6it"]
|
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_1b6it"]
|
||||||
sky_horizon_color = Color(0.59625, 0.6135, 0.6375, 1)
|
sky_horizon_color = Color(0.59625, 0.6135, 0.6375, 1)
|
||||||
@@ -19,6 +21,8 @@ sky = SubResource("Sky_weucl")
|
|||||||
|
|
||||||
[node name="TestSceneRoot" type="Node3D"]
|
[node name="TestSceneRoot" type="Node3D"]
|
||||||
|
|
||||||
|
[node name="Systems" parent="." instance=ExtResource("1_3x3uf")]
|
||||||
|
|
||||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||||
environment = SubResource("Environment_18twt")
|
environment = SubResource("Environment_18twt")
|
||||||
|
|
||||||
@@ -34,3 +38,6 @@ light_energy = 15.315
|
|||||||
omni_range = 281.646
|
omni_range = 281.646
|
||||||
|
|
||||||
[node name="test" parent="." instance=ExtResource("4_18e1y")]
|
[node name="test" parent="." instance=ExtResource("4_18e1y")]
|
||||||
|
|
||||||
|
[node name="MapBounds" parent="." instance=ExtResource("4_gv7tl")]
|
||||||
|
transform = Transform3D(22.0363, 0, 0, 0, 7.5201, 0, 0, 0, 19.278, 1.48402, 2.89779, 1.65935)
|
||||||
|
13
scenes/Testing/TestCube.tscn
Normal file
13
scenes/Testing/TestCube.tscn
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://dlwauw7qvyxnn"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_qpmw6"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_lddii"]
|
||||||
|
|
||||||
|
[node name="TestCube" type="StaticBody3D"]
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("BoxShape3D_qpmw6")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
|
mesh = SubResource("BoxMesh_lddii")
|
@@ -1,4 +1,5 @@
|
|||||||
extends CharacterBody3D
|
extends CharacterBody3D
|
||||||
|
class_name OverworldEntity
|
||||||
|
|
||||||
enum Direction {
|
enum Direction {
|
||||||
NORTH,
|
NORTH,
|
||||||
@@ -16,6 +17,12 @@ var meshInstance:MeshInstance3D;
|
|||||||
var underFootTile:int = -1;
|
var underFootTile:int = -1;
|
||||||
var underFootPosition:Vector3;
|
var underFootPosition:Vector3;
|
||||||
|
|
||||||
|
var withinMapBounds:MapBounds;
|
||||||
|
var withinBoundsLastFrame:bool = true;
|
||||||
|
|
||||||
|
func getSystems() -> Systems:
|
||||||
|
return get_tree().current_scene.get_node("Systems") as Systems;
|
||||||
|
|
||||||
func getDirectionVector() -> Vector3:
|
func getDirectionVector() -> Vector3:
|
||||||
match direction:
|
match direction:
|
||||||
Direction.NORTH:
|
Direction.NORTH:
|
||||||
@@ -52,7 +59,7 @@ func _updateTileData() -> void:
|
|||||||
|
|
||||||
var collider = result.collider;
|
var collider = result.collider;
|
||||||
var colliderMesh = collider.get_node("../");
|
var colliderMesh = collider.get_node("../");
|
||||||
if !colliderMesh or !colliderMesh.mesh or colliderMesh.mesh.get_surface_count() == 0:
|
if !colliderMesh or !(colliderMesh is ArrayMesh) or !colliderMesh.mesh or colliderMesh.mesh.get_surface_count() == 0:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
# Get the face index (triangle)
|
# Get the face index (triangle)
|
||||||
@@ -90,6 +97,14 @@ func _ready() -> void:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
func _process(delta:float) -> void:
|
func _process(delta:float) -> void:
|
||||||
|
# Handle entity leaving map bounds
|
||||||
|
if !withinMapBounds:
|
||||||
|
if !withinBoundsLastFrame:
|
||||||
|
print("Entity ", self.name, " was out of map bounds for two frames");
|
||||||
|
withinBoundsLastFrame = false;
|
||||||
|
else:
|
||||||
|
withinBoundsLastFrame = true;
|
||||||
|
|
||||||
# Update logic
|
# Update logic
|
||||||
updateOverworldLogic(delta)
|
updateOverworldLogic(delta)
|
||||||
|
|
@@ -1,4 +1,4 @@
|
|||||||
extends "res://scripts/OverworldEntity.gd"
|
class_name RosaController extends "res://scripts/Entities/OverworldEntity.gd"
|
||||||
|
|
||||||
var interactRange = 0.7;
|
var interactRange = 0.7;
|
||||||
|
|
||||||
@@ -27,7 +27,6 @@ func updateMovement(delta) -> void:
|
|||||||
if(dir.x != 0 or dir.y != 0):
|
if(dir.x != 0 or dir.y != 0):
|
||||||
velocity.x = dir.x * speed * delta;
|
velocity.x = dir.x * speed * delta;
|
||||||
velocity.z = dir.y * speed * delta;
|
velocity.z = dir.y * speed * delta;
|
||||||
print(dir.length());
|
|
||||||
|
|
||||||
# Update direction
|
# Update direction
|
||||||
if(dir.x >= abs(dir.y) and(
|
if(dir.x >= abs(dir.y) and(
|
11
scripts/Entities/TestNPCController.gd
Normal file
11
scripts/Entities/TestNPCController.gd
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
class_name TestNPCController extends "res://scripts/Entities/OverworldEntity.gd"
|
||||||
|
|
||||||
|
func interact(interactor) -> void:
|
||||||
|
var systems = getSystems();
|
||||||
|
systems.ITEM.addItem(systems.ITEM.ITEM_POTION, 1);
|
||||||
|
#var itemSystem = (get_node("Systems") as Systems).ITEM;
|
||||||
|
#itemSystem.addItem(itemSystem.ITEM_POTION, 1);
|
||||||
|
#pass
|
||||||
|
|
||||||
|
func updateMovement(delta) -> void:
|
||||||
|
pass
|
36
scripts/Items/Item.gd
Normal file
36
scripts/Items/Item.gd
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
class_name Item
|
||||||
|
|
||||||
|
enum ItemCategory {
|
||||||
|
MEDICINE,
|
||||||
|
KEY_ITEM,
|
||||||
|
INGREDIENT
|
||||||
|
};
|
||||||
|
|
||||||
|
func getName() -> String:
|
||||||
|
push_error("getName() must be overridden in derived classes");
|
||||||
|
return "";
|
||||||
|
|
||||||
|
func isStackable() -> bool:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
func isDroppable() -> bool:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
func isSellable() -> bool:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
func getSellPrice() -> int:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
func getBuyPrice() -> int:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
func isConsumable() -> bool:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
func consume() -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func getCategory() -> ItemCategory:
|
||||||
|
push_error("getCategory() must be overriden in derived class");
|
||||||
|
return ItemCategory.MEDICINE;
|
8
scripts/Items/ItemStack.gd
Normal file
8
scripts/Items/ItemStack.gd
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
class_name ItemStack
|
||||||
|
|
||||||
|
var item:Item;
|
||||||
|
var quantity:int;
|
||||||
|
|
||||||
|
func _init(item:Item, quantity:int = 1):
|
||||||
|
self.item = item;
|
||||||
|
self.quantity = quantity;
|
13
scripts/Items/Potion.gd
Normal file
13
scripts/Items/Potion.gd
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
class_name Potion extends "res://scripts/Items/Item.gd"
|
||||||
|
|
||||||
|
func getName() -> String:
|
||||||
|
return "Potion"
|
||||||
|
|
||||||
|
func getCategory() -> ItemCategory:
|
||||||
|
return ItemCategory.MEDICINE;
|
||||||
|
|
||||||
|
func isConsumable() -> bool:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
func consume() -> void:
|
||||||
|
print("Consuming Potion");
|
17
scripts/MapBounds.gd
Normal file
17
scripts/MapBounds.gd
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
extends Area3D
|
||||||
|
class_name MapBounds
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func _on_body_entered(body: Node3D) -> void:
|
||||||
|
if (!body is OverworldEntity):
|
||||||
|
return
|
||||||
|
print("Entered overworld ent")
|
||||||
|
(body as OverworldEntity).withinMapBounds = self;
|
||||||
|
|
||||||
|
func _on_body_exited(body: Node3D) -> void:
|
||||||
|
if (!body is OverworldEntity):
|
||||||
|
return
|
||||||
|
print("Entered overworld ent")
|
||||||
|
(body as OverworldEntity).withinMapBounds = null;
|
1
scripts/MapBounds.gd.uid
Normal file
1
scripts/MapBounds.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dbah1pmk8jola
|
1
scripts/OverworldEntity.gd.uid
Normal file
1
scripts/OverworldEntity.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dr3asofxu1pep
|
1
scripts/RosaCamera.gd.uid
Normal file
1
scripts/RosaCamera.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cubx2asrudfyp
|
1
scripts/RosaController.gd.uid
Normal file
1
scripts/RosaController.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dnls1370w0gr4
|
86
scripts/Systems/ItemSystem.gd
Normal file
86
scripts/Systems/ItemSystem.gd
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
class_name ItemSystem
|
||||||
|
const Item = preload("res://scripts/Items/Item.gd");
|
||||||
|
const ItemStack = preload("res://scripts/Items/ItemStack.gd");
|
||||||
|
|
||||||
|
enum ItemSortType {
|
||||||
|
NAME,
|
||||||
|
TYPE
|
||||||
|
};
|
||||||
|
|
||||||
|
class ItemStackNameComparator:
|
||||||
|
static func _sort(a, b):
|
||||||
|
return a.item.getName().to_lower() < b.item.getName().to_lower()
|
||||||
|
|
||||||
|
class ItemStackTypeComparator:
|
||||||
|
static func _sort(a, b):
|
||||||
|
return a.item.getCategory() < b.item.getCategory()
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
const ITEM_STACK_SIZE_MAX = 99;
|
||||||
|
var ITEM_POTION = preload("res://scripts/Items/Potion.gd").new()
|
||||||
|
var inventory:Array[ItemStack] = [];
|
||||||
|
|
||||||
|
# Methods
|
||||||
|
func addItem(item: Item, quantity: int = 1) -> void:
|
||||||
|
print("Adding ", quantity, "x ", item.getName());
|
||||||
|
if !item.isStackable():
|
||||||
|
# Item cannot be stacked, add each item to inv
|
||||||
|
for i in range(quantity):
|
||||||
|
inventory.append(ItemStack.new(item, 1))
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check for existing stacks
|
||||||
|
for stack in inventory:
|
||||||
|
if stack.item != item or stack.quantity >= ITEM_STACK_SIZE_MAX:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var spaceAvailable = ITEM_STACK_SIZE_MAX - stack.quantity
|
||||||
|
|
||||||
|
if quantity <= spaceAvailable:
|
||||||
|
stack.quantity += quantity;
|
||||||
|
return
|
||||||
|
|
||||||
|
stack.quantity = ITEM_STACK_SIZE_MAX;
|
||||||
|
quantity -= spaceAvailable;
|
||||||
|
|
||||||
|
# Add any remaining inventory as new stack.
|
||||||
|
while quantity > 0:
|
||||||
|
var newStackQuantity = min(quantity, ITEM_STACK_SIZE_MAX);
|
||||||
|
inventory.append(ItemStack.new(item, newStackQuantity));
|
||||||
|
quantity -= newStackQuantity;
|
||||||
|
|
||||||
|
func removeItem(item: Item, quantity: int) -> void:
|
||||||
|
var totalQuantity = 0
|
||||||
|
|
||||||
|
# Calculate total quantity of the item in the inventory
|
||||||
|
for stack in inventory:
|
||||||
|
if stack.item != item:
|
||||||
|
continue
|
||||||
|
totalQuantity += stack.quantity
|
||||||
|
|
||||||
|
if totalQuantity < quantity:
|
||||||
|
push_error("Not enough quantity to remove");
|
||||||
|
return
|
||||||
|
|
||||||
|
# Remove the quantity from the stacks
|
||||||
|
for stack in inventory:
|
||||||
|
if stack.item != item:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if stack.quantity < quantity:
|
||||||
|
quantity -= stack.quantity
|
||||||
|
inventory.erase(stack)
|
||||||
|
|
||||||
|
stack.quantity -= quantity
|
||||||
|
if stack.quantity == 0:
|
||||||
|
inventory.erase(stack)
|
||||||
|
|
||||||
|
if quantity == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
func sortBy(by:ItemSortType) -> void:
|
||||||
|
match by:
|
||||||
|
ItemSortType.NAME:
|
||||||
|
inventory.sort_custom(ItemStackNameComparator._sort)
|
||||||
|
ItemSortType.TYPE:
|
||||||
|
inventory.sort_custom(ItemStackTypeComparator._sort)
|
3
scripts/Systems/Systems.gd
Normal file
3
scripts/Systems/Systems.gd
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
class_name Systems extends Node
|
||||||
|
|
||||||
|
var ITEM = preload("res://scripts/Systems/ItemSystem.gd").new()
|
@@ -1,34 +0,0 @@
|
|||||||
extends "res://scripts/OverworldEntity.gd"
|
|
||||||
|
|
||||||
func interact(interactor) -> void:
|
|
||||||
print("Hello, I am an NPC!")
|
|
||||||
pass
|
|
||||||
|
|
||||||
func updateMovement(delta) -> void:
|
|
||||||
pass
|
|
||||||
# User movement
|
|
||||||
#var dir:Vector2 = Input.get_vector("left", "right", "up", "down");
|
|
||||||
#if(dir.x != 0 or dir.y != 0):
|
|
||||||
#velocity.x = dir.x * speed * delta;
|
|
||||||
#velocity.z = dir.y * speed * delta;
|
|
||||||
#
|
|
||||||
## Update direction
|
|
||||||
#if(dir.x > 0):
|
|
||||||
#if(
|
|
||||||
#dir.y == 0 or
|
|
||||||
#(dir.y < 0 and direction == Direction.SOUTH) or
|
|
||||||
#(dir.y > 0 and direction == Direction.NORTH)
|
|
||||||
#):
|
|
||||||
#direction = Direction.EAST;
|
|
||||||
#elif (dir.x < 0):
|
|
||||||
#if(
|
|
||||||
#dir.y == 0 or
|
|
||||||
#(dir.y < 0 and direction == Direction.SOUTH) or
|
|
||||||
#(dir.y > 0 and direction == Direction.NORTH)
|
|
||||||
#):
|
|
||||||
#direction = Direction.WEST;
|
|
||||||
#elif (dir.y > 0):
|
|
||||||
#direction = Direction.SOUTH;
|
|
||||||
#elif (dir.y < 0):
|
|
||||||
#direction = Direction.NORTH;
|
|
||||||
#pass
|
|
1
scripts/TestNPCController.gd.uid
Normal file
1
scripts/TestNPCController.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dq7mgokmvo80u
|
1
shaders/Map Shader.gdshader.uid
Normal file
1
shaders/Map Shader.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://67hsyo0qqlfm
|
1
shaders/NPC Shader.gdshader.uid
Normal file
1
shaders/NPC Shader.gdshader.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://7h2axb2tsh17
|
Reference in New Issue
Block a user