Author SHA1 Message Date
letteka 0f22125007 Updating gitea runners (#2)
Validate Project / validate (push) Successful in 15s
Reviewed-on: #2
Co-authored-by: Andrew Kettel <andrew.kettel@gmail.com>
2026-08-28 09:54:50 -07:00
15 changed files with 1 additions and 2877 deletions
-38
View File
@@ -1,38 +0,0 @@
# =============================================================================
# YeetGeese - Gitea API Configuration Template
# =============================================================================
#
# Instructions:
# 1. Copy this file to .env.gitea in the project root:
# cp .env.gitea.template .env.gitea
#
# 2. Edit .env.gitea with your actual values (especially GITEA_TOKEN)
#
# 3. Load it before using CLI commands:
# source .env.gitea # or export $(cat .env.gitea | grep -v '^#' | xargs)
#
# =============================================================================
# Gitea Server Address (adjust if different from standard port 30009)
GITEA_HOST="https://gitea.letteka.com"
# Your Gitea username
GITEA_USER="letteka"
# Repository name
GITEA_REPO="YeetGeese"
# Personal Access Token (Required!)
# To create a token:
# 1. Go to https://gitea.letteka.com/user/applications
# 2. Click "New Application" or "Create Token"
# 3. Give it a name like "YeetGeese PR Creator"
# 4. Select scopes: admin, user, repo
# 5. Copy the generated token here (replace TOKEN_HERE)
GITEA_TOKEN="TOKEN_HERE"
# Development branch (default target for PRs)
GITEA_BASE_BRANCH="develop"
# SSH URL alternative (if you prefer SSH instead of HTTPS)
# GITEA_SSH_URL="git@gitea.letteka.com:30009/letteka/YeetGeese.git"
-124
View File
@@ -1,124 +0,0 @@
#!/bin/bash
# =============================================================================
# YeetGeese Gitea PR Helper Script
# =============================================================================
# This script automates creating pull requests via Gitea API using your .env.gitea
#
# Usage:
# source .gitea-helper # Load helper into current shell
# create-pr # Creates PR from current branch to develop
# gitea-create-pr # Alias for above
# =============================================================================
# Environment file path
ENV_FILE=".env.gitea"
# Source the environment file if it exists
if [[ -f "$ENV_FILE" ]]; then
export $(grep -v '^#' "$ENV_FILE" | xargs)
echo "✓ Loaded configuration from $ENV_FILE"
else
echo "✗ Error: $ENV_FILE not found!"
echo "Please copy .env.gitea.template to .env.gitea and configure GITEA_TOKEN"
exit 1
fi
# Validate required variables
if [[ -z "$GITEA_TOKEN" ]]; then
echo "✗ Error: GITEA_TOKEN is not set in $ENV_FILE"
echo "Create a Personal Access Token at: https://gitea.letteka.com/user/applications"
exit 1
fi
# Function to get current branch
get_current_branch() {
git rev-parse --abbrev-ref HEAD
}
# Function to create PR using Gitea API
create_pr() {
local target_branch="${1:-develop}"
local current_branch=$(get_current_branch)
echo "=========================================="
echo "Creating Pull Request..."
echo "=========================================="
echo "Source Branch: $current_branch"
echo "Target Branch: $target_branch"
# Get git diff summary for context
local file_count=$(git diff --name-only "$target_branch"..HEAD 2>/dev/null | wc -l)
# Generate PR description with comprehensive details
local pr_body="**Pull Request from \`$current_branch\` to \`$target_branch\`**\n\n## Context\n\nThis pull request reorganizes all AI documentation files into a structured \`AI Docs/\` folder to improve maintainability and clarity for AI-assisted development workflows.\n\n### Files Changed ($file_count files)\n\n#### Documentation Files\n- **01-AI-GUIDE.md → AI Docs/AI_HELP.md** (renamed)\n- **02-ARCHITECTURE.md → AI Docs/ARCHITECTURE.md** (renamed)\n- **PLAN.md → AI Docs/PLAN.md**\n- **PLAN_MORE.md → AI Docs/PLAN_MORE.md**\n- **TESTING-WORKFLOW.md → AI Docs/04-TESTING-WORKFLOW.md**\n- **SKILLS-REFERENCE.md → AI Docs/05-SKILLS-REFERENCE.md**\n\n### Changes Summary\n- All documentation moved to \`AI Docs/\` folder with organized structure\n- Files numbered sequentially (01-, 02-, etc.) for easy navigation\n- Renamed files have better, more descriptive names\n- Architecture and planning docs are now clearly separated\n\n### Testing Strategy\n\n**1. File Structure Verification:**\n - ✓ All documentation files present in \`AI Docs/\` folder\n - ✓ No files deleted from root (only renamed/moved)\n - ✓ Folder structure is clean and organized\n\n**2. Content Verification:**\n - Review each file for readability and proper formatting\n - Check Markdown rendering in browser\n - Verify internal links work correctly\n\n**3. AI Team Review Required:**\n - Review updated guides for clarity and completeness\n - Ensure documentation matches current architecture\n - Update any AI-related references in code or scripts\n\n### Validation Performed\n\n✅ **Git History Preserved**:\n - Changes committed to \`$current_branch\` branch\n - Complete git history maintained\n - No conflicts introduced\n\n✅ **Local Validation:**\n - All files readable and accessible\n - Git status clean (no uncommitted changes)\n - Ready for review and merge\n\n### Reviewer Notes\n\n**Key Areas Requiring Attention:**\n1. Content accuracy in all documentation files\n2. Internal link integrity after reorganization\n3. AI workflow alignment with new structure\n4. Any additional notes or requirements from maintainers",
echo "PR Body Preview (first 500 chars):"
echo "----------------------------------------"
echo "${pr_body:0:500}"
echo "... [truncated] ..."
echo ""
# Create PR via Gitea API
curl -X POST "https://gitea.letteka.com/api/v1/repos/letteka/YeetGeese/pulls" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"title\": \"[AI Docs] Reorganize documentation into structured folder\",\
\"body\": \"${pr_body}\",
\"base\": \"${target_branch}\",
\"head\": \"letteka:${current_branch}\"
}" \
--output /dev/null \
2>/dev/null
if [[ $? -eq 0 ]]; then
local pr_id=$(curl -s "https://gitea.letteka.com/api/v1/repos/letteka/YeetGeese/pulls" \
-H "Authorization: token $GITEA_TOKEN" \
| jq -r '.[] | select(.head\.ref == '"${current_branch}"') | .number' 2>/dev/null)
if [[ ! -z "$pr_id" ]]; then
echo ""
echo "=========================================="
echo "✓ SUCCESS! PR Created!"
echo "=========================================="
echo "PR Number: ${pr_id}"
echo "View at: https://gitea.letteka.com/letteka/YeetGeese/pulls/${pr_id}"
echo ""
echo "Next Steps:"
echo "1. Visit the PR URL above to review"
echo "2. Add any additional comments if needed"
echo "3. Once approved, merge from web UI or API"
else
echo ""
echo "✓ SUCCESS! PR Created!"
echo "View at: https://gitea.letteka.com/letteka/YeetGeese/pulls/new/${current_branch}"
fi
else
echo ""
echo "✗ FAILED to create PR via API"
echo "Fallback: Visit https://gitea.letteka.com/letteka/YeetGeese/pulls/new/move_docs manually"
exit 1
fi
return 0
}
# Main command handling
if [[ "$1" == "" ]]; then
# No arguments - create PR from current branch to develop
create_pr "develop"
elif [[ "$1" == "help" ]]; then
echo "Gitea PR Helper - Commands:"
echo " [no args] Create PR from current branch to 'develop'"
echo " help Show this help message"
else
echo "Unknown command: $1"
echo "Usage: create-pr [target-branch]"
echo ""
echo "Examples:"
echo " create-pr # Create PR to develop branch"
echo " create-pr main # Create PR to main branch"
fi
# Also support alias name
alias gitea-create-pr=create_pr
-5
View File
@@ -13,8 +13,3 @@ desktop.ini
# Build output (keep out of src/) # Build output (keep out of src/)
bin/ bin/
osu!/ osu!/
.env
.env.gitea
*.uid
-39
View File
@@ -1,39 +0,0 @@
{
"name": "make-pr",
"description": "Create pull requests using Gitea API with comprehensive change overview and testing strategies",
"agent_type": "pr-creator",
"capabilities": {
"generate-pr-overview": "Human-readable summary of all changes including files modified, new features, fixes, and refactoring",
"list-testing-strategies": "Suggest comprehensive testing approaches for each change (unit tests, integration tests, manual QA)",
"validate-changes": "Perform git diff analysis to ensure validation is ready before PR creation",
"format-pr-description": "Structure PR description with clear sections for context, changes, testing, and validation"
},
"when_to_use": [
"When you are ready to create a pull request from your current branch to develop",
"Before pushing code that requires peer review",
"When implementing features or fixes that need documentation in the PR",
"To ensure all changes are properly documented and validated before review"
],
"input_required": [
"Target branch (default: 'develop')",
"Optional custom PR title override",
"Optional specific testing requirements for the current change"
],
"prompt_template": "Generate a pull request description from branch '{current_branch}' to '{target_branch}'.\n\nThe PR should include:\n\n1. Human-readable overview of all changes\n - List files modified/created/deleted with brief descriptions\n - Summarize new features, bug fixes, and refactoring\n - Highlight any breaking changes or API modifications\n\n2. Testing strategies for each major change:\n - Unit testing approach (if applicable)\n - Integration testing requirements\n - Manual QA steps needed\n - Regression areas to check\n\n3. Validation already performed:\n - List any tests that pass locally\n - Mention manual validation completed\n - Note any performance checks done\n - Flag any known issues or limitations\n\n4. Clear context for reviewers:\n - What problem does this solve?\n - How does it relate to existing code?\n - Any migration notes needed?",
"validation_steps": [
"Run git diff to analyze all changed files",
"Check that changes compile/validate in the project",
"Review for obvious bugs or unintended side effects",
"Ensure PR description is clear and complete"
],
"output_format": {
"pr_title": "Concise, descriptive title following conventional commits format when applicable",
"pr_body": "Structured with clear sections: Context, Changes, Testing Strategy, Validation Performed",
"reviewer_notes": "Optional notes highlighting key areas requiring attention"
},
"cli_commands": {
"create_pr": "curl -X POST \"${GITEA_HOST:-https://gitea.letteka.com}/api/v1/repos/${GITEA_USER:-letteka}/${GITEA_REPO:-YeetGeese}/pulls\" \\n -H \"Authorization: token ${GITEA_TOKEN}\" \\n -d '{\\n \\\"title\\\": \\\"${PR_TITLE}\\\",\\n \\\"body\\\": \\\"${PR_BODY}\\\",\\n \\\"base\\\": \\\"${TARGET_BRANCH:-develop}\\\",\\n \\\"head\\\": \\\"${GITEA_USER:-letteka}:${CURRENT_BRANCH}\\\"\\n}'",
"get_diff_summary": "git diff --name-only ${TARGET_BRANCH:-develop}..HEAD 2>/dev/null | wc -l || echo \"0\"",
"validate_git_status": "git status --short && git log -1 --oneline --quiet"
}
}
-455
View File
@@ -1,455 +0,0 @@
# Testing Workflow Guide for YeetGeese
This document provides a structured approach to testing Godot 4.x games, with specific focus on the tower defense mechanics of YeetGeese. It covers what to test, how to structure tests, and debugging failed tests.
---
## Table of Contents
1. [Testing Philosophy](#testing-philosophy)
2. [Test Organization](#test-organization)
3. [Test Categories](#test-categories)
4. [Writing Tests](#writing-tests)
5. [Debugging Failed Tests](#debugging-failed-tests)
6. [CI Integration](#ci-integration)
---
## Testing Philosophy
### Why Test?
- **Regression prevention:** Catch unintended side effects from changes
- **Documentation by example:** Tests serve as usage examples
- **Design validation:** Ensure architecture matches intent
- **Confidence for refactoring:** Safe to reorganize code when tested
### What AI Can Help With
AI can:
- Generate boilerplate test scaffolding
- Suggest edge cases and boundary conditions
- Write mock implementations for complex systems
- Explain Godot testing framework capabilities
### What AI Cannot Handle
AI should NOT:
- Design game mechanics or balance (human domain)
- Make subjective quality-of-life judgments
- Replace manual playtesting of actual gameplay feel
- Generate test data for art assets (no AI-generated art rule applies)
---
## Test Organization
### Directory Structure
```
tests/
├── core/ # Autoloads and global state tests
│ ├── wave_progression_test.gd
│ └── currency_manager_test.gd
├── towers/ # Tower behavior tests
│ ├── tower_base_test.gd
│ ├── projectile_spawner_test.gd
│ └── target_finder_test.gd
├── enemies/ # Enemy system tests
│ ├── enemy_mob_test.gd
│ ├── navigation_system_test.gd
│ └── spawner_test.gd
├── projectiles/ # Projectile handling tests
│ ├── goose_projectile_test.gd
│ └── impact_handler_test.gd
├── ui/ # HUD and menu tests
│ ├── health_bar_test.gd
│ └── currency_display_test.gd
├── utils/ # Utility functions
│ └── math_utils_test.gd
└── integration/ # Cross-system tests
├── wave_complete_sequence_test.gd
└── tower_placement_integration_test.gd
```
### Naming Conventions
- Files: `<system>_test.gd` (e.g., `tower_base_test.gd`)
- Functions: `func test_<behavior_description>()` (e.g., `func test_fire_rate_scales_with_level()`)
- Assertions: Use descriptive names like `assert_equal`, `assert_signal_emitted`, `assert_no_error`
---
## Test Categories
### Unit Tests
Test individual functions or methods in isolation.
**Example:** Testing a tower's fire rate calculation
```gdscript
@tool
extends Node
func test_fire_rate_calculation(tower: Node) -> void:
assert_equal(tower.fire_rate, 1.0)
# Modify tower level
tower.tower_level = 2
# Verify fire rate changed appropriately
assert_greater(tower.fire_rate, 1.0)
assert_less(tower.fire_rate, 2.0)
func test_damage_scaling_by_tower_level(tower: Node) -> void:
tower.tower_level = 3
var initial_damage = tower.get_damage_at_current_level()
tower.tower_level = 5
# Verify damage increased with level
assert_greater(tower.get_damage_at_current_level(), initial_damage)
```
**When to use:**
- Testing pure logic (math, state transitions)
- Testing Resource loading and property access
- Testing signal emission patterns
---
### Integration Tests
Test interactions between multiple systems.
**Example:** Testing the full projectile launch sequence
```gdscript
@tool
extends Node
func test_projectile_launch_sequence() -> void:
# Arrange: Create mock tower and target
var tower := _create_mock_tower()
var target := _create_mock_target()
# Act: Fire at target
tower.fire_at(target)
# Assert: Verify projectile spawned in correct state
assert_true(tower.projectile_count == 1)
assert_equal(tower.projectiles[0].source_node, tower.$ProjectileSpawner)
```
**When to use:**
- Testing scene hierarchies with multiple nodes
- Verifying signal connections between systems
- Validating Godot's built-in component behavior (e.g., RigidBody2D movement)
---
### Regression Tests
Tests added when a bug is fixed to ensure it doesn't return.
**Example:** Preventing physics tunneling after a collision fix
```gdscript
@tool
extends Node
func test_projectile_collision_prevents_tunneling() -> void:
# Scenario: Goose projectile moving at high speed
var projectile := _create_goose_with_velocity(100.0)
var enemy := _create_enemy_with_small_hitbox()
# Act: Move projectile toward enemy's hitbox
projectile.yeet_from(projectile.position, enemy.position)
# Assert: Projectile detected collision on this frame
assert_signal_emitted(projectile, 'collision_detected')
```
**When to use:**
- After fixing a critical bug
- When performance regression occurs
- To validate edge case handling
---
## Writing Tests
### Test Function Template
```gdscript
@tool
extends Node
func test_<behavior_under_test>() -> void:
# Arrange: Setup the scenario
var <subject> := _create_mock_<subject>()
# Act: Execute the action being tested
<subject>.<method_or_event>()
# Assert: Verify expected behavior
assert_true(<condition_1>)
assert_false(<condition_2>)
assert_signal_emitted(<signal_source>, '<signal_name>')
```
### Available Assertions
| Assertion | Purpose | Example |
|-----------|---------|---------|
| `assert_equal(a, b)` | Check exact equality | `assert_equal(tower.level, 3)` |
| `assert_not_equal(a, b)` | Check inequality | `assert_not_equal(projectile.speed, 0.0)` |
| `assert_true(condition)` | Verify boolean is true | `assert_true(tower.is_ready())` |
| `assert_false(condition)` | Verify boolean is false | `assert_false(projectile.is_removed())` |
| `assert_greater(a, b)` | Check a > b | `assert_greater(damage_dealt, 10)` |
| `assert_less(a, b)` | Check a < b | `assert_less(enemy.health, 50.0)` |
| `assert_null(obj)` | Verify object is null | `assert_null(projectile.get_target())` |
| `assert_not_null(obj)` | Verify object exists | `assert_not_null(projectile)` |
| `assert_array_size(arr, size)` | Check array length | `assert_array_size(tower.projectiles, 4)` |
### Signal Testing Pattern
```gdscript
var _signal_verified = false
func test_health_changed_signal_emits_correct_values() -> void:
var enemy := EnemyMob.new()
enemy.health_changed.connect(func(new_health) {
assert_true(_signal_verified == false) # Prevent double-firing
assert_equal(new_health, 75.0)
_signal_verified = true
})
enemy.take_damage(25.0)
assert_true(_signal_verified)
```
### Mock Object Helpers
Use these helper functions to create mock objects for tests:
```gdscript
# Create a mock tower with minimal setup
func _create_mock_tower() -> Node:
var tower := TowerBase.new()
tower.tower_level = 1
return tower
# Create a mock enemy for collision testing
func _create_mock_enemy() -> EnemyMob:
var enemy := EnemyMob.new()
enemy.health = 50.0
enemy.damage_taken.connect(func() { pass }) # Prevent death on damage
return enemy
# Verify no error occurred during test
func _assert_no_error(condition: bool) -> void:
assert_true(condition, "Test completed with errors")
```
---
## Debugging Failed Tests
### Common Failure Patterns
#### 1. Test Completes Before Signal Fires
**Problem:** `signal_emitted` verification fails because the test ends too early.
**Solution:** Add a yield or use Godot's built-in coroutine system:
```gdscript
func test_signal_fires_after_delay() -> void:
var subject := _create_subject()
subject.event.triggered.connect(_on_event_triggered)
subject.do_something()
# Ensure signal fires before test ends
get_tree().process_frame.connect(_on_frame_processed)
yield(get_tree(), "process_frame") # Wait for signal
assert_true(_signal_received)
func _on_frame_processed() -> void:
_on_event_triggered.call_deferred()
```
#### 2. Scene Loading in Tests Fails
**Problem:** Godot scenes loaded via `load("res://...")` may not find their resources.
**Solution:** Use absolute paths or ensure test assets are in proper location:
```gdscript
# Bad: Relative path that breaks in tests
var mob_scene := load("enemy_mob.tscn").instantiate()
# Good: Absolute resource path
var mob_scene := load("res://src/enemies/enemy_mob.tscn").instantiate()
```
#### 3. Random Behavior Causes Flaky Tests
**Problem:** Tests pass sometimes but fail others due to randomness (e.g., particle emission).
**Solution:** Disable randomness in test environment:
```gdscript
# At start of test, seed RNG for reproducibility
Rand.randi = func() -> int: return 42 # Fixed value for testing
# Or disable randomness for specific systems
var projectile := Projectile.new()
projectile.random_variation_enabled = false
```
#### 4. Physics Tunneling in Collision Tests
**Problem:** Fast-moving projectiles miss collisions when tested with static enemies.
**Solution:** Use multiple physics frames or smaller time steps:
```gdscript
func test_high_velocity_collision_detection() -> void:
var projectile := _create_goose_with_velocity(200.0)
# Run multiple physics frames for collision detection
for _ in range(5):
get_tree().physics_ticks_processed = 1
get_tree().process_frame()
assert_true(_collision_detected)
```
#### 5. Signal Connections Leak Between Tests
**Problem:** Test A's signal handlers remain active when Test B runs.
**Solution:** Disconnect signals at test end:
```gdscript
func cleanup_test(subject: Node, signal_name: String) -> void:
subject.signal_removed.connect(_disconnect_signals)
# Clear all signals from subject
var signals = subject.get_signal_list()
for s in signals:
if s.is_connected(func):
s.disconnect(func)
# Call cleanup at end of each test function
```
---
## CI Integration (Optional for Indie Teams)
### GitHub Actions / GitLab CI Setup
If using a continuous integration server, add tests to build pipeline.
**Example workflow:**
```yaml
name: YeetGeese Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Godot
run: |
# Download and install Godot 4.x stable
- name: Run Tests
run: |
godot --path . --headless tests/run_all_tests.gd
```
### Local Test Runner Script
Create a script to run all tests from command line:
```gdscript
# tests/run_all_tests.gd
extends Node
func _ready():
var result := 0
# Run unit tests
for file in DirAccess.get_directories() if dir_name == "core" or dir_name == "towers":
pass # Implementation depends on test runner framework
if result == 0:
print("All tests passed!")
else:
error("Some tests failed")
func _exit_tree():
quit(0)
```
---
## Testing Checklist
### Before Writing Tests for New Feature
- [ ] Identify the system(s) being tested
- [ ] Determine unit vs. integration testing needs
- [ ] List expected inputs and outputs
- [ ] Identify edge cases (empty arrays, null objects, etc.)
### Test Coverage Goals
| System Type | Recommended Test Coverage |
|-------------|---------------------------|
| Core game loop | 100% (critical path) |
| Tower logic | 90%+ |
| Enemy AI states | 85%+ |
| UI displays | 80%+ |
| Utility functions | 95%+ |
### Review Checklist for AI-Generated Tests
When asking AI to generate tests, verify:
- [ ] Uses `@tool` directive for editor-only execution
- [ ] Sets up proper mock objects for isolation
- [ ] Disconnects signals at test end to prevent leaks
- [ ] Uses absolute paths for resource loading
- [ ] Handles expected error conditions gracefully
- [ ] Includes assertions for all critical behaviors
---
## Summary
**AI can help with:**
- Generating boilerplate test scaffolding
- Suggesting edge cases and boundary conditions
- Writing mock implementations for complex systems
- Explaining Godot testing framework capabilities
**Remember:**
- Tests should be runnable in editor (`@tool` functions)
- Keep tests focused on one behavior per function
- Disconnect signals to prevent cross-test contamination
- Use absolute paths for resource loading in tests
- Document test intent with clear, descriptive names
For more details, see `AI_HELP.md` for prompt templates when working with AI assistants on testing tasks.
-547
View File
@@ -1,547 +0,0 @@
# Skills, Agents, and Commands Reference
This document provides a reference for AI assistants working with YeetGeese. It describes available capabilities, when to use them, and best practices for interaction.
---
## Table of Contents
1. [Available Skills](#available-skills)
2. [Agent Types & Use Cases](#agent-types--use-cases)
3. [Command Reference](#command-reference)
4. [Prompt Templates](#prompt-templates)
5. [Best Practices](#best-practices)
---
## Available Skills
### `customize-opencode`
**Purpose:** Configure and modify the AI assistant's own settings, including:
- `opencode.json`, `opencode.jsonc` files
- `.opencode/` configuration directory
- `~/.config/opencode/` user settings
- Agent definitions (subagents, skills, plugins, MCP servers)
- Permission rules
**When to use:** When configuring the AI assistant itself, not for project code.
**Example:**
```
"Adjust the maximum context window size for this session."
```
---
### `make-pr` — Pull Request Creation (Gitea Web UI)
**Purpose:** On Gitea, pull requests are created directly via the web interface at:
`https://gitea.letteka.com/letteka/YeetGeese/pulls/new/move_docs`
**How to use on Gitea:**
1. Push changes to a branch (e.g., `move_docs`)
2. Visit the URL above or navigate via Gitea web UI
3. Create PR with descriptive title and body
4. Include testing strategies and validation status in description
**When to use:**
- When ready to submit a pull request from your current branch
- Before pushing code that requires peer review
- To ensure all changes are properly documented and validated
- When creating PRs for features, fixes, or refactoring
**Best practices for Gitea PRs:**
- Use descriptive titles following conventional commits format
- Include file-by-file change summary in PR body
- List testing strategies: unit tests, integration tests, manual QA
- Mention any validation already performed locally
- Flag known issues or limitations clearly
---
## Agent Types & Use Cases
### `code-gen` — Code Generation
**Purpose:** Write new code, implement features, create boilerplate.
**Capabilities:**
- GDScript 4 implementation
- Scene graph construction descriptions
- Resource file (`.tres`) schema design
- Signal declarations and connections
- Method implementations matching project conventions
**When to use:**
- Implementing a new tower or projectile type
- Adding a feature to existing systems
- Creating boilerplate for common patterns
- Writing unit tests
**Input required:**
- Target file path or node description
- Desired behavior/goal
- Any constraints (e.g., "must use Resource for stats")
**Example prompt:**
```
"Create a GDScript 4 class `ImpactEffect.gd` that extends Area2D. It should:
1. Detect collision with enemies in _body_entered
2. Emit signal 'effect_triggered' with damage and target Node2D
3. Apply random color variation to its texture
4. Set lifespan to 0.8 seconds
5. Include comments explaining each step"
```
---
### `debug-helper` — Debugging Assistance
**Purpose:** Analyze errors, suggest debugging strategies, interpret profiler output.
**Capabilities:**
- Error message interpretation (Godot/IDE/compiler)
- Suggesting debugging tool usage (Scene Debugger, Physics Monitor)
- Profiling tips and bottleneck identification
- Common pitfall recognition (e.g., physics tunneling, navmesh gaps)
**When to use:**
- When an error occurs during implementation
- When code behaves unexpectedly
- When performance issues appear in profiler
**Input required:**
- Error message or log output
- Relevant file paths and line numbers if available
- Brief description of expected vs. actual behavior
**Example prompt:**
```
"This tower stops firing after 30 seconds even though fire_rate is set to 1.0.
Error: 'get_tree()' returned null at runtime. Debug it."
```
---
### `refactor-assistant` — Refactoring Support
**Purpose:** Break up large scripts, improve code organization, add documentation.
**Capabilities:**
- Splitting monolithic scripts into smaller nodes
- Extracting methods into separate components
- Adding documentation and type hints
- Applying project conventions consistently
**When to use:**
- Scripts are growing beyond 150 lines
- Multiple unrelated behaviors in one node
- Need to improve readability before review
**Input required:**
- File path or code snippet
- Refactoring goal (e.g., "split into state machines")
- Target organization style
**Example prompt:**
```
"Refactor this 400-line EnemyMob.gd into smaller components:
1. Extract navigation logic to NavigationComponent
2. Extract attack behavior to AttackState
3. Keep health/currency handling in base class
4. Add documentation comments for each section"
```
---
### `test-generator` — Test Generation
**Purpose:** Create unit tests for game logic systems.
**Capabilities:**
- Writing Godot test cases using `@tool` functions
- Setting up mock scenes and signals
- Testing Resource-based stat changes
- Validating collision detection and hit calculations
**When to use:**
- After implementing core logic that should be validated
- Before refactoring (to preserve behavior)
- When adding critical game mechanics
**Input required:**
- System or function being tested
- Expected inputs and outputs
- Edge cases to cover
**Example prompt:**
```
"Create tests for TowerBase._can_build_at(). Test:
1. Returns true in valid tower placement zones
2. Returns false inside enemy navmesh
3. Returns false when grid coordinate exceeds bounds
4. Returns false if parent node is null"
```
---
### `design-patterns` — Design Pattern Suggestions
**Purpose:** Recommend architecture patterns suited to specific problems.
**Capabilities:**
- Suggesting ECS for complex entity management
- Recommending FSM for enemy AI states
- Proposing event-driven systems for decoupled components
- Advising on data-oriented vs. object-oriented design
**When to use:**
- Before implementing a new system
- When performance becomes an issue
- When refactoring existing code
**Input required:**
- Problem description (e.g., "I need many entities with simple movement")
- Performance constraints if any
- Preferred Godot nodes or patterns already in use
**Example prompt:**
```
"I'm building a system for 50+ projectiles that need to track targets, apply damage, and handle collision.
Current approach: individual RigidBody2D for each projectile.
What pattern would scale better?"
```
---
### `balance-helper` — Balance Analysis
**Purpose:** Analyze math relationships and suggest tuning adjustments.
**Capabilities:**
- Calculating damage per second (DPS) from fire rate and projectile stats
- Estimating kill time based on enemy HP and total damage sources
- Suggesting resource stat ranges that preserve balance space
- Identifying scaling relationships between tower levels
**When to use:**
- Before adding new towers/enemies with different power levels
- When gameplay feels too easy or difficult
- During tuning phase of wave progression
**Input required:**
- Current stats (damage, fire rate, enemy HP)
- Desired behavior description (e.g., "kill time should scale with tier")
- Resource file structure if applicable
**Example prompt:**
```
"Current: goose damage=15, fire_rate=1.0/s, chicken HP=80.
Tower Level 2 has 4 geese. Calculate total DPS and suggest enemy HP range
for level-appropriate difficulty (aim for ~30s wave duration)."
```
---
### `level-design-helper` — Level Design Assistance
**Purpose:** Plan layout, progression, and pacing for levels or zones.
**Capabilities:**
- Wave progression suggestions (spawn rates, path complexity)
- Tower placement zone recommendations
- Pacing analysis for difficulty curves
- Zone-based checkpoint design
**When to use:**
- Before creating a new level or wave sequence
- When gameplay feels too repetitive or frustrating
- During playtesting feedback analysis
**Input required:**
- Level description (size, available zones)
- Current wave structure if any
- Difficulty curve goals
**Example prompt:**
```
"I have 4 tower placement zones along a path with 3 turns.
Current waves: linear difficulty increase.
Suggest a progression that introduces new mechanics at zone boundaries."
```
---
### `doc-generator` — Documentation Generation
**Purpose:** Create documentation from existing code or planning data.
**Capabilities:**
- Generating API docs from GDScript class structures
- Writing changelogs from commit history
- Creating release notes with feature summaries
- Producing onboarding guides from project structure
**When to use:**
- Before releasing a version
- After implementing a major feature set
- When new team members join the project
**Input required:**
- Source code or commit messages
- Feature list for changelog entries
- Target audience (developers, players)
**Example prompt:**
```
"Generate API documentation for the WaveRunner system:
1. Describe each public method and its parameters
2. List signals emitted with their payloads
3. Document the Resource dependencies
4. Include usage examples"
```
---
### `onboarding-guide` — Onboarding Documentation
**Purpose:** Create setup tutorials and getting-started guides for new developers.
**Capabilities:**
- Environment setup instructions (OS-specific)
- Project structure explanation
- Editor scene loading order
- Common first tasks with examples
**When to use:**
- Before bringing on new team members
- When updating project structure significantly
- For release candidate documentation
**Input required:**
- Target OS versions supported
- Required Godot version and plugins
- Team conventions to teach
**Example prompt:**
```
"Write an onboarding guide for a new developer joining YeetGeese:
1. Explain folder structure (src/core, src/towers, etc.)
2. Show how to run the game from main.tscn
3. Describe the tower placement workflow
4. List common commands for debugging"
```
---
### `api-specs` — API Specification
**Purpose:** Define external interfaces and save/load contracts.
**Capabilities:**
- Defining save file format schemas
- Documenting modding API endpoints
- Specifying network message protocols
- Creating serialization guides
**When to use:**
- Before implementing persistent storage
- When enabling mod support
- For multiplayer networking design
**Input required:**
- Interface type (save format, mod API, network protocol)
- Required functionality list
- Platform constraints
**Example prompt:**
```
"Define a save file format for YeetGeese:
1. Must store unlocked towers and their levels
2. Must include currency progress and wave number
3. Use Godot Resource serialization (.tres files)
4. Include version field for backward compatibility"
```
---
## Command Reference
### Code Writing Commands
| Command | When to use |
|---------|-------------|
| `create file <path>` | For new classes, scenes, or resource files |
| `modify file <path>` | For adding methods or changing existing code |
| `describe scene <path>` | To generate scene tree descriptions for AI understanding |
### Review Commands
| Command | When to use |
|---------|-------------|
| `review code <path>` | For checking convention compliance |
| `optimize performance <scope>` | For profiling suggestions in specific areas |
| `debug error <message>` | For interpreting errors and suggesting fixes |
### Documentation Commands
| Command | When to use |
|---------|-------------|
| `generate docs` | For API documentation from code |
| `write changelog` | After implementing features or fixing bugs |
| `create onboarding guide` | For new developer setup instructions |
---
## Prompt Templates
### Feature Implementation Template
```
Context: I'm implementing [feature name] in [system/file].
Current state: [brief description of existing code/structure]
Goal: [what this feature should do]
Constraints: [any restrictions like "must use Resource" or "no UI changes"]
Please provide:
1. Complete, runnable GDScript 4 code with comments
2. Scene hierarchy description if new scenes are needed
3. Any new Resources (.tres) and their structure
4. Signal declarations and connection points
```
### Debugging Template
```
Error context: [where the error occurred]
Error message: [full error output]
Expected behavior: [what should have happened]
Actual behavior: [what actually happened]
Debug steps tried: [what you've already attempted]
Please provide:
1. Root cause analysis
2. Minimal fix with explanation
3. Prevention strategy for future occurrences
```
### Refactoring Template
```
Current code: [file path or snippet]
Issues to address: [e.g., "too monolithic", "missing docs"]
Refactoring goals: [what you want to achieve]
Target patterns: [any existing patterns to match]
Please provide:
1. Proposed refactored structure
2. New files and their responsibilities
3. Migration steps for existing code
```
---
## Best Practices
### 1. Always Provide Context First
Before asking for code, share:
- The relevant file path or node description
- The GDScript version being used (Godot 4.x)
- Key related signals and methods already in place
**Good:**
```
"Create an ImpactEffect.gd extending Area2D with these existing methods:
- _body_entered(var area): called on collision
- emit_signal('effect_triggered', damage, target)"
```
**Bad:**
```
"I need a collision effect for projectiles."
```
### 2. Specify Godot 4 Conventions
When requesting code, remind AI of conventions:
- Use typed signals: `signal health_changed(new_health: float)`
- Prefer `@onready` over `$` in scripts
- Type variables and return values consistently
- Keep scenes modular (compose behavior across nodes)
### 3. Reference Existing Architecture
When implementing features, reference existing patterns:
```
"Implement this using the same pattern as TowerBase.fire_at():
- Use projectile_res.instantiate() for new goose projectiles
- Spawn from $ProjectileSpawner.global_position
- Add to parent tree immediately after instantiation"
```
### 4. Specify Resource Dependencies Early
If your project uses Resources for balance:
```
"Create a Resource-based stats file for this tower:
- Fields: damage (float), fire_rate (float), cooldown_reduction (float)
- Make it loadable as a Godot Resource (.tres)
- Show how the tower reads its stats on _ready()"
```
### 5. Ask for Complete, Runnable Code
When requesting implementations:
```
"Return complete, runnable GDScript 4 code with:"
"- Comments explaining each major section"
"- Type annotations for all variables and methods"
"- Signal declarations at top of class"
```
---
## Summary
**Use these skills strategically:**
- `code-gen`: For new features and boilerplate
- `debug-helper`: When errors occur or behavior is wrong
- `refactor-assistant`: Before code grows unmanageable
- `test-generator`: After implementing critical logic
- `design-patterns`: When architecture becomes unclear
**Always provide:**
- File paths, node names, and Godot version context
- Desired behavior in terms of existing patterns
- Constraints (Resource usage, signal conventions)
**When in doubt:** Reference `AI_HELP.md` for project-specific conventions before asking questions.
---
## Note About `make-pr` Skill Availability
The **`make-pr`** skill (`.opencode/skills/make-pr.json`) is available for use! This skill will:
- Generate comprehensive, human-readable PR descriptions
- List testing strategies for each change area
- Validate changes before PR creation
- Format PR descriptions with clear sections
**When to use `make-pr` skill:**
- When ready to submit a PR from your current branch (any platform)
- Before pushing code that requires peer review
- To ensure all changes are properly documented and validated
- When creating PRs for features, fixes, or refactoring
The skill automatically adapts to your hosting platform:
- **GitHub:** Creates PR via API with comprehensive descriptions
- **Gitea:** Falls back to web UI creation (URL provided above)
**Prompt example:**
```
"Create a pull request from move_docs to develop. The changes include moving
all AI documentation files into an 'AI Docs' folder with organized structure."
```
-1445
View File
File diff suppressed because it is too large Load Diff
+1 -15
View File
@@ -22,18 +22,4 @@ When prompting an AI about this project, include:
- Flag any Godot 3 vs 4 API differences (e.g., `move_and_slide()` behavior, signal typing). - Flag any Godot 3 vs 4 API differences (e.g., `move_and_slide()` behavior, signal typing).
- If a request needs multiple scenes, describe the scene hierarchy before showing code. - If a request needs multiple scenes, describe the scene hierarchy before showing code.
Read `ARCHITECTURE.md` for system boundaries and data flow expectations.
## Handling Ambiguity & Assumptions (Crucial!)
When a request is ambiguous, incomplete, or requires knowledge outside the scope of the provided documents:
1. **DO NOT guess.** Do not write code based on assumptions you cannot validate.
2. **Acknowledge the Gap:** Explicitly state what information is missing or unclear (e.g., "The current architecture does not specify how \`WaveRunner\` handles player death.").
3. **Propose Assumptions:** If a concrete implementation path *must* be shown, list all assumptions made clearly before writing code. Use a dedicated section like:
\`\`\`markdown
**[ASSUMPTIONS MADE]**
1. We assume that the \`PlayerStats\` Resource is accessible from the global scope.
2. We are assuming the signal for enemy death will be named \`mob_killed\`.
\`\`\`
This ensures that the final code provided by AI can be reviewed against project reality before integration.
-22
View File
@@ -1,22 +0,0 @@
# 🚀 YeetGeese - Phase 0 Design Summary
**Genre:** Third-Person Over-the-Shoulder Tower Defense
**Core Fantasy:** A lone defender in a farm arena, utilizing powerful projectile geese to defend their base from waves of approaching enemies. The goal is simple but satisfying: yeet and survive!
## 🦢 Core Loop
Enemies spawn → Player maneuvers & aims → **Yeets Goose** (Damage/Stun) → Currency collected (Feathers) → Player upgrades defenses/geese → Wave ends → Repeat with increased difficulty.
## 🎯 Minimum Viable Product (MVP) Scope
| Feature | Detail | Status |
| :--- | :--- | :--- |
| **Arena** | Single, open 3D farm arena. | Defined |
| **Player** | Third-person controller (WASD + Mouse Look). Basic Health System. | Defined |
| **Weapon** | One basic Goose projectile (medium damage, spinning, self-lifetime). | Defined |
| **Enemies** | Two types: **Pigs** (Slow/Tank) & **Chickens** (Fast/Skirmisher). | Defined |
| **Progression** | 5 Waves total. Basic economy (Feathers collected from kills). | Defined |
| **UI/Win/Loss** | Health bar, Feather Count, Wave Counter. Win: Survive 5 waves. Loss: Player HP $\le$ 0. | Defined |
## ⚙️ Technical Foundation
* **Engine:** Godot 4.x (3D, Forward+).
* **Architecture:** Utilize autoloads (`GameState`, `EventBus`, etc.) to manage state centrally and decouple systems.
* **Key Systems:** Input mapping (Movement, Aim, Throw), defined collision layers (Environment, Player, Enemy, Goose, Currency).
-134
View File
@@ -1,134 +0,0 @@
# YeetGeese - Design Document
## Game Concept
**YeetGeese** is an over-the-shoulder third-person tower defense game where the player defends a base by throwing geese as powerful projectiles. The core fantasy is absurdly simple but deeply satisfying: enemies approach your objective, and you yeet geese at them to stop them.
---
## Core Fantasy
> *"I am alone in a 3D farm arena, viewed from behind my shoulders. Farm animals march toward my base. I aim with mouse, throw with a click, and watch geese crash into foes with satisfying honks, spins, and impact. Each throw feels powerful and purposeful."*
- **Player**: A lone defender in over-the-shoulder third-person
- **Weapon**: Throwable geese that act as both projectiles and temporary turrets
- **Objective**: Protect the base from waves of approaching farm animals (Pigs, Chickens)
- **Juice**: Every goose hit produces satisfying feedback (honks, feathers, screen shake)
---
## Core Loop
```
[ENEMIES SPAWN] → [PLAYER MOVES & AIMS] → [YEET GEESE] →
[GEESE DAMAGE/DISTRACT ENEMIES] → [CURRENCY COLLECTED] →
[BUY UPGRADES/NEW GEESE] → [WAVE COMPLETE?] → [NEXT WAVE (HARDER)]
```
### Breakdown:
1. **Enemies spawn** at designated points and march toward the base
2. **Player moves** through the arena in third-person, positioning for optimal throws
3. **Player aims and yeets geese** using mouse look and click
4. **Geese impact enemies**, dealing damage or causing knockback/stun
5. **Currency drops** (feathers) from defeated enemies
6. **Player spends currency** on upgrades or new goose types
7. **Wave ends** when all enemies are eliminated
8. **Next wave begins**, with more/enemy variety/difficulty
---
## MVP Scope
### One Arena
- Simple, open arena with clear spawn and base zones
- Neutral terrain allowing free movement
### One Player Controller
- **Player Controller**: Over-the-shoulder third-person view (WASD + mouse look, throw input)
- **Basic health system**
### One Goose Type
- **Basic Goose**: Standard projectile goose
- Medium damage, standard speed
- Spins on throw
- Flees after impact or short lifetime
### Two Enemy Types
1. **Pig** (formerly Grunt) Slow, low health, standard damage (meat shield)
2. **Chicken** (formerly Runner) Fast, low health, reaches base quickly
### Five Waves
| Wave | Enemies | Description |
|------|-----------------------------------|---------------------------------|
| 1 | 3 Pigs | Tutorial wave |
| 2 | 5 Pigs | Slight increase |
| 3 | 4 Pigs + 2 Chickens | Introduction of speed |
| 4 | 6 Mixed (Pig/Chicken) | Mix of both types |
| 5 | Boss wave: Oinker Boss | Large, high-health farm animal |
### Basic Economy
- **Starting currency**: 100 feathers
- **Enemy drop**: 510 feathers per kill
- **Goose cost**: Free for first type
- **Upgrade/shop unlock**: Every 10 kills unlocks new goose slot
### Basic UI
- Top-left: Health bar, feather count
- Top-right: Wave number
- Pause menu (Escape)
- Game over / Victory screens
### Win/Lose Conditions
- **Win**: Survive all 5 waves
- **Lose**: Player health reaches 0
---
## Godot Setup Summary
### Project Type
- Godot 4.x, 3D project, Forward+ renderer
### Directory Structure
```
res://
├── scripts/ # GDScript files
├── scenes/ # .tscn files
├── assets/
│ ├── audio/
│ ├── meshes/
│ ├── textures/
│ ├── materials/
│ └── animations/
├── ui/ # HUD, menus
├── data/ # Wave/upgrade configs
├── autoload/ # GameState, EventBus, AudioManager
└── tests/
```
### Autoloads
- `GameState.gd` Wave state, currency, lives, pause
- `EventBus.gd` Central signals for gameplay events
- `AudioManager.gd` SFX and music playback
- `SettingsManager.gd` Settings persistence
### Collision Layers
| Layer | Type |
|-------|-------------------------|
| 1 | Environment |
| 2 | Player |
| 3 | Enemy |
| 4 | Goose projectile |
| 5 | Goose turret |
| 6 | Currency/pickups |
| 7 | UI / trigger zones |
---
## Exit Criteria for Phase 0
- [ ] Design document is complete (this one page)
- [ ] Godot project opens cleanly in 3D mode
- [ ] Folders and autoloads are created
- [ ] Input map is configured (WASD, mouse, throw, pause)
- [ ] MVP scope is documented and understood
---
*This document defines the foundation for a small but complete playable prototype. Phase 1 will build exactly this scope; additional content comes later.*
-14
View File
@@ -1,14 +0,0 @@
# AudioManager.gd
extends Node
var music_player # Reference to AudioStreamPlayer for background music
func _ready():
print("AudioManager loaded. Ready to play sounds.")
func play_sfx(sound_path: String):
# Logic to play a sound effect
pass
func play_music(stream: AudioStream):
# Logic to set and play background music
pass
-14
View File
@@ -1,14 +0,0 @@
# SettingsManager.gd
extends Node
const SETTINGS_PATH = "user://settings.save"
func save_setting(key: String, value):
print("Saving setting: " + key)
# Logic to serialize and save settings data
pass
func load_setting(key: String):
print("Loading setting: " + key)
# Logic to read saved setting data
return null
-7
View File
@@ -1,7 +0,0 @@
# EventBus.gd
extends Node
signal event_fired(event: String, data: Dictionary)
func emit_event(event: String, data: Dictionary = {}):
print("Emitting event: " + event)
emit_signal("event_fired", data)
-18
View File
@@ -1,18 +0,0 @@
# GameState.gd
extends Node
# --- COLLISION LAYERS (TASK 4) ---
const LAYER_ENVIRONMENT = 1 # Environment/terrain
const LAYER_PLAYER = 2 # Player character
const LAYER_ENEMY = 3 # Enemy mobs
const LAYER_GOOSE_PROJECTILE = 4 # Goose projectiles
const LAYER_TURRET = 5 # Fixed towers/turrets
const LAYER_PICKUP = 6 # Currency, power-ups
const LAYER_UI_TRIGGER = 7 # UI interaction zones
var score = 0
var currency = 100
var current_wave = 0
var game_state = "PAUSED" # States: PAUSED, RUNNING, WIN, LOSE
func _ready():
print("GameState loaded. Initializing core systems.")