First commit 🎉
This commit is contained in:
commit
43ea213f9b
728 changed files with 37080 additions and 0 deletions
21
addons/popochiu/engine/others/importer_defaults.gd
Normal file
21
addons/popochiu/engine/others/importer_defaults.gd
Normal file
|
@ -0,0 +1,21 @@
|
|||
const PIXEL_TEXTURES := {
|
||||
"compress/bptc_ldr": 0,
|
||||
"compress/hdr_mode": 0,
|
||||
"compress/lossy_quality": 0.7,
|
||||
"compress/mode": 0,
|
||||
"compress/normal_map": 0,
|
||||
"detect_3d": false,
|
||||
"flags/anisotropic": false,
|
||||
"flags/filter": false,
|
||||
"flags/mipmaps": false,
|
||||
"flags/repeat": 0,
|
||||
"flags/srgb": 2,
|
||||
"process/HDR_as_SRGB": false,
|
||||
"process/fix_alpha_border": true,
|
||||
"process/invert_color": false,
|
||||
"process/normal_map_invert_y": false,
|
||||
"process/premult_alpha": false,
|
||||
"size_limit": 0,
|
||||
"stream": false,
|
||||
"svg/scale": 1.0
|
||||
}
|
1
addons/popochiu/engine/others/importer_defaults.gd.uid
Normal file
1
addons/popochiu/engine/others/importer_defaults.gd.uid
Normal file
|
@ -0,0 +1 @@
|
|||
uid://h4w3kyc0qcwx
|
17
addons/popochiu/engine/others/input_actions.gd
Normal file
17
addons/popochiu/engine/others/input_actions.gd
Normal file
|
@ -0,0 +1,17 @@
|
|||
const INTERACT := 'popochiu-interact'
|
||||
const LOOK := 'popochiu-look'
|
||||
const SKIP := 'popochiu-skip'
|
||||
const ACTIONS := [
|
||||
{
|
||||
name = INTERACT,
|
||||
button = MOUSE_BUTTON_LEFT
|
||||
},
|
||||
{
|
||||
name = LOOK,
|
||||
button = MOUSE_BUTTON_RIGHT
|
||||
},
|
||||
{
|
||||
name = SKIP,
|
||||
key = KEY_ESCAPE
|
||||
}
|
||||
]
|
1
addons/popochiu/engine/others/input_actions.gd.uid
Normal file
1
addons/popochiu/engine/others/input_actions.gd.uid
Normal file
|
@ -0,0 +1 @@
|
|||
uid://c5mlt1q8rt2o4
|
6
addons/popochiu/engine/others/popochiu_gui_info.gd
Normal file
6
addons/popochiu/engine/others/popochiu_gui_info.gd
Normal file
|
@ -0,0 +1,6 @@
|
|||
class_name PopochiuGUIInfo
|
||||
extends Resource
|
||||
|
||||
@export var title := ""
|
||||
@export_multiline var description := ""
|
||||
@export var icon: Texture
|
1
addons/popochiu/engine/others/popochiu_gui_info.gd.uid
Normal file
1
addons/popochiu/engine/others/popochiu_gui_info.gd.uid
Normal file
|
@ -0,0 +1 @@
|
|||
uid://dhfh58iawcbav
|
228
addons/popochiu/engine/others/popochiu_save_load.gd
Normal file
228
addons/popochiu/engine/others/popochiu_save_load.gd
Normal file
|
@ -0,0 +1,228 @@
|
|||
class_name PopochiuSaveLoad
|
||||
extends Resource
|
||||
## Class that allows to save and load game data.
|
||||
##
|
||||
## Thanks GDQuest for this! ↴↴↴
|
||||
## https://github.com/GDQuest/godot-demos-2022/tree/main/save-game
|
||||
|
||||
# TODO: This could be in PopochiuSettings for devs to change the path
|
||||
const SAVE_GAME_PATH := "user://save_%d.json"
|
||||
|
||||
|
||||
#region Public #####################################################################################
|
||||
func count_saves() -> int:
|
||||
var saves := 0
|
||||
|
||||
for i in range(1, 5):
|
||||
if FileAccess.file_exists(SAVE_GAME_PATH % i):
|
||||
saves += 1
|
||||
|
||||
return saves
|
||||
|
||||
|
||||
func get_saves_descriptions() -> Dictionary:
|
||||
var saves := {}
|
||||
|
||||
for i in range(1, 5):
|
||||
if FileAccess.file_exists(SAVE_GAME_PATH % i):
|
||||
var opened := FileAccess.open(SAVE_GAME_PATH % i, FileAccess.READ)
|
||||
if not opened:
|
||||
PopochiuUtils.print_error(
|
||||
"Could not open the file %s. Error code: %s" % [
|
||||
SAVE_GAME_PATH % i, opened.get_open_error()
|
||||
]
|
||||
)
|
||||
return {}
|
||||
|
||||
var content := opened.get_as_text()
|
||||
opened.close()
|
||||
|
||||
var test_json_conv = JSON.new()
|
||||
test_json_conv.parse(content)
|
||||
|
||||
if test_json_conv.data == null: continue
|
||||
|
||||
var loaded_data: Dictionary = test_json_conv.data
|
||||
|
||||
saves[i] = loaded_data.description
|
||||
|
||||
return saves
|
||||
|
||||
|
||||
func save_game(slot := 1, description := "") -> bool:
|
||||
var opened := FileAccess.open(SAVE_GAME_PATH % slot, FileAccess.WRITE)
|
||||
if not opened:
|
||||
PopochiuUtils.print_error(
|
||||
"Could not open the file %s. Error code: %s" % [
|
||||
SAVE_GAME_PATH % slot, opened.get_open_error()
|
||||
]
|
||||
)
|
||||
return false
|
||||
|
||||
var data := {
|
||||
description = description,
|
||||
player = {
|
||||
room = PopochiuUtils.r.current.script_name,
|
||||
inventory = PopochiuUtils.i.items,
|
||||
},
|
||||
rooms = {}, # Stores the state of each PopochiuRoomData
|
||||
characters = {}, # Stores the state of each PopochiuCharacterData
|
||||
inventory_items = {}, # Stores the state of each PopochiuInventoryItemData
|
||||
dialogs = {}, # Stores the state of each PopochiuDialog
|
||||
globals = {}, # Stores the state of Globals
|
||||
}
|
||||
|
||||
if PopochiuUtils.c.player:
|
||||
data.player.id = PopochiuUtils.c.player.script_name
|
||||
data.player.position = {
|
||||
x = PopochiuUtils.c.player.global_position.x,
|
||||
y = PopochiuUtils.c.player.global_position.y
|
||||
}
|
||||
|
||||
# Go over each Popochiu type to save its current state -----------------------------------------
|
||||
for type in ["rooms", "characters", "inventory_items", "dialogs"]:
|
||||
_store_data(type, data)
|
||||
|
||||
# Save PopochiuGlobals.gd (Globals) ------------------------------------------------------------
|
||||
# prop = {class_name, hint, hint_string, name, type, usage}
|
||||
for prop in PopochiuUtils.globals.get_script().get_script_property_list():
|
||||
if not prop.type in PopochiuResources.VALID_TYPES: continue
|
||||
|
||||
# Check if the property is a script variable (8192)
|
||||
# or a export variable (8199)
|
||||
if prop.usage == PROPERTY_USAGE_SCRIPT_VARIABLE or prop.usage == (
|
||||
PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
|
||||
):
|
||||
data.globals[prop.name] = PopochiuUtils.globals[prop.name]
|
||||
|
||||
if PopochiuUtils.globals.has_method("on_save"):
|
||||
data.globals.custom_data = PopochiuUtils.globals.on_save()
|
||||
|
||||
if data.globals.is_empty(): data.erase("globals")
|
||||
|
||||
# Write the JSON -------------------------------------------------------------------------------
|
||||
var json_string := JSON.stringify(data)
|
||||
opened.store_string(json_string)
|
||||
opened.close()
|
||||
|
||||
return true
|
||||
|
||||
|
||||
func load_game(slot := 1) -> Dictionary:
|
||||
var opened := FileAccess.open(SAVE_GAME_PATH % slot, FileAccess.READ)
|
||||
if not opened:
|
||||
PopochiuUtils.print_error(
|
||||
"Could not open the file %s. Error code: %s" % [
|
||||
SAVE_GAME_PATH % slot, opened.get_open_error()
|
||||
]
|
||||
)
|
||||
return {}
|
||||
|
||||
var content := opened.get_as_text()
|
||||
opened.close()
|
||||
|
||||
var test_json_conv = JSON.new()
|
||||
test_json_conv.parse(content)
|
||||
var loaded_data: Dictionary = test_json_conv.data
|
||||
|
||||
# Load inventory items
|
||||
for item in loaded_data.player.inventory:
|
||||
PopochiuUtils.i.get_item_instance(item).add(false)
|
||||
|
||||
# Load main object states
|
||||
for type in ["rooms", "characters", "inventory_items", "dialogs"]:
|
||||
if loaded_data.has(type):
|
||||
_load_state(type, loaded_data)
|
||||
|
||||
# Load globals
|
||||
if loaded_data.has("globals"):
|
||||
for prop in loaded_data.globals:
|
||||
if typeof(PopochiuUtils.globals.get(prop)) == TYPE_NIL: continue
|
||||
|
||||
PopochiuUtils.globals[prop] = loaded_data.globals[prop]
|
||||
|
||||
if loaded_data.globals.has("custom_data")\
|
||||
and PopochiuUtils.globals.has_method("on_load"):
|
||||
PopochiuUtils.globals.on_load(loaded_data.globals.custom_data)
|
||||
|
||||
return loaded_data
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private ####################################################################################
|
||||
func _store_data(type: String, save: Dictionary) -> void:
|
||||
for path in PopochiuResources.get_section(type):
|
||||
# load the ___State.tres file
|
||||
var data := load(path)
|
||||
|
||||
save[type][data.script_name] = {}
|
||||
|
||||
PopochiuResources.store_properties(save[type][data.script_name], data)
|
||||
|
||||
match type:
|
||||
"rooms":
|
||||
data.save_children_states()
|
||||
|
||||
for category in PopochiuResources.ROOM_CHILDREN:
|
||||
save[type][data.script_name][category] = data[category]
|
||||
|
||||
save[type][data.script_name]["characters"] = data.characters
|
||||
"dialogs":
|
||||
save[type][data.script_name].options = {}
|
||||
|
||||
for opt in (data as PopochiuDialog).options:
|
||||
save[type][data.script_name].options[opt.id] = {}
|
||||
PopochiuResources.store_properties(
|
||||
save[type][data.script_name].options[opt.id],
|
||||
opt,
|
||||
["id", "always_on"]
|
||||
)
|
||||
|
||||
if save[type][data.script_name].is_empty():
|
||||
save[type].erase(data.script_name)
|
||||
|
||||
if save[type].is_empty():
|
||||
save.erase(type)
|
||||
|
||||
|
||||
func _load_state(type: String, loaded_game: Dictionary) -> void:
|
||||
for id in loaded_game[type]:
|
||||
var state := load(PopochiuResources.get_data_value(type, id, ""))
|
||||
|
||||
for p in loaded_game[type][id]:
|
||||
if p == "custom_data": continue
|
||||
if type == "dialogs" and p == "options": continue
|
||||
|
||||
state[p] = loaded_game[type][id][p]
|
||||
|
||||
match type:
|
||||
"rooms":
|
||||
PopochiuUtils.r.rooms_states[id] = state
|
||||
"characters":
|
||||
PopochiuUtils.c.characters_states[id] = state
|
||||
"inventory_items":
|
||||
PopochiuUtils.i.items_states[id] = state
|
||||
"dialogs":
|
||||
PopochiuUtils.d.trees[id] = state
|
||||
_load_dialog_options(state, loaded_game[type][id].options)
|
||||
|
||||
if loaded_game[type][id].has("custom_data")\
|
||||
and state.has_method("on_load"):
|
||||
state.on_load(loaded_game[type][id].custom_data)
|
||||
|
||||
|
||||
func _load_dialog_options(
|
||||
dialog: PopochiuDialog, loaded_options: Dictionary
|
||||
) -> void:
|
||||
for opt in dialog.options:
|
||||
if not loaded_options.has(opt.id): continue
|
||||
|
||||
for prop in opt.get_script().get_script_property_list():
|
||||
if prop.name == "always_on": continue
|
||||
|
||||
if loaded_options[opt.id].has(prop.name):
|
||||
opt[prop.name] = loaded_options[opt.id][prop.name]
|
||||
|
||||
|
||||
#endregion
|
1
addons/popochiu/engine/others/popochiu_save_load.gd.uid
Normal file
1
addons/popochiu/engine/others/popochiu_save_load.gd.uid
Normal file
|
@ -0,0 +1 @@
|
|||
uid://pg6efyy78l0n
|
220
addons/popochiu/engine/others/popochiu_utils.gd
Normal file
220
addons/popochiu/engine/others/popochiu_utils.gd
Normal file
|
@ -0,0 +1,220 @@
|
|||
@tool
|
||||
class_name PopochiuUtils
|
||||
extends Node
|
||||
## Utility functions for Popochiu.
|
||||
|
||||
static var e: Popochiu = null:
|
||||
get = get_popochiu
|
||||
static var r: PopochiuIRoom = null:
|
||||
get = get_iroom
|
||||
static var c: PopochiuICharacter = null:
|
||||
get = get_icharacter
|
||||
static var i: PopochiuIInventory = null:
|
||||
get = get_iinventory
|
||||
static var d: PopochiuIDialog = null:
|
||||
get = get_idialog
|
||||
static var a: PopochiuIAudio = null:
|
||||
get = get_iaudio
|
||||
static var g: PopochiuIGraphicInterface = null:
|
||||
get = get_igraphic_interface
|
||||
static var cursor: PopochiuCursor = null:
|
||||
get = get_popochiu_cursor
|
||||
static var globals: Node = null:
|
||||
get = get_popochiu_globals
|
||||
|
||||
|
||||
#region Public #####################################################################################
|
||||
## Used by the GUI to get the position of [param node] in the scene transformed to the space of the
|
||||
## [CanvasLayer] where it is is rendered.
|
||||
static func get_screen_coords_for(node: Node, offset: Vector2 = Vector2.ZERO) -> Vector2:
|
||||
return node.get_viewport().canvas_transform * (node.get_global_position() + offset)
|
||||
|
||||
|
||||
## Gets a random index from [param array].
|
||||
static func get_random_array_idx(array: Array) -> int:
|
||||
randomize()
|
||||
var idx := randi() % array.size()
|
||||
|
||||
return idx
|
||||
|
||||
|
||||
## Compares the name of files [param a] and [param b] to check which one comes first in alphabetical
|
||||
## order.
|
||||
static func sort_by_file_name(a: String, b: String) -> bool:
|
||||
if a.get_file() < b.get_file():
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
## Overrides the font [param font_name] in [param node] by [param font].
|
||||
static func override_font(node: Control, font_name: String, font: Font) -> void:
|
||||
node.add_theme_font_override(font_name, font)
|
||||
|
||||
|
||||
## Prints [param msg] with Popochiu's error style.
|
||||
static func print_error(msg: String) -> void:
|
||||
print_rich("[bgcolor=c46c71][color=ffffff][b][Popochiu][/b] %s[/color][/bgcolor]" % msg)
|
||||
|
||||
|
||||
## Prints [param msg] with Popochiu's warning style.
|
||||
static func print_warning(msg: String) -> void:
|
||||
print_rich("[bgcolor=edf171][color=000000][b][Popochiu][/b] %s[/color][/bgcolor]" % msg)
|
||||
|
||||
|
||||
## Prints [param msg] with Popochiu's normal style.
|
||||
static func print_normal(msg: String) -> void:
|
||||
print_rich("[bgcolor=75cec8][color=000000][b][Popochiu][/b] %s[/color][/bgcolor]" % msg)
|
||||
|
||||
|
||||
## Checks if [param event] is an [InputEventMouseButton] or [InputEventScreenTouch] event.
|
||||
static func is_click_or_touch(event: InputEvent) -> bool:
|
||||
return (event is InputEventMouseButton or event is InputEventScreenTouch)
|
||||
|
||||
|
||||
## Checks if [param event] is an [InputEventMouseButton] with [member InputEventMouseButton.double_click]
|
||||
## as [code]true[/code], or an [InputEventScreenTouch] with [member InputEventScreenTouch.double_tap].
|
||||
## as [code]true[/code].
|
||||
static func is_double_click_or_double_tap(event: InputEvent) -> bool:
|
||||
return (
|
||||
(event is InputEventMouseButton and event.double_click)
|
||||
or (event is InputEventScreenTouch and not event.double_tap)
|
||||
)
|
||||
|
||||
|
||||
## Checks if [param event] is an [InputEventMouseButton] or [InputEventScreenTouch] event and if
|
||||
## it is pressed.
|
||||
static func is_click_or_touch_pressed(event: InputEvent) -> bool:
|
||||
# Fix #183 by including `event is InputEventScreenTouch` validation
|
||||
return is_click_or_touch(event) and event.pressed
|
||||
|
||||
|
||||
## Returns the index of [param event] when it is an [InputEventMouseButton] or
|
||||
## [InputEventScreenTouch] event. For a click, [member InputEventMouseButton.button_index] is
|
||||
## returned. For a touch, [member InputEventScreenTouch.index] is returned. Returns [code]0[/code]
|
||||
## if the event isn't pressed or is not neither a click or a touch.
|
||||
static func get_click_or_touch_index(event: InputEvent) -> int:
|
||||
var index := 0
|
||||
|
||||
if is_click_or_touch_pressed(event):
|
||||
if event is InputEventMouseButton:
|
||||
index = event.button_index
|
||||
elif event is InputEventScreenTouch:
|
||||
index = event.index
|
||||
|
||||
return index
|
||||
|
||||
|
||||
## For each element in [param array] calls [param callback] passing the element as a parameter. If
|
||||
## any of the calls returns [code]true[/code], then this function returns [code]true[/code],
|
||||
## otherwise [code]false[/code] is returned.[br][br]
|
||||
## This is an alternate version for [method Array.any] that doesn't stops execution even when one
|
||||
## of the results is [code]true[/code].
|
||||
static func any_exhaustive(array: Array, callback: Callable) -> bool:
|
||||
var any_updated := false
|
||||
for element in array:
|
||||
var updated: bool = callback.call(element)
|
||||
if updated:
|
||||
any_updated = true
|
||||
return any_updated
|
||||
|
||||
|
||||
## Returns a [Vector2] with the values of [param source]. If it is a [String], it will be unpacked
|
||||
## using a regular expression. If it is a [Dictionary], it's [code]x[/code] and [code]y[/code] keys
|
||||
## will be used. If it is a [Vector2], it will be returned as is. Otherwise [constant Vector2.ZERO]
|
||||
## is returned.
|
||||
static func unpack_vector_2(source) -> Vector2:
|
||||
if source is Dictionary:
|
||||
return Vector2(source.x, source.y)
|
||||
elif source is String:
|
||||
var regex = RegEx.new()
|
||||
regex.compile(r'(Vector2\(|\()\s*(?<x>-?\d+)\s*,\s*(?<y>-?\d+)\s*\)')
|
||||
var result := regex.search(source)
|
||||
if result:
|
||||
return Vector2(float(result.get_string("x")), float(result.get_string("y")))
|
||||
elif source is Vector2:
|
||||
return source
|
||||
return Vector2.ZERO
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region SetGet #####################################################################################
|
||||
static func get_popochiu() -> Popochiu:
|
||||
if not is_instance_valid(e):
|
||||
if Engine.get_singleton(&"E"):
|
||||
e = Engine.get_singleton(&"E")
|
||||
else:
|
||||
e = Popochiu.new()
|
||||
return e
|
||||
|
||||
|
||||
static func get_iroom() -> PopochiuIRoom:
|
||||
if not is_instance_valid(r):
|
||||
if Engine.get_singleton(&"R"):
|
||||
r = Engine.get_singleton(&"R")
|
||||
else:
|
||||
r = PopochiuIRoom.new()
|
||||
return r
|
||||
|
||||
|
||||
static func get_icharacter() -> PopochiuICharacter:
|
||||
if not is_instance_valid(c):
|
||||
if Engine.get_singleton(&"C"):
|
||||
c = Engine.get_singleton(&"C")
|
||||
else:
|
||||
c = PopochiuICharacter.new()
|
||||
return c
|
||||
|
||||
|
||||
static func get_iinventory() -> PopochiuIInventory:
|
||||
if not is_instance_valid(i):
|
||||
if Engine.get_singleton(&"I"):
|
||||
i = Engine.get_singleton(&"I")
|
||||
else:
|
||||
i = PopochiuIInventory.new()
|
||||
return i
|
||||
|
||||
|
||||
static func get_idialog() -> PopochiuIDialog:
|
||||
if not is_instance_valid(d):
|
||||
if Engine.get_singleton(&"D"):
|
||||
d = Engine.get_singleton(&"D")
|
||||
else:
|
||||
d = PopochiuIDialog.new()
|
||||
return d
|
||||
|
||||
|
||||
static func get_iaudio() -> PopochiuIAudio:
|
||||
if not is_instance_valid(a):
|
||||
if Engine.get_singleton(&"A"):
|
||||
a = Engine.get_singleton(&"A")
|
||||
else:
|
||||
a = PopochiuIAudio.new()
|
||||
return a
|
||||
|
||||
|
||||
static func get_igraphic_interface() -> PopochiuIGraphicInterface:
|
||||
if not is_instance_valid(g):
|
||||
if Engine.get_singleton(&"G"):
|
||||
g = Engine.get_singleton(&"G")
|
||||
else:
|
||||
g = PopochiuIGraphicInterface.new()
|
||||
return g
|
||||
|
||||
|
||||
static func get_popochiu_cursor() -> PopochiuCursor:
|
||||
if not is_instance_valid(cursor):
|
||||
if Engine.get_singleton(&"Cursor"):
|
||||
cursor = Engine.get_singleton(&"Cursor")
|
||||
else:
|
||||
cursor = PopochiuCursor.new()
|
||||
return cursor
|
||||
|
||||
|
||||
static func get_popochiu_globals() -> Node:
|
||||
if not is_instance_valid(globals):
|
||||
globals = e.get_node("/root/Globals")
|
||||
return globals
|
||||
|
||||
|
||||
#endregion
|
1
addons/popochiu/engine/others/popochiu_utils.gd.uid
Normal file
1
addons/popochiu/engine/others/popochiu_utils.gd.uid
Normal file
|
@ -0,0 +1 @@
|
|||
uid://bk6ljlgyqucql
|
Loading…
Add table
Add a link
Reference in a new issue