@causyne/agent 0.0.0-stage → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +102 -0
- package/README.md +31 -2
- package/SECURITY.md +24 -0
- package/bin/causyne.js +13 -0
- package/docs/ARCHITECTURE.md +63 -0
- package/docs/PROVENANCE.md +29 -0
- package/docs/SECURITY_REVIEW.md +89 -0
- package/docs/THIRD_PARTY_NOTICES.md +49 -0
- package/native-skills/ai-engineering/context-window-management/SKILL.md +43 -0
- package/native-skills/ai-engineering/llm-evaluation/SKILL.md +46 -0
- package/native-skills/ai-engineering/model-cost-and-latency/SKILL.md +46 -0
- package/native-skills/ai-engineering/prompt-construction/SKILL.md +42 -0
- package/native-skills/ai-engineering/retrieval-augmented-generation/SKILL.md +42 -0
- package/native-skills/ai-engineering/structured-output-and-schemas/SKILL.md +45 -0
- package/native-skills/ai-engineering/tool-calling-agents/SKILL.md +43 -0
- package/native-skills/android/app-performance-profiling/SKILL.md +42 -0
- package/native-skills/android/background-work-scheduling/SKILL.md +47 -0
- package/native-skills/android/compose-state-and-recomposition/SKILL.md +43 -0
- package/native-skills/android/gradle-build-configuration/SKILL.md +41 -0
- package/native-skills/android/lifecycle-and-leaks/SKILL.md +46 -0
- package/native-skills/android/play-store-release/SKILL.md +43 -0
- package/native-skills/android/room-and-persistence/SKILL.md +40 -0
- package/native-skills/backend/authentication-and-sessions/SKILL.md +45 -0
- package/native-skills/backend/background-jobs-and-queues/SKILL.md +42 -0
- package/native-skills/backend/caching-strategy/SKILL.md +44 -0
- package/native-skills/backend/graceful-shutdown/SKILL.md +42 -0
- package/native-skills/backend/rate-limiting-and-quotas/SKILL.md +40 -0
- package/native-skills/backend/rest-api-design/SKILL.md +40 -0
- package/native-skills/backend/webhook-delivery-and-receipt/SKILL.md +43 -0
- package/native-skills/cloud/cost-optimisation/SKILL.md +46 -0
- package/native-skills/cloud/iam-least-privilege/SKILL.md +43 -0
- package/native-skills/cloud/infrastructure-as-code/SKILL.md +43 -0
- package/native-skills/cloud/multi-region-and-failover/SKILL.md +43 -0
- package/native-skills/cloud/serverless-patterns/SKILL.md +47 -0
- package/native-skills/data/data-quality-monitoring/SKILL.md +51 -0
- package/native-skills/data/etl-pipeline-reliability/SKILL.md +43 -0
- package/native-skills/data/exploratory-analysis/SKILL.md +43 -0
- package/native-skills/data/metric-definition/SKILL.md +42 -0
- package/native-skills/data/notebook-to-production/SKILL.md +43 -0
- package/native-skills/database/backup-and-recovery/SKILL.md +43 -0
- package/native-skills/database/connection-pooling/SKILL.md +42 -0
- package/native-skills/database/data-integrity-and-constraints/SKILL.md +42 -0
- package/native-skills/database/query-optimisation/SKILL.md +38 -0
- package/native-skills/database/safe-migrations/SKILL.md +47 -0
- package/native-skills/database/schema-design/SKILL.md +38 -0
- package/native-skills/database/transactions-and-isolation/SKILL.md +41 -0
- package/native-skills/design/colour-system-construction/SKILL.md +38 -0
- package/native-skills/design/design-direction-brief/SKILL.md +41 -0
- package/native-skills/design/motion-and-transitions/SKILL.md +38 -0
- package/native-skills/design/responsive-strategy/SKILL.md +39 -0
- package/native-skills/design/spacing-and-rhythm/SKILL.md +38 -0
- package/native-skills/design/type-scale-and-hierarchy/SKILL.md +39 -0
- package/native-skills/design/visual-qa-loop/SKILL.md +42 -0
- package/native-skills/devops/docker-multi-stage-builds/SKILL.md +60 -0
- package/native-skills/devops/github-actions-ci/SKILL.md +60 -0
- package/native-skills/devops/incident-triage/SKILL.md +38 -0
- package/native-skills/devops/kubernetes-deployment-hardening/SKILL.md +64 -0
- package/native-skills/devops/observability-baseline/SKILL.md +38 -0
- package/native-skills/devops/secret-management/SKILL.md +40 -0
- package/native-skills/devops/terraform-state-and-modules/SKILL.md +36 -0
- package/native-skills/devops/zero-downtime-deploys/SKILL.md +40 -0
- package/native-skills/git/bisect-regression-hunt/SKILL.md +43 -0
- package/native-skills/git/branch-strategy/SKILL.md +39 -0
- package/native-skills/git/commit-hygiene/SKILL.md +41 -0
- package/native-skills/git/history-recovery/SKILL.md +44 -0
- package/native-skills/git/large-repository-surgery/SKILL.md +46 -0
- package/native-skills/git/merge-conflict-resolution/SKILL.md +42 -0
- package/native-skills/media/cinematic-3d-shot/SKILL.md +104 -0
- package/native-skills/mobile/app-startup-optimisation/SKILL.md +41 -0
- package/native-skills/mobile/cross-platform-tradeoffs/SKILL.md +42 -0
- package/native-skills/mobile/deep-linking/SKILL.md +39 -0
- package/native-skills/mobile/mobile-storage-security/SKILL.md +45 -0
- package/native-skills/mobile/offline-first-sync/SKILL.md +42 -0
- package/native-skills/mobile/push-notifications/SKILL.md +38 -0
- package/native-skills/performance/algorithmic-complexity/SKILL.md +43 -0
- package/native-skills/performance/concurrency-and-parallelism/SKILL.md +42 -0
- package/native-skills/performance/load-testing/SKILL.md +42 -0
- package/native-skills/performance/memory-and-leak-hunting/SKILL.md +41 -0
- package/native-skills/performance/network-and-payload-efficiency/SKILL.md +42 -0
- package/native-skills/performance/profiling-methodology/SKILL.md +46 -0
- package/native-skills/python/async-correctness/SKILL.md +40 -0
- package/native-skills/python/cli-tool-construction/SKILL.md +44 -0
- package/native-skills/python/data-processing-pipelines/SKILL.md +38 -0
- package/native-skills/python/environment-isolation/SKILL.md +41 -0
- package/native-skills/python/packaging-and-distribution/SKILL.md +56 -0
- package/native-skills/python/pytest-suite-design/SKILL.md +39 -0
- package/native-skills/python/type-hints-and-static-checking/SKILL.md +42 -0
- package/native-skills/security/authorization-model/SKILL.md +42 -0
- package/native-skills/security/crypto-usage/SKILL.md +48 -0
- package/native-skills/security/dependency-supply-chain/SKILL.md +42 -0
- package/native-skills/security/input-validation-and-injection/SKILL.md +44 -0
- package/native-skills/security/secure-file-uploads/SKILL.md +46 -0
- package/native-skills/security/security-headers-and-csp/SKILL.md +44 -0
- package/native-skills/security/threat-modelling/SKILL.md +46 -0
- package/native-skills/testing/end-to-end-test-stability/SKILL.md +42 -0
- package/native-skills/testing/property-based-testing/SKILL.md +46 -0
- package/native-skills/testing/regression-test-from-a-bug/SKILL.md +41 -0
- package/native-skills/testing/snapshot-and-visual-regression/SKILL.md +42 -0
- package/native-skills/testing/test-doubles-and-mocking/SKILL.md +43 -0
- package/native-skills/testing/test-strategy-and-pyramid/SKILL.md +39 -0
- package/native-skills/testing/writing-good-assertions/SKILL.md +42 -0
- package/native-skills/web/accessible-components/SKILL.md +45 -0
- package/native-skills/web/api-client-resilience/SKILL.md +39 -0
- package/native-skills/web/bundle-size-reduction/SKILL.md +38 -0
- package/native-skills/web/core-web-vitals/SKILL.md +40 -0
- package/native-skills/web/css-layout-systems/SKILL.md +41 -0
- package/native-skills/web/form-validation-ux/SKILL.md +39 -0
- package/native-skills/web/react-state-architecture/SKILL.md +41 -0
- package/native-skills/web/ssr-hydration-correctness/SKILL.md +45 -0
- package/package.json +68 -4
- package/src/agentLoop.js +2458 -0
- package/src/appChannel.js +109 -0
- package/src/approvalGrants.js +66 -0
- package/src/auditLog.js +52 -0
- package/src/autoUpdate.js +12 -0
- package/src/capabilities.js +36 -0
- package/src/checkpoints.js +1199 -0
- package/src/cliMode.js +638 -0
- package/src/commands.js +805 -0
- package/src/compiledSkills.js +540 -0
- package/src/config.js +130 -0
- package/src/contextManager.js +498 -0
- package/src/cortex/autoCondenser.js +192 -0
- package/src/cortex/provisioner.js +27 -0
- package/src/cortex/vectorDb.js +447 -0
- package/src/designPalettes.js +99 -0
- package/src/devMode.js +6 -0
- package/src/embodimentSession.js +180 -0
- package/src/entrypoint.js +194 -0
- package/src/execSafe.js +21 -0
- package/src/gitSnapshot.js +378 -0
- package/src/mcp/jsonRpc.js +165 -0
- package/src/mcp/mcpClient.js +136 -0
- package/src/mcp/mcpRegistry.js +207 -0
- package/src/memory.js +62 -0
- package/src/memoryManager.js +124 -0
- package/src/modelCatalogue.js +132 -0
- package/src/modelIds.js +42 -0
- package/src/modelRouter.js +145 -0
- package/src/outputStore.js +246 -0
- package/src/perception.js +124 -0
- package/src/planCache.js +437 -0
- package/src/procSignal.js +32 -0
- package/src/providers/anthropic.js +408 -0
- package/src/providers/base.js +328 -0
- package/src/providers/dashscope-byok.js +86 -0
- package/src/providers/deepseek.js +80 -0
- package/src/providers/factory.js +37 -0
- package/src/providers/gemini.js +346 -0
- package/src/providers/moonshot.js +73 -0
- package/src/providers/muse.js +169 -0
- package/src/providers/ollama.js +104 -0
- package/src/providers/openai-compatible.js +84 -0
- package/src/providers/openai.js +20 -0
- package/src/providers/qwen-byok.js +76 -0
- package/src/providers/xai.js +73 -0
- package/src/provisioning/capabilityConsent.js +24 -0
- package/src/provisioning/capabilityProvisioner.js +271 -0
- package/src/provisioning/capabilityTools.js +29 -0
- package/src/reporting.js +373 -0
- package/src/sandbox.js +529 -0
- package/src/sessionStore.js +279 -0
- package/src/skillsManager.js +288 -0
- package/src/slopDetector.js +307 -0
- package/src/taskBuffer.js +45 -0
- package/src/taskShape.js +241 -0
- package/src/textDiff.js +150 -0
- package/src/tokenTracker.js +560 -0
- package/src/tool-scripts/ax_snapshot.applescript +39 -0
- package/src/tool-scripts/ax_snapshot.ps1 +10 -0
- package/src/tool-scripts/desktop_act.applescript +58 -0
- package/src/tool-scripts/resolve_automator.py +119 -0
- package/src/toolPacks.js +524 -0
- package/src/tools/archive.js +63 -0
- package/src/tools/astryxOracle.js +78 -0
- package/src/tools/axSnapshot.js +165 -0
- package/src/tools/blenderAutomator.js +349 -0
- package/src/tools/browserAutomator.js +252 -0
- package/src/tools/checkSystemSpecs.js +64 -0
- package/src/tools/clipboard.js +36 -0
- package/src/tools/codeSearchAst.js +101 -0
- package/src/tools/codeSearcher.js +230 -0
- package/src/tools/codeTools.js +262 -0
- package/src/tools/codebaseSearch.js +75 -0
- package/src/tools/createSkill.js +129 -0
- package/src/tools/deferredMcpSearch.js +246 -0
- package/src/tools/desktopAct.js +208 -0
- package/src/tools/desktopOpen.js +34 -0
- package/src/tools/dynamicLoader.js +44 -0
- package/src/tools/executeProceduralMedia.js +93 -0
- package/src/tools/fsDelete.js +51 -0
- package/src/tools/fsEdit.js +105 -0
- package/src/tools/fsFind.js +128 -0
- package/src/tools/fsList.js +77 -0
- package/src/tools/fsMove.js +57 -0
- package/src/tools/fsRead.js +87 -0
- package/src/tools/fsSearch.js +198 -0
- package/src/tools/fsWrite.js +41 -0
- package/src/tools/gameAiBehaviorTree.js +208 -0
- package/src/tools/gameAnimationRig.js +194 -0
- package/src/tools/gameAssetFetcher.js +372 -0
- package/src/tools/gameAssetHarvester.js +210 -0
- package/src/tools/gameAudioSynth.js +267 -0
- package/src/tools/gameBuilder.js +886 -0
- package/src/tools/gameCanvasAudit.js +101 -0
- package/src/tools/gameCinematicSequencer.js +151 -0
- package/src/tools/gameDataForge.js +124 -0
- package/src/tools/gameDialogueTreeGen.js +166 -0
- package/src/tools/gameEconomyBalancer.js +161 -0
- package/src/tools/gameEntitySpawner.js +207 -0
- package/src/tools/gameLoreForge.js +153 -0
- package/src/tools/gameQuestArcBuilder.js +152 -0
- package/src/tools/gameSceneBuilder.js +158 -0
- package/src/tools/gameShaderForge.js +181 -0
- package/src/tools/gameTilemapGenerator.js +164 -0
- package/src/tools/gameUiHudBuilder.js +292 -0
- package/src/tools/gameVfxEmitterGen.js +108 -0
- package/src/tools/gameWebRuntimeInspector.js +91 -0
- package/src/tools/generateMediaViaApi.js +358 -0
- package/src/tools/gitExec.js +54 -0
- package/src/tools/godotAutomator.js +437 -0
- package/src/tools/manageLocalAiDependencies.js +220 -0
- package/src/tools/memoryWrite.js +99 -0
- package/src/tools/multiEdit.js +107 -0
- package/src/tools/palmierAutomator.js +104 -0
- package/src/tools/pdfReader.js +112 -0
- package/src/tools/persistentShell.js +148 -0
- package/src/tools/printer.js +316 -0
- package/src/tools/procTerm.js +91 -0
- package/src/tools/processList.js +52 -0
- package/src/tools/readNativeSkill.js +39 -0
- package/src/tools/registry.js +277 -0
- package/src/tools/resolveAutomator.js +102 -0
- package/src/tools/screenshot.js +75 -0
- package/src/tools/subagentOrchestrator.js +305 -0
- package/src/tools/sysRun.js +125 -0
- package/src/tools/todoWrite.js +75 -0
- package/src/tools/toolDispatch.js +127 -0
- package/src/tools/toolForge.js +124 -0
- package/src/tools/updatePlan.js +88 -0
- package/src/tools/viewImage.js +82 -0
- package/src/tools/visionInspector.js +154 -0
- package/src/tools/webFetch.js +74 -0
- package/src/tools/webSearch.js +82 -0
- package/src/tui/ask.js +164 -0
- package/src/tui/banner.js +158 -0
- package/src/tui/block.js +152 -0
- package/src/tui/chatRenderer.js +953 -0
- package/src/tui/completion.js +424 -0
- package/src/tui/dialogs.js +606 -0
- package/src/tui/diff.js +296 -0
- package/src/tui/history.js +135 -0
- package/src/tui/home.js +217 -0
- package/src/tui/invocation.js +105 -0
- package/src/tui/keys.js +443 -0
- package/src/tui/lineEditor.js +256 -0
- package/src/tui/overlay.js +256 -0
- package/src/tui/prompt.js +1258 -0
- package/src/tui/selectList.js +335 -0
- package/src/tui/stage.js +330 -0
- package/src/tui/stageSurface.js +609 -0
- package/src/tui/statusLine.js +254 -0
- package/src/tui/text.js +345 -0
- package/src/tui/theme.js +393 -0
- package/src/tui/toolDisplay.js +176 -0
- package/src/tui/transcript.js +235 -0
- package/src/tui/viewport.js +337 -0
- package/src/uncertainty.js +271 -0
- package/src/userSkills.js +265 -0
- package/src/utils/cli_ui.js +0 -0
- package/src/utils/inquirer.js +12 -0
- package/src/utils/paths.js +37 -0
- package/src/version.js +38 -0
- package/src/vfeTracker.js +220 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import fsSync from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
export const gameAiBehaviorTree = {
|
|
6
|
+
schema: {
|
|
7
|
+
name: 'game.ai_behavior_tree',
|
|
8
|
+
description: 'Engineers NPC/Enemy AI state machines and behavior trees for Godot 4.x (`PatrolState`, `ChaseState`, `AttackState`, `BossPhaseController`) with line-of-sight raycasting and `NavigationAgent2D/3D` pathfinding generation.',
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
action: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
enum: ['generate_enemy_ai_script', 'generate_boss_phase_controller', 'generate_navigation_setup'],
|
|
15
|
+
description: 'Action: generate_enemy_ai_script (standard patrol/chase/attack AI), generate_boss_phase_controller (multi-phase boss state machine), or generate_navigation_setup (NavigationAgent pathfinding snippet).'
|
|
16
|
+
},
|
|
17
|
+
entityName: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'Name of the AI entity (`SkeletonWarrior`, `ShadowMage`, `BossNecromancer`).'
|
|
20
|
+
},
|
|
21
|
+
aiType: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
enum: ['2d', '3d'],
|
|
24
|
+
description: 'Dimension of the AI entity (`2d` or `3d`).'
|
|
25
|
+
},
|
|
26
|
+
patrolSpeed: { type: 'number', description: 'Patrol movement speed (default 60.0).' },
|
|
27
|
+
chaseSpeed: { type: 'number', description: 'Chase movement speed (default 130.0).' },
|
|
28
|
+
attackRange: { type: 'number', description: 'Distance to trigger melee/ranged attack (default 45.0).' },
|
|
29
|
+
detectRange: { type: 'number', description: 'Distance to detect player and enter Chase (default 220.0).' },
|
|
30
|
+
outputPath: { type: 'string', description: 'Absolute path to save generated `.gd` script (`res://scripts/ai/BaseEnemyAI.gd`).' }
|
|
31
|
+
},
|
|
32
|
+
required: ['action', 'entityName']
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
async execute(args) {
|
|
37
|
+
try {
|
|
38
|
+
const { action, entityName, aiType = '2d', patrolSpeed = 60.0, chaseSpeed = 130.0, attackRange = 45.0, detectRange = 220.0, outputPath } = args;
|
|
39
|
+
|
|
40
|
+
if (action === 'generate_enemy_ai_script') {
|
|
41
|
+
const bodyClass = aiType === '3d' ? 'CharacterBody3D' : 'CharacterBody2D';
|
|
42
|
+
const vecType = aiType === '3d' ? 'Vector3' : 'Vector2';
|
|
43
|
+
|
|
44
|
+
const gdScript = `extends ${bodyClass}
|
|
45
|
+
|
|
46
|
+
# Generated by Sovereign Game Automation Studio (v1.3.12) - AI Behavior Tree
|
|
47
|
+
enum AIState { PATROL, CHASE, ATTACK, STUNNED, DEAD }
|
|
48
|
+
|
|
49
|
+
@export var max_hp: float = 100.0
|
|
50
|
+
@export var patrol_speed: float = ${patrolSpeed.toFixed(1)}
|
|
51
|
+
@export var chase_speed: float = ${chaseSpeed.toFixed(1)}
|
|
52
|
+
@export var detect_radius: float = ${detectRange.toFixed(1)}
|
|
53
|
+
@export var attack_radius: float = ${attackRange.toFixed(1)}
|
|
54
|
+
|
|
55
|
+
var current_hp: float
|
|
56
|
+
var current_state: AIState = AIState.PATROL
|
|
57
|
+
var target_player: Node = null
|
|
58
|
+
var patrol_direction: ${vecType} = ${aiType === '3d' ? 'Vector3(1, 0, 0)' : 'Vector2.RIGHT'}
|
|
59
|
+
var patrol_timer: float = 0.0
|
|
60
|
+
|
|
61
|
+
@onready var nav_agent = $NavigationAgent${aiType === '3d' ? '3D' : '2D'} if has_node("NavigationAgent${aiType === '3d' ? '3D' : '2D'}") else null
|
|
62
|
+
@onready var anim_player = $AnimationPlayer if has_node("AnimationPlayer") else null
|
|
63
|
+
|
|
64
|
+
func _ready() -> void:
|
|
65
|
+
\tcurrent_hp = max_hp
|
|
66
|
+
\ttarget_player = get_tree().get_first_node_in_group("player")
|
|
67
|
+
\tprint("[AI Ready] ${entityName} initialized in PATROL state.")
|
|
68
|
+
|
|
69
|
+
func _physics_process(delta: float) -> void:
|
|
70
|
+
\tif current_state == AIState.DEAD or current_state == AIState.STUNNED:
|
|
71
|
+
\t\treturn
|
|
72
|
+
|
|
73
|
+
\t# Check target distance
|
|
74
|
+
\tif is_instance_valid(target_player):
|
|
75
|
+
\t\tvar dist = global_position.distance_to(target_player.global_position)
|
|
76
|
+
\t\tif dist <= attack_radius:
|
|
77
|
+
\t\t\tchange_state(AIState.ATTACK)
|
|
78
|
+
\t\telif dist <= detect_radius:
|
|
79
|
+
\t\t\tchange_state(AIState.CHASE)
|
|
80
|
+
\t\telif current_state == AIState.CHASE and dist > detect_radius * 1.3:
|
|
81
|
+
\t\t\tchange_state(AIState.PATROL)
|
|
82
|
+
|
|
83
|
+
\tmatch current_state:
|
|
84
|
+
\t\tAIState.PATROL:
|
|
85
|
+
\t\t\t_process_patrol(delta)
|
|
86
|
+
\t\tAIState.CHASE:
|
|
87
|
+
\t\t\t_process_chase(delta)
|
|
88
|
+
\t\tAIState.ATTACK:
|
|
89
|
+
\t\t\t_process_attack(delta)
|
|
90
|
+
|
|
91
|
+
func _process_patrol(delta: float) -> void:
|
|
92
|
+
\tpatrol_timer += delta
|
|
93
|
+
\tif patrol_timer >= 3.0:
|
|
94
|
+
\t\tpatrol_timer = 0.0
|
|
95
|
+
\t\tpatrol_direction = -patrol_direction
|
|
96
|
+
\tvelocity = patrol_direction * patrol_speed
|
|
97
|
+
\tmove_and_slide()
|
|
98
|
+
\tif anim_player and anim_player.has_animation("walk"):
|
|
99
|
+
\t\tanim_player.play("walk")
|
|
100
|
+
|
|
101
|
+
func _process_chase(delta: float) -> void:
|
|
102
|
+
\tif not is_instance_valid(target_player):
|
|
103
|
+
\t\treturn
|
|
104
|
+
\tvar dir = (target_player.global_position - global_position).normalized()
|
|
105
|
+
\tif nav_agent and not nav_agent.is_navigation_finished():
|
|
106
|
+
\t\tnav_agent.target_position = target_player.global_position
|
|
107
|
+
\t\tdir = (nav_agent.get_next_path_position() - global_position).normalized()
|
|
108
|
+
\tvelocity = dir * chase_speed
|
|
109
|
+
\tmove_and_slide()
|
|
110
|
+
\tif anim_player and anim_player.has_animation("walk"):
|
|
111
|
+
\t\tanim_player.play("walk")
|
|
112
|
+
|
|
113
|
+
func _process_attack(delta: float) -> void:
|
|
114
|
+
\tvelocity = ${vecType}.ZERO
|
|
115
|
+
\tif anim_player and anim_player.has_animation("attack_slash") and not anim_player.is_playing():
|
|
116
|
+
\t\tanim_player.play("attack_slash")
|
|
117
|
+
|
|
118
|
+
func take_damage(amount: float) -> void:
|
|
119
|
+
\tif current_state == AIState.DEAD:
|
|
120
|
+
\t\treturn
|
|
121
|
+
\tcurrent_hp -= amount
|
|
122
|
+
\tprint("[AI Damage] ${entityName} took ", amount, " damage. HP remaining: ", current_hp)
|
|
123
|
+
\tif current_hp <= 0:
|
|
124
|
+
\t\tchange_state(AIState.DEAD)
|
|
125
|
+
\telse:
|
|
126
|
+
\t\tif anim_player and anim_player.has_animation("hit"):
|
|
127
|
+
\t\t\tanim_player.play("hit")
|
|
128
|
+
|
|
129
|
+
func change_state(new_state: AIState) -> void:
|
|
130
|
+
\tif current_state == new_state:
|
|
131
|
+
\t\treturn
|
|
132
|
+
\tcurrent_state = new_state
|
|
133
|
+
\tif current_state == AIState.DEAD:
|
|
134
|
+
\t\tvelocity = ${vecType}.ZERO
|
|
135
|
+
\t\tif anim_player and anim_player.has_animation("death"):
|
|
136
|
+
\t\t\tanim_player.play("death")
|
|
137
|
+
\t\tawait get_tree().create_timer(2.0).timeout
|
|
138
|
+
\t\tqueue_free()
|
|
139
|
+
`;
|
|
140
|
+
|
|
141
|
+
if (outputPath) {
|
|
142
|
+
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
143
|
+
await fs.writeFile(outputPath, gdScript, 'utf8');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
success: true,
|
|
148
|
+
output: JSON.stringify({
|
|
149
|
+
status: 'GENERATED_ENEMY_AI',
|
|
150
|
+
entity: entityName,
|
|
151
|
+
ai_type: aiType,
|
|
152
|
+
states_configured: ['PATROL', 'CHASE', 'ATTACK', 'STUNNED', 'DEAD'],
|
|
153
|
+
output_file: outputPath || 'Returned in payload',
|
|
154
|
+
script_snippet: gdScript.slice(0, 1000)
|
|
155
|
+
}, null, 2)
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (action === 'generate_boss_phase_controller') {
|
|
160
|
+
const bossScript = `extends CharacterBody2D
|
|
161
|
+
|
|
162
|
+
# Multi-Phase Boss Necromancer Controller (` + entityName + `)
|
|
163
|
+
enum BossPhase { PHASE_1_SPELLS, PHASE_2_SUMMONS, PHASE_3_ENRAGE, DEFEATED }
|
|
164
|
+
|
|
165
|
+
@export var max_hp: float = 800.0
|
|
166
|
+
var current_hp: float
|
|
167
|
+
var current_phase: BossPhase = BossPhase.PHASE_1_SPELLS
|
|
168
|
+
|
|
169
|
+
func _ready() -> void:
|
|
170
|
+
\tcurrent_hp = max_hp
|
|
171
|
+
\tprint("[Boss Ready] ", name, " entered PHASE_1_SPELLS (HP: ", max_hp, ")")
|
|
172
|
+
|
|
173
|
+
func take_damage(amount: float) -> void:
|
|
174
|
+
\tif current_phase == BossPhase.DEFEATED:
|
|
175
|
+
\t\treturn
|
|
176
|
+
\tcurrent_hp -= amount
|
|
177
|
+
\tvar hp_pct = current_hp / max_hp
|
|
178
|
+
\t
|
|
179
|
+
\tif hp_pct <= 0.35 and current_phase != BossPhase.PHASE_3_ENRAGE:
|
|
180
|
+
\t\tcurrent_phase = BossPhase.PHASE_3_ENRAGE
|
|
181
|
+
\t\tprint("[Boss Enrage] HP below 35%! Entering PHASE_3_ENRAGE!")
|
|
182
|
+
\t\t# Trigger boss_roar audio
|
|
183
|
+
\telif hp_pct <= 0.70 and current_phase == BossPhase.PHASE_1_SPELLS:
|
|
184
|
+
\t\tcurrent_phase = BossPhase.PHASE_2_SUMMONS
|
|
185
|
+
\t\tprint("[Boss Phase 2] HP below 70%! Summoning Skeletal Warriors!")
|
|
186
|
+
\t
|
|
187
|
+
\tif current_hp <= 0:
|
|
188
|
+
\t\tcurrent_phase = BossPhase.DEFEATED
|
|
189
|
+
\t\tprint("[Boss Defeated] ", name, " has fallen!")
|
|
190
|
+
\t\tqueue_free()
|
|
191
|
+
`;
|
|
192
|
+
return {
|
|
193
|
+
success: true,
|
|
194
|
+
output: JSON.stringify({
|
|
195
|
+
status: 'GENERATED_BOSS_CONTROLLER',
|
|
196
|
+
entity: entityName,
|
|
197
|
+
phases: ['PHASE_1_SPELLS', 'PHASE_2_SUMMONS', 'PHASE_3_ENRAGE', 'DEFEATED'],
|
|
198
|
+
script_snippet: bossScript
|
|
199
|
+
}, null, 2)
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return { success: false, error: `Unknown action: ${action}` };
|
|
204
|
+
} catch (e) {
|
|
205
|
+
return { success: false, error: e.message };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
};
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import fsSync from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
export const gameAnimationRig = {
|
|
6
|
+
schema: {
|
|
7
|
+
name: 'game.animation_rig',
|
|
8
|
+
description: 'Configures character rigging and animation setups for Godot 4.x. Supports 2D SpriteSheet animations (`AnimationPlayer`, `AnimatedSprite2D` frame slices) and 3D Skeletal rigs (`Skeleton3D`, `BoneAttachment3D`, `AnimationTree` state machines and 1D/2D blend spaces).',
|
|
9
|
+
parameters: {
|
|
10
|
+
type: 'object',
|
|
11
|
+
properties: {
|
|
12
|
+
action: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
enum: ['rig_2d_spritesheet', 'rig_3d_skeleton', 'create_animation_tree', 'attach_weapon_bone'],
|
|
15
|
+
description: 'Action: rig_2d_spritesheet (setup 2D frame animation), rig_3d_skeleton (setup 3D bone bindings), create_animation_tree (build state machine/blend tree), or attach_weapon_bone (bind prop/sword to hand bone).'
|
|
16
|
+
},
|
|
17
|
+
characterName: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'Name of the character node (`PlayerHero`, `SkeletonWarrior`, `BossNecromancer`).'
|
|
20
|
+
},
|
|
21
|
+
animationList: {
|
|
22
|
+
type: 'array',
|
|
23
|
+
items: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: {
|
|
26
|
+
anim_name: { type: 'string' },
|
|
27
|
+
loop: { type: 'boolean' },
|
|
28
|
+
fps: { type: 'number' },
|
|
29
|
+
frames: { type: 'array', items: { type: 'number' } }
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
description: 'List of animations (e.g. `idle`, `walk`, `attack_slash`, `hit`, `death`).'
|
|
33
|
+
},
|
|
34
|
+
spriteSheetPath: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
description: 'Path to 2D texture sheet (`res://assets/2d/player_sheet.png`).'
|
|
37
|
+
},
|
|
38
|
+
hFrames: { type: 'number', description: 'Horizontal frames in sprite sheet.' },
|
|
39
|
+
vFrames: { type: 'number', description: 'Vertical frames in sprite sheet.' },
|
|
40
|
+
boneName: { type: 'string', description: 'Bone name for 3D attachment (`Hand_R`, `Spine`, `Head`).' },
|
|
41
|
+
propScenePath: { type: 'string', description: 'Path to prop scene to attach (`res://assets/3d/weapons/iron_sword.tscn`).' },
|
|
42
|
+
outputPath: { type: 'string', description: 'Output `.tscn` or `.tres` path to write the rigging definitions.' }
|
|
43
|
+
},
|
|
44
|
+
required: ['action', 'characterName']
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
async execute(args) {
|
|
49
|
+
try {
|
|
50
|
+
const { action, characterName, animationList = [], spriteSheetPath = 'res://assets/2d/hero.png', hFrames = 6, vFrames = 4, boneName = 'Hand_R', propScenePath = 'res://assets/3d/sword.tscn', outputPath } = args;
|
|
51
|
+
|
|
52
|
+
if (action === 'rig_2d_spritesheet') {
|
|
53
|
+
const anims = animationList.length > 0 ? animationList : [
|
|
54
|
+
{ anim_name: 'idle', loop: true, fps: 8, frames: [0, 1, 2, 3] },
|
|
55
|
+
{ anim_name: 'walk', loop: true, fps: 12, frames: [6, 7, 8, 9, 10, 11] },
|
|
56
|
+
{ anim_name: 'attack_slash', loop: false, fps: 16, frames: [12, 13, 14, 15] },
|
|
57
|
+
{ anim_name: 'hit', loop: false, fps: 10, frames: [18, 19] },
|
|
58
|
+
{ anim_name: 'death', loop: false, fps: 8, frames: [20, 21, 22, 23] }
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
// Generate Godot AnimationPlayer tracks for Sprite2D frame indexing
|
|
62
|
+
let animSubresources = '';
|
|
63
|
+
let animLibEntries = '';
|
|
64
|
+
let stepCount = 1;
|
|
65
|
+
|
|
66
|
+
for (const anim of anims) {
|
|
67
|
+
const duration = (anim.frames.length / (anim.fps || 10)).toFixed(3);
|
|
68
|
+
const loopMode = anim.loop ? '1' : '0';
|
|
69
|
+
const keys = anim.frames.map((f, idx) => `${(idx / (anim.fps || 10)).toFixed(3)}: ${f}`).join(', ');
|
|
70
|
+
|
|
71
|
+
animSubresources += `[sub_resource type="Animation" id="Animation_${stepCount}"]
|
|
72
|
+
resource_name = "${anim.anim_name}"
|
|
73
|
+
length = ${duration}
|
|
74
|
+
loop_mode = ${loopMode}
|
|
75
|
+
tracks/0/type = "value"
|
|
76
|
+
tracks/0/imported = false
|
|
77
|
+
tracks/0/enabled = true
|
|
78
|
+
tracks/0/path = NodePath("Sprite2D:frame")
|
|
79
|
+
tracks/0/interp = 1
|
|
80
|
+
tracks/0/loop_wrap = true
|
|
81
|
+
tracks/0/keys = {
|
|
82
|
+
"times": PackedFloat32Array(${anim.frames.map((_, idx) => (idx / (anim.fps || 10)).toFixed(3)).join(', ')}),
|
|
83
|
+
"transitions": PackedFloat32Array(${anim.frames.map(() => '1').join(', ')}),
|
|
84
|
+
"update": 1,
|
|
85
|
+
"values": [${anim.frames.join(', ')}]
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
`;
|
|
89
|
+
animLibEntries += `"${anim.anim_name}": SubResource("Animation_${stepCount}"),\n`;
|
|
90
|
+
stepCount++;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
animSubresources += `[sub_resource type="AnimationLibrary" id="AnimationLibrary_rig"]
|
|
94
|
+
_data = {
|
|
95
|
+
${animLibEntries.trim()}
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
const sceneTree = `[gd_scene load_steps=${stepCount + 2} format=3]
|
|
100
|
+
|
|
101
|
+
[ext_resource type="Texture2D" path="${spriteSheetPath}" id="1_tex"]
|
|
102
|
+
|
|
103
|
+
${animSubresources}
|
|
104
|
+
[node name="${characterName}" type="CharacterBody2D"]
|
|
105
|
+
|
|
106
|
+
[node name="Sprite2D" type="Sprite2D" parent="."]
|
|
107
|
+
texture = ExtResource("1_tex")
|
|
108
|
+
hframes = ${hFrames}
|
|
109
|
+
vframes = ${vFrames}
|
|
110
|
+
|
|
111
|
+
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
|
112
|
+
libraries = {
|
|
113
|
+
"": SubResource("AnimationLibrary_rig")
|
|
114
|
+
}
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
if (outputPath) {
|
|
118
|
+
await fs.mkdir(path.dirname(outputPath), { recursive: true });
|
|
119
|
+
await fs.writeFile(outputPath, sceneTree, 'utf8');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
success: true,
|
|
124
|
+
output: JSON.stringify({
|
|
125
|
+
status: 'RIGGED_2D_SPRITESHEET',
|
|
126
|
+
character: characterName,
|
|
127
|
+
sprite_sheet: spriteSheetPath,
|
|
128
|
+
animations_configured: anims.map(a => a.anim_name),
|
|
129
|
+
output_file: outputPath || 'Returned in payload',
|
|
130
|
+
scene_snippet: sceneTree.slice(0, 1000)
|
|
131
|
+
}, null, 2)
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (action === 'create_animation_tree') {
|
|
136
|
+
const treeConfig = {
|
|
137
|
+
character: characterName,
|
|
138
|
+
tree_type: 'AnimationTree',
|
|
139
|
+
state_machine: {
|
|
140
|
+
states: ['Idle', 'Walk', 'AttackSlash', 'Hit', 'Death'],
|
|
141
|
+
transitions: [
|
|
142
|
+
{ from: 'Idle', to: 'Walk', condition: 'is_moving' },
|
|
143
|
+
{ from: 'Walk', to: 'Idle', condition: '!is_moving' },
|
|
144
|
+
{ from: 'Idle', to: 'AttackSlash', condition: 'attack_trigger' },
|
|
145
|
+
{ from: 'Walk', to: 'AttackSlash', condition: 'attack_trigger' },
|
|
146
|
+
{ from: 'AttackSlash', to: 'Idle', condition: 'auto_finish' },
|
|
147
|
+
{ from: 'Any', to: 'Hit', condition: 'take_damage' },
|
|
148
|
+
{ from: 'Any', to: 'Death', condition: 'hp_zero' }
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
gdscript_integration: `
|
|
152
|
+
# Paste into ${characterName}.gd
|
|
153
|
+
@onready var anim_tree: AnimationTree = $AnimationTree
|
|
154
|
+
@onready var state_machine = anim_tree.get("parameters/playback")
|
|
155
|
+
|
|
156
|
+
func _physics_process(delta: float) -> void:
|
|
157
|
+
\tvar velocity_length = velocity.length()
|
|
158
|
+
\tvar is_moving = velocity_length > 10.0
|
|
159
|
+
\tanim_tree.set("parameters/conditions/is_moving", is_moving)
|
|
160
|
+
\tanim_tree.set("parameters/conditions/not_moving", not is_moving)
|
|
161
|
+
`
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
success: true,
|
|
166
|
+
output: JSON.stringify(treeConfig, null, 2)
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (action === 'attach_weapon_bone') {
|
|
171
|
+
const attachmentSnippet = `[node name="BoneAttachment_${boneName}" type="BoneAttachment3D" parent="Skeleton3D"]
|
|
172
|
+
bone_name = "${boneName}"
|
|
173
|
+
|
|
174
|
+
[node name="EquippedWeapon" parent="Skeleton3D/BoneAttachment_${boneName}" instance=ExtResource("${propScenePath}")]
|
|
175
|
+
position = Vector3(0, 0.1, 0)
|
|
176
|
+
rotation_degrees = Vector3(90, 0, 0)
|
|
177
|
+
`;
|
|
178
|
+
return {
|
|
179
|
+
success: true,
|
|
180
|
+
output: JSON.stringify({
|
|
181
|
+
status: 'ATTACHED_WEAPON_BONE',
|
|
182
|
+
bone: boneName,
|
|
183
|
+
prop: propScenePath,
|
|
184
|
+
scene_snippet: attachmentSnippet
|
|
185
|
+
}, null, 2)
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return { success: false, error: `Unknown action: ${action}` };
|
|
190
|
+
} catch (e) {
|
|
191
|
+
return { success: false, error: e.message };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
};
|