Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e440f66405 | ||
|
|
0a08384da2 | ||
|
|
d2f710a6a1 | ||
|
|
44462624cd |
No files matched your search
+38
@@ -0,0 +1,38 @@
|
|||||||
|
# Godot 4.x
|
||||||
|
.godot/
|
||||||
|
.idea/
|
||||||
|
sdk/
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
|
||||||
|
#ai
|
||||||
|
.omo/
|
||||||
|
.opencode/
|
||||||
|
|
||||||
|
gen/
|
||||||
|
obj/
|
||||||
|
bin/
|
||||||
|
art_sources/
|
||||||
|
|
||||||
|
*.tres~
|
||||||
|
*.tscn~
|
||||||
|
|
||||||
|
# GDScript LSP
|
||||||
|
.godot/
|
||||||
|
|
||||||
|
# Export
|
||||||
|
*.exe
|
||||||
|
*.dmg
|
||||||
|
*.apk
|
||||||
|
*.aab
|
||||||
|
*.pck
|
||||||
|
*.zip
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Editor
|
||||||
|
*.import
|
||||||
|
*.godot.uid
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"key": "battle.core",
|
||||||
|
"name": "collection_settings/battle",
|
||||||
|
"description": "collection_settings/battle_hint",
|
||||||
|
"group": "collection_settings/battle_group",
|
||||||
|
"type": "choice",
|
||||||
|
"source": null,
|
||||||
|
"allow_custom": false,
|
||||||
|
"automatic": "collection_settings/battle_auto"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 91 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
+97
@@ -0,0 +1,97 @@
|
|||||||
|
# Turn Battle Base — the platform under every battle
|
||||||
|
|
||||||
|
Turn Battle Base is what all turn-based battles in the collection share: starting a battle from a scenario, the battle scene with the backdrop of the place where it began, the victory and defeat screens, experience and loot, status effects such as stun, and the choice of a **battle system**. It does not decide how the player fights. That is the job of a battle system mod: **FF Battle** (a command menu) or **Card Battle** (cards dragged onto targets).
|
||||||
|
|
||||||
|
## Two battle systems, one platform
|
||||||
|
|
||||||
|
The same fight in RPG Plus — the warrior against a wolf in the village — in the two systems:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Everything around the fight is the same: the village backdrop, the wolf's numbers, the speed buttons **x1 / x4 / x8** at the top right (they speed up the animations; the choice is remembered), and what happens after it.
|
||||||
|
|
||||||
|
A game chooses its system with the collection setting `battle.core`; RPG Plus uses `ff_battle`. Without the setting the first installed system is used. In the collection editor the setting is called *Battle system*.
|
||||||
|
|
||||||
|
## How a battle goes
|
||||||
|
|
||||||
|
```text
|
||||||
|
scenario: battle.init / rpg.battle
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle scene: backdrop of the current place, party from the roster, enemies from their files
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle system (ff_battle or card_battle): player turn <-> enemy turn
|
||||||
|
| |
|
||||||
|
all enemies defeated party defeated
|
||||||
|
v v
|
||||||
|
Victory: experience, loot Defeat: Main menu
|
||||||
|
|
|
||||||
|
v
|
||||||
|
back to the scene the battle started from
|
||||||
|
```
|
||||||
|
|
||||||
|
## Victory and defeat
|
||||||
|
|
||||||
|
When the last enemy falls, the victory screen shows each surviving party member's experience and the loot:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- **Experience.** Each defeated enemy gives its `Level × Exp`, shared equally among the party members still standing. The wolf is level 2 with `Exp` 12 — **+24**.
|
||||||
|
- **Loot.** Each defeated enemy rolls its `Loot` list; the items go straight into the inventory.
|
||||||
|
- **Continue** returns to the scene the battle came from. Health lost in battle stays lost.
|
||||||
|
|
||||||
|
If the whole party falls, the defeat screen offers only **Main menu**: no experience, no loot.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Starting a battle from a scenario
|
||||||
|
|
||||||
|
```scenario
|
||||||
|
action battle.init scene=town_entry enemies=wolf_1,wolf_2 quest_id=MeetingMurakamiQuest new_tag=wolf_battle
|
||||||
|
switch_scene Battle
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- `enemies` — character ids, comma-separated; the same id twice gives two enemies.
|
||||||
|
- `scene` — the scene to return to after a victory.
|
||||||
|
- `quest_id`, `new_tag` (optional) — bind the battle to a quest and give it a tag (a journal notification).
|
||||||
|
- The backdrop is the background shown at that moment, so set it before `battle.init`.
|
||||||
|
|
||||||
|
On a tile map, use `action rpg.battle enemies=rpg_wolf win_flag=rpg_wolf_dead` from the RPG mod instead: it returns to the same map cell and sets the flag on victory.
|
||||||
|
|
||||||
|
`action battle.set_core core=card_battle` switches the battle system for the following battles.
|
||||||
|
|
||||||
|
## Enemies, loot and status effects in data
|
||||||
|
|
||||||
|
Enemies are ordinary characters (see Characters Engine). The loot of the RPG Plus wolf:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Id": "rpg_wolf",
|
||||||
|
"Loot": [
|
||||||
|
{ "ItemId": "rpg_plus/wolf_pelt", "MinCount": 2, "MaxCount": 3, "Probability": 100 },
|
||||||
|
{ "ItemId": "money/coin", "MinCount": 8, "MaxCount": 14, "Probability": 100 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`Probability` is a percentage; the count is a random number from `MinCount` to `MaxCount` inclusive.
|
||||||
|
|
||||||
|
**Status effects** are entities of kind `status_effect`. The platform brings stun — the character skips its turns:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "Id": "effect/physics/stun", "Icon": "characters/effects/stun", "Type": "Stun", "Duration": 3, "Actions": "basic/stun" }
|
||||||
|
```
|
||||||
|
|
||||||
|
A battle action that applies it may set its own number of turns; durations count down at the start of each turn.
|
||||||
|
|
||||||
|
## For mod authors
|
||||||
|
|
||||||
|
A battle system is a mod that registers an `IBattleCore` (with `IBattleAutoPlayable` for the automatic tests). Its actions run through the platform's executors, so a mod such as Battle Formulas adds new kinds of actions to every system at once. Code can react to the end of a battle through `BattleEndedEvent` and to the victory through an `IWingroundListener`; Recruiting uses this to offer defeated enemies a place in the party.
|
||||||
|
|
||||||
|
## If something goes wrong
|
||||||
|
|
||||||
|
1. **The battle has an empty backdrop.** `battle.init` ran before the scene's background was set.
|
||||||
|
2. **The wrong battle system opens.** Check the game's `battle.core` setting, and whether a scenario switched it with `battle.set_core`.
|
||||||
|
3. **No experience after a victory.** Enemies with `Exp` 0 give none; party members who fell get none.
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
# Turn Battle Base — la plataforma común de todos los combates
|
||||||
|
|
||||||
|
Turn Battle Base es lo que comparten todos los combates por turnos de la colección: iniciar un combate desde un escenario, la escena de batalla con el fondo del lugar donde empezó, las pantallas de victoria y derrota, la experiencia y el botín, los efectos de estado como el aturdimiento y la elección del **sistema de combate**. Cómo lucha el jugador no lo decide la plataforma: ese es el trabajo de un mod de sistema de combate, **FF Battle** (menú de comandos) o **Card Battle** (cartas que se arrastran sobre los objetivos).
|
||||||
|
|
||||||
|
## Dos sistemas de combate, una plataforma
|
||||||
|
|
||||||
|
La misma pelea de RPG Plus — el guerrero contra un lobo en la aldea — en los dos sistemas:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Todo lo que rodea al combate es igual: el fondo de la aldea, los números del lobo, los botones de velocidad **x1 / x4 / x8** arriba a la derecha (aceleran las animaciones, y la elección se recuerda) y lo que ocurre después.
|
||||||
|
|
||||||
|
Cada juego elige su sistema con el ajuste de colección `battle.core`; RPG Plus usa `ff_battle`. Sin ese ajuste se toma el primer sistema instalado. En el editor de colecciones el ajuste se llama «Sistema de combate».
|
||||||
|
|
||||||
|
## Cómo se desarrolla un combate
|
||||||
|
|
||||||
|
```text
|
||||||
|
scenario: battle.init / rpg.battle
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle scene: backdrop of the current place, party from the roster, enemies from their files
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle system (ff_battle or card_battle): player turn <-> enemy turn
|
||||||
|
| |
|
||||||
|
all enemies defeated party defeated
|
||||||
|
v v
|
||||||
|
Victory: experience, loot Defeat: Main menu
|
||||||
|
|
|
||||||
|
v
|
||||||
|
back to the scene the battle started from
|
||||||
|
```
|
||||||
|
|
||||||
|
## Victoria y derrota
|
||||||
|
|
||||||
|
Cuando cae el último enemigo, la pantalla de victoria muestra la experiencia de cada miembro del grupo que siga en pie y el botín:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- **Experiencia.** Cada enemigo derrotado aporta su `Level × Exp`, que se reparte a partes iguales entre quienes sigan en pie. El lobo es de nivel 2 con `Exp` 12: **+24**.
|
||||||
|
- **Botín.** Para cada enemigo derrotado se tira su lista de `Loot`; los objetos van directos al inventario.
|
||||||
|
- **Continue** devuelve a la escena de la que salió el combate. La vida perdida en el combate sigue perdida.
|
||||||
|
|
||||||
|
Si cae todo el grupo, la pantalla de derrota solo ofrece **Main menu**: ni experiencia ni botín.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Iniciar un combate desde un escenario
|
||||||
|
|
||||||
|
```scenario
|
||||||
|
action battle.init scene=town_entry enemies=wolf_1,wolf_2 quest_id=MeetingMurakamiQuest new_tag=wolf_battle
|
||||||
|
switch_scene Battle
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- `enemies` — ids de personajes separados por comas; el mismo id dos veces son dos enemigos.
|
||||||
|
- `scene` — la escena a la que volver tras la victoria.
|
||||||
|
- `quest_id`, `new_tag` (opcionales) — vinculan el combate a una misión y le ponen una etiqueta (una notificación en el diario).
|
||||||
|
- El fondo del combate es el que se muestre en ese momento, así que defínelo antes de `battle.init`.
|
||||||
|
|
||||||
|
Sobre un mapa de tiles usa en su lugar el `action rpg.battle enemies=rpg_wolf win_flag=rpg_wolf_dead` del mod RPG: el grupo vuelve a la misma casilla y, al ganar, se activa la bandera.
|
||||||
|
|
||||||
|
La acción `action battle.set_core core=card_battle` cambia el sistema de combate para los combates siguientes.
|
||||||
|
|
||||||
|
## Enemigos, botín y efectos de estado en los datos
|
||||||
|
|
||||||
|
Los enemigos son personajes normales (véase Characters Engine). El botín del lobo de RPG Plus:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Id": "rpg_wolf",
|
||||||
|
"Loot": [
|
||||||
|
{ "ItemId": "rpg_plus/wolf_pelt", "MinCount": 2, "MaxCount": 3, "Probability": 100 },
|
||||||
|
{ "ItemId": "money/coin", "MinCount": 8, "MaxCount": 14, "Probability": 100 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`Probability` es un porcentaje; la cantidad es un número aleatorio entre `MinCount` y `MaxCount`, ambos incluidos.
|
||||||
|
|
||||||
|
Los **efectos de estado** son entidades de tipo `status_effect`. La plataforma trae de serie el aturdimiento: el personaje pierde sus turnos:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "Id": "effect/physics/stun", "Icon": "characters/effects/stun", "Type": "Stun", "Duration": 3, "Actions": "basic/stun" }
|
||||||
|
```
|
||||||
|
|
||||||
|
Una acción de combate que lo aplique puede fijar su propio número de turnos; las duraciones se descuentan al comienzo de cada turno.
|
||||||
|
|
||||||
|
## Para autores de mods
|
||||||
|
|
||||||
|
Un sistema de combate es un mod que registra un `IBattleCore` (y `IBattleAutoPlayable` para las pruebas automáticas). Sus acciones pasan por los ejecutores de la plataforma, así que un mod como Battle Formulas añade nuevos tipos de acciones a todos los sistemas a la vez. El código puede reaccionar al final del combate con `BattleEndedEvent` y a la victoria con un `IWingroundListener`; Recruiting lo aprovecha para ofrecer un puesto en el grupo a los enemigos derrotados.
|
||||||
|
|
||||||
|
## Si algo sale mal
|
||||||
|
|
||||||
|
1. **El combate sale con el fondo vacío.** `battle.init` se ejecutó antes de definir el fondo de la escena.
|
||||||
|
2. **Se abre el sistema de combate equivocado.** Revisa el ajuste `battle.core` del juego y si algún escenario lo cambió con `battle.set_core`.
|
||||||
|
3. **No hay experiencia tras la victoria.** Los enemigos con `Exp` 0 no dan experiencia, y los miembros del grupo caídos tampoco reciben.
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
# Turn Battle Base —— すべての戦闘を支えるプラットフォーム
|
||||||
|
|
||||||
|
Turn Battle Base は、コレクション内のすべてのターン制戦闘に共通する土台です。シナリオからの戦闘開始、戦闘が始まった場所を背景にした戦闘シーン、勝利・敗北の画面、経験値と戦利品、スタンなどのステータス効果、そして**バトルシステム**の選択を担います。プレイヤーがどう戦うかは、ここでは決まりません。それはバトルシステムのModの仕事です。**FF Battle**(コマンドメニュー)と **Card Battle**(カードをターゲットへドラッグ)がそれに当たります。
|
||||||
|
|
||||||
|
## 2つのバトルシステム、1つのプラットフォーム
|
||||||
|
|
||||||
|
RPG Plus での同じ戦闘——村で戦士が狼と対峙する場面——を、2つのシステムで並べます:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
戦闘を取り巻く部分はどちらも同じです。村の背景、狼の数値、右上の速度ボタン **x1 / x4 / x8**(アニメーションを速めるもので、選択は記憶されます)、そして戦闘後の流れです。
|
||||||
|
|
||||||
|
ゲームはコレクション設定 `battle.core` でシステムを選びます。RPG Plus は `ff_battle` を使用します。設定がなければ、最初にインストールされているシステムが使われます。コレクションエディターでは、この設定は「戦闘システム」という名前です。
|
||||||
|
|
||||||
|
## 戦闘の流れ
|
||||||
|
|
||||||
|
```text
|
||||||
|
scenario: battle.init / rpg.battle
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle scene: backdrop of the current place, party from the roster, enemies from their files
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle system (ff_battle or card_battle): player turn <-> enemy turn
|
||||||
|
| |
|
||||||
|
all enemies defeated party defeated
|
||||||
|
v v
|
||||||
|
Victory: experience, loot Defeat: Main menu
|
||||||
|
|
|
||||||
|
v
|
||||||
|
back to the scene the battle started from
|
||||||
|
```
|
||||||
|
|
||||||
|
## 勝利と敗北
|
||||||
|
|
||||||
|
最後の敵が倒れると、勝利画面には生存しているパーティメンバーそれぞれの経験値と戦利品が表示されます:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- **経験値。** 倒した敵はそれぞれ `Level × Exp` を出し、それが生存しているパーティメンバーに均等に分配されます。狼はレベル 2・`Exp` 12 なので **+24** です。
|
||||||
|
- **戦利品。** 倒した敵ごとに `Loot` リストが抽選されます。アイテムはそのままインベントリに入ります。
|
||||||
|
- **Continue** で戦闘が始まったシーンに戻ります。戦闘中に失った体力は戻りません。
|
||||||
|
|
||||||
|
パーティが全滅すると、敗北画面は **Main menu** だけを提示します。経験値も戦利品もありません。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## シナリオから戦闘を開始する
|
||||||
|
|
||||||
|
```scenario
|
||||||
|
action battle.init scene=town_entry enemies=wolf_1,wolf_2 quest_id=MeetingMurakamiQuest new_tag=wolf_battle
|
||||||
|
switch_scene Battle
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- `enemies`——キャラクター id をカンマ区切りで指定します。同じ id を 2 回書けば敵が 2 体になります。
|
||||||
|
- `scene`——勝利後に戻るシーンです。
|
||||||
|
- `quest_id`、`new_tag`(省略可)——戦闘をクエストに結び付け、タグ(ジャーナル通知)を付けます。
|
||||||
|
- 背景にはその時点で表示されている背景が使われます。`battle.init` の前に設定しておいてください。
|
||||||
|
|
||||||
|
タイルマップでは、代わりに RPG Mod の `action rpg.battle enemies=rpg_wolf win_flag=rpg_wolf_dead` を使ってください。同じマップセルに戻り、勝利時にフラグが立ちます。
|
||||||
|
|
||||||
|
`action battle.set_core core=card_battle` は、以降の戦闘で使うバトルシステムを切り替えます。
|
||||||
|
|
||||||
|
## データとしての敵・戦利品・ステータス効果
|
||||||
|
|
||||||
|
敵はごく普通のキャラクターです(Characters Engine を参照)。RPG Plus の狼の戦利品:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Id": "rpg_wolf",
|
||||||
|
"Loot": [
|
||||||
|
{ "ItemId": "rpg_plus/wolf_pelt", "MinCount": 2, "MaxCount": 3, "Probability": 100 },
|
||||||
|
{ "ItemId": "money/coin", "MinCount": 8, "MaxCount": 14, "Probability": 100 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`Probability` はパーセント値です。個数は `MinCount` から `MaxCount` まで(両端を含む)の乱数です。
|
||||||
|
|
||||||
|
**ステータス効果**は `status_effect` 種別のエンティティです。プラットフォームにはスタンが用意されていて、かかるとキャラクターは自分のターンを飛ばします:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "Id": "effect/physics/stun", "Icon": "characters/effects/stun", "Type": "Stun", "Duration": 3, "Actions": "basic/stun" }
|
||||||
|
```
|
||||||
|
|
||||||
|
この効果をかける戦闘アクションは、独自のターン数を指定できます。持続ターン数は毎ターンの開始時に減っていきます。
|
||||||
|
|
||||||
|
## Mod作者向け
|
||||||
|
|
||||||
|
バトルシステムとは、`IBattleCore` を登録するModです(自動テストのため `IBattleAutoPlayable` も実装します)。そのアクションはプラットフォームのエグゼキューターを通って実行されるため、Battle Formulas のようなModは新しい種類のアクションをすべてのシステムに一度に追加できます。コードは `BattleEndedEvent` で戦闘終了を、`IWingroundListener` で勝利を受け取れます。Recruiting はこれを利用して、倒した敵をパーティに勧誘します。
|
||||||
|
|
||||||
|
## うまくいかないときは
|
||||||
|
|
||||||
|
1. **戦闘の背景が空白になる。** シーン背景の設定より先に `battle.init` が実行されています。
|
||||||
|
2. **別のバトルシステムが開く。** ゲームの `battle.core` 設定と、シナリオが `battle.set_core` で切り替えていないかを確認してください。
|
||||||
|
3. **勝利後に経験値が入らない。** `Exp` が 0 の敵は経験値を出しません。倒れたパーティメンバーも得られません。
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
# Turn Battle Base — 모든 전투를 받치는 플랫폼
|
||||||
|
|
||||||
|
Turn Battle Base는 컬렉션의 모든 턴제 전투가 공유하는 부분입니다. 시나리오에서 전투를 여는 일, 전투가 시작된 장소를 배경으로 삼는 전투 장면, 승리·패배 화면, 경험치와 전리품, 기절 같은 상태 이상, 그리고 **전투 시스템** 선택이 모두 여기서 이뤄집니다. 다만 플레이어가 어떻게 싸울지는 정하지 않습니다. 그것은 전투 시스템 모드의 몫입니다. 명령 메뉴 방식의 **FF Battle**이나 카드를 대상에 끌어다 놓는 **Card Battle**이 그 예입니다.
|
||||||
|
|
||||||
|
## 두 가지 전투 시스템, 하나의 플랫폼
|
||||||
|
|
||||||
|
RPG Plus의 같은 전투 — 마을에서 전사가 늑대와 맞서는 장면 — 을 두 시스템으로 보여주면 다음과 같습니다:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
전투를 둘러싼 모든 것은 같습니다. 마을 배경, 늑대의 수치, 오른쪽 위의 속도 버튼 **x1 / x4 / x8**(애니메이션을 빠르게 하며 선택은 기억됩니다), 그리고 전투가 끝난 뒤의 흐름까지요.
|
||||||
|
|
||||||
|
게임은 컬렉션 설정 `battle.core`로 시스템을 고릅니다. RPG Plus는 `ff_battle`을 사용합니다. 설정이 없으면 설치된 첫 번째 시스템을 씁니다. 컬렉션 편집기에서는 이 설정이 "전투 시스템"이라는 이름으로 표시됩니다.
|
||||||
|
|
||||||
|
## 전투의 진행
|
||||||
|
|
||||||
|
```text
|
||||||
|
scenario: battle.init / rpg.battle
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle scene: backdrop of the current place, party from the roster, enemies from their files
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle system (ff_battle or card_battle): player turn <-> enemy turn
|
||||||
|
| |
|
||||||
|
all enemies defeated party defeated
|
||||||
|
v v
|
||||||
|
Victory: experience, loot Defeat: Main menu
|
||||||
|
|
|
||||||
|
v
|
||||||
|
back to the scene the battle started from
|
||||||
|
```
|
||||||
|
|
||||||
|
## 승리와 패배
|
||||||
|
|
||||||
|
마지막 적이 쓰러지면 승리 화면에 살아남은 파티원 각자의 경험치와 전리품이 표시됩니다:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- **경험치.** 쓰러뜨린 적은 각자 자신의 `Level × Exp`를 주며, 살아 있는 파티원들이 똑같이 나눕니다. 늑대는 2레벨에 `Exp` 12이므로 **+24**입니다.
|
||||||
|
- **전리품.** 쓰러뜨린 적마다 자신의 `Loot` 목록이 굴려집니다. 아이템은 곧바로 인벤토리에 들어갑니다.
|
||||||
|
- **Continue**는 전투가 시작됐던 장면으로 돌아갑니다. 전투에서 잃은 체력은 그대로 남습니다.
|
||||||
|
|
||||||
|
파티 전원이 쓰러지면 패배 화면은 **Main menu**만 제안합니다. 경험치도 전리품도 없습니다.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 시나리오에서 전투 시작하기
|
||||||
|
|
||||||
|
```scenario
|
||||||
|
action battle.init scene=town_entry enemies=wolf_1,wolf_2 quest_id=MeetingMurakamiQuest new_tag=wolf_battle
|
||||||
|
switch_scene Battle
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- `enemies` — 캐릭터 id를 쉼표로 나열합니다. 같은 id를 두 번 쓰면 적이 둘 나옵니다.
|
||||||
|
- `scene` — 승리 후 돌아갈 장면입니다.
|
||||||
|
- `quest_id`, `new_tag`(선택) — 전투를 퀘스트에 묶고 태그(저널 알림)를 붙입니다.
|
||||||
|
- 전투 배경은 그 시점에 표시된 배경입니다. `battle.init` 전에 배경을 정해 두세요.
|
||||||
|
|
||||||
|
타일 맵에서는 대신 RPG 모드의 `action rpg.battle enemies=rpg_wolf win_flag=rpg_wolf_dead`를 사용하세요. 같은 맵 칸으로 돌아오고, 승리 시 플래그가 설정됩니다.
|
||||||
|
|
||||||
|
`action battle.set_core core=card_battle` 액션은 이후 전투의 전투 시스템을 바꿉니다.
|
||||||
|
|
||||||
|
## 데이터 속의 적·전리품·상태 이상
|
||||||
|
|
||||||
|
적은 평범한 캐릭터입니다(Characters Engine 참조). RPG Plus 늑대의 전리품:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Id": "rpg_wolf",
|
||||||
|
"Loot": [
|
||||||
|
{ "ItemId": "rpg_plus/wolf_pelt", "MinCount": 2, "MaxCount": 3, "Probability": 100 },
|
||||||
|
{ "ItemId": "money/coin", "MinCount": 8, "MaxCount": 14, "Probability": 100 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`Probability`는 백분율입니다. 개수는 `MinCount`부터 `MaxCount`까지(양 끝 포함)의 무작위 수입니다.
|
||||||
|
|
||||||
|
**상태 이상**은 `status_effect` 종류의 엔티티입니다. 플랫폼에는 기절이 기본으로 들어 있으며, 걸린 캐릭터는 자기 턴을 건너뜁니다:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "Id": "effect/physics/stun", "Icon": "characters/effects/stun", "Type": "Stun", "Duration": 3, "Actions": "basic/stun" }
|
||||||
|
```
|
||||||
|
|
||||||
|
이 효과를 거는 전투 액션이 자체 턴 수를 정할 수도 있습니다. 지속 시간은 매 턴 시작 때 줄어듭니다.
|
||||||
|
|
||||||
|
## 모드 작성자를 위해
|
||||||
|
|
||||||
|
전투 시스템은 `IBattleCore`를 등록하는 모드입니다(자동 테스트를 위한 `IBattleAutoPlayable`도). 이 모드의 액션은 플랫폼의 실행기를 거치므로, Battle Formulas 같은 모드가 새 종류의 액션을 모든 시스템에 한꺼번에 추가할 수 있습니다. 코드는 `BattleEndedEvent`로 전투 종료를, `IWingroundListener`로 승리를 받아볼 수 있습니다. Recruiting이 이를 이용해 쓰러뜨린 적에게 파티 자리를 제안합니다.
|
||||||
|
|
||||||
|
## 문제가 생겼을 때
|
||||||
|
|
||||||
|
1. **전투 배경이 비어 있음.** 장면 배경 설정보다 `battle.init`이 먼저 실행됐습니다.
|
||||||
|
2. **다른 전투 시스템이 열림.** 게임의 `battle.core` 설정과, 시나리오가 `battle.set_core`로 바꾸지 않았는지 확인하세요.
|
||||||
|
3. **승리 후 경험치가 없음.** `Exp`가 0인 적은 경험치를 주지 않고, 쓰러진 파티원도 받지 못합니다.
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
# Turn Battle Base — общая платформа для всех боёв
|
||||||
|
|
||||||
|
Turn Battle Base — это то общее, что есть у всех пошаговых боёв в коллекции: запуск боя из сценария, боевая сцена с фоном того места, где бой начался, экраны победы и поражения, опыт и добыча, статусные эффекты вроде оглушения — и выбор **боевой системы**. Как именно сражается игрок, платформа не решает: это задача мода боевой системы — **FF Battle** (меню команд) или **Card Battle** (карты, которые перетаскивают на цели).
|
||||||
|
|
||||||
|
## Две боевые системы, одна платформа
|
||||||
|
|
||||||
|
Один и тот же бой в RPG Plus — воин против волка в деревне — в обеих системах:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Всё вокруг боя одинаковое: фон деревни, цифры волка, кнопки скорости **x1 / x4 / x8** в правом верхнем углу (они ускоряют анимации, а выбор запоминается) и то, что происходит после боя.
|
||||||
|
|
||||||
|
Свою систему игра выбирает настройкой коллекции `battle.core`; в RPG Plus это `ff_battle`. Без настройки берётся первая из установленных систем. В редакторе коллекций настройка называется «Боевая система».
|
||||||
|
|
||||||
|
## Как проходит бой
|
||||||
|
|
||||||
|
```text
|
||||||
|
scenario: battle.init / rpg.battle
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle scene: backdrop of the current place, party from the roster, enemies from their files
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle system (ff_battle or card_battle): player turn <-> enemy turn
|
||||||
|
| |
|
||||||
|
all enemies defeated party defeated
|
||||||
|
v v
|
||||||
|
Victory: experience, loot Defeat: Main menu
|
||||||
|
|
|
||||||
|
v
|
||||||
|
back to the scene the battle started from
|
||||||
|
```
|
||||||
|
|
||||||
|
## Победа и поражение
|
||||||
|
|
||||||
|
Когда падает последний враг, экран победы показывает опыт каждого уцелевшего члена отряда и добычу:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- **Опыт.** Каждый побеждённый враг приносит свой `Level × Exp`, который поровну делится между теми, кто остался на ногах. Волк — 2-го уровня с `Exp` 12, итого **+24**.
|
||||||
|
- **Добыча.** Для каждого побеждённого врага разыгрывается его список `Loot`; предметы сразу попадают в инвентарь.
|
||||||
|
- **Continue** возвращает в сцену, откуда пришёл бой. Потерянное в бою здоровье не восстанавливается.
|
||||||
|
|
||||||
|
Если падает весь отряд, экран поражения предлагает только **Main menu** — без опыта и без добычи.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Запуск боя из сценария
|
||||||
|
|
||||||
|
```scenario
|
||||||
|
action battle.init scene=town_entry enemies=wolf_1,wolf_2 quest_id=MeetingMurakamiQuest new_tag=wolf_battle
|
||||||
|
switch_scene Battle
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- `enemies` — id персонажей через запятую; один и тот же id дважды — это два врага.
|
||||||
|
- `scene` — сцена, в которую игра вернётся после победы.
|
||||||
|
- `quest_id`, `new_tag` (необязательные) — привязывают бой к заданию и помечают его тегом (уведомление в журнале).
|
||||||
|
- Фон боя — тот, что показан в этот момент, поэтому задайте его до `battle.init`.
|
||||||
|
|
||||||
|
На тайловой карте вместо этого используйте `action rpg.battle enemies=rpg_wolf win_flag=rpg_wolf_dead` из мода RPG: отряд вернётся в ту же клетку карты, а при победе выставится флаг.
|
||||||
|
|
||||||
|
Команда `action battle.set_core core=card_battle` переключает боевую систему для последующих боёв.
|
||||||
|
|
||||||
|
## Враги, добыча и статусные эффекты в данных
|
||||||
|
|
||||||
|
Враги — обычные персонажи (см. Characters Engine). Добыча волка из RPG Plus:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Id": "rpg_wolf",
|
||||||
|
"Loot": [
|
||||||
|
{ "ItemId": "rpg_plus/wolf_pelt", "MinCount": 2, "MaxCount": 3, "Probability": 100 },
|
||||||
|
{ "ItemId": "money/coin", "MinCount": 8, "MaxCount": 14, "Probability": 100 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`Probability` — вероятность в процентах; количество — случайное число от `MinCount` до `MaxCount` включительно.
|
||||||
|
|
||||||
|
**Статусные эффекты** — это сущности вида `status_effect`. Уже в платформе есть оглушение: персонаж пропускает свои ходы:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "Id": "effect/physics/stun", "Icon": "characters/effects/stun", "Type": "Stun", "Duration": 3, "Actions": "basic/stun" }
|
||||||
|
```
|
||||||
|
|
||||||
|
Боевое действие, накладывающее эффект, может задать своё число ходов; длительность уменьшается в начале каждого хода.
|
||||||
|
|
||||||
|
## Авторам модов
|
||||||
|
|
||||||
|
Боевая система — мод, регистрирующий `IBattleCore` (и `IBattleAutoPlayable` для автоматических тестов). Её действия выполняются через исполнители платформы, поэтому мод вроде Battle Formulas добавляет новые виды действий сразу всем системам. Код может узнавать о конце боя через `BattleEndedEvent`, а о победе — через `IWingroundListener`; так работает Recruiting, предлагая побеждённым врагам место в отряде.
|
||||||
|
|
||||||
|
## Если что-то пошло не так
|
||||||
|
|
||||||
|
1. **У боя пустой фон.** `battle.init` выполнился раньше, чем у сцены появился фон.
|
||||||
|
2. **Открывается не та система.** Проверьте настройку игры `battle.core` и не переключал ли её какой-нибудь сценарий через `battle.set_core`.
|
||||||
|
3. **После победы нет опыта.** Враги с `Exp` 0 не дают опыта; павшие члены отряда его не получают.
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
# Turn Battle Base — nền tảng của mọi trận chiến
|
||||||
|
|
||||||
|
Turn Battle Base là phần chung của mọi trận chiến theo lượt trong bộ sưu tập: mở trận từ kịch bản, cảnh chiến đấu lấy nền theo nơi trận nổ ra, màn hình thắng và thua, kinh nghiệm và chiến lợi phẩm, các hiệu ứng trạng thái như choáng, và cả việc chọn **hệ thống chiến đấu**. Còn người chơi đánh thế nào, nó không quyết định — việc đó thuộc về mod hệ thống chiến đấu: **FF Battle** (menu lệnh) hoặc **Card Battle** (kéo thẻ vào mục tiêu).
|
||||||
|
|
||||||
|
## Hai hệ thống chiến đấu, một nền tảng
|
||||||
|
|
||||||
|
Cùng một trận đánh trong RPG Plus — chiến binh đấu với con sói trong làng — dưới hai hệ thống:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Mọi thứ xung quanh trận đánh đều giống nhau: nền làng, các con số của con sói, các nút tốc độ **x1 / x4 / x8** ở góc trên bên phải (chúng tăng tốc hiệu ứng, lựa chọn được ghi nhớ) và những gì diễn ra sau trận đánh.
|
||||||
|
|
||||||
|
Game chọn hệ thống bằng thiết lập `battle.core` của bộ sưu tập; RPG Plus dùng `ff_battle`. Không có thiết lập thì hệ thống được cài đầu tiên sẽ được dùng. Trong trình soạn thảo bộ sưu tập, thiết lập này có tên "Hệ thống chiến đấu".
|
||||||
|
|
||||||
|
## Một trận chiến diễn ra thế nào
|
||||||
|
|
||||||
|
```text
|
||||||
|
scenario: battle.init / rpg.battle
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle scene: backdrop of the current place, party from the roster, enemies from their files
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle system (ff_battle or card_battle): player turn <-> enemy turn
|
||||||
|
| |
|
||||||
|
all enemies defeated party defeated
|
||||||
|
v v
|
||||||
|
Victory: experience, loot Defeat: Main menu
|
||||||
|
|
|
||||||
|
v
|
||||||
|
back to the scene the battle started from
|
||||||
|
```
|
||||||
|
|
||||||
|
## Thắng và thua
|
||||||
|
|
||||||
|
Khi kẻ địch cuối cùng gục xuống, màn hình thắng sẽ hiển thị kinh nghiệm của từng thành viên đội còn sống và phần chiến lợi phẩm:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- **Kinh nghiệm.** Mỗi kẻ địch bị hạ mang lại `Level × Exp` của nó, chia đều cho những thành viên đội còn trụ. Con sói cấp 2 với `Exp` 12 — **+24**.
|
||||||
|
- **Chiến lợi phẩm.** Với mỗi kẻ địch bị hạ, trò chơi quay số theo danh sách `Loot` của nó; vật phẩm vào thẳng túi đồ.
|
||||||
|
- **Continue** đưa bạn về cảnh mà trận chiến bắt đầu. Máu đã mất trong trận chiến vẫn mất.
|
||||||
|
|
||||||
|
Cả đội gục ngã thì màn hình thua chỉ còn **Main menu**: không kinh nghiệm, không chiến lợi phẩm.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Mở trận chiến từ kịch bản
|
||||||
|
|
||||||
|
```scenario
|
||||||
|
action battle.init scene=town_entry enemies=wolf_1,wolf_2 quest_id=MeetingMurakamiQuest new_tag=wolf_battle
|
||||||
|
switch_scene Battle
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- `enemies` — id nhân vật, phân tách bằng dấu phẩy; cùng một id xuất hiện hai lần nghĩa là hai kẻ địch.
|
||||||
|
- `scene` — cảnh sẽ quay về sau khi thắng.
|
||||||
|
- `quest_id`, `new_tag` (tùy chọn) — gắn trận chiến với nhiệm vụ và gán cho nó một thẻ (thông báo trên nhật ký).
|
||||||
|
- Nền trận chiến là nền đang hiển thị tại thời điểm đó, nên hãy đặt nền trước khi gọi `battle.init`.
|
||||||
|
|
||||||
|
Trên bản đồ tile, hãy dùng `action rpg.battle enemies=rpg_wolf win_flag=rpg_wolf_dead` của mod RPG thay thế: đội sẽ về đúng ô cũ và cờ được đặt khi thắng.
|
||||||
|
|
||||||
|
Hành động `action battle.set_core core=card_battle` đổi hệ thống chiến đấu cho các trận chiến tiếp theo.
|
||||||
|
|
||||||
|
## Kẻ địch, chiến lợi phẩm và hiệu ứng trạng thái trong dữ liệu
|
||||||
|
|
||||||
|
Kẻ địch là nhân vật bình thường (xem Characters Engine). Chiến lợi phẩm của con sói trong RPG Plus:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Id": "rpg_wolf",
|
||||||
|
"Loot": [
|
||||||
|
{ "ItemId": "rpg_plus/wolf_pelt", "MinCount": 2, "MaxCount": 3, "Probability": 100 },
|
||||||
|
{ "ItemId": "money/coin", "MinCount": 8, "MaxCount": 14, "Probability": 100 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`Probability` là phần trăm; số lượng là một số ngẫu nhiên từ `MinCount` đến `MaxCount` (bao gồm cả hai đầu).
|
||||||
|
|
||||||
|
**Hiệu ứng trạng thái** là thực thể loại `status_effect`. Nền tảng có sẵn choáng — nhân vật bị bỏ qua các lượt của mình:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "Id": "effect/physics/stun", "Icon": "characters/effects/stun", "Type": "Stun", "Duration": 3, "Actions": "basic/stun" }
|
||||||
|
```
|
||||||
|
|
||||||
|
Hành động chiến đấu gây hiệu ứng này có thể tự đặt số lượt; thời gian giảm dần vào đầu mỗi lượt.
|
||||||
|
|
||||||
|
## Dành cho tác giả mod
|
||||||
|
|
||||||
|
Hệ thống chiến đấu là một mod đăng ký `IBattleCore` (cùng `IBattleAutoPlayable` cho bộ kiểm thử tự động). Các hành động của nó chạy qua bộ thực thi của nền tảng, nên một mod như Battle Formulas có thể thêm loại hành động mới cho tất cả các hệ thống cùng lúc. Mã nguồn có thể phản ứng khi trận chiến kết thúc qua `BattleEndedEvent` và khi thắng qua `IWingroundListener`; Recruiting dùng đúng cơ chế này để mời kẻ địch bị hạ gia nhập đội.
|
||||||
|
|
||||||
|
## Khi có sự cố
|
||||||
|
|
||||||
|
1. **Nền trận chiến trống trơn.** `battle.init` chạy trước khi nền của cảnh được đặt.
|
||||||
|
2. **Mở nhầm hệ thống chiến đấu.** Kiểm tra thiết lập `battle.core` của game và xem có kịch bản nào đã đổi nó bằng `battle.set_core` không.
|
||||||
|
3. **Thắng rồi mà không có kinh nghiệm.** Kẻ địch có `Exp` 0 không cho kinh nghiệm; thành viên đội đã gục cũng không nhận.
|
||||||
+97
@@ -0,0 +1,97 @@
|
|||||||
|
# Turn Battle Base —— 每场战斗背后的平台
|
||||||
|
|
||||||
|
Turn Battle Base 汇集了合集中所有回合制战斗的公共部分:从剧本发起战斗、以开战地点为背景的战斗场景、胜利与失败画面、经验和掉落、眩晕等状态效果,以及**战斗系统**的选择。玩家具体怎么打,平台并不决定——那是战斗系统模组的职责:**FF Battle**(指令菜单)或 **Card Battle**(把卡牌拖到目标上)。
|
||||||
|
|
||||||
|
## 两套战斗系统,一个平台
|
||||||
|
|
||||||
|
RPG Plus 里的同一场战斗——村庄中战士对狼——在两套系统下分别是这样:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
战斗之外的一切都相同:村庄背景、狼的数值、右上角的 **x1 / x4 / x8** 倍速按钮(用于加快动画,选择会被记住),以及战斗结束后的流程。
|
||||||
|
|
||||||
|
游戏通过合集设置 `battle.core` 选择战斗系统;RPG Plus 使用 `ff_battle`。未设置时采用第一个已安装的系统。在合集编辑器中,这项设置名为「战斗系统」。
|
||||||
|
|
||||||
|
## 一场战斗如何进行
|
||||||
|
|
||||||
|
```text
|
||||||
|
scenario: battle.init / rpg.battle
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle scene: backdrop of the current place, party from the roster, enemies from their files
|
||||||
|
|
|
||||||
|
v
|
||||||
|
battle system (ff_battle or card_battle): player turn <-> enemy turn
|
||||||
|
| |
|
||||||
|
all enemies defeated party defeated
|
||||||
|
v v
|
||||||
|
Victory: experience, loot Defeat: Main menu
|
||||||
|
|
|
||||||
|
v
|
||||||
|
back to the scene the battle started from
|
||||||
|
```
|
||||||
|
|
||||||
|
## 胜利与失败
|
||||||
|
|
||||||
|
当最后一个敌人倒下,胜利画面会显示每位幸存队员获得的经验和掉落:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- **经验。** 每个被击败的敌人提供其 `Level × Exp`,由仍然站立的队员平分。狼为 2 级、`Exp` 12,即 **+24**。
|
||||||
|
- **掉落。** 每个被击败的敌人按其 `Loot` 列表掷点;物品直接进入背包。
|
||||||
|
- **Continue** 返回战斗开始前的场景。战斗中损失的生命不会恢复。
|
||||||
|
|
||||||
|
如果全队倒下,失败画面只提供 **Main menu**:没有经验,也没有掉落。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 从剧本发起战斗
|
||||||
|
|
||||||
|
```scenario
|
||||||
|
action battle.init scene=town_entry enemies=wolf_1,wolf_2 quest_id=MeetingMurakamiQuest new_tag=wolf_battle
|
||||||
|
switch_scene Battle
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
- `enemies`——角色 id,逗号分隔;同一个 id 出现两次就是两个敌人。
|
||||||
|
- `scene`——胜利后返回的场景。
|
||||||
|
- `quest_id`、`new_tag`(可选)——把战斗绑定到任务,并给它一个标签(日志通知)。
|
||||||
|
- 战斗背景就是当时显示的背景,所以要在 `battle.init` 之前设置好。
|
||||||
|
|
||||||
|
在图块地图上,请改用 RPG 模组的 `action rpg.battle enemies=rpg_wolf win_flag=rpg_wolf_dead`:队伍会回到同一格,胜利时还会设置标记。
|
||||||
|
|
||||||
|
动作 `action battle.set_core core=card_battle` 为之后的战斗切换战斗系统。
|
||||||
|
|
||||||
|
## 数据中的敌人、掉落与状态效果
|
||||||
|
|
||||||
|
敌人就是普通角色(参见 Characters Engine)。RPG Plus 中狼的掉落:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Id": "rpg_wolf",
|
||||||
|
"Loot": [
|
||||||
|
{ "ItemId": "rpg_plus/wolf_pelt", "MinCount": 2, "MaxCount": 3, "Probability": 100 },
|
||||||
|
{ "ItemId": "money/coin", "MinCount": 8, "MaxCount": 14, "Probability": 100 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`Probability` 是百分比;数量是 `MinCount` 到 `MaxCount` 之间(含两端)的随机数。
|
||||||
|
|
||||||
|
**状态效果**是 `status_effect` 类型的实体。平台自带眩晕——角色会跳过自己的回合:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "Id": "effect/physics/stun", "Icon": "characters/effects/stun", "Type": "Stun", "Duration": 3, "Actions": "basic/stun" }
|
||||||
|
```
|
||||||
|
|
||||||
|
施加该效果的动作可以自行指定回合数;持续时间在每个回合开始时递减。
|
||||||
|
|
||||||
|
## 给模组作者
|
||||||
|
|
||||||
|
战斗系统是一个注册了 `IBattleCore` 的模组(自动测试还需要 `IBattleAutoPlayable`)。它的动作经由平台的执行器运行,因此像 Battle Formulas 这样的模组能一次为所有系统添加新类型的动作。代码可以通过 `BattleEndedEvent` 响应战斗结束,通过 `IWingroundListener` 响应胜利;Recruiting 就是这样邀请被击败的敌人加入队伍的。
|
||||||
|
|
||||||
|
## 出问题怎么办
|
||||||
|
|
||||||
|
1. **战斗背景为空。** `battle.init` 在场景背景设置之前就执行了。
|
||||||
|
2. **打开的战斗系统不对。** 检查游戏的 `battle.core` 设置,以及是否有剧本用 `battle.set_core` 切换过它。
|
||||||
|
3. **胜利后没有经验。** `Exp` 为 0 的敌人不给经验;倒下的队员也拿不到。
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
collection_settings/battle = Battle system
|
||||||
|
collection_settings/battle_hint = Choose a battle system provided by the mods in this collection.
|
||||||
|
collection_settings/battle_auto = Uses the first registered battle system when unspecified.
|
||||||
|
collection_settings/battle_group = Combat
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
collection_settings/battle = Sistema de combate
|
||||||
|
collection_settings/battle_hint = Elige un sistema de combate de los mods de esta colección.
|
||||||
|
collection_settings/battle_auto = Sin valor se usa el primer sistema de combate registrado.
|
||||||
|
collection_settings/battle_group = Combate
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
collection_settings/battle = 戦闘システム
|
||||||
|
collection_settings/battle_hint = 構成に含まれるMODの戦闘システムを選びます。
|
||||||
|
collection_settings/battle_auto = 未指定の場合は最初に登録された戦闘システムを使用。
|
||||||
|
collection_settings/battle_group = 戦闘
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
collection_settings/battle = 전투 시스템
|
||||||
|
collection_settings/battle_hint = 컬렉션에 포함된 모드의 전투 시스템을 선택합니다.
|
||||||
|
collection_settings/battle_auto = 지정하지 않으면 처음 등록된 전투 시스템을 사용합니다.
|
||||||
|
collection_settings/battle_group = 전투
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
collection_settings/battle = Боевая система
|
||||||
|
collection_settings/battle_hint = Выберите боевую систему из включённых в коллекцию модов.
|
||||||
|
collection_settings/battle_auto = Без настройки используется первая зарегистрированная боевая система.
|
||||||
|
collection_settings/battle_group = Бой
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
collection_settings/battle = Hệ thống chiến đấu
|
||||||
|
collection_settings/battle_hint = Chọn hệ thống chiến đấu từ các mod trong bộ sưu tập.
|
||||||
|
collection_settings/battle_auto = Nếu không đặt, dùng hệ thống chiến đấu được đăng ký đầu tiên.
|
||||||
|
collection_settings/battle_group = Chiến đấu
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
collection_settings/battle = 战斗系统
|
||||||
|
collection_settings/battle_hint = 选择此合集模组提供的战斗系统。
|
||||||
|
collection_settings/battle_auto = 未指定时使用第一个注册的战斗系统。
|
||||||
|
collection_settings/battle_group = 战斗
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
mod_turn_battle_base_name = Turn-based Battle Engine
|
mod_turn_battle_base_name = Turn Battle Base
|
||||||
mod_turn_battle_base_desc = Turn-based battle platform: battle ruleset contracts (IBattleCore), the core registry, action executors, status effects, the battle scene, victory/defeat screens and EXP/loot reports.
|
mod_turn_battle_base_desc = The platform under every turn-based battle: starting from a scenario, the battle scene, victory and defeat, experience and loot — how the player fights is a separate battle system.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod_turn_battle_base_name = Motor de combate por turnos
|
||||||
|
mod_turn_battle_base_desc = La plataforma bajo cada combate por turnos: inicio desde un escenario, la escena de batalla, victoria y derrota, experiencia y botín; cómo lucha el jugador es cosa de un sistema de combate aparte.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod_turn_battle_base_name = ターン制バトルエンジン
|
||||||
|
mod_turn_battle_base_desc = すべてのターン制戦闘の土台:シナリオからの開始、戦闘シーン、勝利と敗北、経験値と戦利品。プレイヤーの戦い方は、別のバトルシステムが担います。
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod_turn_battle_base_name = 턴제 전투 엔진
|
||||||
|
mod_turn_battle_base_desc = 모든 턴제 전투의 기반: 시나리오에서 시작, 전투 장면, 승리와 패배, 경험치와 전리품 — 플레이어가 어떻게 싸울지는 별도의 전투 시스템이 담당합니다.
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
mod_turn_battle_base_name = Движок пошаговых боёв
|
mod_turn_battle_base_name = Движок пошаговых боёв
|
||||||
mod_turn_battle_base_desc = Платформа пошаговых боёв: контракты боевых ядер (IBattleCore), реестр ядер, исполнители действий, статус-эффекты, боевая сцена, экраны победы/поражения и отчёты опыта и добычи.
|
mod_turn_battle_base_desc = Платформа любого пошагового боя: запуск из сценария, боевая сцена, победа и поражение, опыт и добыча — а как именно сражаться, решает отдельная боевая система.
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
battle/schema/builtin/battle_init = Start a battle
|
||||||
|
battle/schema/builtin/battle_init_desc = A battle from a novel scene: enemies, the return scene, a quest
|
||||||
|
battle/schema/field/enemies = Enemies
|
||||||
|
battle/schema/field/scene = Scene
|
||||||
|
battle/schema/field/quest = Quest
|
||||||
|
battle/schema/field/tag = Tag
|
||||||
|
battle/schema/builtin/set_core = Battle core
|
||||||
|
battle/schema/builtin/set_core_desc = Which rules the next battle follows
|
||||||
|
battle/schema/field/core = Core
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
battle/schema/builtin/battle_init = Empezar un combate
|
||||||
|
battle/schema/builtin/battle_init_desc = Un combate desde una escena de novela: enemigos, escena de regreso, misión
|
||||||
|
battle/schema/field/enemies = Enemigos
|
||||||
|
battle/schema/field/scene = Escena
|
||||||
|
battle/schema/field/quest = Misión
|
||||||
|
battle/schema/field/tag = Etiqueta
|
||||||
|
battle/schema/builtin/set_core = Núcleo de combate
|
||||||
|
battle/schema/builtin/set_core_desc = Qué reglas sigue el próximo combate
|
||||||
|
battle/schema/field/core = Núcleo
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
battle/schema/builtin/battle_init = 戦闘を始める
|
||||||
|
battle/schema/builtin/battle_init_desc = ノベルのシーンからの戦闘:敵、戻り先のシーン、クエスト
|
||||||
|
battle/schema/field/enemies = 敵
|
||||||
|
battle/schema/field/scene = シーン
|
||||||
|
battle/schema/field/quest = クエスト
|
||||||
|
battle/schema/field/tag = タグ
|
||||||
|
battle/schema/builtin/set_core = バトルコア
|
||||||
|
battle/schema/builtin/set_core_desc = 次の戦闘がどのルールに従うか
|
||||||
|
battle/schema/field/core = コア
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
battle/schema/builtin/battle_init = 전투 시작
|
||||||
|
battle/schema/builtin/battle_init_desc = 노벨 장면에서의 전투: 적, 돌아올 장면, 퀘스트
|
||||||
|
battle/schema/field/enemies = 적
|
||||||
|
battle/schema/field/scene = 장면
|
||||||
|
battle/schema/field/quest = 퀘스트
|
||||||
|
battle/schema/field/tag = 태그
|
||||||
|
battle/schema/builtin/set_core = 전투 코어
|
||||||
|
battle/schema/builtin/set_core_desc = 다음 전투가 따를 규칙
|
||||||
|
battle/schema/field/core = 코어
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
battle/schema/builtin/battle_init = Начать бой
|
||||||
|
battle/schema/builtin/battle_init_desc = Бой из сцены новеллы: враги, сцена возврата, квест
|
||||||
|
battle/schema/field/enemies = Враги
|
||||||
|
battle/schema/field/scene = Сцена
|
||||||
|
battle/schema/field/quest = Квест
|
||||||
|
battle/schema/field/tag = Метка
|
||||||
|
battle/schema/builtin/set_core = Боевое ядро
|
||||||
|
battle/schema/builtin/set_core_desc = Каким правилам подчиняется следующий бой
|
||||||
|
battle/schema/field/core = Ядро
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
battle/schema/builtin/battle_init = Bắt đầu trận đấu
|
||||||
|
battle/schema/builtin/battle_init_desc = Trận đấu từ cảnh tiểu thuyết: kẻ địch, cảnh quay về, nhiệm vụ
|
||||||
|
battle/schema/field/enemies = Kẻ địch
|
||||||
|
battle/schema/field/scene = Cảnh
|
||||||
|
battle/schema/field/quest = Nhiệm vụ
|
||||||
|
battle/schema/field/tag = Thẻ
|
||||||
|
battle/schema/builtin/set_core = Lõi chiến đấu
|
||||||
|
battle/schema/builtin/set_core_desc = Trận tới theo luật nào
|
||||||
|
battle/schema/field/core = Lõi
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
battle/schema/builtin/battle_init = 开始战斗
|
||||||
|
battle/schema/builtin/battle_init_desc = 来自小说场景的战斗:敌人、返回场景、任务
|
||||||
|
battle/schema/field/enemies = 敌人
|
||||||
|
battle/schema/field/scene = 场景
|
||||||
|
battle/schema/field/quest = 任务
|
||||||
|
battle/schema/field/tag = 标签
|
||||||
|
battle/schema/builtin/set_core = 战斗核心
|
||||||
|
battle/schema/builtin/set_core_desc = 下一场战斗遵循哪套规则
|
||||||
|
battle/schema/field/core = 核心
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod_turn_battle_base_name = Engine chiến đấu theo lượt
|
||||||
|
mod_turn_battle_base_desc = Nền tảng của mọi trận chiến theo lượt: khởi đầu từ kịch bản, cảnh chiến đấu, thắng và thua, kinh nghiệm và chiến lợi phẩm — người chơi đánh thế nào là việc của một hệ thống chiến đấu riêng.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod_turn_battle_base_name = 回合制战斗引擎
|
||||||
|
mod_turn_battle_base_desc = 每场回合制战斗背后的平台:从剧本发起战斗、战斗场景、胜利与失败、经验和掉落——玩家怎么打,由独立的战斗系统决定。
|
||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"id": "turn_battle_base",
|
"id": "turn_battle_base",
|
||||||
"name": "Turn-based battle engine",
|
"name": "Turn Battle Base",
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"author": "ct",
|
"author": "ct",
|
||||||
"description": "Turn-based battle platform: battle ruleset contracts, core registry, action executors, status effects, battle scene, victory/defeat screens, EXP and loot reports",
|
"description": "The platform under every turn-based battle: starting from a scenario, the battle scene, victory and defeat, experience and loot — how the player fights is a separate battle system.",
|
||||||
"category": "engine, gameplay",
|
"category": "engine, gameplay",
|
||||||
"sources": [
|
"sources": [
|
||||||
"src/**/*.cs"
|
"src/**/*.cs"
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"Actions": [
|
||||||
|
{
|
||||||
|
"Id": "battle.init",
|
||||||
|
"Name": "battle/schema/builtin/battle_init",
|
||||||
|
"Description": "battle/schema/builtin/battle_init_desc",
|
||||||
|
"Category": "battle",
|
||||||
|
"Params": [
|
||||||
|
{
|
||||||
|
"Key": "enemies",
|
||||||
|
"Type": "ref_list",
|
||||||
|
"Kind": "character",
|
||||||
|
"Required": true,
|
||||||
|
"Name": "battle/schema/field/enemies"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Key": "scene",
|
||||||
|
"Type": "scene",
|
||||||
|
"Name": "battle/schema/field/scene"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Key": "quest_id",
|
||||||
|
"Type": "ref",
|
||||||
|
"Kind": "quest",
|
||||||
|
"Name": "battle/schema/field/quest"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Key": "new_tag",
|
||||||
|
"Type": "text",
|
||||||
|
"Name": "battle/schema/field/tag"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": "battle.set_core",
|
||||||
|
"Name": "battle/schema/builtin/set_core",
|
||||||
|
"Description": "battle/schema/builtin/set_core_desc",
|
||||||
|
"Category": "battle",
|
||||||
|
"Params": [
|
||||||
|
{
|
||||||
|
"Key": "core",
|
||||||
|
"Type": "choice",
|
||||||
|
"Options": [
|
||||||
|
"ff_battle",
|
||||||
|
"card_battle"
|
||||||
|
],
|
||||||
|
"Required": true,
|
||||||
|
"Name": "battle/schema/field/core"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace Cthangover.Core.Battle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// One extra bar of a battle unit next to its health (mana, rage, ammo…), as an
|
||||||
|
/// <see cref="IBattleUnitGauge"/> reads it at this moment.
|
||||||
|
/// </summary>
|
||||||
|
public class BattleGauge
|
||||||
|
{
|
||||||
|
/// <summary>Stable id (a stat id, for example) the cores key their rows by.</summary>
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Short label, a locale key or plain text ("MP").</summary>
|
||||||
|
public string Label { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Current value.</summary>
|
||||||
|
public int Current { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Maximum; a bar with Max <= 0 is not drawn.</summary>
|
||||||
|
public int Max { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Fill colour as HTML ("#4a8cff"); null = the theme's info colour.</summary>
|
||||||
|
public string Color { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
namespace Cthangover.Core.Battle
|
||||||
|
{
|
||||||
|
using Cthangover.Core.Mods.Consumers;
|
||||||
|
|
||||||
|
/// <summary>Registers every <see cref="IBattleUnitGauge"/> of a loaded mod assembly in <see cref="BattleUnitGauges"/>.</summary>
|
||||||
|
public class BattleUnitGaugeConsumer : ModTypeConsumer<IBattleUnitGauge>
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string Id => "turn_battle_base.unit_gauges";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Add(IBattleUnitGauge instance, string modId) => BattleUnitGauges.Add(instance);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Remove(IBattleUnitGauge instance, string modId) => BattleUnitGauges.Remove(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
namespace Cthangover.Core.Battle
|
||||||
|
{
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Cthangover.Core.Characters;
|
||||||
|
using Cthangover.Core.Utils;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The registered <see cref="IBattleUnitGauge"/>s and the bars they give for a unit. A
|
||||||
|
/// provider calls <see cref="NotifyChanged"/> when a value moved (mana spent), so the
|
||||||
|
/// cores redraw that unit; cores also read the bars whenever they redraw it themselves.
|
||||||
|
/// </summary>
|
||||||
|
public static class BattleUnitGauges
|
||||||
|
{
|
||||||
|
private static readonly List<IBattleUnitGauge> Providers = new();
|
||||||
|
|
||||||
|
/// <summary>Raised with a unit id (null = every unit) when its bars changed.</summary>
|
||||||
|
public static event Action<string> Changed;
|
||||||
|
|
||||||
|
/// <summary>Registers a provider.</summary>
|
||||||
|
public static void Add(IBattleUnitGauge gauge)
|
||||||
|
{
|
||||||
|
if (gauge != null && !Providers.Contains(gauge))
|
||||||
|
Providers.Add(gauge);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Removes a provider (its mod is unloaded).</summary>
|
||||||
|
public static void Remove(IBattleUnitGauge gauge) => Providers.Remove(gauge);
|
||||||
|
|
||||||
|
/// <summary>Every bar of <paramref name="unit"/> with a positive maximum, providers in order; a failing provider is logged and skipped.</summary>
|
||||||
|
public static List<BattleGauge> Read(Character unit)
|
||||||
|
{
|
||||||
|
var result = new List<BattleGauge>();
|
||||||
|
if (unit == null)
|
||||||
|
return result;
|
||||||
|
foreach (var provider in Providers.OrderBy(p => p.Order).ToList())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result.AddRange((provider.Read(unit) ?? Enumerable.Empty<BattleGauge>()).Where(g => g != null && g.Max > 0));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
GameLogger.Log("BATTLE", $"gauge provider {provider.GetType().Name} failed for '{unit.ID}': {ex.Message}", LogLevel.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Tells the cores that the bars of <paramref name="unitId"/> changed.</summary>
|
||||||
|
public static void NotifyChanged(string unitId) => Changed?.Invoke(unitId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
namespace Cthangover.Core.Battle
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Cthangover.Core.Characters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Supplies extra bars of battle units (found in mod assemblies by
|
||||||
|
/// <see cref="BattleUnitGaugeConsumer"/>): a mod that adds a resource — mana of
|
||||||
|
/// <c>battle_formulas</c>, a rage meter — shows it in every battle core that draws
|
||||||
|
/// <see cref="BattleUnitGauges"/>, without knowing the cores.
|
||||||
|
/// </summary>
|
||||||
|
public interface IBattleUnitGauge
|
||||||
|
{
|
||||||
|
/// <summary>Order among the providers (lower first).</summary>
|
||||||
|
int Order { get; }
|
||||||
|
|
||||||
|
/// <summary>The bars of <paramref name="unit"/> now; empty when it has none.</summary>
|
||||||
|
IEnumerable<BattleGauge> Read(Character unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user