Compare commits
4 Commits
better-mcp
...
35c2887011
| Author | SHA1 | Date | |
|---|---|---|---|
| 35c2887011 | |||
| 5b2670f08c | |||
| 8661fbad15 | |||
| 975b51a2b5 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "kq4-sierra-decompile"]
|
||||
path = kq4-sierra-decompile
|
||||
url = ssh://raspberrypi/~/git/sierra-decompile
|
||||
[submodule "godot-mcp"]
|
||||
path = godot-mcp
|
||||
url = https://github.com/tugcantopaloglu/godot-mcp
|
||||
|
||||
281
.opencode/package-lock.json
generated
281
.opencode/package-lock.json
generated
@@ -5,100 +5,21 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@opencode-ai/plugin": "1.14.27"
|
||||
"@opencode-ai/plugin": "1.3.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
|
||||
"integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz",
|
||||
"integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz",
|
||||
"integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz",
|
||||
"integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz",
|
||||
"integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz",
|
||||
"integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@opencode-ai/plugin": {
|
||||
"version": "1.14.27",
|
||||
"resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.14.27.tgz",
|
||||
"integrity": "sha512-8J8JkrInF5oWaR2rsLuwQktdF9Yq3xoyA8B42/B8Te74/q4rqOt7YzWK2I/ZSxvKA/Ct+iQ8f2OeUrpQ2INgSw==",
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@opencode-ai/plugin/-/plugin-1.3.14.tgz",
|
||||
"integrity": "sha512-dIEko9B4KytL1pABotkSw2Rm3/BKXb+5Z4g4c/aXjVd2cu86UIsFz8orgMB4zsQOa0bECzESaQzHOKTn3gMEMw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@opencode-ai/sdk": "1.14.27",
|
||||
"effect": "4.0.0-beta.48",
|
||||
"@opencode-ai/sdk": "1.3.14",
|
||||
"zod": "4.1.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentui/core": ">=0.1.105",
|
||||
"@opentui/solid": ">=0.1.105"
|
||||
"@opentui/core": ">=0.1.96",
|
||||
"@opentui/solid": ">=0.1.96"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@opentui/core": {
|
||||
@@ -110,20 +31,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@opencode-ai/sdk": {
|
||||
"version": "1.14.27",
|
||||
"resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.14.27.tgz",
|
||||
"integrity": "sha512-mpzDFDAGi+8wKEcm4aP0HVtS56rN/q2hVs8Ai6JziPu7NuTMddfFoEvddArYsgkRWUfHL5ypZc1mDmAMEiO1vg==",
|
||||
"version": "1.3.14",
|
||||
"resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.3.14.tgz",
|
||||
"integrity": "sha512-8sNOFYB86d3b2KiIiL6wtio4V9U0mKEiJAlehzuaigZWiZMsI11Gq1Fdq+tIf9RWNQNsZSMYFuofLabPWQs7qA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cross-spawn": "7.0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@standard-schema/spec": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
||||
"integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@@ -138,135 +53,12 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/effect": {
|
||||
"version": "4.0.0-beta.48",
|
||||
"resolved": "https://registry.npmjs.org/effect/-/effect-4.0.0-beta.48.tgz",
|
||||
"integrity": "sha512-MMAM/ZabuNdNmgXiin+BAanQXK7qM8mlt7nfXDoJ/Gn9V8i89JlCq+2N0AiWmqFLXjGLA0u3FjiOjSOYQk5uMw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"fast-check": "^4.6.0",
|
||||
"find-my-way-ts": "^0.1.6",
|
||||
"ini": "^6.0.0",
|
||||
"kubernetes-types": "^1.30.0",
|
||||
"msgpackr": "^1.11.9",
|
||||
"multipasta": "^0.2.7",
|
||||
"toml": "^4.1.1",
|
||||
"uuid": "^13.0.0",
|
||||
"yaml": "^2.8.3"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-check": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.7.0.tgz",
|
||||
"integrity": "sha512-NsZRtqvSSoCP0HbNjUD+r1JH8zqZalyp6gLY9e7OYs7NK9b6AHOs2baBFeBG7bVNsuoukh89x2Yg3rPsul8ziQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/dubzzz"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fast-check"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pure-rand": "^8.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/find-my-way-ts": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/find-my-way-ts/-/find-my-way-ts-0.1.6.tgz",
|
||||
"integrity": "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ini": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz",
|
||||
"integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/kubernetes-types": {
|
||||
"version": "1.30.0",
|
||||
"resolved": "https://registry.npmjs.org/kubernetes-types/-/kubernetes-types-1.30.0.tgz",
|
||||
"integrity": "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/msgpackr": {
|
||||
"version": "1.11.10",
|
||||
"resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.10.tgz",
|
||||
"integrity": "sha512-iCZNq+HszvF+fC3anCm4nBmWEnbeIAfpDs6IStAEKhQ2YSgkjzVG2FF9XJqwwQh5bH3N9OUTUt4QwVN6MLMLtA==",
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"msgpackr-extract": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/msgpackr-extract": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz",
|
||||
"integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build-optional-packages": "5.2.2"
|
||||
},
|
||||
"bin": {
|
||||
"download-msgpackr-prebuilds": "bin/download-prebuilds.js"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
|
||||
"@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
|
||||
"@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/multipasta": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/multipasta/-/multipasta-0.2.7.tgz",
|
||||
"integrity": "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-gyp-build-optional-packages": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
|
||||
"integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"node-gyp-build-optional-packages": "bin.js",
|
||||
"node-gyp-build-optional-packages-optional": "optional.js",
|
||||
"node-gyp-build-optional-packages-test": "build-test.js"
|
||||
}
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
@@ -276,22 +68,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pure-rand": {
|
||||
"version": "8.4.0",
|
||||
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.0.tgz",
|
||||
"integrity": "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/dubzzz"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/fast-check"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
@@ -313,28 +89,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/toml": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/toml/-/toml-4.1.1.tgz",
|
||||
"integrity": "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz",
|
||||
"integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist-node/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
@@ -350,21 +104,6 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
|
||||
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/eemeli"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "4.1.8",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extends Node
|
||||
|
||||
enum Action { WALK = 0, LOOK = 1, TOUCH = 2, TALK = 3 }
|
||||
enum Action { WALK = 0, LOOK = 1, TOUCH = 2, TALK = 3, ITEM = 4 }
|
||||
|
||||
var current_action: int = Action.WALK:
|
||||
set(value):
|
||||
@@ -22,6 +22,7 @@ func get_action_name() -> String:
|
||||
Action.LOOK: return "look"
|
||||
Action.TOUCH: return "touch"
|
||||
Action.TALK: return "talk"
|
||||
Action.ITEM: return "item"
|
||||
return "walk"
|
||||
|
||||
func get_action_enum() -> int:
|
||||
|
||||
@@ -476,5 +476,54 @@ func switch_camera(path):
|
||||
func reset_camera():
|
||||
var thing = ResetCamera.new()
|
||||
return thing
|
||||
|
||||
class GiveItem:
|
||||
extends ScriptNode
|
||||
var item_id: String = ""
|
||||
var text: String = ""
|
||||
var subject: Node2D = null
|
||||
var done = false
|
||||
var started = false
|
||||
|
||||
func step_type():
|
||||
return "GiveItem " + item_id
|
||||
|
||||
func init(scene):
|
||||
super(scene)
|
||||
|
||||
func do(delta):
|
||||
if not started:
|
||||
started = true
|
||||
if text:
|
||||
await scene.find_child("dialogue").say(text)
|
||||
InventoryManager.acquire_item(item_id)
|
||||
done = true
|
||||
|
||||
func is_done():
|
||||
return done
|
||||
|
||||
func interrupt():
|
||||
done = true
|
||||
|
||||
class GiveItemDeferred:
|
||||
extends GiveItem
|
||||
var subject_name: String = ""
|
||||
|
||||
func init(scene):
|
||||
super(scene)
|
||||
subject = scene.get_node(subject_name)
|
||||
|
||||
func give_item(item_id: String, text: String = ""):
|
||||
var step = GiveItem.new()
|
||||
step.item_id = item_id
|
||||
step.text = text
|
||||
return step
|
||||
|
||||
func give_item_deferred(item_id: String, subject_name: String, text: String = ""):
|
||||
var step = GiveItemDeferred.new()
|
||||
step.item_id = item_id
|
||||
step.subject_name = subject_name
|
||||
step.text = text
|
||||
return step
|
||||
|
||||
var current_script : ScriptGraph = null
|
||||
|
||||
14
MainGame.gd
14
MainGame.gd
@@ -78,5 +78,15 @@ func _input(event):
|
||||
if event.is_action_released("quit"):
|
||||
get_tree().quit()
|
||||
if event.is_action_released("right_click") and not is_cursor_locked:
|
||||
ActionState.current_action = (ActionState.current_action + 1) % 4
|
||||
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
|
||||
var prev_action = ActionState.current_action
|
||||
ActionState.current_action = (ActionState.current_action + 1) % 5
|
||||
if ActionState.current_action == ActionState.Action.ITEM:
|
||||
if InventoryManager.selected_item:
|
||||
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
|
||||
else:
|
||||
ActionState.current_action = (ActionState.current_action + 1) % 5
|
||||
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
|
||||
else:
|
||||
if prev_action == ActionState.Action.ITEM:
|
||||
InventoryManager.clear_selection()
|
||||
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
|
||||
|
||||
46
Scene.gd
46
Scene.gd
@@ -128,7 +128,12 @@ func _unhandled_input(event):
|
||||
if ScriptBuilder.current_script and not ScriptBuilder.current_script.can_interrupt:
|
||||
if ScriptBuilder.current_script.handle_input(event):
|
||||
return
|
||||
|
||||
|
||||
# Block input when inventory overlay is active
|
||||
var overlay = get_node_or_null("/root/Node2D/InventoryOverlay")
|
||||
if overlay and overlay is InventoryOverlay and overlay.is_active():
|
||||
return
|
||||
|
||||
var root = get_node("/root/Node2D")
|
||||
# If look cursor is active and we got here, no SetPiece handled the input
|
||||
# so this is a room-wide look
|
||||
@@ -138,7 +143,46 @@ func _unhandled_input(event):
|
||||
if ActionState.current_action == ActionState.Action.WALK:
|
||||
var path = NavigationServer2D.map_get_path(map, ego.position, pathfind.to_local(get_global_mouse_position()), true)
|
||||
start_main_script(ScriptBuilder.init(ScriptBuilder.walk_path(ego, path)).can_interrupt().build(self, "_on_script_complete"))
|
||||
if ActionState.current_action == ActionState.Action.ITEM:
|
||||
_on_item_use_in_world()
|
||||
|
||||
func _on_room_looked() -> void:
|
||||
# Default room look description - override in room scripts
|
||||
pass
|
||||
|
||||
func _on_item_use_in_world() -> void:
|
||||
if not InventoryManager.selected_item:
|
||||
return
|
||||
var item_id = InventoryManager.selected_item
|
||||
var top_piece = ActionState.get_top_hovered_setpiece()
|
||||
if top_piece:
|
||||
_use_item_on_setpiece(item_id, top_piece)
|
||||
else:
|
||||
_on_item_used_empty_space(item_id)
|
||||
|
||||
func _use_item_on_setpiece(item_id: String, piece: SetPiece) -> void:
|
||||
if piece.has_method("_on_item_used"):
|
||||
piece._on_item_used(item_id)
|
||||
else:
|
||||
var def = InventoryManager.get_item_definition(item_id)
|
||||
var item_name = item_id
|
||||
if def:
|
||||
item_name = def.name
|
||||
var piece_name = piece.label if piece.label else piece.name
|
||||
start_main_script(ScriptBuilder.init(ScriptBuilder.say(ego, "I can't use the %s on the %s." % [item_name, piece_name])).build(self, "_on_script_complete"))
|
||||
|
||||
func _on_item_used_empty_space(item_id: String) -> void:
|
||||
var def = InventoryManager.get_item_definition(item_id)
|
||||
var item_name = item_id
|
||||
if def:
|
||||
item_name = def.name
|
||||
start_main_script(ScriptBuilder.init(ScriptBuilder.say(ego, "There's nothing to use the %s on here." % [item_name])).build(self, "_on_script_complete"))
|
||||
|
||||
func give_item(item_id: String) -> void:
|
||||
InventoryManager.acquire_item(item_id)
|
||||
|
||||
func remove_item(item_id: String, quiet: bool = false) -> void:
|
||||
InventoryManager.remove_item(item_id, quiet)
|
||||
|
||||
func strip_items(event_items: Array[String], exempt_items: Array[String] = []) -> void:
|
||||
InventoryManager.bulk_strip_items(event_items, exempt_items)
|
||||
|
||||
@@ -75,3 +75,9 @@ func _input(event):
|
||||
ActionState.Action.TALK:
|
||||
if talked.get_connections().size() > 0:
|
||||
emit_signal("talked")
|
||||
ActionState.Action.ITEM:
|
||||
if InventoryManager.selected_item:
|
||||
var item_id = InventoryManager.selected_item
|
||||
var scene = get_node_or_null("/root/Node2D/SceneViewport/background")
|
||||
if scene and scene is Scene:
|
||||
scene._use_item_on_setpiece(item_id, self)
|
||||
|
||||
Submodule godot-mcp deleted from b77dfc7c62
101
inventory/InventoryManager.gd
Normal file
101
inventory/InventoryManager.gd
Normal file
@@ -0,0 +1,101 @@
|
||||
extends Node
|
||||
|
||||
# Signals
|
||||
signal item_acquired(item_id: String)
|
||||
signal item_removed(item_id: String)
|
||||
signal inventory_changed
|
||||
signal combination_attempted(item_a_id: String, item_b_id: String)
|
||||
|
||||
# State
|
||||
var inventory: Array[String] = []
|
||||
var obtained_items: Dictionary = {}
|
||||
var stripped_items: Array[String] = []
|
||||
var selected_item: String = ""
|
||||
|
||||
# Item definitions registry
|
||||
var _item_definitions: Dictionary = {}
|
||||
|
||||
|
||||
# -- Queries --
|
||||
|
||||
func has_item(item_id: String) -> bool:
|
||||
return inventory.has(item_id)
|
||||
|
||||
func has_obtained(item_id: String) -> bool:
|
||||
return obtained_items.has(item_id)
|
||||
|
||||
func has_any_of(item_ids: Array[String]) -> bool:
|
||||
if item_ids.is_empty():
|
||||
return false
|
||||
for item_id in item_ids:
|
||||
if has_item(item_id):
|
||||
return true
|
||||
return false
|
||||
|
||||
func has_obtained_any_of(item_ids: Array[String]) -> bool:
|
||||
if item_ids.is_empty():
|
||||
return false
|
||||
for item_id in item_ids:
|
||||
if has_obtained(item_id):
|
||||
return true
|
||||
return false
|
||||
|
||||
func has_obtained_all_of(item_ids: Array[String]) -> bool:
|
||||
if item_ids.is_empty():
|
||||
return true
|
||||
for item_id in item_ids:
|
||||
if not has_obtained(item_id):
|
||||
return false
|
||||
return true
|
||||
|
||||
|
||||
# -- Mutations --
|
||||
|
||||
func acquire_item(item_id: String) -> void:
|
||||
inventory.append(item_id)
|
||||
obtained_items[item_id] = true
|
||||
item_acquired.emit(item_id)
|
||||
inventory_changed.emit()
|
||||
|
||||
func remove_item(item_id: String, quiet: bool = false) -> void:
|
||||
var idx = inventory.find(item_id)
|
||||
if idx == -1:
|
||||
return
|
||||
inventory.remove_at(idx)
|
||||
if not quiet:
|
||||
item_removed.emit(item_id)
|
||||
inventory_changed.emit()
|
||||
|
||||
func bulk_strip_items(event_items: Array[String], exempt_items: Array[String] = []) -> void:
|
||||
var remaining: Array[String] = []
|
||||
for item_id in inventory:
|
||||
if event_items.has(item_id) and not exempt_items.has(item_id):
|
||||
stripped_items.append(item_id)
|
||||
else:
|
||||
remaining.append(item_id)
|
||||
inventory = remaining
|
||||
inventory_changed.emit()
|
||||
|
||||
|
||||
# -- Items --
|
||||
|
||||
func register_item(item_def: ItemDefinition) -> void:
|
||||
_item_definitions[item_def.id] = item_def
|
||||
|
||||
func get_item_definition(item_id: String) -> ItemDefinition:
|
||||
return _item_definitions.get(item_id, null)
|
||||
|
||||
|
||||
# -- Combinations --
|
||||
|
||||
func attempt_combine(item_a_id: String, item_b_id: String) -> void:
|
||||
combination_attempted.emit(item_a_id, item_b_id)
|
||||
|
||||
|
||||
# -- Selection --
|
||||
|
||||
func select_item(item_id: String) -> void:
|
||||
selected_item = item_id
|
||||
|
||||
func clear_selection() -> void:
|
||||
selected_item = ""
|
||||
233
inventory/inventory_backpack/InventoryBackpack.gd
Normal file
233
inventory/inventory_backpack/InventoryBackpack.gd
Normal file
@@ -0,0 +1,233 @@
|
||||
extends Control
|
||||
class_name InventoryBackpack
|
||||
|
||||
signal overlay_show_requested
|
||||
signal overlay_hide_requested
|
||||
signal item_selected(item_id: String)
|
||||
signal returning_to_idle
|
||||
signal skip_action_requested
|
||||
|
||||
enum State { IDLE, OPEN, SELECTED, ACQUIRE, REMOVE }
|
||||
|
||||
var _state: State = State.IDLE
|
||||
var _animating: bool = false
|
||||
var _active_tween: Tween = null
|
||||
var _floating_item_color: Color = Color(1, 1, 1, 0)
|
||||
|
||||
@onready var backpack_icon: ColorRect = $BackpackIcon
|
||||
@onready var floating_item: ColorRect = $FloatingItem
|
||||
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
||||
|
||||
func _ready() -> void:
|
||||
floating_item.modulate = Color(1, 1, 1, 0)
|
||||
floating_item.visible = false
|
||||
InventoryManager.item_acquired.connect(_on_item_acquired)
|
||||
InventoryManager.item_removed.connect(_on_item_removed)
|
||||
InventoryManager.inventory_changed.connect(_on_inventory_changed)
|
||||
_update_floating_item()
|
||||
|
||||
func get_state() -> State:
|
||||
return _state
|
||||
|
||||
func is_busy() -> bool:
|
||||
return _animating
|
||||
|
||||
func _update_floating_item() -> void:
|
||||
if InventoryManager.selected_item:
|
||||
var def = InventoryManager.get_item_definition(InventoryManager.selected_item)
|
||||
if def:
|
||||
floating_item.visible = true
|
||||
floating_item.modulate = Color(1, 0.6, 0.2, 1)
|
||||
else:
|
||||
floating_item.visible = true
|
||||
floating_item.modulate = Color(0.8, 0.8, 0.8, 1)
|
||||
else:
|
||||
floating_item.visible = false
|
||||
|
||||
func transition_to(new_state: State) -> void:
|
||||
if _animating and new_state != _state:
|
||||
_kill_tween()
|
||||
match new_state:
|
||||
State.IDLE:
|
||||
_transition_to_idle()
|
||||
State.OPEN:
|
||||
_transition_to_open()
|
||||
State.SELECTED:
|
||||
_transition_to_selected()
|
||||
State.ACQUIRE:
|
||||
_transition_to_acquire()
|
||||
State.REMOVE:
|
||||
_transition_to_remove()
|
||||
|
||||
func _transition_to_idle() -> void:
|
||||
if _state == State.IDLE:
|
||||
return
|
||||
_set_state(State.IDLE)
|
||||
overlay_hide_requested.emit()
|
||||
backpack_icon.modulate = Color(1, 1, 1, 1)
|
||||
floating_item.visible = false
|
||||
|
||||
var tween = create_tween().bind_node(self)
|
||||
_active_tween = tween
|
||||
_animating = true
|
||||
tween.tween_property(backpack_icon, "rotation", 0.0, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||
tween.tween_property(backpack_icon, "position", backpack_icon.position, 0.35).set_trans(Tween.TRANS_SINE_IN)
|
||||
tween.tween_callback(_on_transition_complete).bind(State.IDLE)
|
||||
|
||||
func _transition_to_open() -> void:
|
||||
var can_open = _check_guards()
|
||||
if not can_open:
|
||||
if _state == State.IDLE:
|
||||
skip_action_requested.emit()
|
||||
return
|
||||
|
||||
_set_state(State.OPEN)
|
||||
|
||||
var tween = create_tween().bind_node(self)
|
||||
_active_tween = tween
|
||||
_animating = true
|
||||
tween.tween_property(backpack_icon, "rotation", PI / 4, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||
tween.tween_property(backpack_icon, "position", Vector2(backpack_icon.position.x + 20, backpack_icon.position.y + 20), 0.35).set_trans(Tween.TRANS_SINE_IN)
|
||||
tween.tween_callback(_on_transition_complete).bind(State.OPEN)
|
||||
tween.tween_callback(overlay_show_requested.emit)
|
||||
|
||||
func _transition_to_selected() -> void:
|
||||
if _state == State.SELECTED:
|
||||
return
|
||||
|
||||
_set_state(State.SELECTED)
|
||||
_update_floating_item()
|
||||
|
||||
var tween = create_tween().bind_node(self)
|
||||
_active_tween = tween
|
||||
_animating = true
|
||||
|
||||
floating_item.visible = true
|
||||
floating_item.modulate = Color(1, 1, 1, 0)
|
||||
tween.tween_property(floating_item, "modulate", Color(1, 1, 1, 1), 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||
tween.tween_callback(_on_transition_complete).bind(State.SELECTED)
|
||||
|
||||
func _transition_to_acquire() -> void:
|
||||
if _state == State.ACQUIRE or _state == State.REMOVE:
|
||||
_kill_tween()
|
||||
|
||||
_set_state(State.ACQUIRE)
|
||||
|
||||
var tween = create_tween().bind_node(self)
|
||||
_active_tween = tween
|
||||
_animating = true
|
||||
|
||||
backpack_icon.modulate = Color(1, 1, 1, 1)
|
||||
tween.tween_property(backpack_icon, "rotation", PI / 4, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||
tween.tween_callback(_start_acquire_item_anim)
|
||||
|
||||
func _start_acquire_item_anim() -> void:
|
||||
var tween = create_tween().bind_node(self)
|
||||
_active_tween = tween
|
||||
|
||||
floating_item.visible = true
|
||||
floating_item.modulate = Color(1, 1, 1, 0)
|
||||
floating_item.position = Vector2(backpack_icon.position.x - 20, backpack_icon.position.y - 40)
|
||||
|
||||
tween.tween_property(floating_item, "modulate", Color(1, 1, 1, 1), 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||
tween.tween_property(floating_item, "position", backpack_icon.position, 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||
tween.tween_callback(_on_acquire_complete)
|
||||
|
||||
func _on_acquire_complete() -> void:
|
||||
floating_item.visible = false
|
||||
transition_to(State.IDLE)
|
||||
|
||||
func _transition_to_remove() -> void:
|
||||
if _state == State.ACQUIRE or _state == State.REMOVE:
|
||||
_kill_tween()
|
||||
|
||||
_set_state(State.REMOVE)
|
||||
|
||||
var tween = create_tween().bind_node(self)
|
||||
_active_tween = tween
|
||||
_animating = true
|
||||
|
||||
backpack_icon.modulate = Color(1, 1, 1, 1)
|
||||
tween.tween_property(backpack_icon, "rotation", PI / 4, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||
tween.tween_callback(_start_remove_item_anim)
|
||||
|
||||
func _start_remove_item_anim() -> void:
|
||||
var tween = create_tween().bind_node(self)
|
||||
_active_tween = tween
|
||||
|
||||
floating_item.visible = true
|
||||
floating_item.modulate = Color(1, 1, 1, 1)
|
||||
floating_item.position = backpack_icon.position
|
||||
|
||||
tween.tween_property(floating_item, "position", Vector2(backpack_icon.position.x - 20, backpack_icon.position.y - 80), 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||
tween.parallel().tween_property(floating_item, "modulate", Color(1, 1, 1, 0), 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||
tween.tween_callback(_on_remove_complete)
|
||||
|
||||
func _on_remove_complete() -> void:
|
||||
floating_item.visible = false
|
||||
var was_selected = InventoryManager.selected_item != ""
|
||||
transition_to(State.IDLE)
|
||||
if was_selected:
|
||||
InventoryManager.clear_selection()
|
||||
|
||||
func _set_state(new_state: State) -> void:
|
||||
_state = new_state
|
||||
|
||||
func _check_guards() -> bool:
|
||||
var main_game = get_node_or_null("/root/Node2D")
|
||||
if not main_game:
|
||||
return true
|
||||
|
||||
if main_game.is_script_running:
|
||||
return false
|
||||
|
||||
var fade = get_node_or_null("/root/Node2D/SceneDisplay/Fade")
|
||||
if fade and fade.modulate.a > 0.5:
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
func _kill_tween() -> void:
|
||||
if _active_tween:
|
||||
_active_tween.kill()
|
||||
_active_tween = null
|
||||
_animating = false
|
||||
|
||||
func _on_transition_complete(completed_state: State) -> void:
|
||||
_animating = false
|
||||
_active_tween = null
|
||||
if completed_state == State.OPEN:
|
||||
pass
|
||||
elif completed_state == State.IDLE:
|
||||
returning_to_idle.emit()
|
||||
|
||||
func _on_item_acquired(item_id: String) -> void:
|
||||
if _state == State.IDLE:
|
||||
transition_to(State.ACQUIRE)
|
||||
|
||||
func _on_item_removed(item_id: String) -> void:
|
||||
if _state == State.IDLE:
|
||||
if InventoryManager.selected_item == item_id:
|
||||
InventoryManager.clear_selection()
|
||||
_update_floating_item()
|
||||
transition_to(State.REMOVE)
|
||||
else:
|
||||
transition_to(State.REMOVE)
|
||||
elif _state == State.SELECTED and InventoryManager.selected_item == item_id:
|
||||
InventoryManager.clear_selection()
|
||||
_update_floating_item()
|
||||
transition_to(State.REMOVE)
|
||||
|
||||
func _on_inventory_changed() -> void:
|
||||
_update_floating_item()
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
|
||||
if _state == State.IDLE:
|
||||
transition_to(State.OPEN)
|
||||
elif _state == State.OPEN:
|
||||
transition_to(State.IDLE)
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
_kill_tween()
|
||||
1
inventory/inventory_backpack/InventoryBackpack.gd.uid
Normal file
1
inventory/inventory_backpack/InventoryBackpack.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://2x3g0ethsdcgo
|
||||
31
inventory/inventory_backpack/InventoryBackpack.tscn
Normal file
31
inventory/inventory_backpack/InventoryBackpack.tscn
Normal file
@@ -0,0 +1,31 @@
|
||||
[gd_scene format=3 uid="uid://1406xmcnkygw0"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://2x3g0ethsdcgo" path="res://inventory/inventory_backpack/InventoryBackpack.gd" id="1"]
|
||||
|
||||
[node name="InventoryBackpack" type="Control" unique_id=1000000001]
|
||||
layout_mode = 3
|
||||
anchors_preset = 2
|
||||
anchor_right = 1.0
|
||||
offset_top = 10.0
|
||||
offset_right = -10.0
|
||||
offset_bottom = 70.0
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="BackpackIcon" type="ColorRect" parent="." unique_id=1000000002]
|
||||
layout_mode = 0
|
||||
offset_left = 0.0
|
||||
offset_top = 0.0
|
||||
offset_right = 60.0
|
||||
offset_bottom = 60.0
|
||||
color = Color(0.4, 0.6, 0.9, 1)
|
||||
|
||||
[node name="FloatingItem" type="ColorRect" parent="." unique_id=1000000003]
|
||||
layout_mode = 0
|
||||
offset_left = 20.0
|
||||
offset_top = -30.0
|
||||
offset_right = 50.0
|
||||
offset_bottom = 0.0
|
||||
color = Color(1, 0.6, 0.2, 1)
|
||||
visible = false
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1000000004]
|
||||
1
inventory/inventory_backpack/InventoryBackpack.tscn.uid
Normal file
1
inventory/inventory_backpack/InventoryBackpack.tscn.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://1406xmcnkygw0
|
||||
215
inventory/inventory_overlay/InventoryOverlay.gd
Normal file
215
inventory/inventory_overlay/InventoryOverlay.gd
Normal file
@@ -0,0 +1,215 @@
|
||||
extends Control
|
||||
class_name InventoryOverlay
|
||||
|
||||
signal close_requested
|
||||
signal item_confirmed(item_id: String)
|
||||
signal combine_requested(item_a_id: String, item_b_id: String)
|
||||
signal inspect_requested(item_id: String)
|
||||
|
||||
var input_active: bool = false
|
||||
var _is_visible: bool = false
|
||||
var _selected_slot: InventorySlot = null
|
||||
var _drag_start_time: float = 0.0
|
||||
var _is_dragging: bool = false
|
||||
var _dragged_item: Control = null
|
||||
var _hovered_slot: InventorySlot = null
|
||||
var _fade_tween: Tween = null
|
||||
|
||||
const FADE_DURATION: float = 0.2
|
||||
const LONG_PRESS_THRESHOLD: float = 0.5
|
||||
const SLOTS_PER_ROW: int = 8
|
||||
const SLOT_SIZE: Vector2i = Vector2i(64, 64)
|
||||
|
||||
@onready var background: ColorRect = $Background
|
||||
@onready var panel: Control = $InventoryPanel
|
||||
@onready var frame: ColorRect = $InventoryPanel/Frame
|
||||
@onready var grid: GridContainer = $InventoryPanel/ItemGrid
|
||||
@onready var hover_label: Label = $InventoryPanel/HoverLabel
|
||||
|
||||
func _ready() -> void:
|
||||
hide()
|
||||
background.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
InventoryManager.inventory_changed.connect(_refresh_grid)
|
||||
InventoryManager.combination_attempted.connect(_on_combination_attempted)
|
||||
|
||||
func show_overlay() -> void:
|
||||
if _fade_tween:
|
||||
_fade_tween.kill()
|
||||
_fade_tween = null
|
||||
|
||||
_is_visible = true
|
||||
show()
|
||||
modulate = Color(1, 1, 1, 0)
|
||||
input_active = false
|
||||
|
||||
var tween = create_tween().bind_node(self)
|
||||
_fade_tween = tween
|
||||
tween.tween_property(self, "modulate", Color(1, 1, 1, 1), FADE_DURATION)
|
||||
tween.tween_callback(_on_fade_in_complete)
|
||||
|
||||
func hide_overlay() -> void:
|
||||
if _fade_tween:
|
||||
_fade_tween.kill()
|
||||
_fade_tween = null
|
||||
|
||||
input_active = false
|
||||
_clear_selection()
|
||||
|
||||
var tween = create_tween().bind_node(self)
|
||||
_fade_tween = tween
|
||||
tween.tween_property(self, "modulate", Color(1, 1, 1, 0), FADE_DURATION)
|
||||
tween.tween_callback(_on_fade_out_complete)
|
||||
|
||||
func _on_fade_in_complete() -> void:
|
||||
input_active = true
|
||||
|
||||
func _on_fade_out_complete() -> void:
|
||||
_is_visible = false
|
||||
hide()
|
||||
input_active = false
|
||||
|
||||
func is_active() -> bool:
|
||||
return _is_visible and input_active
|
||||
|
||||
func _refresh_grid() -> void:
|
||||
for child in grid.get_children():
|
||||
child.queue_free()
|
||||
|
||||
for item_id in InventoryManager.inventory:
|
||||
var def = InventoryManager.get_item_definition(item_id)
|
||||
if not def:
|
||||
def = ItemDefinition.new()
|
||||
def.id = item_id
|
||||
def.name = item_id
|
||||
|
||||
var slot_scene = load("res://inventory/inventory_overlay/InventorySlot.tscn")
|
||||
var slot: InventorySlot = slot_scene.instantiate()
|
||||
slot.set_item(def)
|
||||
slot.clicked.connect(_on_slot_clicked)
|
||||
slot.right_clicked.connect(_on_slot_right_clicked)
|
||||
slot.hovered.connect(_on_slot_hovered)
|
||||
slot.unhovered.connect(_on_slot_unhovered)
|
||||
grid.add_child(slot)
|
||||
|
||||
grid.columns = SLOTS_PER_ROW
|
||||
|
||||
func _on_slot_clicked(item_id: String) -> void:
|
||||
if not input_active:
|
||||
return
|
||||
|
||||
for child in grid.get_children():
|
||||
if child is InventorySlot and child.item_id == item_id:
|
||||
if _selected_slot == null:
|
||||
_selected_slot = child
|
||||
_drag_start_time = Time.get_ticks_msec() / 1000.0
|
||||
_is_dragging = true
|
||||
_create_drag_preview(child)
|
||||
elif _selected_slot.item_id == item_id:
|
||||
_handle_release_same_item()
|
||||
else:
|
||||
combine_requested.emit(_selected_slot.item_id, item_id)
|
||||
_clear_selection()
|
||||
break
|
||||
|
||||
func _on_slot_right_clicked(item_id: String) -> void:
|
||||
if not input_active:
|
||||
return
|
||||
inspect_requested.emit(item_id)
|
||||
hide_overlay()
|
||||
|
||||
func _on_slot_hovered(item_id: String) -> void:
|
||||
if not input_active:
|
||||
return
|
||||
_hovered_slot = null
|
||||
for child in grid.get_children():
|
||||
if child is InventorySlot and child.item_id == item_id:
|
||||
_hovered_slot = child
|
||||
break
|
||||
_update_hover_label()
|
||||
|
||||
func _on_slot_unhovered(item_id: String) -> void:
|
||||
if _hovered_slot and _hovered_slot.item_id == item_id:
|
||||
_hovered_slot = null
|
||||
_update_hover_label()
|
||||
|
||||
func _create_drag_preview(slot: InventorySlot) -> void:
|
||||
var preview = ColorRect.new()
|
||||
preview.color = Color(1, 0.6, 0.2, 0.7)
|
||||
preview.size = Vector2(48, 48)
|
||||
preview.position = slot.global_position - global_position
|
||||
panel.add_child(preview)
|
||||
_dragged_item = preview
|
||||
|
||||
func _handle_release_same_item() -> void:
|
||||
var elapsed = Time.get_ticks_msec() / 1000.0 - _drag_start_time
|
||||
if elapsed <= LONG_PRESS_THRESHOLD:
|
||||
item_confirmed.emit(_selected_slot.item_id)
|
||||
hide_overlay()
|
||||
else:
|
||||
_clear_selection()
|
||||
|
||||
func _clear_selection() -> void:
|
||||
_selected_slot = null
|
||||
_is_dragging = false
|
||||
if _dragged_item:
|
||||
_dragged_item.queue_free()
|
||||
_dragged_item = null
|
||||
_update_hover_label()
|
||||
|
||||
func _update_hover_label() -> void:
|
||||
if _selected_slot and _hovered_slot and _selected_slot.item_id != _hovered_slot.item_id:
|
||||
var def_a = InventoryManager.get_item_definition(_selected_slot.item_id)
|
||||
var def_b = InventoryManager.get_item_definition(_hovered_slot.item_id)
|
||||
var name_a = _selected_slot.item_id
|
||||
var name_b = _hovered_slot.item_id
|
||||
if def_a:
|
||||
name_a = def_a.name
|
||||
if def_b:
|
||||
name_b = def_b.name
|
||||
hover_label.text = "Use %s with %s" % [name_a, name_b]
|
||||
elif _hovered_slot:
|
||||
var def = InventoryManager.get_item_definition(_hovered_slot.item_id)
|
||||
if def:
|
||||
hover_label.text = def.name
|
||||
else:
|
||||
hover_label.text = _hovered_slot.item_id
|
||||
else:
|
||||
hover_label.text = ""
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if not _is_visible:
|
||||
return
|
||||
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == 1 and event.pressed:
|
||||
if not _is_dragging:
|
||||
pass
|
||||
elif event.button_index == 1 and not event.pressed:
|
||||
if _is_dragging:
|
||||
if _hovered_slot == null:
|
||||
_clear_selection()
|
||||
hide_overlay()
|
||||
close_requested.emit()
|
||||
elif _hovered_slot == _selected_slot:
|
||||
_handle_release_same_item()
|
||||
else:
|
||||
combine_requested.emit(_selected_slot.item_id, _hovered_slot.item_id)
|
||||
_clear_selection()
|
||||
return
|
||||
|
||||
if event is InputEventMouseMotion and _is_dragging and _dragged_item:
|
||||
_dragged_item.position = get_local_mouse_position() - Vector2(24, 24)
|
||||
var panel_rect = panel.get_global_rect()
|
||||
if not panel_rect.has_point(get_global_mouse_position()):
|
||||
_clear_selection()
|
||||
hide_overlay()
|
||||
close_requested.emit()
|
||||
|
||||
func _on_combination_attempted(item_a_id: String, item_b_id: String) -> void:
|
||||
pass
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_PREDELETE:
|
||||
if _fade_tween:
|
||||
_fade_tween.kill()
|
||||
_fade_tween = null
|
||||
1
inventory/inventory_overlay/InventoryOverlay.gd.uid
Normal file
1
inventory/inventory_overlay/InventoryOverlay.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://3mkdj9s1oe1jz
|
||||
63
inventory/inventory_overlay/InventoryOverlay.tscn
Normal file
63
inventory/inventory_overlay/InventoryOverlay.tscn
Normal file
@@ -0,0 +1,63 @@
|
||||
[gd_scene format=3 uid="uid://1p46uzngsih9o"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://3mkdj9s1oe1jz" path="res://inventory/inventory_overlay/InventoryOverlay.gd" id="1"]
|
||||
|
||||
[sub_resource type="LabelSettings" id="LabelSettings_inv"]
|
||||
font_size = 20
|
||||
outline_size = 3
|
||||
outline_color = Color(0, 0, 0, 1)
|
||||
|
||||
[node name="InventoryOverlay" type="Control" unique_id=3000000001]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="Background" type="ColorRect" parent="." unique_id=3000000002]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0, 0, 0, 0.7)
|
||||
|
||||
[node name="InventoryPanel" type="Control" parent="." unique_id=3000000003]
|
||||
layout_mode = 1
|
||||
anchors_preset = 7
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -350.0
|
||||
offset_top = -150.0
|
||||
offset_right = 350.0
|
||||
offset_bottom = 150.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Frame" type="ColorRect" parent="InventoryPanel" unique_id=3000000004]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(0.15, 0.15, 0.2, 1)
|
||||
|
||||
[node name="ItemGrid" type="GridContainer" parent="InventoryPanel" unique_id=3000000005]
|
||||
layout_mode = 1
|
||||
anchors_preset = 0
|
||||
offset_left = 10.0
|
||||
offset_top = 10.0
|
||||
offset_right = -10.0
|
||||
offset_bottom = -50.0
|
||||
|
||||
[node name="HoverLabel" type="Label" parent="InventoryPanel" unique_id=3000000006]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_bottom = -10.0
|
||||
grow_horizontal = 2
|
||||
horizontal_alignment = 1
|
||||
label_settings = SubResource("LabelSettings_inv")
|
||||
1
inventory/inventory_overlay/InventoryOverlay.tscn.uid
Normal file
1
inventory/inventory_overlay/InventoryOverlay.tscn.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://1p46uzngsih9o
|
||||
55
inventory/inventory_overlay/InventorySlot.gd
Normal file
55
inventory/inventory_overlay/InventorySlot.gd
Normal file
@@ -0,0 +1,55 @@
|
||||
extends Control
|
||||
class_name InventorySlot
|
||||
|
||||
signal clicked(item_id: String)
|
||||
signal right_clicked(item_id: String)
|
||||
signal hovered(item_id: String)
|
||||
signal unhovered(item_id: String)
|
||||
|
||||
var item_id: String = ""
|
||||
var is_hovered: bool = false
|
||||
|
||||
@onready var item_box: ColorRect = $ItemBox
|
||||
@onready var hover_highlight: ColorRect = $HoverHighlight
|
||||
|
||||
func _ready() -> void:
|
||||
hover_highlight.visible = false
|
||||
|
||||
func set_item(item_def: ItemDefinition) -> void:
|
||||
item_id = item_def.id
|
||||
item_box.color = Color(1, 0.6, 0.2, 1)
|
||||
|
||||
func set_item_color(color: Color) -> void:
|
||||
item_box.color = color
|
||||
|
||||
func set_hover(hovered: bool) -> void:
|
||||
is_hovered = hovered
|
||||
hover_highlight.visible = hovered
|
||||
if hovered:
|
||||
item_box.color = item_box.color.lightened(0.2)
|
||||
else:
|
||||
var def = InventoryManager.get_item_definition(item_id)
|
||||
if def:
|
||||
item_box.color = Color(1, 0.6, 0.2, 1)
|
||||
else:
|
||||
item_box.color = Color(0.8, 0.8, 0.8, 1)
|
||||
|
||||
func _gui_input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == 1 and event.pressed:
|
||||
clicked.emit(item_id)
|
||||
elif event.button_index == 2:
|
||||
right_clicked.emit(item_id)
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseMotion:
|
||||
var rect = get_global_rect()
|
||||
var mouse_pos = get_global_mouse_position()
|
||||
var was_hovered = is_hovered
|
||||
is_hovered = rect.has_point(mouse_pos)
|
||||
if is_hovered != was_hovered:
|
||||
set_hover(is_hovered)
|
||||
if is_hovered:
|
||||
hovered.emit(item_id)
|
||||
else:
|
||||
unhovered.emit(item_id)
|
||||
1
inventory/inventory_overlay/InventorySlot.gd.uid
Normal file
1
inventory/inventory_overlay/InventorySlot.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://oegm753jbl9m
|
||||
26
inventory/inventory_overlay/InventorySlot.tscn
Normal file
26
inventory/inventory_overlay/InventorySlot.tscn
Normal file
@@ -0,0 +1,26 @@
|
||||
[gd_scene format=3 uid="uid://1esl88fgtd2p6"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://oegm753jbl9m" path="res://inventory/inventory_overlay/InventorySlot.gd" id="1"]
|
||||
|
||||
[node name="InventorySlot" type="Control" unique_id=2000000001]
|
||||
custom_minimum_size = Vector2i(64, 64)
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="ItemBox" type="ColorRect" parent="." unique_id=2000000002]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.062
|
||||
anchor_top = 0.062
|
||||
anchor_right = 0.938
|
||||
anchor_bottom = 0.938
|
||||
color = Color(1, 0.6, 0.2, 1)
|
||||
|
||||
[node name="HoverHighlight" type="ColorRect" parent="." unique_id=2000000003]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
color = Color(1, 1, 1, 0.3)
|
||||
visible = false
|
||||
1
inventory/inventory_overlay/InventorySlot.tscn.uid
Normal file
1
inventory/inventory_overlay/InventorySlot.tscn.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://1esl88fgtd2p6
|
||||
@@ -23,7 +23,7 @@ config/icon="res://icon.png"
|
||||
|
||||
ActionState="*res://ActionState.gd"
|
||||
CameraTransition="*res://camera_transition.tscn"
|
||||
McpInteractionServer="*uid://dovjioj1jyqpp"
|
||||
InventoryManager="*res://inventory/InventoryManager.gd"
|
||||
|
||||
[display]
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
uid://dovjioj1jyqpp
|
||||
Reference in New Issue
Block a user