Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 130 additions & 0 deletions .trae/skills/撰写文档-write-documentation/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
---
name: 撰写文档 Write Documentation
description: "### Write Documentation\n\nThis command is invoked when the code changes for a feature or bugfix are complete on a branch (branched from `develop`) and documentation is the only remaining task. The AI should discover what changed, categorize it, and write the appropriate documentation entries."
---

#### Workflow

**Step 0: Determine the author**

Use `git log develop...HEAD --format="%an <%ae>"` to list commits on the current branch that are not in `develop`. If the branch has extra commits, use the author name(s) from those commits as the user's identity for `CREDITS.md` and `Whats-New.md`. If there are no extra commits or the author cannot be determined from commit information, ask the user directly for their identity before proceeding.

**Step 1: Discover what changed**

Run `git diff develop...HEAD --stat` to see which files were modified. Then inspect the diffs in detail using `git diff develop...HEAD` (or `git diff develop...HEAD -- <specific files>`) to understand the nature of each change. Key things to identify:
- New/changed INI keys (tags) — look for `.Read(exINI, ...)` calls in `LoadFromINIFile` / `LoadBeforeTypeData` etc.
- New/changed hooks — look for `DEFINE_HOOK`, `DEFINE_JUMP`, `DEFINE_PATCH` macros.
- New types/classes — look for new files in `src/New/` or new `ExtData` classes.
- Whether the change is a new feature, an enhancement of existing behavior, a bugfix, a UI change, an AI/scripting change, or something miscellaneous.

**Step 2: Categorize the change**

Determine which doc pages need updating:

| Change type | Where to document |
|-------------|------------------|
| New feature (brand new functionality) | New `### ` section in the appropriate primary doc page, inserted in **dictionary (alphabetical) order** among existing sibling `### ` headings |
| Enhancement of existing game behavior that adds new INI tags | New `### ` section in the appropriate primary doc page, likewise in alphabetical order |
| Enhancement/bugfix of existing game behavior with **no new INI tags** | A bullet point under `## Bugfixes and miscellaneous` in `docs/Fixed-or-Improved-Logics.md` |
| User interface change (new hotkey, display, sidebar, tooltip) | `docs/User-Interface.md` |
| AI, scripting, trigger, or mapping change | `docs/AI-Scripting-and-Mapping.md` |
| Uncategorized change | `docs/Miscellanous.md` |
| New user setting in RA2MD.INI | `docs/Whats-New.md` (under "New user settings") |

Primary doc page mapping:
- Most game logic features → `docs/New-or-Enhanced-Logics.md`
- Within this file, `## ` headings are categories (e.g., `## Buildings`, `## Projectiles`, `## Warheads`). Place new `### ` sections under the appropriate category, sorted alphabetically.

Additionally, every non-trivial change requires:
- **`docs/Whats-New.md`** — changelog entry.
- **`CREDITS.md`** — credit the author.

**Step 3: Draft the documentation text — user review required before writing**

Before writing any documentation, draft the descriptive text and present it to the user for review. Use the following format for the draft:

```
### <Feature Name>

- <Brief meaning of the feature.>
- (tab-indented) <INI key> controls/determines/is used for <explanation>.
```

Two styles for the first bullet point:
- **New feature** (brand new functionality):
```
- Now you can <do something>. (新功能)
```
- **Enhancement of existing behavior** (patches/improves vanilla logic):
```
- In vanilla, <describe the problem>. Now you can <describe the fix/enhancement>.
```

Wait for the user to approve the drafted text before proceeding to write it into the actual doc files.

**Step 4: Write the main documentation**

After user approval, write the approved text into the appropriate doc file. For sections in `docs/New-or-Enhanced-Logics.md` or similar, insert the new `### ` section in alphabetical order among existing sibling headings under the correct `## ` category. Look at existing sibling `### ` headings to determine the correct insertion point.

Continue with the INI code block following existing conventions:

````markdown
In `rulesmd.ini`:
```ini
[SECTION] ; ObjectType
KeyName=default ; accepted type
KeyName.WithDots=default ; accepted type with optional explanation
```
````

Key rules for INI documentation:
- Use ` ```ini ` fenced code blocks.
- Section header comment format: `[SOMENAME]` followed by spaces then `; ObjectType` (e.g., `; BuildingType`, `; TechnoType`, `; WarheadType`, `; SuperWeaponType`).
- For global sections use the literal section name: `[General]`, `[AudioVisual]`, `[CombatDamage]`, `[Radiation]`, `[AI]`, etc.
- Key name, equals sign, default value (or blank if empty), spaces, semicolon, type description.
- Boolean types are documented as `; boolean`.
- Integer types as `; integer`.
- Floating point types as `; double` or `; float`.
- Pointer types as `; AnimType` (just the game class name, not full C++ type).
- List types as `; list of TechnoType` etc.
- If the INI key name contains dots, it maps naturally (e.g. `KeyName.SubKey` stays as-is in docs).

When there are many related keys, group them logically within the same section and INI block. Put them in the order they appear in the INI section.

**Step 5: Chinese translation**

After the English documentation has been written and confirmed, produce a Chinese translation of the new section(s). Present the Chinese text to the user for review and confirmation. Update the corresponding `.po` files in `docs/locale/zh_CN/LC_MESSAGES/` after the user approves the translation.

**Step 6: Write `docs/Whats-New.md` entry**

Whats-New entries go under the `### Version TBD (develop branch nightly builds)` section. Use the author identity determined in Step 0. The entry should be a bullet point briefly describing the change and how it might affect existing mods:

```markdown
- <description of what changed and what modders need to do to adapt> (by <AuthorName>)
```

If new INI keys are user-facing settings in `RA2MD.INI`, also add them under the `### New user settings in RA2MD.INI` section:
```ini
[Phobos]
NewKeyName=true ; boolean
```

If INI keys were renamed, add entries under `### Changed tags` using the format seen in existing entries:
```markdown
- `[Section] -> OldName` -> `[Section] -> NewName`
```

**Step 7: Write `CREDITS.md` entry**

Use the author identity determined in Step 0. Find the author's section in `CREDITS.md`. If the author doesn't have a section yet, create one. Add a bullet describing the contribution:

```markdown
- **AuthorName (GitHubUsername)**:
- Feature description matching the phrasing used in other entries
```

Do not skip the CREDITS entry unless the user explicitly says to skip it.

**Step 8: Review and confirm**

After writing all entries, present a summary to the user showing which files were modified and what was added.
124 changes: 124 additions & 0 deletions .trae/skills/生成ini标签-generate-ini-tag/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
name: 生成INI标签 Generate INI tag
description: "A \"tag\" is an INI key that generally corresponds to a C++ property. Defining a tag requires modifications in four places within the target `ExtData` class: **declaration**, **initialization**, **serialization**, and **INI loading**. If the user does not provide all information explicitly, the AI should infer the missing pieces, present them to the user for confirmation, and only proceed after approval."
---

#### 1. Determine the Class

Game entities have **instance classes** (e.g., `BuildingClass`) and **static type classes** (e.g., `BuildingTypeClass`). Tags are almost always defined in the static type class's `ExtData` — when the user says "add a tag for buildings", they mean `BuildingTypeExt::ExtData`. Same pattern applies:

| User says | Corresponding ExtData |
|-----------|----------------------|
| Building / BuildingType | `BuildingTypeExt::ExtData` |
| Vehicle / Unit / UnitType | `UnitTypeExt::ExtData` (or `TechnoTypeExt::ExtData`) |
| Infantry / InfantryType | `InfantryTypeClass` → `TechnoTypeExt::ExtData` |
| Aircraft / AircraftType | `AircraftTypeClass` → `TechnoTypeExt::ExtData` |
| Warhead | `WarheadTypeExt::ExtData` |
| Weapon | `WeaponTypeExt::ExtData` |
| Bullet / Projectile | `BulletTypeExt::ExtData` |
| SuperWeapon / SW | `SWTypeExt::ExtData` |
| Animation / Anim | `AnimTypeExt::ExtData` |
| Particle | `ParticleTypeExt::ExtData` |
| Terrain / TerrainType | `TerrainTypeExt::ExtData` |
| Overlay / OverlayType | `OverlayTypeExt::ExtData` |
| Global / Rules | `RulesExt::ExtData` |

Note: `TechnoTypeExt::ExtData` is the **common base class** extension for `BuildingType`, `UnitType`, `InfantryType`, and `AircraftType`. If a tag applies to all Techno types, place it in `TechnoTypeExt`; if it applies only to a specific subtype, place it in the corresponding subclass Ext (e.g., buildings only → `BuildingTypeExt`).

#### 2. Determine the Section

- **Non-global tags**: Read from `pSection` (the INI section matching the instance ID/name) inside `LoadFromINIFile`. Determine whether to use `pSection` or `pArtSection`:
- `pSection` = `pThis->ID` — reads from the identically-named section in `rulesmd.ini`. The vast majority of tags go here.
- `pArtSection` = `pThis->ImageFile` — reads from the identically-named section in `artmd.ini`, using `INI_Art` / `exArtINI`. Generally used for visual, graphical, or animation-related tags. Check whether the class's `LoadFromINIFile` defines a `pArtSection` variable and `exArtINI` to see if this is supported.
- **Global tags**: For `RulesExt::ExtData`, read from fixed global sections such as `GameStrings::General` (`[General]`), `GameStrings::CombatDamage` (`[CombatDamage]`), `GameStrings::Radiation` (`[Radiation]`), `GameStrings::AudioVisual` (`[AudioVisual]`), `GameStrings::AI` (`[AI]`), etc. Infer the appropriate section based on the key name's semantics.

#### 3. Determine the Key Name

The INI key name specified by the user. **Critical conversion rule: dots `.` in the key name become underscores `_` in the C++ property name.**

For example: `"Factory.IsSuper"` → C++ property name `Factory_IsSuper`

#### 4. Determine the Type

Infer the C++ type based on semantics. Common types and their wrappers:

| Semantics | C++ Type | Wrapper |
|-----------|---------|---------|
| Boolean on/off switch | `bool` | `Valueable<bool>` |
| Integer (count, frames, int percentage) | `int` | `Valueable<int>` |
| Floating point (ratio, multiplier, speed) | `double` | `Valueable<double>` |
| In-game distance (Lepton) | `Leptons` | `Valueable<Leptons>` |
| Coordinate | `CoordStruct` / `Point2D` | `Valueable<CoordStruct>` |
| Color | `ColorStruct` | `Valueable<ColorStruct>` |
| Nullable (omitting means use default logic) | any | `Nullable<T>` |
| List (comma-separated values) | `std::vector<T>` | `ValueableVector<T>` |
| Pointer to another game type | `WeaponTypeClass*` etc. | `Valueable<WeaponTypeClass*>` |
| Index lookup (sounds etc.) | see `ValueableIdx` | `ValueableIdx<VocClass>` |
| Enum | game enum | `Valueable<AffectedHouse>` etc. |

**Inference rules:**
- Key name contains `Is`/`Can`/`Allow`/`Use`/`Has`/`Enable`/`Disable` → likely `Valueable<bool>`
- Key name contains `Amount`/`Count`/`Max`/`Min`/`Delay`/`Rate`/`Frame` (integer) → likely `Valueable<int>`
- Key name contains `Factor`/`Mult`/`Percent`/`Speed`/`Ratio`/`Chance` → likely `Valueable<double>`
- Key name contains `Type` (singular pointer) → `Valueable<SomeTypeClass*>`
- Key name contains `Types` (plural) → `ValueableVector<SomeTypeClass*>`
- When unsure about optionality, default to `Valueable<T>` (required); use `Nullable<T>` if omitting is semantically valid.

#### 5. Implementation Steps

Modify the `Body.h` and `Body.cpp` of the target ExtData. Follow these four steps:

**A. Declare the property (Body.h → ExtData public section)**

Follow existing declaration style, e.g.:
```cpp
Valueable<bool> Factory_IsSuper;
```

**B. Initialize the property (Body.h → ExtData constructor initializer list)**

Add a default value in the constructor, matching the existing format (comma-first, aligned):
```cpp
, Factory_IsSuper { false }
```

**C. Register in serialization (Body.cpp → Serialize function)**

Insert into the `Stm` chain in `Serialize(T& Stm)`, ordered alphabetically or logically:
```cpp
.Process(this->Factory_IsSuper)
```

**D. INI loading (Body.cpp → LoadFromINIFile function)**

Based on the section determined in step 2, choose `exINI` or `exArtINI`, and `pSection` or `pArtSection`:
```cpp
// From rulesmd.ini (most common)
this->Factory_IsSuper.Read(exINI, pSection, "Factory.IsSuper");

// From artmd.ini (visual/graphical)
this->Factory_IsSuper.Read(exArtINI, pArtSection, "Factory.IsSuper");

// Global tag example (RulesExt)
this->Factory_IsSuper.Read(exINI, GameStrings::General, "Factory.IsSuper");
```

If the property is a pointer to another game type (e.g., `Valueable<WeaponTypeClass*>`), use `.Read<true>` to enable auto-creation:
```cpp
this->SomeWeapon.Read<true>(exINI, pSection, "SomeWeapon");
```

#### 6. Full Example

User says: "add a tag called `Factory.IsSuper` for buildings"

Inference process:
- Class: `BuildingTypeExt::ExtData` ("buildings" → building type static data)
- Section: `pSection` (not visual-related)
- Key: `Factory.IsSuper` → property name `Factory_IsSuper`
- Type: `Valueable<bool>` (contains `Is`, boolean semantics)
- Default: `false` (conservative default)

After confirmation, modify:
- [Body.h](file:///f:/RA2%20Engine%20Extension/MJobos/src/Ext/BuildingType/Body.h): declaration + initialization
- [Body.cpp](file:///f:/RA2%20Engine%20Extension/MJobos/src/Ext/BuildingType/Body.cpp): Serialize + LoadFromINIFile
Loading