Skip to content

Commit

Permalink
Feat/loot-and-drop (#17)
Browse files Browse the repository at this point in the history
* feat: adds drop system

* chore(docs): adds docs for loot and drop

* chore(tests): adds drop tests
  • Loading branch information
OctoD authored May 4, 2023
1 parent 6fd4601 commit d8bf1d4
Show file tree
Hide file tree
Showing 27 changed files with 648 additions and 72 deletions.
4 changes: 2 additions & 2 deletions .gut_editor_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@
"post_run_script": "",
"pre_run_script": "",
"prefix": "test_",
"selected": null,
"selected": "test_drop.gd",
"should_exit": true,
"should_exit_on_success": false,
"should_maximize": false,
"show_help": false,
"suffix": ".gd",
"tests": [],
"unit_test_name": null
"unit_test_name": "test_drop"
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://u02qmnlc1nk4"
path="res://.godot/imported/DropGroupIcon.png-082ecee561eb77062736d4b1913eae84.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://addons/godot_gameplay_systems/inventory_system/assets/DropGroupIcon.png"
dest_files=["res://.godot/imported/DropGroupIcon.png-082ecee561eb77062736d4b1913eae84.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://bv0eepnnlr8rx"
path="res://.godot/imported/DropIcon.png-5ab37537aade41394994437130bd02be.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://addons/godot_gameplay_systems/inventory_system/assets/DropIcon.png"
dest_files=["res://.godot/imported/DropIcon.png-5ab37537aade41394994437130bd02be.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://b8tbsu1m5bjj5"
path="res://.godot/imported/DropNode2D.png-505269c443c6f334a033e07591488b87.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://addons/godot_gameplay_systems/inventory_system/assets/DropNode2D.png"
dest_files=["res://.godot/imported/DropNode2D.png-505269c443c6f334a033e07591488b87.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://c8b1c3dfii8cw"
path="res://.godot/imported/DropNode3D.png-543cba8655b833053b0a70d8f6995260.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://addons/godot_gameplay_systems/inventory_system/assets/DropNode3D.png"
dest_files=["res://.godot/imported/DropNode3D.png-543cba8655b833053b0a70d8f6995260.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://bnlfgtgq5m3es"
path="res://.godot/imported/DropTableIcon.png-dc6f72115d3a8fc32c80629bde52acf7.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://addons/godot_gameplay_systems/inventory_system/assets/DropTableIcon.png"
dest_files=["res://.godot/imported/DropTableIcon.png-dc6f72115d3a8fc32c80629bde52acf7.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
89 changes: 89 additions & 0 deletions addons/godot_gameplay_systems/inventory_system/nodes/drop.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
@tool
class_name Drop extends Node

## It is the node responsible for dropping an array of [Items].
##

## Emitted when some [Item]s have been dropped.
signal items_dropped(items: Array[Item], drop_owner: Node)


@export_category("Drop")
## The table used to drop items
@export var drop_table: DropTable = null
## The path to the owning node. This will determine if the drop will be performed in a 2D or 3D world.
## [br]Note that the drop will occur at the same position of the owning node.
@export_node_path("Node2D", "Node3D") var owning_node_path := NodePath()


## It could be either a [Node2D] or [Node3D]
var owning_node: Variant:
get:
if owning_node_path != null and not owning_node_path.is_empty():
return get_node(owning_node_path)
return null


## Called when some [Item]s have been dropped.
func _drop(items: Array[Item]) -> void:
var instances: Array[Node] = []
var _owning_node = owning_node

if _owning_node == null:
return

for item in items:
if item.scene and item.scene.can_instantiate():
var instance = item.scene.instantiate()
var nearest_drop = find_nearest_drop()

instance.position = _owning_node.position

if nearest_drop:
nearest_drop.add_child(instance)
nearest_drop.item_dropped.emit(item, instance)


## It gets the droppable [Item]s from the [DropTable].
## [br]It accepts an optional argument [code]drop_modifier[/code] which increases (or decreases if negative) drop chances for each [DropGroup] pool.
## [br]The greater the modifier, the higher the chances to drop an [Item] from the [member DropTable.pools].
func drop_items(drop_modifier: float = 0.0) -> void:
var items = drop_table.drop(drop_modifier)

if items.size() > 0:
# Who knows what happens in this method. Let's await it.
await _drop(items)

items_dropped.emit(items)


## Finds the nearest [Drop2D] or [Drop3D] node.
## [br]This could be useful in a world-partitioned scenario (like open world rpgs).
func find_nearest_drop() -> Node:
var owner_node = owning_node

if owner_node == null:
return null

# gets all dropzones
var dropzones = get_tree().get_nodes_in_group("ggs.drop-node").duplicate()
var position = owner_node.position
var is_2d = (owner_node as Node2D) != null
var is_3d = (owner_node as Node3D) != null

if dropzones.size() == 0:
return null


# the sorting function, we will take the nearest [Drop2D] or [Drop3D] node.
dropzones.sort_custom(func (a: Variant, b: Variant) -> bool:
if a is Node2D and b is Node2D and is_2d:
return b.position.distance_to(position) > a.position.distance_to(position)
elif a is Node3D and b is Node3D and is_3d:
return b.position.distance_to(position) > a.position.distance_to(position)

return false
)

return dropzones[0]

12 changes: 12 additions & 0 deletions addons/godot_gameplay_systems/inventory_system/nodes/drop_2d.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class_name Drop2D extends Node2D


## Is a drop zone in a 2D world


# Emitted when items are dropped in this node.
signal item_dropped(item: Item, node: Node2D)


func _ready() -> void:
add_to_group("ggs.drop-node")
11 changes: 11 additions & 0 deletions addons/godot_gameplay_systems/inventory_system/nodes/drop_3d.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class_name Drop3D extends Node3D

## Is a drop zone in a 3D world


# Emitted when items are dropped in this node.
signal item_dropped(item: Item, node: Node3D)


func _ready() -> void:
add_to_group("ggs.drop-node")
15 changes: 15 additions & 0 deletions addons/godot_gameplay_systems/inventory_system/plugin.gd
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,20 @@ const item_script = preload("res://addons/godot_gameplay_systems/inventory_syste
const item_activation_event_script = preload("res://addons/godot_gameplay_systems/inventory_system/objects/item_activation_event.gd")
const pickable_item_2d = preload("res://addons/godot_gameplay_systems/inventory_system/nodes/pickable_item_2d.gd")
const pickable_item_3d = preload("res://addons/godot_gameplay_systems/inventory_system/nodes/pickable_item_3d.gd")
const drop_group_script = preload("res://addons/godot_gameplay_systems/inventory_system/resources/drop_group.gd")
const drop_table_script = preload("res://addons/godot_gameplay_systems/inventory_system/resources/drop_table.gd")
const drop_script = preload("res://addons/godot_gameplay_systems/inventory_system/nodes/drop.gd")
const drop_2d_script = preload("res://addons/godot_gameplay_systems/inventory_system/nodes/drop_2d.gd")
const drop_3d_script = preload("res://addons/godot_gameplay_systems/inventory_system/nodes/drop_3d.gd")


func _enter_tree() -> void:
add_custom_type("Item", "Resource", item_script, preload("res://addons/godot_gameplay_systems/inventory_system/assets/ItemIcon.png"))
add_custom_type("Drop", "Node", drop_script, preload("res://addons/godot_gameplay_systems/inventory_system/assets/DropIcon.png"))
add_custom_type("Drop2D", "Node2D", drop_2d_script, preload("res://addons/godot_gameplay_systems/inventory_system/assets/DropNode2D.png"))
add_custom_type("Drop3D", "Node3D", drop_3d_script, preload("res://addons/godot_gameplay_systems/inventory_system/assets/DropNode3D.png"))
add_custom_type("DropGroup", "Resource", drop_group_script, preload("res://addons/godot_gameplay_systems/inventory_system/assets/DropGroupIcon.png"))
add_custom_type("DropTable", "Resource", drop_table_script, preload("res://addons/godot_gameplay_systems/inventory_system/assets/DropTableIcon.png"))
add_custom_type("ItemActivationEvent", "RefCounted", item_activation_event_script, null)
add_custom_type("Inventory", "Node", inventory_script, preload("res://addons/godot_gameplay_systems/inventory_system/assets/InventoryIcon.png"))
add_custom_type("Equipment", "Node", equipment_script, preload("res://addons/godot_gameplay_systems/inventory_system/assets/EquipmentIcon.png"))
Expand All @@ -27,5 +37,10 @@ func _exit_tree() -> void:
remove_custom_type("Equipment")
remove_custom_type("Inventory")
remove_custom_type("ItemActivationEvent")
remove_custom_type("DropTable")
remove_custom_type("DropGroup")
remove_custom_type("Drop")
remove_custom_type("Drop3D")
remove_custom_type("Drop2D")
remove_custom_type("Item")

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class_name DropGroup extends Resource

## Represents a drop rule.
##
##

@export_category("Drop")
## Represents the pool of droppable [Item]s.
@export var items_pool: Array[Item] = []
## Represents the chance of dropping one item from the [member DropGroup.items_pool] pool.
## [br]The higher the value, the higher the chances.
@export_range(0.0, 100.0, 0.01) var drop_chance: float = 50.0


## Returns if the group can drop an item from the [member DropGroup.items_pool] pool.
## [br]It accepts an optional argument [code]drop_modifier[/code] which increases (or decreases if negative) drop chances.
## [br]The greater the modifier, the higher the chances to drop an [Item] from the pool.
func can_be_dropped(modifier: float = 0.0) -> bool:
return drop_chance + modifier >= randf_range(0.0, 100.0)


## Drops an [Item].
## [br]If the drop is unsuccessfull, it returns [code]null[/code].
## [br]It accepts an optional argument [code]drop_modifier[/code] which increases (or decreases if negative) drop chances.
## [br]The greater the modifier, the higher the chances to drop an [Item] from the pool.
func drop(drop_modifier: float = 0.0) -> Item:
if can_be_dropped(drop_modifier):
return items_pool.pick_random()

return null
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class_name DropTable extends Resource

## Represents a drop table.
##
## It has several [DropGroup] pools. Each pool has a chance of dropping one [Item] based on it's [member DropGroup.drop_chance].

@export_category("Drop")
## An array of [DropGroup]. Each pool can drop one item.
@export var pools: Array[DropGroup] = []


## Drops an array of [Item]s.
## [br]It accepts an optional argument [code]drop_modifier[/code] which increases (or decreases if negative) drop chances for each [DropGroup] pool.
## [br]The greater the modifier, the higher the chances to drop [Item]s from the pools.
func drop(drop_modifier: float = 0.0) -> Array[Item]:
var out: Array[Item] = []

for pool in pools:
var maybe_item = pool.drop(drop_modifier)

if maybe_item != null:
out.append(maybe_item)

return out

Loading

0 comments on commit d8bf1d4

Please sign in to comment.