Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bf22f2d6e | ||
|
|
5da782d21b | ||
|
|
4f97fc704c | ||
|
|
5b0827072b | ||
|
|
ccabd3e7ac | ||
|
|
cba87dcb31 | ||
|
|
932cd0582f | ||
|
|
1ef1720bae | ||
|
|
bea880a999 | ||
|
|
6f2225f911 | ||
|
|
fea0a29d10 | ||
|
|
f89781d78b | ||
|
|
be63c21e15 | ||
|
|
86614f3104 | ||
|
|
38ba2b0eff | ||
|
|
a42f25d5fa | ||
|
|
14f542c8a1 | ||
|
|
af6bc82c67 | ||
|
|
e5f41bde07 |
@@ -108,6 +108,13 @@ yarn-error.log*
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# .NET tooling under tools/ (Unity's own Library/ ignores live in the Unity
|
||||
# project's .gitignore and don't reach this far up)
|
||||
# ---------------------------------------------------------------------------
|
||||
tools/**/bin/
|
||||
tools/**/obj/
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# AI / agent tooling
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"cSpell.enableFiletypes": [
|
||||
"yarnspinner"
|
||||
],
|
||||
"cSpell.languageSettings": [
|
||||
{
|
||||
"languageId": "yarnspinner",
|
||||
"patterns": [
|
||||
{
|
||||
"name": "yarn-commands",
|
||||
"pattern": "/<<[^>]*>>/g"
|
||||
},
|
||||
{
|
||||
"name": "yarn-expressions",
|
||||
"pattern": "/\\{[^}]*\\}/g"
|
||||
},
|
||||
{
|
||||
"name": "yarn-variables",
|
||||
"pattern": "/\\$[a-zA-Z_][a-zA-Z0-9_]*/g"
|
||||
},
|
||||
{
|
||||
"name": "yarn-markup",
|
||||
"pattern": "/\\[[^\\]]*\\]/g"
|
||||
},
|
||||
{
|
||||
"name": "yarn-hashtags",
|
||||
"pattern": "/#[a-zA-Z_][a-zA-Z0-9_:-]*/g"
|
||||
},
|
||||
{
|
||||
"name": "yarn-node-markers",
|
||||
"pattern": "/^(---|===)$/gm"
|
||||
},
|
||||
{
|
||||
"name": "yarn-headers",
|
||||
"pattern": "/^(title|tags|position|color|colorID|tracking|custom|style):.*/gm"
|
||||
},
|
||||
{
|
||||
"name": "yarn-character-names",
|
||||
"pattern": "/^\\s*[A-Za-z_][A-Za-z0-9_]*(?=:)/gm"
|
||||
},
|
||||
{
|
||||
"name": "yarn-comments",
|
||||
"pattern": "/\\/\\/.*$/gm"
|
||||
}
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
"yarn-commands",
|
||||
"yarn-expressions",
|
||||
"yarn-variables",
|
||||
"yarn-markup",
|
||||
"yarn-hashtags",
|
||||
"yarn-node-markers",
|
||||
"yarn-headers",
|
||||
"yarn-character-names",
|
||||
"yarn-comments"
|
||||
]
|
||||
}
|
||||
],
|
||||
"cSpell.words": [
|
||||
"Cassian",
|
||||
"Thal",
|
||||
"Vaselian"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
# AGENTS.md
|
||||
|
||||
This repository's agent instructions live in [`CLAUDE.md`](./CLAUDE.md). It is
|
||||
tool-agnostic — repository layout, the Unity command line, the dialogue content
|
||||
pipeline, validation, conventions, and known traps.
|
||||
|
||||
Read `CLAUDE.md` before making changes, regardless of which agent you are.
|
||||
|
||||
Design and migration plans are in [`docs/`](./docs/), most relevantly
|
||||
[`docs/restructure-plan.md`](./docs/restructure-plan.md).
|
||||
@@ -0,0 +1,361 @@
|
||||
# Nightclub Arcadia — agent reference
|
||||
|
||||
Reference for coding agents (Claude Code and others) working in this repository.
|
||||
Human-facing design docs live in `docs/`. This file is the operational one: where
|
||||
things are, what is generated, and how to build/test/validate from the terminal.
|
||||
|
||||
Companion: `AGENTS.md` (pointer file, same content applies).
|
||||
|
||||
---
|
||||
|
||||
## 1. Repository layout
|
||||
|
||||
Repo root is `nightlcub-arcadia` (the typo is in the directory name, not a mistake
|
||||
to fix — it is the checkout path). The Unity project is a **subdirectory**:
|
||||
|
||||
```
|
||||
/Users/lennart/Dev/nightlcub-arcadia/ # git root
|
||||
├── CLAUDE.md, AGENTS.md # this reference
|
||||
├── docs/ # design + plan docs (markdown)
|
||||
├── tools/YarnCheck/ # .NET 9 Yarn compiler/player, no Unity needed
|
||||
├── .gitignore # macOS / IDE / toolchain rules
|
||||
└── NightclubArcadia/ # ← the Unity project (-projectPath)
|
||||
├── .gitignore # Unity rules (anchored, must stay here)
|
||||
├── Assets/
|
||||
├── Packages/ # incl. embedded dev.yarnspinner.unity
|
||||
└── ProjectSettings/
|
||||
```
|
||||
|
||||
**Two `.gitignore` files, deliberately.** The Unity one anchors every rule with a
|
||||
leading `/`, so it only works at the root of the Unity project folder. Do not merge them.
|
||||
|
||||
Unity **6000.5.8f1**, URP 17.5.0, Cinemachine 3.1.7, Input System 1.20.0,
|
||||
AI Navigation 2.0.14, ProBuilder 6.1.2, Test Framework 1.7.0. Yarn Spinner is an
|
||||
**embedded package** at `NightclubArcadia/Packages/dev.yarnspinner.unity` (plus the
|
||||
`textanimator` addon) — it is committed, not resolved from a registry.
|
||||
|
||||
---
|
||||
|
||||
## 2. Ground rules
|
||||
|
||||
1. **Never hand-edit generated `.asset` files.** `Assets/Skills/Definitions/*.asset`,
|
||||
`Assets/Skills/SkillDatabase.asset`, `Assets/Candidates/Definitions/*.asset` and
|
||||
`Assets/Candidates/CandidateDatabase.asset` are *build output*. Their sources are
|
||||
`Assets/Skills/skill_bible.json` and `Assets/Candidates/candidates.json`. Edits are
|
||||
overwritten by the Editor setup scripts. Edit the JSON.
|
||||
2. **Never hand-edit scene or prefab YAML unless you have read the surrounding block.**
|
||||
GUID/fileID surgery in `.unity` / `.prefab` files silently detaches components.
|
||||
3. **One Unity instance per project path.** Unity refuses to open a project in batch
|
||||
mode while the Editor has it open — a single instance at a time. Always check before
|
||||
any `-batchmode` invocation (§3.1).
|
||||
4. **Prefer YarnCheck over Unity for dialogue validation.** It is seconds, not minutes,
|
||||
and needs no Editor lock (§5.3).
|
||||
5. **Do not commit on the user's behalf** unless asked. Unity writes to tracked files
|
||||
(`ProjectSettings/*`, `.meta`, scenes) as a side effect of simply being open, so
|
||||
`git status` noise is expected and is not always yours.
|
||||
|
||||
---
|
||||
|
||||
## 3. Unity from the command line
|
||||
|
||||
### 3.0 Two different tools, both present
|
||||
|
||||
| | What it is | Status |
|
||||
|---|---|---|
|
||||
| `/Users/lennart/.unity/bin/unity` | The **Unity CLI** (v1.0.0-beta.6). Wraps the Editor for CI-shaped work: `build`, `test`, `run`, `open`, plus editor/license/cloud management. | Installed. **Prefer this.** |
|
||||
| `/Applications/Unity/Hub/Editor/6000.5.8f1/Unity.app/Contents/MacOS/Unity` | The **Editor executable**. Raw `-batchmode` flags. | Installed. Fallback, for flags the CLI does not expose. |
|
||||
|
||||
The CLI is **not on `PATH` for non-interactive shells** — `which unity` fails even though the
|
||||
binary exists, and `unity doctor` reports `check.binary-on-path warn`. Always invoke it by
|
||||
absolute path, or export it:
|
||||
|
||||
```bash
|
||||
export UNITY_CLI="/Users/lennart/.unity/bin/unity"
|
||||
export UNITY="/Applications/Unity/Hub/Editor/6000.5.8f1/Unity.app/Contents/MacOS/Unity"
|
||||
export UNITY_PROJECT="/Users/lennart/Dev/nightlcub-arcadia/NightclubArcadia"
|
||||
```
|
||||
|
||||
`unity doctor --no-banner` confirms the environment: signed in via OAuth keyring, editor
|
||||
`6000.5.8f1` arm64 resolved from `ProjectVersion.txt`. Add `--json` to any command for
|
||||
machine-readable output and `--no-banner` to keep logs clean.
|
||||
|
||||
### 3.1 Always check the lock first
|
||||
|
||||
Only one Unity instance per project path. Check before any headless run:
|
||||
|
||||
```bash
|
||||
pgrep -fl "Unity.app/Contents/MacOS/Unity" | grep -v AssetImportWorker
|
||||
```
|
||||
|
||||
`AssetImportWorker*` processes are children of the main Editor — filter them out or you will
|
||||
misread the check. `Temp/UnityLockfile` and `unity status` are the other two signals.
|
||||
|
||||
### 3.2 Run tests
|
||||
|
||||
```bash
|
||||
"$UNITY_CLI" test "$UNITY_PROJECT" --no-banner --mode EditMode \
|
||||
--output /tmp/editmode-results.xml \
|
||||
--report-format both --junit-output /tmp/editmode-junit.xml
|
||||
```
|
||||
|
||||
Useful flags: `--filter <pattern>`, `--retries <0-10>` (reports tests that pass on retry as
|
||||
flaky), `--rerun-failed`, `--shard N/M` for parallel CI, `--coverage`, `--timeout <seconds>`.
|
||||
|
||||
`--mode PlayMode` runs the PlayMode suite. **There are none yet** — `Assets/Tests/` is EditMode
|
||||
only, so that command reports zero tests. A PlayMode suite needs a new
|
||||
`Assets/Tests/PlayMode/*.asmdef` referencing `UnityEngine.TestRunner` with `includePlatforms`
|
||||
left empty.
|
||||
|
||||
Raw-Editor equivalent, if you need a flag the CLI does not expose:
|
||||
|
||||
```bash
|
||||
"$UNITY" -batchmode -nographics -projectPath "$UNITY_PROJECT" \
|
||||
-runTests -testPlatform EditMode \
|
||||
-testResults /tmp/editmode-results.xml -logFile /tmp/unity-editmode.log
|
||||
```
|
||||
|
||||
**Do not add `-quit` to a `-runTests` run** — the runner terminates the Editor itself, and
|
||||
`-quit` on top of async work can hang it.
|
||||
|
||||
**Parse the results XML; do not trust the exit code.** Unity's own docs state there is no common
|
||||
exit-code definition across the components under test. Read `total`/`passed`/`failed` off the
|
||||
root element and list any `test-case` whose `result` is not `Passed`.
|
||||
|
||||
### 3.3 Build a player
|
||||
|
||||
```bash
|
||||
"$UNITY_CLI" build "$UNITY_PROJECT" --no-banner \
|
||||
--target StandaloneOSX -o /tmp/NightclubArcadia.app
|
||||
```
|
||||
|
||||
Without `--execute-method` the CLI uses Unity's built-in build — a Build Profile on Unity 6+, or
|
||||
the legacy desktop player flags — and builds whatever scenes `EditorBuildSettings` enables.
|
||||
`--profile <name>` selects a profile from `Assets/Settings/Build Profiles` (the profile defines
|
||||
the target). `-l/--log-file` overrides the log path; the log streams to console unless `--no-tail`.
|
||||
|
||||
**No build script exists yet.** When one is added, put it at `Assets/Editor/BuildPipeline.cs` and
|
||||
call `--execute-method NightclubArcadia.Editor.BuildPipeline.BuildMacOS`. The CLI forwards the
|
||||
output path as `-buildOutput` and **your method is responsible for honouring it**. A build method
|
||||
must call `EditorApplication.Exit(1)` on failure, or Unity exits 0 and CI reports a green build
|
||||
that produced nothing.
|
||||
|
||||
### 3.4 Run an arbitrary Editor method
|
||||
|
||||
```bash
|
||||
"$UNITY_CLI" run "$UNITY_PROJECT" --no-banner --timeout 900 -- \
|
||||
-executeMethod SomeClass.SomeStaticMethod
|
||||
```
|
||||
|
||||
**`unity run` owns `-batchmode`, `-nographics`, `-quit` and `-logFile`.** Passing any of them
|
||||
after `--` fails with a reserved-flag error. Pass only your own arguments.
|
||||
|
||||
Output does **not** stream to stdout. The log lands at `$UNITY_PROJECT/Logs/Editor.log` (the
|
||||
previous run rotates to `Editor-prev.log`), so tag your `Debug.Log` calls and grep for them:
|
||||
|
||||
```bash
|
||||
grep -n "\[YourTag\]" "$UNITY_PROJECT/Logs/Editor.log" | tail -20
|
||||
```
|
||||
|
||||
This is the mechanism for the JSON → ScriptableObject regeneration in
|
||||
`Assets/Editor/SkillSystemSetup.cs` and `CandidateSystemSetup.cs`. Read the actual class and
|
||||
method names out of those files before invoking — do not guess them.
|
||||
|
||||
## 4. The dialogue content pipeline
|
||||
|
||||
### 4.1 Where content lives
|
||||
|
||||
```
|
||||
NightclubArcadia/Assets/Dialogue/
|
||||
├── NightclubArcadia.yarnproject # globs **/*.yarn — new files need no registration
|
||||
├── Common.yarn # every <<declare>>, project-wide. Never played.
|
||||
├── Commentary.yarn # passive skill barks, one node per (context, skill)
|
||||
├── Scenes/ SC101, SC102, Debug
|
||||
├── Characters/ Bartender, Bradford Kane, Chevalier Cassian Thal
|
||||
└── Objects/ Chair
|
||||
```
|
||||
|
||||
**Dialogue is already plain text in the repo.** It is authored in `.yarn` files, not inside
|
||||
the Unity Editor, and any new `.yarn` file dropped anywhere under `Assets/Dialogue/` is picked
|
||||
up automatically by the `**/*.yarn` glob in the `.yarnproject`. Adding a scene or a character
|
||||
requires **no C#, no Unity, and no `.yarnproject` edit**.
|
||||
|
||||
The one caveat: the `.yarnproject` also stores `editorOptions.yarnScriptEditor.projectGraphPositions`
|
||||
— per-file x/y coordinates for the Yarn graph editor. These churn whenever anyone opens the
|
||||
graph view. Treat that block as editor state; do not fight over it in review.
|
||||
|
||||
### 4.2 The variable contract
|
||||
|
||||
Every variable used anywhere must be `<<declare>>`d in `Common.yarn`. This is the whole point
|
||||
of that file: the compiler then catches `$reputaton` instead of silently creating a second
|
||||
variable at runtime. Adding a scene flag means adding a `<<declare>>` line — that is a writer
|
||||
action, not a code action.
|
||||
|
||||
Naming families that are load-bearing (enforced or lint-checked):
|
||||
|
||||
| Family | Meaning | Checked by |
|
||||
|---|---|---|
|
||||
| `$self_lean_<candidate_id>` | identity-lean counter | `CandidateYarnLintTests` — id must exist in `candidates.json` |
|
||||
| `$found_<clue_id>` | clue coverage | `CandidateYarnLintTests` — id must exist in `candidates.json` |
|
||||
| `$visited_<location_id>` | first arrival | convention; `unlockFlag` in `candidates.json` may only name these |
|
||||
| `$errand_<errand_id>` | errand state | same |
|
||||
| `$seen_<scene_id>` | scene witnessed | convention |
|
||||
| `$check_*` | written by `<<check>>` | **never `<<set>>` by hand** |
|
||||
|
||||
### 4.3 Writer-facing Yarn vocabulary
|
||||
|
||||
Commands and functions registered by game code, i.e. the full set a writer may use:
|
||||
|
||||
| Syntax | Defined in | Notes |
|
||||
|---|---|---|
|
||||
| `<<check <skill> <Band>>>` | `Skills/Yarn/YarnSkillCommands.cs` | writes `$check_result`, `$check_roll`, `$check_total`, `$check_dc`, `$check_modifier`, `$check_degree`, `$check_skill` |
|
||||
| `<<skill_mod <source> <skill> <n>>>` | same | `source` = bucket key, e.g. `scene`, `drunk` |
|
||||
| `<<clear_skill_mods <source>>>` | same | |
|
||||
| `skill_rank(<skill>)` | same | function |
|
||||
| `top_skill(a, b, …)` | `Dialogue/DialougueSkillComparison.cs` | **returns its FIRST argument on a tie** — argument order is a design decision, not incidental |
|
||||
| `alias_name(<name>)` | `Dialogue/AliasNameGenerator.cs` | deterministic; `$player_alias` is a smart variable derived from it |
|
||||
| `<<enter_environment>>` | `Dialogue/DialogueTransitionController.cs` | hands control back to the world |
|
||||
|
||||
(The filename `DialougueSkillComparison.cs` is misspelled in the repo. Left alone deliberately —
|
||||
renaming it changes a `.meta` GUID. Fold it into a rename batch, not a drive-by fix.)
|
||||
|
||||
### 4.4 Flow control discipline
|
||||
|
||||
`<<detour>>` returns to the caller; `<<jump>>` does not and clears the return stack.
|
||||
The rule the existing files follow, and which new content must follow:
|
||||
|
||||
- A node started directly by `DialogueInteractable` has nothing waiting on it → its branches
|
||||
`<<jump>>`, and each destination calls `<<enter_environment>>` itself.
|
||||
- A sub-conversation that must resume its caller → `<<detour>>`, and **never** `<<jump>>` inside it.
|
||||
|
||||
Nodes sharing a `title:` form a **node group**; Yarn runs the most specific variation whose
|
||||
`when:` conditions pass. Prefer adding a variation over growing an `<<if>>` chain.
|
||||
|
||||
### 4.5 How content reaches Unity
|
||||
|
||||
There is **no manual sync step** for dialogue. The chain is:
|
||||
|
||||
```
|
||||
.yarn file saved → Unity's YarnProjectImporter recompiles the .yarnproject on focus
|
||||
→ DialogueRunner plays the new nodes on next Play
|
||||
```
|
||||
|
||||
The only things that need a human/Editor step are the *data* files, not the dialogue:
|
||||
|
||||
```
|
||||
skill_bible.json → Tools ▸ Nightclub Arcadia ▸ (SkillSystemSetup) → Skills/Definitions/*.asset + SkillDatabase.asset
|
||||
candidates.json → Tools ▸ Nightclub Arcadia ▸ (CandidateSystemSetup) → Candidates/Definitions/*.asset + CandidateDatabase.asset
|
||||
```
|
||||
|
||||
Those setup scripts also register a `[DidReloadScripts]` callback, so in practice the assets
|
||||
regenerate on script reload too. The JSON is the source of truth either way.
|
||||
|
||||
### 4.6 Code-owned vs writer-owned
|
||||
|
||||
| Writer-owned (edit freely, no Unity) | Code-owned (needs an engineer) |
|
||||
|---|---|
|
||||
| `Assets/Dialogue/**/*.yarn` | `Assets/Scripts/**/*.cs` |
|
||||
| `<<declare>>` lines in `Common.yarn` | `Assets/Editor/**/*.cs` |
|
||||
| `Assets/Skills/skill_bible.json` (prose fields) | Yarn command/function *implementations* |
|
||||
| `Assets/Candidates/candidates.json` (`status`, `sceneId`, `notes`, `unlockFlag`) | `.asset`, `.prefab`, `.unity`, `.meta` |
|
||||
| `docs/` writing docs | `ProjectSettings/**` |
|
||||
|
||||
**A writer must never need to open Unity or touch C# to write or revise a scene, a character,
|
||||
or a branch.** If a writing task requires either, that is a pipeline bug — file it.
|
||||
|
||||
---
|
||||
|
||||
## 5. Validation
|
||||
|
||||
### 5.1 EditMode test suite
|
||||
|
||||
`NightclubArcadia/Assets/Tests/EditMode/` — 7 files, ~870 LOC, two assemblies:
|
||||
|
||||
- `NightclubArcadia.Skills.Tests` — `SkillRosterTests`, `SkillCheckSystemTests`, `DcBandTests`,
|
||||
`CommentaryPickerTests`, `CandidateRegistryTests`, `CandidateYarnLintTests`
|
||||
- `NightclubArcadia.Locomotion.Math.Tests` — `MotionInputMathTests`
|
||||
|
||||
`CandidateYarnLintTests` is a **regex lint over Yarn source**: it asserts every
|
||||
`$self_lean_*` / `$found_*` in any `.yarn` file resolves to a real id in `CandidateDatabase`.
|
||||
It is a tripwire, not a proof.
|
||||
|
||||
### 5.2 One-click in-Editor run
|
||||
|
||||
`Tools ▸ Nightclub Arcadia ▸ Run Skill EditMode Tests` (`Assets/Editor/SkillSystemTestRunner.cs`).
|
||||
|
||||
### 5.3 YarnCheck — validate dialogue without Unity ⭐
|
||||
|
||||
`tools/YarnCheck` is a .NET 9 console app that compiles **and plays** the Yarn scripts using
|
||||
the exact Yarn Spinner DLLs shipped in `Packages/dev.yarnspinner.unity/Runtime/DLLs`, so it
|
||||
can never drift from the compiler the game uses. This is the fastest correctness signal in the
|
||||
repo and it needs no Editor lock. Use it on every dialogue change.
|
||||
|
||||
```bash
|
||||
cd /Users/lennart/Dev/nightlcub-arcadia/tools/YarnCheck
|
||||
|
||||
# compile everything — exit 1 + diagnostics on failure
|
||||
dotnet run -- ../../NightclubArcadia/Assets/Dialogue
|
||||
|
||||
# compile, then play a node, choosing option 2, 2, 0, 0
|
||||
dotnet run -- ../../NightclubArcadia/Assets/Dialogue Bartender_Talk 2 2 0 0
|
||||
```
|
||||
|
||||
Leftover picks restart the node — that deliberately models the player walking away and coming
|
||||
back, which is how these scenes are actually played.
|
||||
|
||||
**What it does not model** (read traces with this in mind): Unity commands are printed, not
|
||||
executed, so `<<check>>` / `<<enter_environment>>` / `<<skill_mod>>` are stepped over and
|
||||
`$check_result` stays `false` — every check-gated branch shows its *failure* side. Yarn
|
||||
functions are stubbed: `top_skill` mirrors the real first-argument-wins tie behaviour,
|
||||
`alias_name` returns a placeholder, `skill_rank` returns 0. Variables reset to their
|
||||
`<<declare>>` defaults each run; there is no save state.
|
||||
|
||||
Requires the .NET 9 SDK. `tools/YarnCheck/bin/` and `obj/` are currently **committed** and
|
||||
should not be — see `docs/restructure-plan.md`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Code conventions
|
||||
|
||||
- Namespaces: `NightclubArcadia.<Area>` — `Skills`, `Dialogue`, `UI`, `UI.Dialogue`,
|
||||
`UI.HUD`, `UI.Menu`, `Cinematics`, `Interaction`, `Player`, `Player.Math`.
|
||||
**Exception:** `NPCStandIn.cs` sits in the global namespace. That is a scaffold tell, not a
|
||||
convention to copy — new runtime types always get a namespace.
|
||||
- Assembly definitions exist for `NightclubArcadia.Skills` and `NightclubArcadia.Locomotion.Math`
|
||||
only. Camera, Player, UI, Dialogue, NPCs and Interaction all currently compile into the
|
||||
default `Assembly-CSharp`. Widening asmdef coverage is planned, not done.
|
||||
- Comments in this codebase carry *decision history* — why a flag is written at the bottom of a
|
||||
node rather than the top, why four voices in SC-101 breaks the three-voice cap on purpose.
|
||||
Match that density. Do not strip such comments as "noise"; they are the design record.
|
||||
- Editor-only code lives under `Assets/Editor/`. Anything there is stripped from builds and may
|
||||
reference `UnityEditor`.
|
||||
|
||||
---
|
||||
|
||||
## 7. Traps
|
||||
|
||||
1. **`Assets/Scenes/DialogueTest.unity` is serialized as binary**, and Unity will not convert it
|
||||
from a headless run. The project is set to Force Text (`m_SerializationMode: 2`) and the API
|
||||
agrees — `EditorSettings.serializationMode` reads `ForceText` — but Force Text governs
|
||||
conversion **at the moment the setting changes**, not on every save. A file that entered the
|
||||
project as binary stays binary. Four approaches were tried and all failed silently:
|
||||
`AssetDatabase.ForceReserializeAssets` does not rewrite scene files; `OpenScene` +
|
||||
`MarkSceneDirty` + `SaveScene` to the same path returns `true` and writes nothing, because
|
||||
`MarkSceneDirty` does not take in batch mode; `SaveScene` to a *new* path writes a fresh file
|
||||
that is also binary; and re-assigning `serializationMode` (Mixed → ForceText) from script
|
||||
does not trigger a reserialize pass. **The fix is Editor-UI only:** Project Settings ▸ Editor
|
||||
▸ Asset Serialization, switch the mode and switch it back, which reserializes on apply.
|
||||
Until then the scene is not diffable or mergeable. It is committed and intact (14 roots).
|
||||
2. **`unity run` reserves `-batchmode`, `-nographics`, `-quit`, `-logFile`.** Passing any of them
|
||||
after `--` is a hard error, and its output does not reach stdout — read `Logs/Editor.log` (§3.4).
|
||||
3. **`-quit` with `-runTests`** hangs or truncates. Omit it (§3.2).
|
||||
4. **Exit code alone is not a test verdict.** Parse the results XML (§3.2).
|
||||
5. **`which unity` fails** in non-interactive shells even though the CLI is installed. Use the
|
||||
absolute path `/Users/lennart/.unity/bin/unity` (§3.0).
|
||||
6. **Editor lock** — check before every headless run, filtering out `AssetImportWorker` children (§3.1).
|
||||
7. **Regenerated assets** — hand edits to `Skills/Definitions/*`, `Candidates/Definitions/*`
|
||||
and the two `*Database.asset` files are silently discarded (§2.1).
|
||||
8. **`top_skill` ties** resolve to the first argument. Reordering arguments changes the game.
|
||||
9. **No `.gitattributes`** — no Unity YAML merge driver, no LFS rule for `Assets/Art/`.
|
||||
Scene and prefab merges will conflict destructively under branching.
|
||||
10. **Template leftovers still present**: `Assets/Scenes/SampleScene.unity`, `Assets/Readme.asset`,
|
||||
`Assets/TutorialInfo/`. `SampleScene` is in the build scene list. Not load-bearing.
|
||||
@@ -180,3 +180,40 @@ InitTestScene*.unity*
|
||||
# Source-generator output for attributed commands/functions (regenerated).
|
||||
YarnActionRegistration.cs
|
||||
YarnActionRegistration.cs.meta
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# ProBuilder (com.unity.probuilder, embedded as source under /Packages instead
|
||||
# of resolving through the registry into Library/PackageCache)
|
||||
# ---------------------------------------------------------------------------
|
||||
# Folders ending in "~" are already invisible to the Unity Editor/AssetDatabase
|
||||
# (no .meta files are ever generated for them), so committing them only bloats
|
||||
# the repo for content nobody can reference from the project:
|
||||
# Documentation~/ ~16 MB of package docs
|
||||
# Samples~/ ~1 MB of optional sample scenes/scripts
|
||||
/[Pp]ackages/com.unity.probuilder/Documentation~/
|
||||
/[Pp]ackages/com.unity.probuilder/Samples~/
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# StarterAssets (Unity's ThirdPerson Starter Assets package, imported under
|
||||
# /Assets/StarterAssets)
|
||||
# ---------------------------------------------------------------------------
|
||||
# Vendor onboarding readme + its screenshot, shown once in the Editor's
|
||||
# "Readme" inspector window. Not referenced by any scene or script.
|
||||
/[Aa]ssets/StarterAssets/Readme.asset
|
||||
/[Aa]ssets/StarterAssets/Readme.asset.meta
|
||||
/[Aa]ssets/StarterAssets/TutorialInfo/
|
||||
|
||||
# Vendor PDF manual, not used at runtime.
|
||||
/[Aa]ssets/StarterAssets/StarterAssets_Documentation_v1.1.pdf
|
||||
/[Aa]ssets/StarterAssets/StarterAssets_Documentation_v1.1.pdf.meta
|
||||
|
||||
# "Playground" demo scene the package ships to showcase the controller.
|
||||
# Not in EditorBuildSettings and not referenced by any of the project's own
|
||||
# scenes — includes baked LightingData + reflection probe .exr captures that
|
||||
# only apply to that demo scene's lighting setup.
|
||||
/[Aa]ssets/StarterAssets/ThirdPersonController/Scenes/Playground.unity
|
||||
/[Aa]ssets/StarterAssets/ThirdPersonController/Scenes/Playground.unity.meta
|
||||
/[Aa]ssets/StarterAssets/ThirdPersonController/Scenes/Playground/
|
||||
/[Aa]ssets/StarterAssets/ThirdPersonController/Scenes/Playground.meta
|
||||
/[Aa]ssets/StarterAssets/ThirdPersonController/Scenes/PlaygroundSettings.lighting
|
||||
/[Aa]ssets/StarterAssets/ThirdPersonController/Scenes/PlaygroundSettings.lighting.meta
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98c69c750f094ae79e2f9362c4422647
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6270e22570864d7c862434241018328f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bffd4617fb74418f9eb0d0d6378cf79a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff84645ddce3641b0a7e9c68db56c8db
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1,84 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1b2c3d4e5f60718293a4b5c6d7e8f90
|
||||
TextureImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 13
|
||||
mipmaps:
|
||||
mipMapMode: 0
|
||||
enableMipMap: 0
|
||||
sRGBTexture: 1
|
||||
linearTexture: 0
|
||||
fadeOut: 0
|
||||
borderMipMap: 0
|
||||
mipMapFadeDistanceStart: 1
|
||||
mipMapFadeDistanceEnd: 3
|
||||
bumpmap:
|
||||
convertToNormalMap: 0
|
||||
externalNormalMap: 0
|
||||
heightScale: 0.25
|
||||
normalMapFilter: 0
|
||||
flipGreenChannel: 0
|
||||
isReadable: 0
|
||||
streamingMipmaps: 0
|
||||
streamingMipmapsPriority: 0
|
||||
vTOnly: 0
|
||||
ignoreMipmapLimit: 0
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 6
|
||||
cubemapConvolution: 0
|
||||
seamlessCubemap: 0
|
||||
textureFormat: 1
|
||||
maxTextureSize: 2048
|
||||
textureSettings:
|
||||
serializedVersion: 2
|
||||
filterMode: 1
|
||||
aniso: 1
|
||||
mipBias: 0
|
||||
wrapU: 1
|
||||
wrapV: 1
|
||||
wrapW: 1
|
||||
nPOTScale: 0
|
||||
lightmap: 0
|
||||
compressionQuality: 50
|
||||
spriteMode: 1
|
||||
spriteExtrude: 1
|
||||
spriteMeshType: 1
|
||||
alignment: 0
|
||||
spritePivot: {x: 0.5, y: 0.5}
|
||||
spritePixelsToUnits: 100
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spriteGenerateFallbackPhysicsShape: 1
|
||||
alphaUsage: 1
|
||||
alphaIsTransparency: 1
|
||||
spriteTessellationDetail: -1
|
||||
textureType: 8
|
||||
textureShape: 1
|
||||
singleChannelComponent: 0
|
||||
flipbookRows: 1
|
||||
flipbookColumns: 1
|
||||
maxTextureSizeSet: 0
|
||||
compressionQualitySet: 0
|
||||
textureFormatSet: 0
|
||||
ignorePngGamma: 0
|
||||
applyGammaDecoding: 0
|
||||
swizzle: 50462976
|
||||
cookieLightType: 0
|
||||
platformSettings: []
|
||||
spriteSheet:
|
||||
serializedVersion: 2
|
||||
sprites: []
|
||||
outline: []
|
||||
physicsShape: []
|
||||
bones: []
|
||||
spriteID: 5e97eb03825dee720800000000000000
|
||||
internalID: 0
|
||||
vertices: []
|
||||
indices:
|
||||
edges: []
|
||||
weights: []
|
||||
spritePackingTag:
|
||||
pSDRemoveMatte: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,107 @@
|
||||
// Everything the bartender ever says.
|
||||
//
|
||||
// Stack discipline (the player comes back to the bar, so it matters):
|
||||
// `Bartender_Talk` is the node DialogueInteractable starts, so nothing is
|
||||
// waiting for it to return. Its branches therefore <<jump>> — they are the last
|
||||
// thing the node does — and each destination hands control back with
|
||||
// <<enter_environment>> itself. <<detour>> is only for sub-conversations that
|
||||
// have to resume the caller; a <<jump>> inside one would clear the return stack.
|
||||
|
||||
title: Bartender_Talk
|
||||
position: -121,-60
|
||||
---
|
||||
<<if $spoke_to_bartender>>
|
||||
<<if $revealed_fugue_to_bartender>>
|
||||
Bartender: Ah, still hazy? A drink?
|
||||
<<else>>
|
||||
Bartender: Ah, {$player_alias}. A drink?
|
||||
<<endif>>
|
||||
-> Yes, please.
|
||||
<<jump SC101_Hook_Drink_Bartender_Talk>>
|
||||
-> No, I have questions.
|
||||
<<jump SC101_Hook_Questions_Bartender_Talk>>
|
||||
<<else>>
|
||||
<<set $spoke_to_bartender = true>>
|
||||
Bartender: Ah, {$player_alias}, back again?
|
||||
Narrator: What does he mean? "Back again?"
|
||||
-> Back? I have never been here.
|
||||
<<set $revealed_fugue_to_bartender = true>>
|
||||
Narrator: The bartender squints with a critical look.
|
||||
FACEWORK: He will tell on you. This is the face of a man who is not only here to tend the bar, but to watch, to observe. And to report back to his masters.
|
||||
Bartender: I could have sworn you are {$player_alias}, weren't you with Mr. Doss a few days ago?
|
||||
<<if $looking_for_doss eq false>>
|
||||
<<set $looking_for_doss = true>>
|
||||
Narrator: Mr. Doss?
|
||||
PROVENANCE: Mr. Doss. We need to find him, appraise him, document our findings, file them, cross-reference them ...
|
||||
<<else>>
|
||||
CONFLUENCE: There he is again: Mr. Doss.
|
||||
<<endif>>
|
||||
<<set $self_lean_made_asset += 1>>
|
||||
Bartender: What can I get ya?
|
||||
-> What can you recommend?
|
||||
Bartender: Last time you tooke the Estate.
|
||||
Narrator: You ignore the jab.
|
||||
<<jump SC101_Hook_Drink_Bartender_Talk>>
|
||||
-> Whatever.
|
||||
<<jump SC101_Hook_Drink_Bartender_Talk>>
|
||||
-> Yes. I'll take the usual.
|
||||
Narrator: The bartender doesn't even flinch, while taking ingredients from the bar.
|
||||
PROVENANCE: We cannot remember these substances.
|
||||
AMNESTY: Is this really our favorite drink?
|
||||
<<set $self_lean_inheritor += 1>>
|
||||
<<jump SC101_Hook_Drink_Bartender_Talk>>
|
||||
-> I am, and I have a few questions.
|
||||
<<jump SC101_Hook_Questions_Bartender_Talk>>
|
||||
<<endif>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_Drink_Bartender_Talk
|
||||
position: 116,222
|
||||
---
|
||||
// $had_the_estate_drink is written at the BOTTOM of this node, not here. The whole
|
||||
// node reads first-glass state — the pour, the taste, and the lean write under the
|
||||
// answer — and the glass is only recorded once all of it has run. Setting the flag
|
||||
// up here (as this node used to) leaves the tests below reading a flag this same
|
||||
// run already flipped, and the lean write can never fire.
|
||||
Bartender: One Estate coming right up.
|
||||
<<if $had_the_estate_drink>>
|
||||
Narrator: He puts another amber drink before you.
|
||||
<<else>>
|
||||
Narrator: He puts a deep amber drink before you.
|
||||
HOUSE POUR: It smells like old wood, oak, which went sour with age, like a library shelf that's been rained on once and dried wrong.
|
||||
Narrator: You take a sip.
|
||||
HOUSE POUR: Deceptively soft. Brown sugar, a little burnt. Vanilla that's actually oak-tannin doing an impression of vanilla.
|
||||
<<endif>>
|
||||
AMNESTY: Is that the taste of our favorite drink? I cannot remember ...
|
||||
-> Yes, it is!
|
||||
<<if $had_the_estate_drink eq false>>
|
||||
<<set $self_lean_inheritor += 1>>
|
||||
HOUSE POUR: Long, dry, faintly bitter - gentian root or scorched citrus pith - and it doesn't fade so much as recede, like it's waiting to be poured again.
|
||||
<<else>>
|
||||
HOUSE POUR: Long and dry, it recedes again.
|
||||
<<endif>>
|
||||
-> I don't think so.
|
||||
<<if $had_the_estate_drink eq false>>
|
||||
<<set $self_lean_inheritor -= 1>>
|
||||
HOUSE POUR: Bitter, at the end. Like it's waiting to be poured again.
|
||||
<<else>>
|
||||
HOUSE POUR: Still bitter.
|
||||
<<endif>>
|
||||
<<set $had_the_estate_drink = true>>
|
||||
<<enter_environment>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_Questions_Bartender_Talk
|
||||
position: -139,224
|
||||
---
|
||||
Bartender: Sure, what do you want to know?
|
||||
-> Question 1
|
||||
Bartender: Answer 1
|
||||
-> Question 2
|
||||
Bartender: Answer 2
|
||||
-> Nothing.
|
||||
Bartender: Alright.
|
||||
<<enter_environment>>
|
||||
<<stop>>
|
||||
<<jump SC101_Hook_Questions_Bartender_Talk>>
|
||||
===
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 582cd3b2ab9274b8ca0737660a0d6b1a
|
||||
guid: 6b8ac538a619b45b8a197ad048a94505
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
@@ -1,65 +0,0 @@
|
||||
// Everything the bouncer ever says.
|
||||
//
|
||||
// These nodes share a title, which makes them a node group. Callers just
|
||||
// `<<detour Bouncer_Talk>>` and Yarn runs the most specific variation whose
|
||||
// `when:` conditions pass. Adding a new variation later means adding a node,
|
||||
// not editing a growing <<if>> chain.
|
||||
//
|
||||
// Each variation sets $went_inside so the calling scene knows the verdict.
|
||||
|
||||
title: Bouncer_Talk
|
||||
when: once
|
||||
---
|
||||
Bouncer: Evening. Name on the list?
|
||||
You: Depends who's asking.
|
||||
-> I'm on the list.
|
||||
<<set $claimed_to_be_on_list = true>>
|
||||
<<check placement routine>>
|
||||
<<if $check_result>>
|
||||
Bouncer: ...you're not on the list.
|
||||
Bouncer: But it's slow tonight. Go on.
|
||||
<<set $went_inside = true>>
|
||||
<<else>>
|
||||
Bouncer: Nobody's on the list tonight. Especially not you.
|
||||
<<set $went_inside = false>>
|
||||
<<endif>>
|
||||
-> Let me through. <<if skill_rank("undisclosed") >= 2>>
|
||||
<<check undisclosed hard -1>>
|
||||
<<if $check_degree == "critical_success">>
|
||||
Bouncer: ...yeah. Yeah, okay.
|
||||
<<set $reputation += 2>>
|
||||
<<set $went_inside = true>>
|
||||
<<elseif $check_result>>
|
||||
Bouncer: Fine. Don't make it a thing.
|
||||
<<set $went_inside = true>>
|
||||
<<else>>
|
||||
Bouncer: Try that again and you're talking to the pavement.
|
||||
<<set $reputation -= 1>>
|
||||
<<set $went_inside = false>>
|
||||
<<endif>>
|
||||
-> Actually, I'll head home.
|
||||
Bouncer: Smart choice.
|
||||
<<set $went_inside = false>>
|
||||
===
|
||||
|
||||
title: Bouncer_Talk
|
||||
when: $is_vip
|
||||
---
|
||||
Bouncer: Didn't even see you there. Go on in.
|
||||
<<set $went_inside = true>>
|
||||
===
|
||||
|
||||
title: Bouncer_Talk
|
||||
when: $claimed_to_be_on_list
|
||||
---
|
||||
Bouncer: Still not on the list, I assume.
|
||||
Bouncer: Go on, before I change my mind.
|
||||
<<set $went_inside = true>>
|
||||
===
|
||||
|
||||
title: Bouncer_Talk
|
||||
when: always
|
||||
---
|
||||
Bouncer: Back again.
|
||||
<<set $went_inside = true>>
|
||||
===
|
||||
@@ -0,0 +1,13 @@
|
||||
// Everything Bradford Kane ever says.
|
||||
//
|
||||
// These nodes share a title, which makes them a node group. Callers just
|
||||
// `<<detour Bradford_Kane_Talk>>` and Yarn runs the most specific variation whose
|
||||
// `when:` conditions pass. Adding a new variation later means adding a node,
|
||||
// not editing a growing <<if>> chain.
|
||||
//
|
||||
// Each variation sets $went_inside so the calling scene knows the verdict.
|
||||
|
||||
title: Bradford_Kane_Talk
|
||||
---
|
||||
<<set $spoke_to_bradford_kane = true>>
|
||||
===
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb0faaa47fe2440d78e49de30f921218
|
||||
guid: a1ee2125b1dbf4068868b09cbb685aa8
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,150 @@
|
||||
// Everything Ser Cassian Thal ever says.
|
||||
//
|
||||
// These nodes share a title, which makes them a node group. Callers just
|
||||
// `<<detour Chevalier_Cassian_Thal_Talk>>` and Yarn runs the most specific variation whose
|
||||
// `when:` conditions pass. Adding a new variation later means adding a node,
|
||||
// not editing a growing <<if>> chain.
|
||||
//
|
||||
// Each variation sets $went_inside so the calling scene knows the verdict.
|
||||
|
||||
title: Chevalier_Cassian_Thal_Talk
|
||||
position: 44,-117
|
||||
---
|
||||
<<if $spoke_to_chevalier_cassian_thal>>
|
||||
Chevalier Cassian Thal: Well met good sir.
|
||||
<<else>>
|
||||
<<set $spoke_to_chevalier_cassian_thal = true>>
|
||||
Narrator: You introduce yourself to the man. He takes measure before bowing his head and tipping his forehead with a half-open fist.
|
||||
Chevalier Cassian Thal: {$player_name_full}, nice to meet you. I'm Chevalier Cassian Thal of Basel and Cyprus.
|
||||
THE FLOAT: His name reeks of money. Old money.
|
||||
<<check provenance Hard>>
|
||||
<<if $check_result>>
|
||||
PROVENANCE: Basel? Makes total sense. But which connections does this old codger have to Cyprus?
|
||||
-> Inquire further about Cyprus.
|
||||
<<detour SC101_Inquire_Cypurs_Chevalier_Cassian_Thal_Talk>>
|
||||
-> Leave it be.
|
||||
<<endif>>
|
||||
<<endif>>
|
||||
<<if $saw_knights_atlantean_cross_on_place_card eq true and $had_the_estate_drink eq true>>
|
||||
<<detour SC101_Hook_Asks_Candidate_Chevalier_Cassian_Thal_Talk>>
|
||||
<<endif>>
|
||||
===
|
||||
|
||||
title: SC101_Inquire_Cypurs_Chevalier_Cassian_Thal_Talk
|
||||
position: -175,95
|
||||
---
|
||||
<<set $inquired_about_cyprus = true>>
|
||||
Chevalier Cassian Thal: Oh, a sharp question, {$player_name_full}.
|
||||
Narrator: The knight laughs.
|
||||
Chevalier Cassian Thal: I assume you should ask your friend Mr. Doss, I am of no right to reveal this connection.
|
||||
<<if $looking_for_doss eq false>>
|
||||
<<set $looking_for_doss = true>>
|
||||
Narrator: Mr. Doss?
|
||||
PROVENANCE: Mr. Doss. We need to find him, appraise him, document our findings, file them, cross-reference them ...
|
||||
<<else>>
|
||||
CONFLUENCE: There he is again: Mr. Doss.
|
||||
<<endif>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_Asks_Candidate_Chevalier_Cassian_Thal_Talk
|
||||
position: 146,85
|
||||
---
|
||||
<<if $inquired_about_cyprus>>
|
||||
Chevalier Cassian Thal: This were a lot of questions. Now tell me something about yourself, old chap.
|
||||
<<endif>>
|
||||
<<detour SC101_Asks_Candidate_Chevalier_Cassian_Thal_Talk>>
|
||||
<<if $declared_candidate_to_chevalier_cassian_thal>>
|
||||
Narrator: Chevalier Cassian Thal turns towards the head of the table again, just, when another man stands up.
|
||||
<<jump SC102_Table>>
|
||||
<<endif>>
|
||||
===
|
||||
|
||||
title: SC101_Asks_Candidate_Chevalier_Cassian_Thal_Talk
|
||||
position: 157,261
|
||||
---
|
||||
<<set $winner = top_skill($self_lean_made_asset, "asset", $self_lean_journalist, "journalist", $self_lean_inheritor, "inheritor")>>
|
||||
<<set $previous_winner = $winner>>
|
||||
<<if $winner eq "asset">>
|
||||
Narrator: He leans in and whispers:
|
||||
Chevalier Cassian Thal: I assume you are here to observe the gathering in the interest of ... our friends of the Vaselian Concordat?
|
||||
-> Yes, I am.
|
||||
<<set $self_lean_made_asset += 1>>
|
||||
<<detour SC101_Declares_Asset_Chevalier_Cassian_Thal_Talk>>
|
||||
-> You must be mistaken.
|
||||
<<set $self_lean_journalist += 1>>
|
||||
<<set $self_lean_inheritor += 1>>
|
||||
<<detour SC101_Deny_Candidate_Chevalier_Cassian_Thal_Talk>>
|
||||
<<elseif $winner eq "journalist">>
|
||||
Chevalier Cassian Thal: I got the feeling I may read my answers in tomorrow's newspaper.
|
||||
Narrator: He says it with a boyish grin, as if he is sure he hasn't disclosed anything contentious.
|
||||
-> You actually may.
|
||||
<<set $self_lean_journalist += 1>>
|
||||
<<detour SC101_Declares_Journalist_Chevalier_Cassian_Thal_Talk>>
|
||||
-> No, I got nothing to do with newspapers and such!
|
||||
<<set $self_lean_made_asset += 1>>
|
||||
<<set $self_lean_inheritor += 1>>
|
||||
<<detour SC101_Deny_Candidate_Chevalier_Cassian_Thal_Talk>>
|
||||
<<else>>
|
||||
Chevalier Cassian Thal: You probably look to settle your parent's debts?
|
||||
FACEWORK: He doesn't seem emotional about it, he is just interested.
|
||||
-> I actually am.
|
||||
<<set $self_lean_inheritor += 1>>
|
||||
<<detour SC101_Declares_Inheritor_Chevalier_Cassian_Thal_Talk>>
|
||||
-> Oh, I don't know about any debt, I hope they didn't borrow money from you?
|
||||
<<set $self_lean_journalist += 1>>
|
||||
<<set $self_lean_made_asset +=1>>
|
||||
Chevalier Cassian Thal: Oh god, no, they didn't borrow anything from us.
|
||||
CONFLUENCE: Us?
|
||||
<<detour SC101_Deny_Candidate_Chevalier_Cassian_Thal_Talk>>
|
||||
<<endif>>
|
||||
===
|
||||
|
||||
title: SC101_Declares_Asset_Chevalier_Cassian_Thal_Talk
|
||||
position: -9,670
|
||||
---
|
||||
<<set $declared_candidate_to_chevalier_cassian_thal = true>>
|
||||
Narrator: Chevalier Cassian Thal looks knowingly and cannot hide a little smirk.
|
||||
Chevalier Cassian Thal: Well, then let us hope the ... others follow the Knight's compromise.
|
||||
Narrator: He winks at you.
|
||||
FACEWORK: He seems to know more about us, than we know about ourselves. Though if we back out now he will become suspicious.
|
||||
===
|
||||
|
||||
title: SC101_Declares_Journalist_Chevalier_Cassian_Thal_Talk
|
||||
position: -222,667
|
||||
---
|
||||
<<set $declared_candidate_to_chevalier_cassian_thal = true>>
|
||||
Narrator: Chevalier Cassian Thal laughs.
|
||||
Chevalier Cassian Thal: Well, then let me give you something to write about: You and your readers will be surprised to hear, what you will witness in a second.
|
||||
CONFLUENCE: He can hardly hide his smirk.
|
||||
===
|
||||
|
||||
title: SC101_Declares_Inheritor_Chevalier_Cassian_Thal_Talk
|
||||
position: 207,664
|
||||
---
|
||||
<<set $declared_candidate_to_chevalier_cassian_thal = true>>
|
||||
Chevalier Cassian Thal: You may very well get your chance this week, my boy.
|
||||
FACEWORK: His look is benevolent, nearly fatherly.
|
||||
CONFLUENCE: What should our parents have done, that requires repayment?
|
||||
===
|
||||
|
||||
title: SC101_Deny_Candidate_Chevalier_Cassian_Thal_Talk
|
||||
position: 436,260
|
||||
---
|
||||
Chevalier Cassian Thal: Oh, I am rarely wrong in matters like these. Though enlighten me: What else could have been your wish coming here?
|
||||
FACEWORK: He looks genuinely interested.
|
||||
<<set $winner = top_skill($self_lean_made_asset, "asset", $self_lean_journalist, "journalist", $self_lean_inheritor, "inheritor")>>
|
||||
<<if $previous_winner == $winner>>
|
||||
-> No, you are totally right, indeed.
|
||||
<<if $winner == "asset">>
|
||||
<<detour SC101_Declares_Asset_Chevalier_Cassian_Thal_Talk>>
|
||||
<<elseif $winner == "journalist">>
|
||||
<<detour SC101_Declares_Journalist_Chevalier_Cassian_Thal_Talk>>
|
||||
<<else>>
|
||||
<<detour SC101_Declares_Inheritor_Chevalier_Cassian_Thal_Talk>>
|
||||
<<endif>>
|
||||
-> Actually ...
|
||||
<<detour SC101_Asks_Candidate_Chevalier_Cassian_Thal_Talk>>
|
||||
<<else>>
|
||||
<<detour SC101_Asks_Candidate_Chevalier_Cassian_Thal_Talk>>
|
||||
<<endif>>
|
||||
===
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9f603a6134614e0fa576727d10d487a
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 94073015eacc34c1d8fc6786e43d60ca, type: 3}
|
||||
@@ -18,16 +18,6 @@ title: Declarations
|
||||
// How much the door staff likes you.
|
||||
<<declare $reputation = 0 as number>>
|
||||
|
||||
// Set when the player has tried the "I'm on the list" line at least once.
|
||||
<<declare $claimed_to_be_on_list = false as bool>>
|
||||
|
||||
// The bouncer's verdict, read by the scene that called him.
|
||||
<<declare $went_inside = false as bool>>
|
||||
|
||||
// Smart variable: derived, not stored. Can never drift out of sync with
|
||||
// $reputation, so there's nothing to remember to update.
|
||||
<<declare $is_vip = $reputation > 10>>
|
||||
|
||||
// Written by <<check>> (YarnSkillCommands). Never <<set>> these by hand.
|
||||
<<declare $check_result = false as bool>>
|
||||
<<declare $check_roll = 0 as number>>
|
||||
@@ -37,10 +27,25 @@ title: Declarations
|
||||
<<declare $check_degree = "" as string>>
|
||||
<<declare $check_skill = "" as string>>
|
||||
|
||||
// Used by top_skill
|
||||
<<declare $winner = "" as string>>
|
||||
<<declare $previous_winner = "" as string>>
|
||||
|
||||
// Candidate lean. Three permanently-live readings of who the PC is; they are
|
||||
// not mutually exclusive and never resolve. Writers <<set>> these; no code
|
||||
// reads them. There is deliberately NO derived "winning candidate" variable —
|
||||
// see docs/candidate-system-implementation-plan.md §6.
|
||||
// not mutually exclusive and never resolve into a canonical identity.
|
||||
//
|
||||
// DESIGN DECISION 2026-08-16 — amends the "no code ever reads lean" guardrail in
|
||||
// docs/candidate-system-implementation-plan.md §6.1: scenes are meant to tilt
|
||||
// toward one reading and NPCs are meant to act on the current tilt, so that a
|
||||
// player who thinks they have settled on a path gets challenged on it in the
|
||||
// next scene. Reading lean through top_skill(...) is therefore sanctioned, as in
|
||||
// SC101_Asks_Candidate_Chevalier_Cassian_Thal_Talk. top_skill returns its FIRST
|
||||
// argument on a tie, which is why made_asset is passed first — the Made Asset
|
||||
// bias on an even score is deliberate, not an accident of argument order.
|
||||
//
|
||||
// What the amendment does NOT license: a stored winner. There is still no
|
||||
// $dominant_candidate, no ground-truth identity field, and nothing in save data
|
||||
// beyond these three integers. $winner above is scratch, recomputed per use.
|
||||
<<declare $self_lean_made_asset = 0 as number>>
|
||||
<<declare $self_lean_journalist = 0 as number>>
|
||||
<<declare $self_lean_inheritor = 0 as number>>
|
||||
@@ -56,12 +61,16 @@ title: Declarations
|
||||
<<declare $found_made_asset_testimony = false as bool>>
|
||||
<<declare $found_made_asset_document = false as bool>>
|
||||
<<declare $found_made_asset_intuition = false as bool>>
|
||||
|
||||
<<declare $found_journalist_object = false as bool>>
|
||||
<<declare $found_journalist_testimony = false as bool>>
|
||||
<<declare $found_journalist_document = false as bool>>
|
||||
<<declare $found_journalist_intuition = false as bool>>
|
||||
|
||||
<<declare $found_inheritor_object = false as bool>>
|
||||
<<declare $found_inheritor_testimony = false as bool>>
|
||||
<<declare $looking_for_doss = false as bool>>
|
||||
<<declare $had_the_estate_drink = false as bool>>
|
||||
<<declare $found_inheritor_document = false as bool>>
|
||||
<<declare $found_inheritor_intuition = false as bool>>
|
||||
|
||||
@@ -79,4 +88,30 @@ title: Declarations
|
||||
<<declare $errand_door_list = false as bool>>
|
||||
<<declare $errand_find_contact = false as bool>>
|
||||
<<declare $errand_ask_about_name = false as bool>>
|
||||
<<declare $spoke_to_bartender = false as bool>>
|
||||
<<declare $revealed_fugue_to_bartender = false as bool>>
|
||||
|
||||
// Player name substitution. Uppercase [PC] in the Skill Bible means the full,
|
||||
// formal form (STANDING ORDER, PROVENANCE); lowercase [pc] means the familiar
|
||||
// short form (CONFLUENCE, FACEWORK). Two variables, not one — collapsing them
|
||||
// loses a characterisation rule the bible states for four separate voices.
|
||||
// Defaults are placeholders; naming the PC is design's call.
|
||||
<<declare $player_name = "Vesper" as string>>
|
||||
<<declare $player_name_full = "Vesper Adaire" as string>>
|
||||
|
||||
// Club alias. Smart variable: deterministically derived from $player_name via
|
||||
// AliasNameGenerator.alias_name (hash-seeded pick from two word pools), so it
|
||||
// is never in sync-drift and never <<set>> by hand. Same real name always
|
||||
// yields the same alias; the alias itself bears no resemblance to the input.
|
||||
<<declare $player_alias = alias_name($player_name) as string>>
|
||||
|
||||
// Information about history and symbols
|
||||
<<declare $sat_down_at_table = false as bool>>
|
||||
<<declare $saw_knights_atlantean_cross_on_place_card = false as bool>>
|
||||
|
||||
// Character dialogue gates
|
||||
<<declare $spoke_to_chevalier_cassian_thal = false as bool>>
|
||||
<<declare $spoke_to_bradford_kane = false as bool>>
|
||||
<<declare $inquired_about_cyprus = false as bool>>
|
||||
<<declare $declared_candidate_to_chevalier_cassian_thal = false as bool>>
|
||||
===
|
||||
|
||||
@@ -1,15 +1,61 @@
|
||||
{
|
||||
"projectFileVersion": 4,
|
||||
"sourceFiles": [
|
||||
"**/*.yarn"
|
||||
],
|
||||
"excludeFiles": [
|
||||
"**/*~/*",
|
||||
"./Samples/Yarn Spinner*/*"
|
||||
],
|
||||
"localisation": {},
|
||||
"baseLanguage": "en",
|
||||
"compilerOptions": {
|
||||
"diagnosticsSeverity": {}
|
||||
}
|
||||
"projectFileVersion": 4,
|
||||
"sourceFiles": [
|
||||
"**/*.yarn"
|
||||
],
|
||||
"excludeFiles": [
|
||||
"**/*~/*",
|
||||
"./Samples/Yarn Spinner*/*"
|
||||
],
|
||||
"localisation": {},
|
||||
"baseLanguage": "en",
|
||||
"compilerOptions": {
|
||||
"diagnosticsSeverity": {}
|
||||
},
|
||||
"projectName": "NightclubArcade",
|
||||
"authorName": [
|
||||
"LennartGrabowski"
|
||||
],
|
||||
"editorOptions": {
|
||||
"yarnScriptEditor": {
|
||||
"projectGraphPositions": {
|
||||
"Bartender.yarn": {
|
||||
"x": 282,
|
||||
"y": 12
|
||||
},
|
||||
"Bradford Kane.yarn": {
|
||||
"x": 1320,
|
||||
"y": 2287
|
||||
},
|
||||
"Chevalier Cassian Thal.yarn": {
|
||||
"x": 1621,
|
||||
"y": 2260
|
||||
},
|
||||
"Commentary.yarn": {
|
||||
"x": 12,
|
||||
"y": 231
|
||||
},
|
||||
"Common.yarn": {
|
||||
"x": 12,
|
||||
"y": 12
|
||||
},
|
||||
"Chair.yarn": {
|
||||
"x": 866,
|
||||
"y": 1104
|
||||
},
|
||||
"Debug.yarn": {
|
||||
"x": 14,
|
||||
"y": 448
|
||||
},
|
||||
"SC101.yarn": {
|
||||
"x": 820,
|
||||
"y": -3
|
||||
},
|
||||
"SC102.yarn": {
|
||||
"x": 2595,
|
||||
"y": 2682
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: beedfd387b0d049ffb7534a81d2df45f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,121 @@
|
||||
// Everything that can be interacted with the chair.
|
||||
//
|
||||
// Stack discipline (the player re-enters all of this, so it matters):
|
||||
// `Chair_Interaction` is the node DialogueInteractable starts, so nothing above
|
||||
// it is waiting for a return. The menu therefore LOOPS with <<jump>>, which
|
||||
// replaces the current node and pushes nothing, and only sub-conversations that
|
||||
// have to come back use <<detour>>. Never <<jump>> out of a detoured node —
|
||||
// that clears the return stack and the caller never resumes.
|
||||
//
|
||||
// The sit-down line lives in its own node so the menu loop can't replay it,
|
||||
// while a player who stands up and sits down again still gets it.
|
||||
|
||||
title: Chair_Interaction
|
||||
position: -334,-601
|
||||
---
|
||||
Narrator: An empty chair with a place card: {$player_name}.
|
||||
-> Sit down.
|
||||
<<set $sat_down_at_table = true>>
|
||||
<<jump SC101_Hook_Sitting_Chair_Interaction>>
|
||||
-> Not yet.
|
||||
<<enter_environment>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_Sitting_Chair_Interaction
|
||||
position: -328,-360
|
||||
---
|
||||
Narrator: You sit down between two very distinguished gentlemen.
|
||||
<<jump SC101_Hook_Menu_Chair_Interaction>>
|
||||
===
|
||||
|
||||
// The loop target. Every menu variation jumps back here when its sub-conversation
|
||||
// returns, so which variation shows is re-evaluated after every interaction.
|
||||
title: SC101_Hook_Menu_Chair_Interaction
|
||||
position: -328,-205
|
||||
---
|
||||
<<if $spoke_to_chevalier_cassian_thal eq true and $spoke_to_bradford_kane eq true>>
|
||||
<<jump SC101_Hook_Both_Chair_Interaction>>
|
||||
<<elseif $spoke_to_chevalier_cassian_thal eq true and $spoke_to_bradford_kane eq false>>
|
||||
<<jump SC101_Hook_Left_Not_Right_Chair_Interaction>>
|
||||
<<elseif $spoke_to_chevalier_cassian_thal eq false and $spoke_to_bradford_kane eq true>>
|
||||
<<jump SC101_Hook_Right_Not_Left_Chair_Interaction>>
|
||||
<<else>>
|
||||
<<jump SC101_Hook_First_Sitting_Chair_Interaction>>
|
||||
<<endif>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_First_Sitting_Chair_Interaction
|
||||
position: -320,-51
|
||||
---
|
||||
-> Look at the details of the place card.
|
||||
<<detour SC101_Hook_Place_Card_Chair_Interaction>>
|
||||
-> Introduce yourself to the gentleman on your left, sitting closer to the head of the table.
|
||||
<<detour Chevalier_Cassian_Thal_Talk>>
|
||||
-> Introduce yourself to the gentleman on your right.
|
||||
<<detour Bradford_Kane_Talk>>
|
||||
-> Stand up.
|
||||
<<enter_environment>>
|
||||
<<stop>>
|
||||
<<jump SC101_Hook_Menu_Chair_Interaction>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_Left_Not_Right_Chair_Interaction
|
||||
position: -95,-48
|
||||
---
|
||||
-> Look at the details of the place card.
|
||||
<<detour SC101_Hook_Place_Card_Chair_Interaction>>
|
||||
-> Talk to Chevalier Cassian Thal.
|
||||
<<detour Chevalier_Cassian_Thal_Talk>>
|
||||
-> Introduce yourself to the gentleman on your right.
|
||||
<<detour Bradford_Kane_Talk>>
|
||||
-> Stand up.
|
||||
<<enter_environment>>
|
||||
<<stop>>
|
||||
<<jump SC101_Hook_Menu_Chair_Interaction>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_Right_Not_Left_Chair_Interaction
|
||||
position: 134,-32
|
||||
---
|
||||
-> Look at the details of the place card.
|
||||
<<detour SC101_Hook_Place_Card_Chair_Interaction>>
|
||||
-> Introduce yourself to the gentleman on your left, sitting closer to the head of the table.
|
||||
<<detour Chevalier_Cassian_Thal_Talk>>
|
||||
-> Talk to Bradford Kane.
|
||||
<<detour Bradford_Kane_Talk>>
|
||||
-> Stand up.
|
||||
<<enter_environment>>
|
||||
<<stop>>
|
||||
<<jump SC101_Hook_Menu_Chair_Interaction>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_Both_Chair_Interaction
|
||||
position: 363,-36
|
||||
---
|
||||
-> Look at the details of the place card.
|
||||
<<detour SC101_Hook_Place_Card_Chair_Interaction>>
|
||||
-> Talk to Chevalier Cassian Thal.
|
||||
<<detour Chevalier_Cassian_Thal_Talk>>
|
||||
-> Talk to Bradford Kane.
|
||||
<<detour Bradford_Kane_Talk>>
|
||||
-> Stand up.
|
||||
<<enter_environment>>
|
||||
<<stop>>
|
||||
<<jump SC101_Hook_Menu_Chair_Interaction>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_Place_Card_Chair_Interaction
|
||||
position: -296,331
|
||||
---
|
||||
Narrator: You take the place card and take a look.
|
||||
<<check provenance Hard>>
|
||||
<<if $check_result>>
|
||||
<<set $saw_knights_atlantean_cross_on_place_card = true>>
|
||||
PROVENANCE: What is this?
|
||||
Narrator: You see a plain equal-armed cross inside a circle embossed in the upper right corner.
|
||||
PROVENANCE: We are in Switzerland, after all. Though this symbol is not known to be associated with Switzerland. Most peculiar.
|
||||
<<else>>
|
||||
Narrator: You see a cross inside a circle embossed in the upper right corner.
|
||||
PROVENANCE: This is probably related to Switzerland.
|
||||
<<endif>>
|
||||
===
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f6437b77328240e590f205a6605cfcb
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 94073015eacc34c1d8fc6786e43d60ca, type: 3}
|
||||
@@ -1,26 +0,0 @@
|
||||
// The door. Scene files stay thin: they set the stage, detour into character
|
||||
// nodes for the actual talking, then branch on the outcome.
|
||||
//
|
||||
// `Start` is the DialogueRunner's entry node (set on the Dialogue System
|
||||
// prefab), so this is where the game begins.
|
||||
|
||||
title: Start
|
||||
---
|
||||
Narrator: Neon bleeds across wet asphalt. The queue hasn't moved in ten minutes.
|
||||
<<detour Bouncer_Talk>>
|
||||
<<if $went_inside>>
|
||||
<<jump Entrance_Inside>>
|
||||
<<else>>
|
||||
<<jump Entrance_Outside>>
|
||||
<<endif>>
|
||||
===
|
||||
|
||||
title: Entrance_Inside
|
||||
---
|
||||
Narrator: The bass hits you like a wall.
|
||||
===
|
||||
|
||||
title: Entrance_Outside
|
||||
---
|
||||
Narrator: The night swallows you back up.
|
||||
===
|
||||
@@ -7,10 +7,10 @@
|
||||
// stack types so trust becomes an artifact of imbalance.
|
||||
// See Assets/Candidates/candidates.json.
|
||||
//
|
||||
// Discovery order: hooks are independently reachable in any order via
|
||||
// <<detour>> from the desk. Never <<if>>-guard a hook on another hook having
|
||||
// fired, on any $self_lean_*, or on skill_rank(...). Never make a hook only
|
||||
// reachable as fall-through from another.
|
||||
// Beat order: hooks fire in sequence from SC101_Desk (STANDING ORDER →
|
||||
// HOUSE POUR → FACEWORK → CONFLUENCE). Each remains an independently authored
|
||||
// node. Never <<if>>-guard a hook on another hook having fired, on any
|
||||
// $self_lean_*, or on skill_rank(...).
|
||||
//
|
||||
// Passive pattern (clue-bearing):
|
||||
// one voice per hook, from the candidate's attached pair;
|
||||
@@ -24,49 +24,53 @@
|
||||
//
|
||||
// Body stays neutral on purpose: no lean, no candidate attachment.
|
||||
|
||||
title: Start
|
||||
position: -17,-276
|
||||
---
|
||||
<<jump SC101_Desk>>
|
||||
===
|
||||
|
||||
title: SC101_Desk
|
||||
position: -19,-36
|
||||
---
|
||||
<<set $seen_sc_101 = true>>
|
||||
<<set $visited_desk = true>>
|
||||
Narrator: A desk under a single lamp. The card is face-down. Your hands already know where the corners are.
|
||||
-> Made Asset hook
|
||||
<<detour SC101_Hook_MadeAsset>>
|
||||
<<jump SC101_Desk>>
|
||||
-> Journalist hook
|
||||
<<detour SC101_Hook_Journalist>>
|
||||
<<jump SC101_Desk>>
|
||||
-> Inheritor hook
|
||||
<<detour SC101_Hook_Inheritor>>
|
||||
<<jump SC101_Desk>>
|
||||
-> Neutral hook
|
||||
<<detour SC101_Hook_Neutral>>
|
||||
<<jump SC101_Desk>>
|
||||
-> Leave the desk
|
||||
Narrator: You leave the card where it is. The lamp keeps the shape of your hands on the blotter.
|
||||
Narrator: The mahogany doors are too heavy for the hinges someone recently, badly, tightened — you feel the extra half-second of resistance before either side gives. Beyond them: a hall built for four hundred people politely disagreeing about tariffs, hosting perhaps sixty, none of whom look like they've read the programme.
|
||||
Narrator: Someone left a card with your name on it at the registration desk three hours before you decided to come. You don't remember deciding.
|
||||
<<detour SC101_Hook_Inheritor>>
|
||||
<<detour SC101_Hook_Neutral>>
|
||||
<<detour SC101_Hook_Journalist>>
|
||||
<<detour SC101_Hook_MadeAsset>>
|
||||
Narrator: You're drawn toward a seat — toward a waiting conversation you didn't agree to have yet.
|
||||
<<enter_environment>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_MadeAsset
|
||||
position: -40,567
|
||||
---
|
||||
CONFLUENCE: You don't turn it over. You don't have to. The stock, the margin, the way the emboss catches — one, two, three, and three is the one. Which means somebody trained you for a card like this.
|
||||
CONFLUENCE: One: the seating chart's alphabetical. Two: one gap in it, held open past the start time. Three, and three is the one, {$player_name}: whoever printed this knew you'd be late to your own arrival. Which means somebody in this room has already met you, {$player_name}, and you're the only one who doesn't know it.
|
||||
<<set $found_made_asset_intuition = true>>
|
||||
<<set $self_lean_made_asset += 1>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_Journalist
|
||||
position: -299,452
|
||||
---
|
||||
FACEWORK: Your throat tightens before you decide what the card is. Not curiosity. Recognition of a person you haven't named yet. That reaction is wrong for a story. It's right for a meeting.
|
||||
FACEWORK: His hands gave it away before his face did — a flinch toward you, checked, turned into reaching for a drink that wasn't there. That's not a stranger's hands. What did you do to earn that flinch?
|
||||
<<set $found_journalist_intuition = true>>
|
||||
<<set $self_lean_journalist += 1>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_Inheritor
|
||||
position: 335,366
|
||||
---
|
||||
STANDING ORDER: You straighten the card so its top edge is parallel to the desk's. Nobody taught you that. You correct it anyway. The rule is older than you are, and it still applies.
|
||||
STANDING ORDER: You are standing in a doorway, {$player_name_full}. That's the whole of what's certain. Build outward from there — a person who starts anywhere else is a person coming apart in public.
|
||||
<<set $found_inheritor_intuition = true>>
|
||||
<<set $self_lean_inheritor += 1>>
|
||||
===
|
||||
|
||||
title: SC101_Hook_Neutral
|
||||
position: 87,310
|
||||
---
|
||||
HOUSE POUR: The lamp is warm enough. Your mouth is dry. Neither of those is information about who you are — only about how long you've been standing here.
|
||||
HOUSE POUR: Cigar smoke, spilled aperitif, and under it — cold, sharp — the ammonia bite of a floor mopped in a hurry, love. Someone's trying to make this room smell like money. It smells like panic with good cologne on top.
|
||||
===
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// SC-102 — The figure at the head of the table just stood up.
|
||||
|
||||
title: SC102_Table
|
||||
---
|
||||
Figure at the head of the table: "Welcome."
|
||||
===
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 717dc562b961f41c49f5615fb8415f67
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
script: {fileID: 11500000, guid: 94073015eacc34c1d8fc6786e43d60ca, type: 3}
|
||||
@@ -0,0 +1,316 @@
|
||||
using NightclubArcadia.Cinematics;
|
||||
using NightclubArcadia.Interaction;
|
||||
using NightclubArcadia.Player;
|
||||
using StarterAssets;
|
||||
using Unity.AI.Navigation;
|
||||
using Unity.Cinemachine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
/// <summary>
|
||||
/// Wires player control, navigation, and camera systems into DialogueTest.unity.
|
||||
/// Run via Tools → Nightclub Arcadia → Set Up Player Control & Camera.
|
||||
/// </summary>
|
||||
public static class PlayerControlSetup
|
||||
{
|
||||
const string ScenePath = "Assets/Scenes/DialogueTest.unity";
|
||||
const string PlayerPrefabPath = "Assets/StarterAssets/ThirdPersonController/Prefabs/PlayerArmature.prefab";
|
||||
const string SettingsFolder = "Assets/Settings";
|
||||
|
||||
[MenuItem("Tools/Nightclub Arcadia/Set Up Player Control & Camera")]
|
||||
public static void SetUp()
|
||||
{
|
||||
EnsurePlayerPrefab();
|
||||
WireScene();
|
||||
AssetDatabase.SaveAssets();
|
||||
Debug.Log("[PlayerControlSetup] Player control and camera setup complete.");
|
||||
}
|
||||
|
||||
static void EnsurePlayerPrefab()
|
||||
{
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(PlayerPrefabPath);
|
||||
if (prefab == null)
|
||||
{
|
||||
Debug.LogError($"[PlayerControlSetup] Missing prefab at {PlayerPrefabPath}");
|
||||
return;
|
||||
}
|
||||
|
||||
var root = PrefabUtility.LoadPrefabContents(PlayerPrefabPath);
|
||||
|
||||
EnsureComponent<PlayerPointerInput>(root);
|
||||
EnsureComponent<PlayerMotionArbiter>(root);
|
||||
EnsureComponent<ClickToMoveController>(root);
|
||||
EnsureComponent<PointerNavigationInput>(root);
|
||||
EnsureComponent<NavMeshAgent>(root);
|
||||
|
||||
var inputs = root.GetComponent<StarterAssetsInputs>();
|
||||
if (inputs != null)
|
||||
{
|
||||
inputs.analogMovement = true;
|
||||
inputs.cursorLocked = false;
|
||||
}
|
||||
|
||||
var controller = root.GetComponent<ThirdPersonController>();
|
||||
if (controller != null)
|
||||
{
|
||||
controller.LockCameraPosition = true;
|
||||
}
|
||||
|
||||
var clickToMove = root.GetComponent<ClickToMoveController>();
|
||||
var pointerNav = root.GetComponent<PointerNavigationInput>();
|
||||
var pointerInput = root.GetComponent<PlayerPointerInput>();
|
||||
var arbiter = root.GetComponent<PlayerMotionArbiter>();
|
||||
|
||||
WireSerializedReference(clickToMove, "brainCamera", null);
|
||||
WireSerializedReference(pointerNav, "pointerInput", pointerInput);
|
||||
WireSerializedReference(pointerNav, "clickToMove", clickToMove);
|
||||
WireSerializedReference(pointerNav, "motionArbiter", arbiter);
|
||||
|
||||
PrefabUtility.SaveAsPrefabAsset(root, PlayerPrefabPath);
|
||||
PrefabUtility.UnloadPrefabContents(root);
|
||||
}
|
||||
|
||||
static void WireScene()
|
||||
{
|
||||
var scene = EditorSceneManager.OpenScene(ScenePath, OpenSceneMode.Single);
|
||||
var player = GameObject.FindGameObjectWithTag("Player");
|
||||
if (player == null)
|
||||
{
|
||||
Debug.LogError("[PlayerControlSetup] No Player-tagged object found in scene.");
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureComponent<PlayerPointerInput>(player);
|
||||
EnsureComponent<PlayerMotionArbiter>(player);
|
||||
EnsureComponent<ClickToMoveController>(player);
|
||||
EnsureComponent<PointerNavigationInput>(player);
|
||||
EnsureComponent<NavMeshAgent>(player);
|
||||
|
||||
var inputs = player.GetComponent<StarterAssetsInputs>();
|
||||
if (inputs != null)
|
||||
{
|
||||
inputs.analogMovement = true;
|
||||
inputs.cursorLocked = false;
|
||||
}
|
||||
|
||||
var controller = player.GetComponent<ThirdPersonController>();
|
||||
if (controller != null)
|
||||
{
|
||||
controller.LockCameraPosition = true;
|
||||
}
|
||||
|
||||
var brainCamera = Camera.main;
|
||||
var pointerInput = player.GetComponent<PlayerPointerInput>();
|
||||
var clickToMove = player.GetComponent<ClickToMoveController>();
|
||||
var pointerNav = player.GetComponent<PointerNavigationInput>();
|
||||
var arbiter = player.GetComponent<PlayerMotionArbiter>();
|
||||
|
||||
WireSerializedReference(clickToMove, "brainCamera", brainCamera);
|
||||
WireSerializedReference(pointerNav, "brainCamera", brainCamera);
|
||||
WireSerializedReference(pointerNav, "pointerInput", pointerInput);
|
||||
WireSerializedReference(pointerNav, "clickToMove", clickToMove);
|
||||
WireSerializedReference(pointerNav, "motionArbiter", arbiter);
|
||||
|
||||
var groundLayer = LayerMask.NameToLayer("Ground");
|
||||
var interactableLayer = LayerMask.NameToLayer("Interactable");
|
||||
SetLayerIfExists("Floor", groundLayer);
|
||||
SetLayerIfExists("Room_101", groundLayer);
|
||||
SetLayerIfExists("Wall_Back", groundLayer);
|
||||
SetLayerIfExists("Wall_Front", groundLayer);
|
||||
SetLayerIfExists("Table", groundLayer);
|
||||
|
||||
WireBartender("Bartender", interactableLayer);
|
||||
WireBartender("Bartender (1)", interactableLayer);
|
||||
|
||||
EnsureNavigation(player.transform.position);
|
||||
EnsureCameraAnchor(player.transform, brainCamera);
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(scene);
|
||||
EditorSceneManager.SaveScene(scene);
|
||||
}
|
||||
|
||||
static void WireBartender(string objectName, int interactableLayer)
|
||||
{
|
||||
var bartender = GameObject.Find(objectName);
|
||||
if (bartender == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (interactableLayer >= 0)
|
||||
{
|
||||
bartender.layer = interactableLayer;
|
||||
}
|
||||
|
||||
EnsureComponent<ClickInteractableBridge>(bartender);
|
||||
EnsureComponent<CameraPointOfInterest>(bartender);
|
||||
}
|
||||
|
||||
static void EnsureNavigation(Vector3 sampleOrigin)
|
||||
{
|
||||
var navigation = GameObject.Find("Navigation");
|
||||
if (navigation == null)
|
||||
{
|
||||
navigation = new GameObject("Navigation");
|
||||
}
|
||||
|
||||
var surface = EnsureComponent<NavMeshSurface>(navigation);
|
||||
surface.agentTypeID = 0;
|
||||
surface.collectObjects = CollectObjects.All;
|
||||
surface.useGeometry = NavMeshCollectGeometry.RenderMeshes;
|
||||
|
||||
var included = 0;
|
||||
var defaultLayer = LayerMask.NameToLayer("Default");
|
||||
var groundLayer = LayerMask.NameToLayer("Ground");
|
||||
if (defaultLayer >= 0)
|
||||
{
|
||||
included |= 1 << defaultLayer;
|
||||
}
|
||||
|
||||
if (groundLayer >= 0)
|
||||
{
|
||||
included |= 1 << groundLayer;
|
||||
}
|
||||
|
||||
surface.layerMask = included;
|
||||
|
||||
var table = GameObject.Find("Table");
|
||||
if (table != null)
|
||||
{
|
||||
var modifier = EnsureComponent<NavMeshModifier>(table);
|
||||
modifier.overrideArea = true;
|
||||
modifier.area = NavMesh.GetAreaFromName("Not Walkable");
|
||||
}
|
||||
|
||||
surface.BuildNavMesh();
|
||||
|
||||
if (!NavMesh.SamplePosition(sampleOrigin, out _, 2f, NavMesh.AllAreas))
|
||||
{
|
||||
Debug.LogWarning("[PlayerControlSetup] NavMesh bake did not cover the player start position.");
|
||||
}
|
||||
}
|
||||
|
||||
static void EnsureCameraAnchor(Transform followTarget, Camera brainCamera)
|
||||
{
|
||||
var vcamObject = GameObject.Find("CinemachineCamera");
|
||||
if (vcamObject == null)
|
||||
{
|
||||
Debug.LogError("[PlayerControlSetup] CinemachineCamera not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
var vcam = vcamObject.GetComponent<CinemachineCamera>();
|
||||
var composer = vcamObject.GetComponent<CinemachinePositionComposer>();
|
||||
|
||||
var anchorObject = GameObject.Find("CameraAnchor");
|
||||
if (anchorObject == null)
|
||||
{
|
||||
anchorObject = new GameObject("CameraAnchor");
|
||||
}
|
||||
|
||||
anchorObject.transform.position = followTarget.position;
|
||||
|
||||
var anchor = EnsureComponent<CameraRigAnchor>(anchorObject);
|
||||
EnsureComponent<CameraPanInput>(anchorObject);
|
||||
EnsureComponent<CameraPointOfInterestDirector>(anchorObject);
|
||||
EnsureComponent<CameraStateDirector>(anchorObject);
|
||||
|
||||
WireSerializedReference(anchor, "followTarget", followTarget);
|
||||
WireSerializedReference(anchor, "composer", composer);
|
||||
|
||||
if (vcam != null)
|
||||
{
|
||||
vcam.Target.TrackingTarget = anchorObject.transform;
|
||||
vcam.Priority.Value = 10;
|
||||
}
|
||||
|
||||
var pan = anchorObject.GetComponent<CameraPanInput>();
|
||||
WireSerializedReference(pan, "brainCamera", brainCamera);
|
||||
WireSerializedReference(pan, "anchor", anchor);
|
||||
WireSerializedReference(pan, "stateDirector", anchorObject.GetComponent<CameraStateDirector>());
|
||||
|
||||
var poiDirector = anchorObject.GetComponent<CameraPointOfInterestDirector>();
|
||||
WireSerializedReference(poiDirector, "anchor", anchor);
|
||||
WireSerializedReference(poiDirector, "stateDirector", anchorObject.GetComponent<CameraStateDirector>());
|
||||
|
||||
var stateDirector = anchorObject.GetComponent<CameraStateDirector>();
|
||||
WireSerializedReference(stateDirector, "anchor", anchor);
|
||||
|
||||
EnsureRevealCamera(vcamObject, followTarget);
|
||||
}
|
||||
|
||||
static void EnsureRevealCamera(GameObject followVcam, Transform followTarget)
|
||||
{
|
||||
var revealName = "CM_Reveal_Room101";
|
||||
var revealObject = GameObject.Find(revealName);
|
||||
if (revealObject == null)
|
||||
{
|
||||
revealObject = new GameObject(revealName);
|
||||
revealObject.transform.SetPositionAndRotation(
|
||||
followVcam.transform.position + new Vector3(-4f, 2f, -2f),
|
||||
followVcam.transform.rotation);
|
||||
}
|
||||
|
||||
var revealCam = EnsureComponent<CinemachineCamera>(revealObject);
|
||||
revealCam.Target.TrackingTarget = followTarget;
|
||||
revealCam.Priority.Value = 0;
|
||||
revealCam.Lens.FieldOfView = followVcam.GetComponent<CinemachineCamera>().Lens.FieldOfView;
|
||||
|
||||
var volumeObject = GameObject.Find("RevealVolume_Room101");
|
||||
if (volumeObject == null)
|
||||
{
|
||||
volumeObject = new GameObject("RevealVolume_Room101");
|
||||
volumeObject.transform.position = followTarget.position + new Vector3(0f, 1f, 2f);
|
||||
}
|
||||
|
||||
var box = EnsureComponent<BoxCollider>(volumeObject);
|
||||
box.isTrigger = true;
|
||||
box.size = new Vector3(6f, 3f, 4f);
|
||||
|
||||
var volume = EnsureComponent<CameraFramingVolume>(volumeObject);
|
||||
WireSerializedReference(volume, "revealCamera", revealCam);
|
||||
}
|
||||
|
||||
static T EnsureComponent<T>(GameObject target) where T : Component
|
||||
{
|
||||
var component = target.GetComponent<T>();
|
||||
if (component == null)
|
||||
{
|
||||
component = target.AddComponent<T>();
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
static void SetLayerIfExists(string objectName, int layer)
|
||||
{
|
||||
if (layer < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var obj = GameObject.Find(objectName);
|
||||
if (obj != null)
|
||||
{
|
||||
obj.layer = layer;
|
||||
}
|
||||
}
|
||||
|
||||
static void WireSerializedReference(Object target, string propertyName, Object value)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var so = new SerializedObject(target);
|
||||
var property = so.FindProperty(propertyName);
|
||||
if (property != null)
|
||||
{
|
||||
property.objectReferenceValue = value;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eedfabcda58c94099b2ad3e19f141b09
|
||||
@@ -0,0 +1,818 @@
|
||||
using System.IO;
|
||||
using NightclubArcadia.Cinematics;
|
||||
using NightclubArcadia.Dialogue;
|
||||
using NightclubArcadia.Skills;
|
||||
using NightclubArcadia.UI;
|
||||
using NightclubArcadia.UI.Dialogue;
|
||||
using NightclubArcadia.UI.HUD;
|
||||
using NightclubArcadia.UI.Menu;
|
||||
using StarterAssets;
|
||||
using TMPro;
|
||||
using Unity.Cinemachine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Yarn.Unity;
|
||||
|
||||
/// <summary>
|
||||
/// Builds UI prefabs and wires them into DialogueTest.unity.
|
||||
/// Run via Tools → Nightclub Arcadia → Set Up UI Layer.
|
||||
/// </summary>
|
||||
public static class UILayerSetup
|
||||
{
|
||||
const string ScenePath = "Assets/Scenes/DialogueTest.unity";
|
||||
const string PrefabFolder = "Assets/Prefabs/UI";
|
||||
const string ArtFolder = "Assets/Art/UI/Placeholder";
|
||||
|
||||
// Nested Resources folder: UILayerBootstrap builds the HUD at runtime and
|
||||
// can only reach the sprite through Resources.Load. Keeping it under
|
||||
// Art/UI/Placeholder preserves the organisation while making it
|
||||
// build-safe — an AssetDatabase-only path is null outside the editor.
|
||||
const string PortraitFolder = ArtFolder + "/Resources";
|
||||
const string PortraitPath = PortraitFolder + "/portrait_placeholder.png";
|
||||
const string MessageRowPrefabPath = PrefabFolder + "/DialogueMessageRow.prefab";
|
||||
const string StreamCanvasPrefabPath = PrefabFolder + "/DialogueStreamCanvas.prefab";
|
||||
const string HudCanvasPrefabPath = PrefabFolder + "/HudCanvas.prefab";
|
||||
const string SkillRowPrefabPath = PrefabFolder + "/SkillRow.prefab";
|
||||
const string MenuCanvasPrefabPath = PrefabFolder + "/PlayerMenuCanvas.prefab";
|
||||
|
||||
[MenuItem("Tools/Nightclub Arcadia/Set Up UI Layer")]
|
||||
public static void SetUp()
|
||||
{
|
||||
EnsureFolders();
|
||||
CreatePortraitPlaceholder();
|
||||
|
||||
var messageRow = CreateMessageRowPrefab();
|
||||
var skillRow = CreateSkillRowPrefab();
|
||||
var streamCanvas = CreateDialogueStreamCanvasPrefab(messageRow);
|
||||
var hudCanvas = CreateHudCanvasPrefab();
|
||||
var menuCanvas = CreatePlayerMenuCanvasPrefab(skillRow);
|
||||
|
||||
WireScene(streamCanvas, hudCanvas, menuCanvas);
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
Debug.Log("[UILayerSetup] UI layer setup complete.");
|
||||
}
|
||||
|
||||
static void EnsureFolders()
|
||||
{
|
||||
EnsureFolder("Assets/Prefabs");
|
||||
EnsureFolder(PrefabFolder);
|
||||
EnsureFolder("Assets/Art");
|
||||
EnsureFolder("Assets/Art/UI");
|
||||
EnsureFolder(ArtFolder);
|
||||
EnsureFolder(PortraitFolder);
|
||||
}
|
||||
|
||||
static void EnsureFolder(string path)
|
||||
{
|
||||
if (AssetDatabase.IsValidFolder(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var parent = Path.GetDirectoryName(path)?.Replace('\\', '/');
|
||||
var name = Path.GetFileName(path);
|
||||
if (!string.IsNullOrEmpty(parent) && !string.IsNullOrEmpty(name))
|
||||
{
|
||||
AssetDatabase.CreateFolder(parent, name);
|
||||
}
|
||||
}
|
||||
|
||||
static void CreatePortraitPlaceholder()
|
||||
{
|
||||
if (File.Exists(PortraitPath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tex = new Texture2D(512, 512, TextureFormat.RGBA32, false);
|
||||
var dark = new Color(0.12f, 0.12f, 0.14f, 1f);
|
||||
var mid = new Color(0.35f, 0.35f, 0.4f, 1f);
|
||||
for (var y = 0; y < 512; y++)
|
||||
{
|
||||
for (var x = 0; x < 512; x++)
|
||||
{
|
||||
var dx = (x - 256) / 256f;
|
||||
var dy = (y - 280) / 256f;
|
||||
var inHead = dx * dx + dy * dy < 0.12f;
|
||||
var inBody = Mathf.Abs(dx) < 0.22f && y < 220 && y > 40;
|
||||
tex.SetPixel(x, y, inHead || inBody ? mid : dark);
|
||||
}
|
||||
}
|
||||
|
||||
tex.Apply();
|
||||
File.WriteAllBytes(PortraitPath, tex.EncodeToPNG());
|
||||
Object.DestroyImmediate(tex);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
var importer = AssetImporter.GetAtPath(PortraitPath) as TextureImporter;
|
||||
if (importer != null)
|
||||
{
|
||||
importer.textureType = TextureImporterType.Sprite;
|
||||
importer.spritePixelsPerUnit = 100;
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
}
|
||||
|
||||
static GameObject CreateMessageRowPrefab()
|
||||
{
|
||||
var root = new GameObject("DialogueMessageRow", typeof(RectTransform), typeof(DialogueMessageRow));
|
||||
var rootRt = root.GetComponent<RectTransform>();
|
||||
rootRt.sizeDelta = new Vector2(0f, 80f);
|
||||
|
||||
var layout = root.AddComponent<VerticalLayoutGroup>();
|
||||
layout.padding = new RectOffset(12, 12, 8, 8);
|
||||
layout.spacing = 4f;
|
||||
layout.childControlHeight = true;
|
||||
layout.childControlWidth = true;
|
||||
layout.childForceExpandHeight = false;
|
||||
layout.childForceExpandWidth = true;
|
||||
|
||||
var fitter = root.AddComponent<ContentSizeFitter>();
|
||||
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
fitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
|
||||
|
||||
var speakerGo = CreateTmp("Speaker", root.transform, 22f, FontStyles.Bold, TextAlignmentOptions.Left);
|
||||
var bodyGo = CreateTmp("Body", root.transform, 28f, FontStyles.Normal, TextAlignmentOptions.TopLeft);
|
||||
|
||||
var row = root.GetComponent<DialogueMessageRow>();
|
||||
var so = new SerializedObject(row);
|
||||
so.FindProperty("speakerText").objectReferenceValue = speakerGo.GetComponent<TMP_Text>();
|
||||
so.FindProperty("bodyText").objectReferenceValue = bodyGo.GetComponent<TMP_Text>();
|
||||
so.FindProperty("speakerLabel").objectReferenceValue = speakerGo;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
var prefab = PrefabUtility.SaveAsPrefabAsset(root, MessageRowPrefabPath);
|
||||
Object.DestroyImmediate(root);
|
||||
return prefab;
|
||||
}
|
||||
|
||||
static GameObject CreateSkillRowPrefab()
|
||||
{
|
||||
var root = new GameObject("SkillRow", typeof(RectTransform), typeof(SkillRowView));
|
||||
var rootRt = root.GetComponent<RectTransform>();
|
||||
rootRt.sizeDelta = new Vector2(0f, 48f);
|
||||
|
||||
var hlg = root.AddComponent<HorizontalLayoutGroup>();
|
||||
hlg.padding = new RectOffset(8, 8, 4, 4);
|
||||
hlg.spacing = 12f;
|
||||
hlg.childAlignment = TextAnchor.MiddleLeft;
|
||||
hlg.childControlHeight = true;
|
||||
hlg.childControlWidth = true;
|
||||
hlg.childForceExpandHeight = true;
|
||||
hlg.childForceExpandWidth = false;
|
||||
|
||||
var stripe = CreateUiImage("Accent", root.transform, new Color(1f, 1f, 1f, 1f));
|
||||
stripe.GetComponent<LayoutElement>().preferredWidth = 6f;
|
||||
stripe.GetComponent<LayoutElement>().flexibleWidth = 0f;
|
||||
|
||||
var nameGo = CreateTmp("Name", root.transform, 24f, FontStyles.Bold, TextAlignmentOptions.Left);
|
||||
nameGo.GetComponent<LayoutElement>().flexibleWidth = 1f;
|
||||
|
||||
var barGo = new GameObject("Bar", typeof(RectTransform), typeof(Image), typeof(LayoutElement));
|
||||
barGo.transform.SetParent(root.transform, false);
|
||||
barGo.GetComponent<Image>().color = new Color(0.2f, 0.2f, 0.22f, 1f);
|
||||
barGo.GetComponent<LayoutElement>().preferredWidth = 160f;
|
||||
barGo.GetComponent<LayoutElement>().flexibleWidth = 0f;
|
||||
barGo.GetComponent<LayoutElement>().preferredHeight = 16f;
|
||||
|
||||
var fillGo = CreateUiImage("Fill", barGo.transform, Color.white);
|
||||
var fillRt = fillGo.GetComponent<RectTransform>();
|
||||
fillRt.anchorMin = Vector2.zero;
|
||||
fillRt.anchorMax = Vector2.one;
|
||||
fillRt.offsetMin = Vector2.zero;
|
||||
fillRt.offsetMax = Vector2.zero;
|
||||
var fillImage = fillGo.GetComponent<Image>();
|
||||
fillImage.type = Image.Type.Filled;
|
||||
fillImage.fillMethod = Image.FillMethod.Horizontal;
|
||||
fillImage.fillAmount = 0.2f;
|
||||
Object.DestroyImmediate(fillGo.GetComponent<LayoutElement>());
|
||||
|
||||
var rankGo = CreateTmp("Rank", root.transform, 24f, FontStyles.Normal, TextAlignmentOptions.Right);
|
||||
rankGo.GetComponent<LayoutElement>().preferredWidth = 40f;
|
||||
rankGo.GetComponent<LayoutElement>().flexibleWidth = 0f;
|
||||
|
||||
var view = root.GetComponent<SkillRowView>();
|
||||
var so = new SerializedObject(view);
|
||||
so.FindProperty("nameLabel").objectReferenceValue = nameGo.GetComponent<TMP_Text>();
|
||||
so.FindProperty("rankLabel").objectReferenceValue = rankGo.GetComponent<TMP_Text>();
|
||||
so.FindProperty("barFill").objectReferenceValue = fillImage;
|
||||
so.FindProperty("accentStripe").objectReferenceValue = stripe.GetComponent<Image>();
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
var prefab = PrefabUtility.SaveAsPrefabAsset(root, SkillRowPrefabPath);
|
||||
Object.DestroyImmediate(root);
|
||||
return prefab;
|
||||
}
|
||||
|
||||
static GameObject CreateDialogueStreamCanvasPrefab(GameObject messageRowPrefab)
|
||||
{
|
||||
var canvasGo = CreateCanvas("DialogueStreamCanvas", 5);
|
||||
var canvasGroup = canvasGo.AddComponent<CanvasGroup>();
|
||||
|
||||
var panel = new GameObject("Panel", typeof(RectTransform), typeof(Image));
|
||||
panel.transform.SetParent(canvasGo.transform, false);
|
||||
var panelRt = panel.GetComponent<RectTransform>();
|
||||
panelRt.anchorMin = new Vector2(0.66f, 0f);
|
||||
panelRt.anchorMax = new Vector2(1f, 1f);
|
||||
panelRt.offsetMin = Vector2.zero;
|
||||
panelRt.offsetMax = Vector2.zero;
|
||||
panel.GetComponent<Image>().color = new Color(0.05f, 0.05f, 0.08f, 0.92f);
|
||||
|
||||
var scrollGo = new GameObject("Scroll", typeof(RectTransform), typeof(ScrollRect), typeof(Image));
|
||||
scrollGo.transform.SetParent(panel.transform, false);
|
||||
Stretch(scrollGo.GetComponent<RectTransform>(), 8f);
|
||||
scrollGo.GetComponent<Image>().color = new Color(0f, 0f, 0f, 0.01f);
|
||||
|
||||
var viewport = new GameObject("Viewport", typeof(RectTransform), typeof(RectMask2D), typeof(Image));
|
||||
viewport.transform.SetParent(scrollGo.transform, false);
|
||||
Stretch(viewport.GetComponent<RectTransform>());
|
||||
viewport.GetComponent<Image>().color = new Color(1f, 1f, 1f, 0.01f);
|
||||
|
||||
var content = new GameObject("Content", typeof(RectTransform), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter));
|
||||
content.transform.SetParent(viewport.transform, false);
|
||||
var contentRt = content.GetComponent<RectTransform>();
|
||||
contentRt.anchorMin = new Vector2(0f, 0f);
|
||||
contentRt.anchorMax = new Vector2(1f, 0f);
|
||||
contentRt.pivot = new Vector2(0.5f, 0f);
|
||||
contentRt.sizeDelta = new Vector2(0f, 0f);
|
||||
|
||||
var vlg = content.GetComponent<VerticalLayoutGroup>();
|
||||
vlg.childAlignment = TextAnchor.LowerCenter;
|
||||
vlg.childControlHeight = true;
|
||||
vlg.childControlWidth = true;
|
||||
vlg.childForceExpandHeight = false;
|
||||
vlg.childForceExpandWidth = true;
|
||||
vlg.spacing = 6f;
|
||||
vlg.padding = new RectOffset(4, 4, 8, 8);
|
||||
|
||||
var csf = content.GetComponent<ContentSizeFitter>();
|
||||
csf.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
|
||||
var messages = new GameObject("Messages", typeof(RectTransform), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter));
|
||||
messages.transform.SetParent(content.transform, false);
|
||||
ConfigureVerticalContent(messages);
|
||||
|
||||
var options = new GameObject("Options", typeof(RectTransform), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter), typeof(CanvasGroup));
|
||||
options.transform.SetParent(content.transform, false);
|
||||
ConfigureVerticalContent(options);
|
||||
var optionsGroup = options.GetComponent<CanvasGroup>();
|
||||
optionsGroup.alpha = 0f;
|
||||
optionsGroup.interactable = false;
|
||||
optionsGroup.blocksRaycasts = false;
|
||||
|
||||
var scroll = scrollGo.GetComponent<ScrollRect>();
|
||||
scroll.content = contentRt;
|
||||
scroll.viewport = viewport.GetComponent<RectTransform>();
|
||||
scroll.horizontal = false;
|
||||
scroll.vertical = true;
|
||||
scroll.movementType = ScrollRect.MovementType.Clamped;
|
||||
|
||||
var streamPresenter = canvasGo.AddComponent<DialogueStreamPresenter>();
|
||||
var streamSo = new SerializedObject(streamPresenter);
|
||||
streamSo.FindProperty("messageRowPrefab").objectReferenceValue = messageRowPrefab.GetComponent<DialogueMessageRow>();
|
||||
streamSo.FindProperty("messageContainer").objectReferenceValue = messages.GetComponent<RectTransform>();
|
||||
streamSo.FindProperty("scrollRect").objectReferenceValue = scroll;
|
||||
streamSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
var optionPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(
|
||||
"Packages/dev.yarnspinner.unity/Prefabs/Option Item.prefab");
|
||||
var optionsPresenter = canvasGo.AddComponent<DialogueStreamOptionsPresenter>();
|
||||
var optSo = new SerializedObject(optionsPresenter);
|
||||
if (optionPrefab != null)
|
||||
{
|
||||
optSo.FindProperty("optionViewPrefab").objectReferenceValue = optionPrefab.GetComponent<OptionItem>();
|
||||
}
|
||||
|
||||
optSo.FindProperty("optionsContainer").objectReferenceValue = options.transform;
|
||||
optSo.FindProperty("canvasGroup").objectReferenceValue = optionsGroup;
|
||||
optSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
// Start hidden — DialogueTransitionController shows it.
|
||||
canvasGroup.alpha = 0f;
|
||||
canvasGroup.interactable = false;
|
||||
canvasGroup.blocksRaycasts = false;
|
||||
|
||||
var prefab = PrefabUtility.SaveAsPrefabAsset(canvasGo, StreamCanvasPrefabPath);
|
||||
Object.DestroyImmediate(canvasGo);
|
||||
return prefab;
|
||||
}
|
||||
|
||||
static GameObject CreateHudCanvasPrefab()
|
||||
{
|
||||
var canvasGo = CreateCanvas("HudCanvas", 10);
|
||||
var portraitSprite = AssetDatabase.LoadAssetAtPath<Sprite>(PortraitPath);
|
||||
|
||||
var panel = new GameObject("PortraitPanel", typeof(RectTransform), typeof(CanvasGroup), typeof(Image), typeof(Button));
|
||||
panel.transform.SetParent(canvasGo.transform, false);
|
||||
var panelRt = panel.GetComponent<RectTransform>();
|
||||
panelRt.anchorMin = new Vector2(1f, 0f);
|
||||
panelRt.anchorMax = new Vector2(1f, 0f);
|
||||
panelRt.pivot = new Vector2(1f, 0f);
|
||||
panelRt.sizeDelta = new Vector2(220f, 280f);
|
||||
panelRt.anchoredPosition = new Vector2(-24f, 24f);
|
||||
panel.GetComponent<Image>().color = new Color(0.15f, 0.15f, 0.18f, 0.95f);
|
||||
if (portraitSprite != null)
|
||||
{
|
||||
panel.GetComponent<Image>().sprite = portraitSprite;
|
||||
panel.GetComponent<Image>().preserveAspect = true;
|
||||
}
|
||||
|
||||
var hint = CreateTmp("TabHint", panel.transform, 18f, FontStyles.Normal, TextAlignmentOptions.Center);
|
||||
var hintRt = hint.GetComponent<RectTransform>();
|
||||
hintRt.anchorMin = new Vector2(0f, 0f);
|
||||
hintRt.anchorMax = new Vector2(1f, 0f);
|
||||
hintRt.pivot = new Vector2(0.5f, 0f);
|
||||
hintRt.sizeDelta = new Vector2(0f, 28f);
|
||||
hintRt.anchoredPosition = new Vector2(0f, 4f);
|
||||
hint.GetComponent<TMP_Text>().text = "Tab";
|
||||
Object.DestroyImmediate(hint.GetComponent<LayoutElement>());
|
||||
|
||||
var view = canvasGo.AddComponent<PortraitHudView>();
|
||||
var so = new SerializedObject(view);
|
||||
so.FindProperty("panelRoot").objectReferenceValue = panel;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
var prefab = PrefabUtility.SaveAsPrefabAsset(canvasGo, HudCanvasPrefabPath);
|
||||
Object.DestroyImmediate(canvasGo);
|
||||
return prefab;
|
||||
}
|
||||
|
||||
static GameObject CreatePlayerMenuCanvasPrefab(GameObject skillRowPrefab)
|
||||
{
|
||||
var canvasGo = CreateCanvas("PlayerMenuCanvas", 20);
|
||||
var rootGroup = canvasGo.AddComponent<CanvasGroup>();
|
||||
|
||||
var dimmer = CreateUiImage("Dimmer", canvasGo.transform, new Color(0f, 0f, 0f, 0.6f));
|
||||
Stretch(dimmer.GetComponent<RectTransform>());
|
||||
Object.DestroyImmediate(dimmer.GetComponent<LayoutElement>());
|
||||
|
||||
var body = new GameObject("MenuBody", typeof(RectTransform), typeof(Image));
|
||||
body.transform.SetParent(canvasGo.transform, false);
|
||||
var bodyRt = body.GetComponent<RectTransform>();
|
||||
bodyRt.anchorMin = new Vector2(0.15f, 0.1f);
|
||||
bodyRt.anchorMax = new Vector2(0.85f, 0.9f);
|
||||
bodyRt.offsetMin = Vector2.zero;
|
||||
bodyRt.offsetMax = Vector2.zero;
|
||||
body.GetComponent<Image>().color = new Color(0.08f, 0.08f, 0.1f, 0.98f);
|
||||
|
||||
var tabBarGo = new GameObject("TabBar", typeof(RectTransform), typeof(HorizontalLayoutGroup), typeof(MenuTabBar));
|
||||
tabBarGo.transform.SetParent(body.transform, false);
|
||||
var tabBarRt = tabBarGo.GetComponent<RectTransform>();
|
||||
tabBarRt.anchorMin = new Vector2(0f, 1f);
|
||||
tabBarRt.anchorMax = new Vector2(1f, 1f);
|
||||
tabBarRt.pivot = new Vector2(0.5f, 1f);
|
||||
tabBarRt.sizeDelta = new Vector2(0f, 56f);
|
||||
tabBarRt.anchoredPosition = Vector2.zero;
|
||||
var tabHlg = tabBarGo.GetComponent<HorizontalLayoutGroup>();
|
||||
tabHlg.spacing = 8f;
|
||||
tabHlg.padding = new RectOffset(12, 12, 8, 8);
|
||||
// childControl* default to FALSE on a script-added layout group. Left
|
||||
// false, each tab button keeps its own 100px sizeDelta ("Character"
|
||||
// clips to "Charact") and childForceExpandWidth dumps all the leftover
|
||||
// room between them as a gap instead of widening them.
|
||||
tabHlg.childControlWidth = true;
|
||||
tabHlg.childControlHeight = true;
|
||||
tabHlg.childForceExpandWidth = true;
|
||||
tabHlg.childForceExpandHeight = true;
|
||||
|
||||
var contentArea = new GameObject("ContentArea", typeof(RectTransform));
|
||||
contentArea.transform.SetParent(body.transform, false);
|
||||
var contentRt = contentArea.GetComponent<RectTransform>();
|
||||
contentRt.anchorMin = new Vector2(0f, 0f);
|
||||
contentRt.anchorMax = new Vector2(1f, 1f);
|
||||
contentRt.offsetMin = new Vector2(16f, 16f);
|
||||
contentRt.offsetMax = new Vector2(-16f, -64f);
|
||||
|
||||
var characterPanel = CreateTabPanel("CharacterPanel", contentArea.transform);
|
||||
var skillsPanel = CreateTabPanel("SkillsPanel", contentArea.transform);
|
||||
var journalPanel = CreateTabPanel("JournalPanel", contentArea.transform);
|
||||
|
||||
// Character content
|
||||
var charView = characterPanel.AddComponent<CharacterPanelView>();
|
||||
var nameLabel = CreateTmp("Name", characterPanel.transform, 36f, FontStyles.Bold, TextAlignmentOptions.Left);
|
||||
var aliasLabel = CreateTmp("Alias", characterPanel.transform, 28f, FontStyles.Italic, TextAlignmentOptions.Left);
|
||||
var invLabel = CreateTmp("Inventory", characterPanel.transform, 24f, FontStyles.Normal, TextAlignmentOptions.Left);
|
||||
var charVlg = characterPanel.AddComponent<VerticalLayoutGroup>();
|
||||
charVlg.spacing = 12f;
|
||||
charVlg.padding = new RectOffset(8, 8, 8, 8);
|
||||
charVlg.childControlWidth = true;
|
||||
charVlg.childControlHeight = true;
|
||||
charVlg.childForceExpandWidth = true;
|
||||
charVlg.childForceExpandHeight = false;
|
||||
var charSo = new SerializedObject(charView);
|
||||
charSo.FindProperty("nameLabel").objectReferenceValue = nameLabel.GetComponent<TMP_Text>();
|
||||
charSo.FindProperty("aliasLabel").objectReferenceValue = aliasLabel.GetComponent<TMP_Text>();
|
||||
charSo.FindProperty("inventoryPlaceholder").objectReferenceValue = invLabel.GetComponent<TMP_Text>();
|
||||
charSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
// Skills content
|
||||
var skillsScroll = new GameObject("SkillsScroll", typeof(RectTransform), typeof(ScrollRect));
|
||||
skillsScroll.transform.SetParent(skillsPanel.transform, false);
|
||||
Stretch(skillsScroll.GetComponent<RectTransform>());
|
||||
var skillsViewport = new GameObject("Viewport", typeof(RectTransform), typeof(RectMask2D), typeof(Image));
|
||||
skillsViewport.transform.SetParent(skillsScroll.transform, false);
|
||||
Stretch(skillsViewport.GetComponent<RectTransform>());
|
||||
skillsViewport.GetComponent<Image>().color = new Color(1f, 1f, 1f, 0.01f);
|
||||
var skillsContent = new GameObject("Content", typeof(RectTransform), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter));
|
||||
skillsContent.transform.SetParent(skillsViewport.transform, false);
|
||||
ConfigureVerticalContent(skillsContent);
|
||||
var skillsContentRt = skillsContent.GetComponent<RectTransform>();
|
||||
skillsContentRt.anchorMin = new Vector2(0f, 1f);
|
||||
skillsContentRt.anchorMax = new Vector2(1f, 1f);
|
||||
skillsContentRt.pivot = new Vector2(0.5f, 1f);
|
||||
var skillsScrollRect = skillsScroll.GetComponent<ScrollRect>();
|
||||
skillsScrollRect.content = skillsContentRt;
|
||||
skillsScrollRect.viewport = skillsViewport.GetComponent<RectTransform>();
|
||||
skillsScrollRect.horizontal = false;
|
||||
|
||||
var axisHeaderTemplate = CreateTmp("AxisHeaderTemplate", skillsContent.transform, 20f, FontStyles.Bold, TextAlignmentOptions.Left);
|
||||
axisHeaderTemplate.SetActive(false);
|
||||
|
||||
var skillsView = skillsPanel.AddComponent<SkillsPanelView>();
|
||||
var skillsSo = new SerializedObject(skillsView);
|
||||
skillsSo.FindProperty("contentRoot").objectReferenceValue = skillsContentRt;
|
||||
skillsSo.FindProperty("rowPrefab").objectReferenceValue = skillRowPrefab.GetComponent<SkillRowView>();
|
||||
skillsSo.FindProperty("axisHeaderPrefab").objectReferenceValue = axisHeaderTemplate.GetComponent<TMP_Text>();
|
||||
skillsSo.FindProperty("displayMaxRank").intValue = 6;
|
||||
skillsSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
// Journal content
|
||||
var journalView = journalPanel.AddComponent<JournalPanelView>();
|
||||
var journalLabel = CreateTmp("Placeholder", journalPanel.transform, 28f, FontStyles.Italic, TextAlignmentOptions.Center);
|
||||
Stretch(journalLabel.GetComponent<RectTransform>());
|
||||
Object.DestroyImmediate(journalLabel.GetComponent<LayoutElement>());
|
||||
var journalSo = new SerializedObject(journalView);
|
||||
journalSo.FindProperty("placeholderLabel").objectReferenceValue = journalLabel.GetComponent<TMP_Text>();
|
||||
journalSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
var charBtn = CreateTabButton("Character", tabBarGo.transform);
|
||||
var skillsBtn = CreateTabButton("Skills", tabBarGo.transform);
|
||||
var journalBtn = CreateTabButton("Journal", tabBarGo.transform);
|
||||
|
||||
var tabBar = tabBarGo.GetComponent<MenuTabBar>();
|
||||
var tabSo = new SerializedObject(tabBar);
|
||||
var tabsProp = tabSo.FindProperty("tabs");
|
||||
tabsProp.arraySize = 3;
|
||||
// Character tab must refresh on show for the same reason as Skills:
|
||||
// panels toggle via CanvasGroup, so OnEnable never fires again.
|
||||
SetTabEntry(tabsProp.GetArrayElementAtIndex(0), charBtn.GetComponent<Button>(), characterPanel.GetComponent<CanvasGroup>(), charView, "Refresh");
|
||||
SetTabEntry(tabsProp.GetArrayElementAtIndex(1), skillsBtn.GetComponent<Button>(), skillsPanel.GetComponent<CanvasGroup>(), skillsView, "Refresh");
|
||||
SetTabEntry(tabsProp.GetArrayElementAtIndex(2), journalBtn.GetComponent<Button>(), journalPanel.GetComponent<CanvasGroup>(), null);
|
||||
tabSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
var menuController = canvasGo.AddComponent<PlayerMenuController>();
|
||||
var menuSo = new SerializedObject(menuController);
|
||||
menuSo.FindProperty("menuRoot").objectReferenceValue = canvasGo;
|
||||
menuSo.FindProperty("tabBar").objectReferenceValue = tabBar;
|
||||
menuSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
rootGroup.alpha = 0f;
|
||||
rootGroup.interactable = false;
|
||||
rootGroup.blocksRaycasts = false;
|
||||
|
||||
var prefab = PrefabUtility.SaveAsPrefabAsset(canvasGo, MenuCanvasPrefabPath);
|
||||
Object.DestroyImmediate(canvasGo);
|
||||
return prefab;
|
||||
}
|
||||
|
||||
static void SetTabEntry(SerializedProperty entry, Button button, CanvasGroup panel, Object target, string method = null)
|
||||
{
|
||||
entry.FindPropertyRelative("button").objectReferenceValue = button;
|
||||
entry.FindPropertyRelative("panel").objectReferenceValue = panel;
|
||||
if (target != null && method != null)
|
||||
{
|
||||
var onShown = entry.FindPropertyRelative("onShown");
|
||||
onShown.FindPropertyRelative("m_PersistentCalls.m_Calls").arraySize = 1;
|
||||
var call = onShown.FindPropertyRelative("m_PersistentCalls.m_Calls").GetArrayElementAtIndex(0);
|
||||
call.FindPropertyRelative("m_Target").objectReferenceValue = target;
|
||||
call.FindPropertyRelative("m_MethodName").stringValue = method;
|
||||
call.FindPropertyRelative("m_Mode").enumValueIndex = 1; // Void
|
||||
call.FindPropertyRelative("m_CallState").enumValueIndex = 2; // RuntimeOnly
|
||||
}
|
||||
}
|
||||
|
||||
static void WireScene(GameObject streamCanvasPrefab, GameObject hudCanvasPrefab, GameObject menuCanvasPrefab)
|
||||
{
|
||||
var scene = EditorSceneManager.OpenScene(ScenePath, OpenSceneMode.Single);
|
||||
|
||||
// UI System root
|
||||
var uiSystem = GameObject.Find("UI System");
|
||||
if (uiSystem == null)
|
||||
{
|
||||
uiSystem = new GameObject("UI System");
|
||||
}
|
||||
|
||||
if (uiSystem.GetComponent<UIStateController>() == null)
|
||||
{
|
||||
uiSystem.AddComponent<UIStateController>();
|
||||
}
|
||||
|
||||
// Player components
|
||||
var player = GameObject.Find("PlayerArmature");
|
||||
if (player == null)
|
||||
{
|
||||
Debug.LogError("[UILayerSetup] PlayerArmature not found in scene.");
|
||||
return;
|
||||
}
|
||||
|
||||
var controlLock = player.GetComponent<PlayerControlLock>();
|
||||
if (controlLock == null)
|
||||
{
|
||||
controlLock = player.AddComponent<PlayerControlLock>();
|
||||
}
|
||||
|
||||
var menuInput = player.GetComponent<PlayerMenuInput>();
|
||||
if (menuInput == null)
|
||||
{
|
||||
menuInput = player.AddComponent<PlayerMenuInput>();
|
||||
}
|
||||
|
||||
var inputs = player.GetComponent<StarterAssetsInputs>();
|
||||
if (inputs != null)
|
||||
{
|
||||
inputs.cursorLocked = false;
|
||||
EditorUtility.SetDirty(inputs);
|
||||
}
|
||||
|
||||
// DialogueTransitionController
|
||||
var transition = Object.FindFirstObjectByType<DialogueTransitionController>();
|
||||
if (transition != null)
|
||||
{
|
||||
var tSo = new SerializedObject(transition);
|
||||
tSo.FindProperty("controlLock").objectReferenceValue = controlLock;
|
||||
tSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
// Instantiate / refresh UI prefab instances
|
||||
var streamInstance = EnsurePrefabInstance(streamCanvasPrefab, "DialogueStreamCanvas");
|
||||
var hudInstance = EnsurePrefabInstance(hudCanvasPrefab, "HudCanvas");
|
||||
var menuInstance = EnsurePrefabInstance(menuCanvasPrefab, "PlayerMenuCanvas");
|
||||
|
||||
// Wire menu controller refs
|
||||
var menuController = menuInstance.GetComponent<PlayerMenuController>();
|
||||
if (menuController != null)
|
||||
{
|
||||
var mSo = new SerializedObject(menuController);
|
||||
mSo.FindProperty("menuInput").objectReferenceValue = menuInput;
|
||||
mSo.FindProperty("controlLock").objectReferenceValue = controlLock;
|
||||
mSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
// Portrait → Open menu
|
||||
var portraitButton = hudInstance.GetComponentInChildren<Button>(true);
|
||||
if (portraitButton != null && menuController != null)
|
||||
{
|
||||
while (portraitButton.onClick.GetPersistentEventCount() > 0)
|
||||
{
|
||||
UnityEditor.Events.UnityEventTools.RemovePersistentListener(portraitButton.onClick, 0);
|
||||
}
|
||||
|
||||
UnityEditor.Events.UnityEventTools.AddPersistentListener(portraitButton.onClick, menuController.Open);
|
||||
EditorUtility.SetDirty(portraitButton);
|
||||
}
|
||||
|
||||
// Camera framing
|
||||
var vcam = GameObject.Find("CinemachineCamera");
|
||||
if (vcam != null)
|
||||
{
|
||||
var framing = vcam.GetComponent<DialogueCameraFraming>();
|
||||
if (framing == null)
|
||||
{
|
||||
framing = vcam.AddComponent<DialogueCameraFraming>();
|
||||
}
|
||||
|
||||
var composer = vcam.GetComponent<CinemachinePositionComposer>();
|
||||
var fSo = new SerializedObject(framing);
|
||||
fSo.FindProperty("composer").objectReferenceValue = composer;
|
||||
fSo.FindProperty("dialogueScreenX").floatValue = -0.17f;
|
||||
fSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
// Re-point DialogueRunner presenters
|
||||
var runner = Object.FindFirstObjectByType<DialogueRunner>();
|
||||
var streamPresenter = streamInstance.GetComponent<DialogueStreamPresenter>();
|
||||
var optionsPresenter = streamInstance.GetComponent<DialogueStreamOptionsPresenter>();
|
||||
var lineAdvancer = Object.FindFirstObjectByType<LineAdvancer>();
|
||||
|
||||
if (runner != null && streamPresenter != null && optionsPresenter != null)
|
||||
{
|
||||
var rSo = new SerializedObject(runner);
|
||||
var presenters = rSo.FindProperty("dialoguePresenters");
|
||||
if (presenters != null)
|
||||
{
|
||||
presenters.arraySize = lineAdvancer != null ? 3 : 2;
|
||||
presenters.GetArrayElementAtIndex(0).objectReferenceValue = streamPresenter;
|
||||
presenters.GetArrayElementAtIndex(1).objectReferenceValue = optionsPresenter;
|
||||
if (lineAdvancer != null)
|
||||
{
|
||||
presenters.GetArrayElementAtIndex(2).objectReferenceValue = lineAdvancer;
|
||||
}
|
||||
|
||||
rSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
}
|
||||
|
||||
if (lineAdvancer != null && streamPresenter != null)
|
||||
{
|
||||
var aSo = new SerializedObject(lineAdvancer);
|
||||
aSo.FindProperty("presenter").objectReferenceValue = streamPresenter;
|
||||
aSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
// Point DialogueTransitionController.dialogueUI at the new canvas
|
||||
if (transition != null && streamInstance != null)
|
||||
{
|
||||
var tSo = new SerializedObject(transition);
|
||||
tSo.FindProperty("dialogueUI").objectReferenceValue = streamInstance;
|
||||
tSo.FindProperty("controlLock").objectReferenceValue = controlLock;
|
||||
tSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
|
||||
// Deactivate the package Dialogue System Canvas (keep EventSystem alive)
|
||||
var dialogueSystem = GameObject.Find("Dialogue System");
|
||||
if (dialogueSystem != null)
|
||||
{
|
||||
var packageCanvas = dialogueSystem.transform.Find("Canvas");
|
||||
if (packageCanvas != null)
|
||||
{
|
||||
// Rescue the Skill Check Banner onto the scene-owned Skill Check
|
||||
// Canvas — NOT into streamInstance. EnsurePrefabInstance
|
||||
// DestroyImmediates the stream canvas on every re-run, so
|
||||
// anything parented under it dies with it; that is what left
|
||||
// SkillRuntime.resultView null after the second setup run.
|
||||
// Skill Check Canvas is scene-owned, survives re-runs, and its
|
||||
// sortingOrder 100 already draws above the dialogue canvas.
|
||||
var banner = packageCanvas.Find("Skill Check Banner");
|
||||
if (banner != null)
|
||||
{
|
||||
var bannerHost = GameObject.Find("Skill Check Canvas");
|
||||
if (bannerHost != null)
|
||||
{
|
||||
banner.SetParent(bannerHost.transform, false);
|
||||
}
|
||||
}
|
||||
|
||||
packageCanvas.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Repair SkillRuntime.resultView. It can be left dangling by an earlier
|
||||
// run of this menu item, and a null here silently disables every roll
|
||||
// banner ("SkillCheckResultView is not assigned; skipping roll banner").
|
||||
// Prefer an active view if more than one survives.
|
||||
SkillCheckResultView resultView = null;
|
||||
foreach (var candidate in Object.FindObjectsByType<SkillCheckResultView>(
|
||||
FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||
{
|
||||
if (resultView == null
|
||||
|| (!resultView.gameObject.activeInHierarchy && candidate.gameObject.activeInHierarchy))
|
||||
{
|
||||
resultView = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
var skillRuntime = Object.FindFirstObjectByType<SkillRuntime>();
|
||||
if (skillRuntime != null && resultView != null)
|
||||
{
|
||||
var skillSo = new SerializedObject(skillRuntime);
|
||||
skillSo.FindProperty("resultView").objectReferenceValue = resultView;
|
||||
skillSo.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
else if (skillRuntime != null)
|
||||
{
|
||||
Debug.LogWarning("[UILayerSetup] No SkillCheckResultView found in the scene; roll banners will not display.", skillRuntime);
|
||||
}
|
||||
|
||||
// Update NPCStandIn dialogueUI refs to the new canvas
|
||||
foreach (var npc in Object.FindObjectsByType<NPCStandIn>(FindObjectsInactive.Include, FindObjectsSortMode.None))
|
||||
{
|
||||
var so = new SerializedObject(npc);
|
||||
var uiProp = so.FindProperty("dialogueUI");
|
||||
if (uiProp != null)
|
||||
{
|
||||
uiProp.objectReferenceValue = streamInstance;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
}
|
||||
}
|
||||
|
||||
EditorSceneManager.MarkSceneDirty(scene);
|
||||
EditorSceneManager.SaveScene(scene);
|
||||
}
|
||||
|
||||
static GameObject EnsurePrefabInstance(GameObject prefab, string name)
|
||||
{
|
||||
var existing = GameObject.Find(name);
|
||||
if (existing != null)
|
||||
{
|
||||
Object.DestroyImmediate(existing);
|
||||
}
|
||||
|
||||
var instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
|
||||
instance.name = name;
|
||||
return instance;
|
||||
}
|
||||
|
||||
static GameObject CreateCanvas(string name, int sortingOrder)
|
||||
{
|
||||
var go = new GameObject(name, typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster));
|
||||
var canvas = go.GetComponent<Canvas>();
|
||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
canvas.sortingOrder = sortingOrder;
|
||||
var scaler = go.GetComponent<CanvasScaler>();
|
||||
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||||
scaler.referenceResolution = new Vector2(1920f, 1080f);
|
||||
scaler.matchWidthOrHeight = 0.5f;
|
||||
return go;
|
||||
}
|
||||
|
||||
static GameObject CreateTabPanel(string name, Transform parent)
|
||||
{
|
||||
var go = new GameObject(name, typeof(RectTransform), typeof(CanvasGroup));
|
||||
go.transform.SetParent(parent, false);
|
||||
Stretch(go.GetComponent<RectTransform>());
|
||||
var group = go.GetComponent<CanvasGroup>();
|
||||
group.alpha = 0f;
|
||||
group.interactable = false;
|
||||
group.blocksRaycasts = false;
|
||||
return go;
|
||||
}
|
||||
|
||||
static GameObject CreateTabButton(string label, Transform parent)
|
||||
{
|
||||
var go = new GameObject(label, typeof(RectTransform), typeof(Image), typeof(Button), typeof(LayoutElement));
|
||||
go.transform.SetParent(parent, false);
|
||||
go.GetComponent<Image>().color = new Color(0.2f, 0.2f, 0.25f, 1f);
|
||||
var text = CreateTmp("Label", go.transform, 22f, FontStyles.Bold, TextAlignmentOptions.Center);
|
||||
Stretch(text.GetComponent<RectTransform>());
|
||||
Object.DestroyImmediate(text.GetComponent<LayoutElement>());
|
||||
text.GetComponent<TMP_Text>().text = label;
|
||||
return go;
|
||||
}
|
||||
|
||||
static GameObject CreateTmp(string name, Transform parent, float size, FontStyles style, TextAlignmentOptions align)
|
||||
{
|
||||
var go = new GameObject(name, typeof(RectTransform), typeof(TextMeshProUGUI), typeof(LayoutElement));
|
||||
go.transform.SetParent(parent, false);
|
||||
var tmp = go.GetComponent<TextMeshProUGUI>();
|
||||
tmp.fontSize = size;
|
||||
tmp.fontStyle = style;
|
||||
tmp.alignment = align;
|
||||
tmp.color = Color.white;
|
||||
tmp.text = name;
|
||||
tmp.textWrappingMode = TextWrappingModes.Normal;
|
||||
|
||||
// Deliberately no LayoutElement.preferredHeight. A fixed height here is
|
||||
// one line's worth, and LayoutElement outranks TMP's own ILayoutElement
|
||||
// report — so a wrapped 4-line body would be allocated ~40px while
|
||||
// rendering ~150px, and consecutive rows draw on top of each other.
|
||||
// Leaving it at the -1 default lets TMP measure the wrapped text.
|
||||
// The component stays so callers can still set preferredWidth /
|
||||
// flexibleWidth (see the skill row).
|
||||
return go;
|
||||
}
|
||||
|
||||
static GameObject CreateUiImage(string name, Transform parent, Color color)
|
||||
{
|
||||
var go = new GameObject(name, typeof(RectTransform), typeof(Image), typeof(LayoutElement));
|
||||
go.transform.SetParent(parent, false);
|
||||
go.GetComponent<Image>().color = color;
|
||||
return go;
|
||||
}
|
||||
|
||||
static void Stretch(RectTransform rt, float pad = 0f)
|
||||
{
|
||||
rt.anchorMin = Vector2.zero;
|
||||
rt.anchorMax = Vector2.one;
|
||||
rt.offsetMin = new Vector2(pad, pad);
|
||||
rt.offsetMax = new Vector2(-pad, -pad);
|
||||
}
|
||||
|
||||
static void ConfigureVerticalContent(GameObject go)
|
||||
{
|
||||
var rt = go.GetComponent<RectTransform>();
|
||||
rt.anchorMin = new Vector2(0f, 0f);
|
||||
rt.anchorMax = new Vector2(1f, 0f);
|
||||
rt.pivot = new Vector2(0.5f, 0f);
|
||||
|
||||
// A RectTransform added via `new GameObject(..., typeof(RectTransform))`
|
||||
// starts at sizeDelta (100,100). With horizontal-stretch anchors that
|
||||
// makes the rect parentWidth + 100 wide, centred — overhanging 50px off
|
||||
// each side, and the RectMask2D shears the left edge off every label.
|
||||
// ContentSizeFitter only governs the vertical axis, so it never
|
||||
// corrects this. Zero the horizontal size explicitly.
|
||||
rt.sizeDelta = new Vector2(0f, rt.sizeDelta.y);
|
||||
rt.anchoredPosition = Vector2.zero;
|
||||
|
||||
var vlg = go.GetComponent<VerticalLayoutGroup>();
|
||||
vlg.childControlHeight = true;
|
||||
vlg.childControlWidth = true;
|
||||
vlg.childForceExpandHeight = false;
|
||||
vlg.childForceExpandWidth = true;
|
||||
vlg.spacing = 4f;
|
||||
var csf = go.GetComponent<ContentSizeFitter>();
|
||||
csf.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5bdf044f1ab04312b76895dac1740b37
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Reminds the user to run the one-shot prefab/scene wiring menu after scripts
|
||||
/// compile. Runtime play works without it via UILayerBootstrap.
|
||||
/// </summary>
|
||||
[InitializeOnLoad]
|
||||
static class UILayerSetupAutoRun
|
||||
{
|
||||
const string PrefKey = "NightclubArcadia.UILayerSetup.Reminded";
|
||||
const string MarkerPrefab = "Assets/Prefabs/UI/PlayerMenuCanvas.prefab";
|
||||
|
||||
static UILayerSetupAutoRun()
|
||||
{
|
||||
EditorApplication.delayCall += RemindIfNeeded;
|
||||
}
|
||||
|
||||
static void RemindIfNeeded()
|
||||
{
|
||||
if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (AssetDatabase.LoadAssetAtPath<GameObject>(MarkerPrefab) != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (EditorPrefs.GetBool(PrefKey, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorPrefs.SetBool(PrefKey, true);
|
||||
Debug.Log(
|
||||
"[UILayer] Prefabs not built yet. Play Mode works via UILayerBootstrap. " +
|
||||
"To author prefabs into the scene, run Tools → Nightclub Arcadia → Set Up UI Layer.");
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Nightclub Arcadia/Reset UI Layer Auto-Setup Flag")]
|
||||
static void ResetFlag()
|
||||
{
|
||||
EditorPrefs.DeleteKey(PrefKey);
|
||||
Debug.Log("[UILayer] Reminder flag cleared.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c0e3c886ff143d3b26b7f55d7f22410
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe41419ba50842189534933e2b64e958
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11e75200bdad4ff48299a7d24bb8df99
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,413 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &3506879458838080580
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1649868454372858534}
|
||||
- component: {fileID: 5353601244371665078}
|
||||
- component: {fileID: 3249155410833833935}
|
||||
- component: {fileID: 3956878563407369997}
|
||||
m_Layer: 0
|
||||
m_Name: DialogueMessageRow
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1649868454372858534
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3506879458838080580}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 5063401541721017946}
|
||||
- {fileID: 7857316982467238224}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 80}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &5353601244371665078
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3506879458838080580}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a7773ea9a6f44798aa98356903037d16, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Dialogue.DialogueMessageRow
|
||||
speakerText: {fileID: 5900251945930220314}
|
||||
bodyText: {fileID: 1670956017877202442}
|
||||
speakerLabel: {fileID: 5822252844234204748}
|
||||
--- !u!114 &3249155410833833935
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3506879458838080580}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.VerticalLayoutGroup
|
||||
m_Padding:
|
||||
m_Left: 12
|
||||
m_Right: 12
|
||||
m_Top: 8
|
||||
m_Bottom: 8
|
||||
m_ChildAlignment: 0
|
||||
m_Spacing: 4
|
||||
m_ChildForceExpandWidth: 1
|
||||
m_ChildForceExpandHeight: 0
|
||||
m_ChildControlWidth: 1
|
||||
m_ChildControlHeight: 1
|
||||
m_ChildScaleWidth: 0
|
||||
m_ChildScaleHeight: 0
|
||||
m_ReverseArrangement: 0
|
||||
--- !u!114 &3956878563407369997
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3506879458838080580}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ContentSizeFitter
|
||||
m_HorizontalFit: 0
|
||||
m_VerticalFit: 2
|
||||
--- !u!1 &5450003319614969337
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7857316982467238224}
|
||||
- component: {fileID: 3605186933310922639}
|
||||
- component: {fileID: 1670956017877202442}
|
||||
- component: {fileID: 6572944391823112727}
|
||||
m_Layer: 0
|
||||
m_Name: Body
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &7857316982467238224
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5450003319614969337}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1649868454372858534}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 200, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &3605186933310922639
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5450003319614969337}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1670956017877202442
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5450003319614969337}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: Body
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 28
|
||||
m_fontSizeBase: 28
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 256
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!114 &6572944391823112727
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5450003319614969337}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: -1
|
||||
m_FlexibleWidth: -1
|
||||
m_FlexibleHeight: -1
|
||||
m_LayoutPriority: 1
|
||||
--- !u!1 &5822252844234204748
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5063401541721017946}
|
||||
- component: {fileID: 4569120956328637162}
|
||||
- component: {fileID: 5900251945930220314}
|
||||
- component: {fileID: 3733932380812113541}
|
||||
m_Layer: 0
|
||||
m_Name: Speaker
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &5063401541721017946
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5822252844234204748}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1649868454372858534}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 200, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &4569120956328637162
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5822252844234204748}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &5900251945930220314
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5822252844234204748}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: Speaker
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 22
|
||||
m_fontSizeBase: 22
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 1
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!114 &3733932380812113541
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5822252844234204748}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: -1
|
||||
m_FlexibleWidth: -1
|
||||
m_FlexibleHeight: -1
|
||||
m_LayoutPriority: 1
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90818ef7dc74247ceb348994755cea86
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,673 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1431520567503728820
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4838388606347767229}
|
||||
- component: {fileID: 848167695161913818}
|
||||
- component: {fileID: 872887529246740654}
|
||||
m_Layer: 0
|
||||
m_Name: Messages
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4838388606347767229
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1431520567503728820}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 6371610150170887506}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0}
|
||||
--- !u!114 &848167695161913818
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1431520567503728820}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.VerticalLayoutGroup
|
||||
m_Padding:
|
||||
m_Left: 0
|
||||
m_Right: 0
|
||||
m_Top: 0
|
||||
m_Bottom: 0
|
||||
m_ChildAlignment: 0
|
||||
m_Spacing: 4
|
||||
m_ChildForceExpandWidth: 1
|
||||
m_ChildForceExpandHeight: 0
|
||||
m_ChildControlWidth: 1
|
||||
m_ChildControlHeight: 1
|
||||
m_ChildScaleWidth: 0
|
||||
m_ChildScaleHeight: 0
|
||||
m_ReverseArrangement: 0
|
||||
--- !u!114 &872887529246740654
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1431520567503728820}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ContentSizeFitter
|
||||
m_HorizontalFit: 0
|
||||
m_VerticalFit: 2
|
||||
--- !u!1 &2888832924926796905
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8553742246756266605}
|
||||
- component: {fileID: 7475958128581596541}
|
||||
- component: {fileID: 5788080976967704390}
|
||||
m_Layer: 0
|
||||
m_Name: Panel
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &8553742246756266605
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2888832924926796905}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 6287368187237088396}
|
||||
m_Father: {fileID: 1243836425688988300}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.66, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7475958128581596541
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2888832924926796905}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &5788080976967704390
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2888832924926796905}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.05, g: 0.05, b: 0.08, a: 0.92}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &4923635399097880277
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3746324764683222304}
|
||||
- component: {fileID: 3035847077530824546}
|
||||
- component: {fileID: 5149667566061008557}
|
||||
- component: {fileID: 2566128074157561357}
|
||||
m_Layer: 0
|
||||
m_Name: Viewport
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &3746324764683222304
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4923635399097880277}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 6371610150170887506}
|
||||
m_Father: {fileID: 6287368187237088396}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &3035847077530824546
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4923635399097880277}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3312d7739989d2b4e91e6319e9a96d76, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.RectMask2D
|
||||
m_Padding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Softness: {x: 0, y: 0}
|
||||
--- !u!222 &5149667566061008557
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4923635399097880277}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &2566128074157561357
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4923635399097880277}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 0.01}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &5260492858234310193
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6371610150170887506}
|
||||
- component: {fileID: 2397794206583674815}
|
||||
- component: {fileID: 5419335647702174254}
|
||||
m_Layer: 0
|
||||
m_Name: Content
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &6371610150170887506
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5260492858234310193}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 4838388606347767229}
|
||||
- {fileID: 6329947636030823459}
|
||||
m_Father: {fileID: 3746324764683222304}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0}
|
||||
--- !u!114 &2397794206583674815
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5260492858234310193}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.VerticalLayoutGroup
|
||||
m_Padding:
|
||||
m_Left: 4
|
||||
m_Right: 4
|
||||
m_Top: 8
|
||||
m_Bottom: 8
|
||||
m_ChildAlignment: 7
|
||||
m_Spacing: 6
|
||||
m_ChildForceExpandWidth: 1
|
||||
m_ChildForceExpandHeight: 0
|
||||
m_ChildControlWidth: 1
|
||||
m_ChildControlHeight: 1
|
||||
m_ChildScaleWidth: 0
|
||||
m_ChildScaleHeight: 0
|
||||
m_ReverseArrangement: 0
|
||||
--- !u!114 &5419335647702174254
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 5260492858234310193}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ContentSizeFitter
|
||||
m_HorizontalFit: 0
|
||||
m_VerticalFit: 2
|
||||
--- !u!1 &7249108092969100431
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6329947636030823459}
|
||||
- component: {fileID: 5824694681547497274}
|
||||
- component: {fileID: 6817391513969849154}
|
||||
- component: {fileID: 5117926241503925785}
|
||||
m_Layer: 0
|
||||
m_Name: Options
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &6329947636030823459
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7249108092969100431}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 6371610150170887506}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0}
|
||||
--- !u!114 &5824694681547497274
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7249108092969100431}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.VerticalLayoutGroup
|
||||
m_Padding:
|
||||
m_Left: 0
|
||||
m_Right: 0
|
||||
m_Top: 0
|
||||
m_Bottom: 0
|
||||
m_ChildAlignment: 0
|
||||
m_Spacing: 4
|
||||
m_ChildForceExpandWidth: 1
|
||||
m_ChildForceExpandHeight: 0
|
||||
m_ChildControlWidth: 1
|
||||
m_ChildControlHeight: 1
|
||||
m_ChildScaleWidth: 0
|
||||
m_ChildScaleHeight: 0
|
||||
m_ReverseArrangement: 0
|
||||
--- !u!114 &6817391513969849154
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7249108092969100431}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ContentSizeFitter
|
||||
m_HorizontalFit: 0
|
||||
m_VerticalFit: 2
|
||||
--- !u!225 &5117926241503925785
|
||||
CanvasGroup:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7249108092969100431}
|
||||
m_Enabled: 1
|
||||
m_Alpha: 0
|
||||
m_Interactable: 0
|
||||
m_BlocksRaycasts: 0
|
||||
m_IgnoreParentGroups: 0
|
||||
--- !u!1 &8691714907102969075
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1243836425688988300}
|
||||
- component: {fileID: 1592513625297910240}
|
||||
- component: {fileID: 7055069541643637941}
|
||||
- component: {fileID: 4390775391658295920}
|
||||
- component: {fileID: 3476584232491665726}
|
||||
- component: {fileID: 6097567599041115085}
|
||||
- component: {fileID: 307489608854241188}
|
||||
m_Layer: 0
|
||||
m_Name: DialogueStreamCanvas
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1243836425688988300
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8691714907102969075}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 8553742246756266605}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0, y: 0}
|
||||
--- !u!223 &1592513625297910240
|
||||
Canvas:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8691714907102969075}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_RenderMode: 0
|
||||
m_Camera: {fileID: 0}
|
||||
m_PlaneDistance: 100
|
||||
m_PixelPerfect: 0
|
||||
m_ReceivesEvents: 1
|
||||
m_OverrideSorting: 0
|
||||
m_OverridePixelPerfect: 0
|
||||
m_SortingBucketNormalizedSize: 0
|
||||
m_VertexColorAlwaysGammaSpace: 0
|
||||
m_UseReflectionProbes: 0
|
||||
m_AdditionalShaderChannelsFlag: 0
|
||||
m_UpdateRectTransformForStandalone: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 5
|
||||
m_TargetDisplay: 0
|
||||
--- !u!114 &7055069541643637941
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8691714907102969075}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.CanvasScaler
|
||||
m_UiScaleMode: 1
|
||||
m_ReferencePixelsPerUnit: 100
|
||||
m_ScaleFactor: 1
|
||||
m_ReferenceResolution: {x: 1920, y: 1080}
|
||||
m_ScreenMatchMode: 0
|
||||
m_MatchWidthOrHeight: 0.5
|
||||
m_PhysicalUnit: 3
|
||||
m_FallbackScreenDPI: 96
|
||||
m_DefaultSpriteDPI: 96
|
||||
m_DynamicPixelsPerUnit: 1
|
||||
m_PresetInfoIsWorld: 0
|
||||
--- !u!114 &4390775391658295920
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8691714907102969075}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.GraphicRaycaster
|
||||
m_IgnoreReversedGraphics: 1
|
||||
m_BlockingObjects: 0
|
||||
m_BlockingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
--- !u!225 &3476584232491665726
|
||||
CanvasGroup:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8691714907102969075}
|
||||
m_Enabled: 1
|
||||
m_Alpha: 0
|
||||
m_Interactable: 0
|
||||
m_BlocksRaycasts: 0
|
||||
m_IgnoreParentGroups: 0
|
||||
--- !u!114 &6097567599041115085
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8691714907102969075}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 88cb6495795a4e13ac7fb72343c132af, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Dialogue.DialogueStreamPresenter
|
||||
messageRowPrefab: {fileID: 5353601244371665078, guid: 90818ef7dc74247ceb348994755cea86, type: 3}
|
||||
messageContainer: {fileID: 4838388606347767229}
|
||||
scrollRect: {fileID: 7105587415705135446}
|
||||
maxRows: 100
|
||||
lettersPerSecond: 60
|
||||
--- !u!114 &307489608854241188
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8691714907102969075}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 8d86cc99d5b545c4a3fad9e1482031a2, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Dialogue.DialogueStreamOptionsPresenter
|
||||
optionViewPrefab: {fileID: 2576261519635394347, guid: e605972137b0b4c1399ffb07beae9a9b, type: 3}
|
||||
optionsContainer: {fileID: 6329947636030823459}
|
||||
canvasGroup: {fileID: 5117926241503925785}
|
||||
showUnavailableOptions: 0
|
||||
--- !u!1 &8898733438161318853
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6287368187237088396}
|
||||
- component: {fileID: 7105587415705135446}
|
||||
- component: {fileID: 6289533314517078144}
|
||||
- component: {fileID: 7217060756955950799}
|
||||
m_Layer: 0
|
||||
m_Name: Scroll
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &6287368187237088396
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8898733438161318853}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 3746324764683222304}
|
||||
m_Father: {fileID: 8553742246756266605}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: -16, y: -16}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &7105587415705135446
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8898733438161318853}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.ScrollRect
|
||||
m_Content: {fileID: 6371610150170887506}
|
||||
m_Horizontal: 0
|
||||
m_Vertical: 1
|
||||
m_MovementType: 2
|
||||
m_Elasticity: 0.1
|
||||
m_Inertia: 1
|
||||
m_DecelerationRate: 0.135
|
||||
m_ScrollSensitivity: 1
|
||||
m_Viewport: {fileID: 3746324764683222304}
|
||||
m_HorizontalScrollbar: {fileID: 0}
|
||||
m_VerticalScrollbar: {fileID: 0}
|
||||
m_HorizontalScrollbarVisibility: 0
|
||||
m_VerticalScrollbarVisibility: 0
|
||||
m_HorizontalScrollbarSpacing: 0
|
||||
m_VerticalScrollbarSpacing: 0
|
||||
m_OnValueChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!222 &6289533314517078144
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8898733438161318853}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &7217060756955950799
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8898733438161318853}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0, g: 0, b: 0, a: 0.01}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55fc979a64b174ce796ffa39b13b7259
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,390 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &3845905829654890729
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4691680407920056117}
|
||||
- component: {fileID: 9194898352646057999}
|
||||
- component: {fileID: 7450534218736675587}
|
||||
m_Layer: 0
|
||||
m_Name: TabHint
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4691680407920056117
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3845905829654890729}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 252585930844827291}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 4}
|
||||
m_SizeDelta: {x: 0, y: 28}
|
||||
m_Pivot: {x: 0.5, y: 0}
|
||||
--- !u!222 &9194898352646057999
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3845905829654890729}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &7450534218736675587
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3845905829654890729}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: Tab
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 18
|
||||
m_fontSizeBase: 18
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &4914891251226459434
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 8125896019114993279}
|
||||
- component: {fileID: 637496887729740374}
|
||||
- component: {fileID: 7333171482869056901}
|
||||
- component: {fileID: 3439018567020279905}
|
||||
- component: {fileID: 4573334312575796821}
|
||||
m_Layer: 0
|
||||
m_Name: HudCanvas
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &8125896019114993279
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4914891251226459434}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 252585930844827291}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0, y: 0}
|
||||
--- !u!223 &637496887729740374
|
||||
Canvas:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4914891251226459434}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 3
|
||||
m_RenderMode: 0
|
||||
m_Camera: {fileID: 0}
|
||||
m_PlaneDistance: 100
|
||||
m_PixelPerfect: 0
|
||||
m_ReceivesEvents: 1
|
||||
m_OverrideSorting: 0
|
||||
m_OverridePixelPerfect: 0
|
||||
m_SortingBucketNormalizedSize: 0
|
||||
m_VertexColorAlwaysGammaSpace: 0
|
||||
m_UseReflectionProbes: 0
|
||||
m_AdditionalShaderChannelsFlag: 0
|
||||
m_UpdateRectTransformForStandalone: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 10
|
||||
m_TargetDisplay: 0
|
||||
--- !u!114 &7333171482869056901
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4914891251226459434}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.CanvasScaler
|
||||
m_UiScaleMode: 1
|
||||
m_ReferencePixelsPerUnit: 100
|
||||
m_ScaleFactor: 1
|
||||
m_ReferenceResolution: {x: 1920, y: 1080}
|
||||
m_ScreenMatchMode: 0
|
||||
m_MatchWidthOrHeight: 0.5
|
||||
m_PhysicalUnit: 3
|
||||
m_FallbackScreenDPI: 96
|
||||
m_DefaultSpriteDPI: 96
|
||||
m_DynamicPixelsPerUnit: 1
|
||||
m_PresetInfoIsWorld: 0
|
||||
--- !u!114 &3439018567020279905
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4914891251226459434}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.GraphicRaycaster
|
||||
m_IgnoreReversedGraphics: 1
|
||||
m_BlockingObjects: 0
|
||||
m_BlockingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
--- !u!114 &4573334312575796821
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4914891251226459434}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fd1354ade14b4b1d80da9acac4aa9e12, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.HUD.PortraitHudView
|
||||
panelRoot: {fileID: 4989543578856257477}
|
||||
--- !u!1 &4989543578856257477
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 252585930844827291}
|
||||
- component: {fileID: 7861001760273437131}
|
||||
- component: {fileID: 1348039723167098503}
|
||||
- component: {fileID: 4045319608296230342}
|
||||
- component: {fileID: 1473442362196520338}
|
||||
m_Layer: 0
|
||||
m_Name: PortraitPanel
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &252585930844827291
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4989543578856257477}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 4691680407920056117}
|
||||
m_Father: {fileID: 8125896019114993279}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 1, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 0}
|
||||
m_AnchoredPosition: {x: -24, y: 24}
|
||||
m_SizeDelta: {x: 220, y: 280}
|
||||
m_Pivot: {x: 1, y: 0}
|
||||
--- !u!225 &7861001760273437131
|
||||
CanvasGroup:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4989543578856257477}
|
||||
m_Enabled: 1
|
||||
m_Alpha: 1
|
||||
m_Interactable: 1
|
||||
m_BlocksRaycasts: 1
|
||||
m_IgnoreParentGroups: 0
|
||||
--- !u!222 &1348039723167098503
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4989543578856257477}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &4045319608296230342
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4989543578856257477}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.15, g: 0.15, b: 0.18, a: 0.95}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: a1b2c3d4e5f60718293a4b5c6d7e8f90, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 1
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &1473442362196520338
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4989543578856257477}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Button
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 4045319608296230342}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 792e1d4c4cde942e8a71947301a3868c
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb4c52aaa2c9e41aabc4bb11fa6372ba
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,669 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &738428826500747930
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7033684844244958404}
|
||||
- component: {fileID: 8854647563054178895}
|
||||
- component: {fileID: 7773152306665733045}
|
||||
- component: {fileID: 3269936702826226914}
|
||||
m_Layer: 0
|
||||
m_Name: Accent
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &7033684844244958404
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 738428826500747930}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 6014094232834212140}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 100, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &8854647563054178895
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 738428826500747930}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &7773152306665733045
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 738428826500747930}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &3269936702826226914
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 738428826500747930}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: 6
|
||||
m_PreferredHeight: -1
|
||||
m_FlexibleWidth: 0
|
||||
m_FlexibleHeight: -1
|
||||
m_LayoutPriority: 1
|
||||
--- !u!1 &1043270585848180102
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6266953780690568889}
|
||||
- component: {fileID: 6662307575930959716}
|
||||
- component: {fileID: 874797289038649292}
|
||||
- component: {fileID: 3005905926608676038}
|
||||
m_Layer: 0
|
||||
m_Name: Bar
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &6266953780690568889
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1043270585848180102}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 437950331768363985}
|
||||
m_Father: {fileID: 6014094232834212140}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 100, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &6662307575930959716
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1043270585848180102}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &874797289038649292
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1043270585848180102}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.2, g: 0.2, b: 0.22, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &3005905926608676038
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1043270585848180102}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: 160
|
||||
m_PreferredHeight: 16
|
||||
m_FlexibleWidth: 0
|
||||
m_FlexibleHeight: -1
|
||||
m_LayoutPriority: 1
|
||||
--- !u!1 &1311471292218943158
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4484942689062487776}
|
||||
- component: {fileID: 285052103366591294}
|
||||
- component: {fileID: 6986784551111800944}
|
||||
- component: {fileID: 4453305505185908855}
|
||||
m_Layer: 0
|
||||
m_Name: Rank
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4484942689062487776
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1311471292218943158}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 6014094232834212140}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 200, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &285052103366591294
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1311471292218943158}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &6986784551111800944
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1311471292218943158}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: Rank
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 24
|
||||
m_fontSizeBase: 24
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 4
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!114 &4453305505185908855
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1311471292218943158}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: 40
|
||||
m_PreferredHeight: -1
|
||||
m_FlexibleWidth: 0
|
||||
m_FlexibleHeight: -1
|
||||
m_LayoutPriority: 1
|
||||
--- !u!1 &3239427835033733195
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4775921688302885094}
|
||||
- component: {fileID: 3498508026980942921}
|
||||
- component: {fileID: 4172720891822695416}
|
||||
- component: {fileID: 6787294827931527212}
|
||||
m_Layer: 0
|
||||
m_Name: Name
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4775921688302885094
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3239427835033733195}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 6014094232834212140}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 200, y: 50}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &3498508026980942921
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3239427835033733195}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &4172720891822695416
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3239427835033733195}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: Name
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 24
|
||||
m_fontSizeBase: 24
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 1
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_characterHorizontalScale: 1
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!114 &6787294827931527212
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3239427835033733195}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.LayoutElement
|
||||
m_IgnoreLayout: 0
|
||||
m_MinWidth: -1
|
||||
m_MinHeight: -1
|
||||
m_PreferredWidth: -1
|
||||
m_PreferredHeight: -1
|
||||
m_FlexibleWidth: 1
|
||||
m_FlexibleHeight: -1
|
||||
m_LayoutPriority: 1
|
||||
--- !u!1 &3768236759226886124
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 437950331768363985}
|
||||
- component: {fileID: 5606763019278455248}
|
||||
- component: {fileID: 1019288287942172810}
|
||||
m_Layer: 0
|
||||
m_Name: Fill
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &437950331768363985
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3768236759226886124}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 6266953780690568889}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &5606763019278455248
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3768236759226886124}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1019288287942172810
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3768236759226886124}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.Image
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 3
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 0
|
||||
m_FillAmount: 0.2
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &7442810364304304402
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6014094232834212140}
|
||||
- component: {fileID: 1141587833647839303}
|
||||
- component: {fileID: 8736413170534072599}
|
||||
m_Layer: 0
|
||||
m_Name: SkillRow
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &6014094232834212140
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7442810364304304402}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 7033684844244958404}
|
||||
- {fileID: 4775921688302885094}
|
||||
- {fileID: 6266953780690568889}
|
||||
- {fileID: 4484942689062487776}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 48}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1141587833647839303
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7442810364304304402}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6ccda37aee7e42b09a0628f8a5729060, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: NightclubArcadia.Skills::NightclubArcadia.Skills.SkillRowView
|
||||
nameLabel: {fileID: 4172720891822695416}
|
||||
rankLabel: {fileID: 6986784551111800944}
|
||||
barFill: {fileID: 1019288287942172810}
|
||||
accentStripe: {fileID: 7773152306665733045}
|
||||
--- !u!114 &8736413170534072599
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7442810364304304402}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.HorizontalLayoutGroup
|
||||
m_Padding:
|
||||
m_Left: 8
|
||||
m_Right: 8
|
||||
m_Top: 4
|
||||
m_Bottom: 4
|
||||
m_ChildAlignment: 3
|
||||
m_Spacing: 12
|
||||
m_ChildForceExpandWidth: 0
|
||||
m_ChildForceExpandHeight: 1
|
||||
m_ChildControlWidth: 1
|
||||
m_ChildControlHeight: 1
|
||||
m_ChildScaleWidth: 0
|
||||
m_ChildScaleHeight: 0
|
||||
m_ReverseArrangement: 0
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e14f68d6a57ea4945bd93c44202db910
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1647a101742545fe8af6187e3a743858
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,81 @@
|
||||
using Unity.Cinemachine;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Cinematics
|
||||
{
|
||||
/// <summary>
|
||||
/// Raises a reveal camera priority while the player is inside the volume.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(BoxCollider))]
|
||||
public sealed class CameraFramingVolume : MonoBehaviour
|
||||
{
|
||||
[SerializeField] CinemachineCamera revealCamera;
|
||||
[SerializeField] int activePriority = 20;
|
||||
[SerializeField] float minDwell = 0.5f;
|
||||
|
||||
CameraStateDirector stateDirector;
|
||||
int defaultPriority;
|
||||
int occupants;
|
||||
float exitTimer;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
var box = GetComponent<BoxCollider>();
|
||||
box.isTrigger = true;
|
||||
|
||||
if (revealCamera != null)
|
||||
{
|
||||
defaultPriority = revealCamera.Priority.Value;
|
||||
}
|
||||
|
||||
stateDirector = FindFirstObjectByType<CameraStateDirector>();
|
||||
}
|
||||
|
||||
void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (!other.CompareTag("Player") || revealCamera == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
occupants++;
|
||||
exitTimer = 0f;
|
||||
revealCamera.Priority.Value = activePriority;
|
||||
stateDirector?.RegisterReveal();
|
||||
}
|
||||
|
||||
void OnTriggerExit(Collider other)
|
||||
{
|
||||
if (!other.CompareTag("Player") || revealCamera == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
occupants = Mathf.Max(0, occupants - 1);
|
||||
if (occupants == 0)
|
||||
{
|
||||
exitTimer = minDwell;
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (occupants > 0 || revealCamera == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (exitTimer > 0f)
|
||||
{
|
||||
exitTimer -= Time.deltaTime;
|
||||
return;
|
||||
}
|
||||
|
||||
if (revealCamera.Priority.Value != defaultPriority)
|
||||
{
|
||||
revealCamera.Priority.Value = defaultPriority;
|
||||
stateDirector?.UnregisterReveal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7cccc93b78eb84019b4524d65305612a
|
||||
@@ -0,0 +1,162 @@
|
||||
using NightclubArcadia.Player;
|
||||
using NightclubArcadia.Player.Math;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Cinematics
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts mouse drag-pan into CameraRigAnchor manual offset with recenter rules.
|
||||
/// </summary>
|
||||
public sealed class CameraPanInput : MonoBehaviour
|
||||
{
|
||||
[SerializeField] Camera brainCamera;
|
||||
[SerializeField] CameraRigAnchor anchor;
|
||||
[SerializeField] CameraStateDirector stateDirector;
|
||||
[SerializeField] PlayerPointerInput pointerInput;
|
||||
[SerializeField] float panMetresPerPixel = 0.02f;
|
||||
[SerializeField] float maxPanDistance = 12f;
|
||||
[SerializeField] float recenterDelay = 2.5f;
|
||||
[SerializeField] float recenterSmoothTime = 0.8f;
|
||||
[SerializeField] float movementRecenterDelay = 0.4f;
|
||||
|
||||
float releaseTimer = float.MaxValue;
|
||||
Vector3 recenterVelocity;
|
||||
Vector3 camRight;
|
||||
Vector3 camForward;
|
||||
bool basisInitialized;
|
||||
|
||||
public bool IsManualPanActive => pointerInput != null && pointerInput.IsPanning || releaseTimer < recenterDelay;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (anchor == null)
|
||||
{
|
||||
anchor = GetComponent<CameraRigAnchor>();
|
||||
}
|
||||
|
||||
if (stateDirector == null)
|
||||
{
|
||||
stateDirector = GetComponent<CameraStateDirector>();
|
||||
}
|
||||
|
||||
if (brainCamera == null)
|
||||
{
|
||||
brainCamera = Camera.main;
|
||||
}
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (pointerInput == null)
|
||||
{
|
||||
var player = GameObject.FindGameObjectWithTag("Player");
|
||||
if (player != null)
|
||||
{
|
||||
pointerInput = player.GetComponent<PlayerPointerInput>();
|
||||
}
|
||||
}
|
||||
|
||||
if (pointerInput != null)
|
||||
{
|
||||
pointerInput.PanDelta += OnPanDelta;
|
||||
pointerInput.PanEnded += OnPanEnded;
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (pointerInput != null)
|
||||
{
|
||||
pointerInput.PanDelta -= OnPanDelta;
|
||||
pointerInput.PanEnded -= OnPanEnded;
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (anchor == null || stateDirector == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (stateDirector.AllowsManualPan && pointerInput != null && pointerInput.IsPanning)
|
||||
{
|
||||
releaseTimer = 0f;
|
||||
}
|
||||
else if (releaseTimer < recenterDelay)
|
||||
{
|
||||
releaseTimer += Time.deltaTime;
|
||||
}
|
||||
|
||||
if (ShouldShortenRecenter())
|
||||
{
|
||||
releaseTimer = Mathf.Max(releaseTimer, recenterDelay - movementRecenterDelay);
|
||||
}
|
||||
|
||||
if (!stateDirector.AllowsManualPan)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (releaseTimer >= recenterDelay && (pointerInput == null || !pointerInput.IsPanning))
|
||||
{
|
||||
anchor.ManualPanOffset = Vector3.SmoothDamp(
|
||||
anchor.ManualPanOffset,
|
||||
Vector3.zero,
|
||||
ref recenterVelocity,
|
||||
recenterSmoothTime);
|
||||
}
|
||||
|
||||
anchor.ClampManualPan(maxPanDistance);
|
||||
}
|
||||
|
||||
void OnPanDelta(Vector2 delta)
|
||||
{
|
||||
if (stateDirector == null || !stateDirector.AllowsManualPan || anchor == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureCameraBasis();
|
||||
anchor.Nudge(MotionInputMath.ScreenDeltaToWorldPan(delta, camRight, camForward, panMetresPerPixel));
|
||||
anchor.ClampManualPan(maxPanDistance);
|
||||
}
|
||||
|
||||
void OnPanEnded()
|
||||
{
|
||||
releaseTimer = 0f;
|
||||
}
|
||||
|
||||
bool ShouldShortenRecenter()
|
||||
{
|
||||
var player = GameObject.FindGameObjectWithTag("Player");
|
||||
if (player == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var arbiter = player.GetComponent<PlayerMotionArbiter>();
|
||||
return arbiter != null && arbiter.ActiveSource != MotionSource.None;
|
||||
}
|
||||
|
||||
void EnsureCameraBasis()
|
||||
{
|
||||
if (brainCamera == null)
|
||||
{
|
||||
brainCamera = Camera.main;
|
||||
}
|
||||
|
||||
if (brainCamera == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!basisInitialized)
|
||||
{
|
||||
camRight = brainCamera.transform.right;
|
||||
camForward = brainCamera.transform.forward;
|
||||
basisInitialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f9b06ade88f2643a3b9f52a80e06081d
|
||||
@@ -0,0 +1,31 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Cinematics
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker on NPCs and props that the POI director may bias toward.
|
||||
/// </summary>
|
||||
public sealed class CameraPointOfInterest : MonoBehaviour
|
||||
{
|
||||
[SerializeField] float weight = 1f;
|
||||
[SerializeField] float triggerRadius = 8f;
|
||||
[SerializeField] float maxBias = 2.5f;
|
||||
[SerializeField] float extraDistance = 1.5f;
|
||||
|
||||
public float Weight => weight;
|
||||
public float TriggerRadius => triggerRadius;
|
||||
public float MaxBias => maxBias;
|
||||
public float ExtraDistance => extraDistance;
|
||||
public Transform Target => transform;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
CameraPointOfInterestDirector.Register(this);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
CameraPointOfInterestDirector.Unregister(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7862f80331f384d28b27600075971a77
|
||||
@@ -0,0 +1,161 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Cinematics
|
||||
{
|
||||
/// <summary>
|
||||
/// Scores registered POIs and writes bias onto the camera anchor.
|
||||
/// </summary>
|
||||
public sealed class CameraPointOfInterestDirector : MonoBehaviour
|
||||
{
|
||||
static readonly List<CameraPointOfInterest> Registered = new List<CameraPointOfInterest>();
|
||||
|
||||
[SerializeField] CameraRigAnchor anchor;
|
||||
[SerializeField] CameraStateDirector stateDirector;
|
||||
[SerializeField] float poiSmoothTime = 1f;
|
||||
[SerializeField] float poiReleaseTime = 1.4f;
|
||||
[SerializeField] float maxHeadingAngle = 100f;
|
||||
|
||||
Vector3 poiVelocity;
|
||||
float distanceVelocity;
|
||||
CameraPointOfInterest activePoi;
|
||||
|
||||
public bool HasActivePoi => activePoi != null;
|
||||
|
||||
public static void Register(CameraPointOfInterest poi)
|
||||
{
|
||||
if (poi != null && !Registered.Contains(poi))
|
||||
{
|
||||
Registered.Add(poi);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(CameraPointOfInterest poi)
|
||||
{
|
||||
Registered.Remove(poi);
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (anchor == null)
|
||||
{
|
||||
anchor = GetComponent<CameraRigAnchor>();
|
||||
}
|
||||
|
||||
if (stateDirector == null)
|
||||
{
|
||||
stateDirector = GetComponent<CameraStateDirector>();
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (anchor == null || stateDirector == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var follow = anchor.FollowTarget;
|
||||
if (follow == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stateDirector.AllowsPointOfInterest)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (stateDirector.Current == CameraState.ManualPan)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
activePoi = FindBestPoi(follow);
|
||||
if (activePoi == null)
|
||||
{
|
||||
ReleasePoi();
|
||||
return;
|
||||
}
|
||||
|
||||
var toPoi = activePoi.Target.position - follow.position;
|
||||
toPoi.y = 0f;
|
||||
var targetBias = Vector3.ClampMagnitude(toPoi, activePoi.MaxBias);
|
||||
|
||||
anchor.PoiBias = Vector3.SmoothDamp(
|
||||
anchor.PoiBias,
|
||||
targetBias,
|
||||
ref poiVelocity,
|
||||
poiSmoothTime);
|
||||
|
||||
anchor.DistanceBias = Mathf.SmoothDamp(
|
||||
anchor.DistanceBias,
|
||||
activePoi.ExtraDistance,
|
||||
ref distanceVelocity,
|
||||
poiSmoothTime);
|
||||
}
|
||||
|
||||
CameraPointOfInterest FindBestPoi(Transform follow)
|
||||
{
|
||||
CameraPointOfInterest best = null;
|
||||
var bestScore = 0f;
|
||||
var forward = follow.forward;
|
||||
|
||||
foreach (var poi in Registered)
|
||||
{
|
||||
if (poi == null || !poi.isActiveAndEnabled)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var offset = poi.Target.position - follow.position;
|
||||
offset.y = 0f;
|
||||
var distance = offset.magnitude;
|
||||
if (distance > poi.TriggerRadius || distance <= 0.01f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var angle = Vector3.Angle(forward, offset);
|
||||
if (angle > maxHeadingAngle)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var score = poi.Weight * (1f - distance / poi.TriggerRadius);
|
||||
if (score > bestScore)
|
||||
{
|
||||
bestScore = score;
|
||||
best = poi;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
void ReleasePoi()
|
||||
{
|
||||
if (anchor == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
anchor.PoiBias = Vector3.SmoothDamp(
|
||||
anchor.PoiBias,
|
||||
Vector3.zero,
|
||||
ref poiVelocity,
|
||||
poiReleaseTime);
|
||||
|
||||
anchor.DistanceBias = Mathf.SmoothDamp(
|
||||
anchor.DistanceBias,
|
||||
0f,
|
||||
ref distanceVelocity,
|
||||
poiReleaseTime);
|
||||
|
||||
if (anchor.PoiBias.sqrMagnitude < 0.0001f && Mathf.Abs(anchor.DistanceBias) < 0.01f)
|
||||
{
|
||||
activePoi = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3343417e1de440f095b73e55c6977b6
|
||||
@@ -0,0 +1,85 @@
|
||||
using Unity.Cinemachine;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Cinematics
|
||||
{
|
||||
/// <summary>
|
||||
/// Proxy transform the follow camera tracks. Combines player follow,
|
||||
/// POI bias, manual pan offset, and distance bias.
|
||||
/// </summary>
|
||||
public sealed class CameraRigAnchor : MonoBehaviour
|
||||
{
|
||||
[SerializeField] Transform followTarget;
|
||||
[SerializeField] CinemachinePositionComposer composer;
|
||||
[SerializeField] float followSmoothTime = 0.12f;
|
||||
[SerializeField] float distanceSmoothTime = 0.8f;
|
||||
|
||||
float defaultCameraDistance = 10f;
|
||||
float distanceVelocity;
|
||||
Vector3 followVelocity;
|
||||
|
||||
public Vector3 PoiBias { get; set; }
|
||||
public Vector3 ManualPanOffset { get; set; }
|
||||
public float DistanceBias { get; set; }
|
||||
|
||||
public Transform FollowTarget => followTarget;
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (composer == null)
|
||||
{
|
||||
composer = FindFirstObjectByType<CinemachinePositionComposer>();
|
||||
}
|
||||
|
||||
if (composer != null)
|
||||
{
|
||||
defaultCameraDistance = composer.CameraDistance;
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (followTarget == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var targetPosition = followTarget.position + PoiBias + ManualPanOffset;
|
||||
transform.position = Vector3.SmoothDamp(
|
||||
transform.position,
|
||||
targetPosition,
|
||||
ref followVelocity,
|
||||
followSmoothTime);
|
||||
|
||||
if (composer != null)
|
||||
{
|
||||
var targetDistance = defaultCameraDistance + DistanceBias;
|
||||
composer.CameraDistance = Mathf.SmoothDamp(
|
||||
composer.CameraDistance,
|
||||
targetDistance,
|
||||
ref distanceVelocity,
|
||||
distanceSmoothTime);
|
||||
}
|
||||
}
|
||||
|
||||
public void Nudge(Vector3 worldDelta)
|
||||
{
|
||||
ManualPanOffset += worldDelta;
|
||||
}
|
||||
|
||||
public void ClampManualPan(float maxDistance)
|
||||
{
|
||||
if (followTarget == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var offset = ManualPanOffset;
|
||||
offset.y = 0f;
|
||||
if (offset.magnitude > maxDistance)
|
||||
{
|
||||
ManualPanOffset = offset.normalized * maxDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16d6717a3703a4bb3a8c3bb0bb0392de
|
||||
@@ -0,0 +1,135 @@
|
||||
using NightclubArcadia.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Cinematics
|
||||
{
|
||||
public enum CameraState
|
||||
{
|
||||
Follow,
|
||||
ManualPan,
|
||||
PointOfInterest,
|
||||
Reveal,
|
||||
Dialogue,
|
||||
Menu
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves which camera subsystem may write each frame.
|
||||
/// </summary>
|
||||
public sealed class CameraStateDirector : MonoBehaviour
|
||||
{
|
||||
[SerializeField] CameraRigAnchor anchor;
|
||||
[SerializeField] float dialogueRecenterTime = 0.5f;
|
||||
|
||||
int activeRevealCount;
|
||||
float dialogueRecenterTimer;
|
||||
bool wasDialogueActive;
|
||||
bool wasMenuOpen;
|
||||
|
||||
public CameraState Current { get; private set; } = CameraState.Follow;
|
||||
|
||||
public bool AllowsManualPan =>
|
||||
Current != CameraState.Dialogue
|
||||
&& Current != CameraState.Menu
|
||||
&& Current != CameraState.Reveal;
|
||||
|
||||
public bool AllowsPointOfInterest =>
|
||||
Current == CameraState.Follow || Current == CameraState.PointOfInterest;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (anchor == null)
|
||||
{
|
||||
anchor = GetComponent<CameraRigAnchor>();
|
||||
}
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (UIStateController.Instance != null)
|
||||
{
|
||||
UIStateController.Instance.StateChanged += OnUiStateChanged;
|
||||
}
|
||||
|
||||
ResolveState(false);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (UIStateController.Instance != null)
|
||||
{
|
||||
UIStateController.Instance.StateChanged -= OnUiStateChanged;
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
ResolveState(true);
|
||||
|
||||
if (Current == CameraState.Dialogue && anchor != null)
|
||||
{
|
||||
dialogueRecenterTimer += Time.deltaTime;
|
||||
var t = Mathf.Clamp01(dialogueRecenterTimer / dialogueRecenterTime);
|
||||
anchor.ManualPanOffset = Vector3.Lerp(anchor.ManualPanOffset, Vector3.zero, t);
|
||||
}
|
||||
}
|
||||
|
||||
void OnUiStateChanged() => ResolveState(true);
|
||||
|
||||
public void RegisterReveal() => activeRevealCount++;
|
||||
|
||||
public void UnregisterReveal() => activeRevealCount = Mathf.Max(0, activeRevealCount - 1);
|
||||
|
||||
void ResolveState(bool allowManualPanPromotion)
|
||||
{
|
||||
var ui = UIStateController.Instance;
|
||||
var menuOpen = ui != null && ui.IsMenuOpen;
|
||||
var dialogueActive = ui != null && ui.IsDialogueActive;
|
||||
|
||||
if (menuOpen)
|
||||
{
|
||||
Current = CameraState.Menu;
|
||||
}
|
||||
else if (dialogueActive)
|
||||
{
|
||||
if (!wasDialogueActive)
|
||||
{
|
||||
dialogueRecenterTimer = 0f;
|
||||
}
|
||||
|
||||
Current = CameraState.Dialogue;
|
||||
}
|
||||
else if (activeRevealCount > 0)
|
||||
{
|
||||
Current = CameraState.Reveal;
|
||||
}
|
||||
else if (allowManualPanPromotion && IsManualPanActive())
|
||||
{
|
||||
Current = CameraState.ManualPan;
|
||||
}
|
||||
else if (HasActivePointOfInterest())
|
||||
{
|
||||
Current = CameraState.PointOfInterest;
|
||||
}
|
||||
else
|
||||
{
|
||||
Current = CameraState.Follow;
|
||||
}
|
||||
|
||||
wasDialogueActive = dialogueActive;
|
||||
wasMenuOpen = menuOpen;
|
||||
}
|
||||
|
||||
bool IsManualPanActive()
|
||||
{
|
||||
var pan = GetComponent<CameraPanInput>();
|
||||
return pan != null && pan.IsManualPanActive;
|
||||
}
|
||||
|
||||
bool HasActivePointOfInterest()
|
||||
{
|
||||
var director = GetComponent<CameraPointOfInterestDirector>();
|
||||
return director != null && director.HasActivePoi;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca0160e4d996040238dab18725a2e844
|
||||
@@ -0,0 +1,72 @@
|
||||
using NightclubArcadia.UI;
|
||||
using Unity.Cinemachine;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Cinematics
|
||||
{
|
||||
/// <summary>
|
||||
/// Shifts CinemachinePositionComposer.Composition.ScreenPosition so the
|
||||
/// player is centred in the screen space left of the dialogue panel.
|
||||
/// </summary>
|
||||
public sealed class DialogueCameraFraming : MonoBehaviour
|
||||
{
|
||||
[SerializeField] CinemachinePositionComposer composer;
|
||||
[SerializeField] float dialogueScreenX = -0.17f;
|
||||
[SerializeField] bool suppressDeadZoneXInDialogue = true;
|
||||
|
||||
float defaultDeadZoneX = 0.2f;
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (composer == null)
|
||||
{
|
||||
composer = FindFirstObjectByType<CinemachinePositionComposer>();
|
||||
}
|
||||
|
||||
if (composer != null)
|
||||
{
|
||||
defaultDeadZoneX = composer.Composition.DeadZone.Size.x;
|
||||
}
|
||||
|
||||
if (UIStateController.Instance != null)
|
||||
{
|
||||
UIStateController.Instance.StateChanged += OnStateChanged;
|
||||
}
|
||||
|
||||
ApplyFraming();
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (UIStateController.Instance != null)
|
||||
{
|
||||
UIStateController.Instance.StateChanged -= OnStateChanged;
|
||||
}
|
||||
}
|
||||
|
||||
void OnStateChanged() => ApplyFraming();
|
||||
|
||||
void ApplyFraming()
|
||||
{
|
||||
if (composer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var active = UIStateController.Instance != null && UIStateController.Instance.IsDialogueActive;
|
||||
var target = active ? dialogueScreenX : 0f;
|
||||
|
||||
var composition = composer.Composition;
|
||||
composition.ScreenPosition = new Vector2(target, composition.ScreenPosition.y);
|
||||
|
||||
if (suppressDeadZoneXInDialogue)
|
||||
{
|
||||
var size = composition.DeadZone.Size;
|
||||
size.x = active ? 0f : defaultDeadZoneX;
|
||||
composition.DeadZone.Size = size;
|
||||
}
|
||||
|
||||
composer.Composition = composition;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56142a5f8795401498df8e01dc74b258
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16d046b9603964894b61827ac87b5020
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace NightclubArcadia.Dialogue
|
||||
{
|
||||
/// <summary>
|
||||
/// Deterministically turns the player's real name into an unrelated club
|
||||
/// alias. Same input name always yields the same alias (hash-seeded pick
|
||||
/// from two word pools), but the alias carries no resemblance to the
|
||||
/// input — it's a stage name, not a nickname derived from it.
|
||||
///
|
||||
/// Used from Yarn as a smart variable (see $player_alias in Common.yarn)
|
||||
/// or directly: {alias_name($player_name)}
|
||||
/// </summary>
|
||||
public static class AliasNameGenerator
|
||||
{
|
||||
static readonly string[] FirstWords =
|
||||
{
|
||||
"Midnight", "Velvet", "Neon", "Crimson", "Static", "Amber",
|
||||
"Obsidian", "Electric", "Hollow", "Silver", "Violet", "Iron",
|
||||
"Phantom", "Copper", "Glass", "Ashen",
|
||||
};
|
||||
|
||||
static readonly string[] SecondWords =
|
||||
{
|
||||
"Vex", "Wilde", "Sable", "Rook", "Marlowe", "Cross",
|
||||
"Vane", "Thorn", "Rye", "Blaze", "Faye", "Quinn",
|
||||
"Storm", "Reyes", "Lark", "Doyle",
|
||||
};
|
||||
|
||||
[YarnFunction("alias_name")]
|
||||
public static string AliasName(string realName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(realName))
|
||||
{
|
||||
realName = "unknown";
|
||||
}
|
||||
|
||||
var hash = Fnv1aHash(realName);
|
||||
var first = FirstWords[hash % (uint)FirstWords.Length];
|
||||
var second = SecondWords[(hash / (uint)FirstWords.Length) % (uint)SecondWords.Length];
|
||||
return $"{first} {second}";
|
||||
}
|
||||
|
||||
// FNV-1a: simple, stable across platforms and .NET versions (unlike
|
||||
// string.GetHashCode, which is not guaranteed stable run-to-run).
|
||||
static uint Fnv1aHash(string value)
|
||||
{
|
||||
const uint offsetBasis = 2166136261;
|
||||
const uint prime = 16777619;
|
||||
|
||||
var hash = offsetBasis;
|
||||
foreach (var c in value)
|
||||
{
|
||||
hash ^= c;
|
||||
hash *= prime;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee985664120c84b41921806fadeccb34
|
||||
@@ -0,0 +1,69 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace NightclubArcadia.Dialogue
|
||||
{
|
||||
/// <summary>
|
||||
/// Trigger-zone interactable: player walks in range, presses E, and this
|
||||
/// starts the given Yarn node. The reverse of DialogueTransitionController's
|
||||
/// <<enter_environment>> — this is the "step into dialogue" half of the loop.
|
||||
/// </summary>
|
||||
public class DialogueInteractable : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private DialogueRunner dialogueRunner;
|
||||
[SerializeField] private GameObject dialogueUI;
|
||||
[SerializeField] private string yarnNodeName = "Bartender_Chat";
|
||||
|
||||
private bool playerInRange;
|
||||
private InputAction interactAction;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
interactAction = new InputAction("Interact");
|
||||
interactAction.AddBinding("<Keyboard>/e");
|
||||
interactAction.AddBinding("<Gamepad>/buttonNorth");
|
||||
interactAction.performed += _ =>
|
||||
{
|
||||
if (playerInRange)
|
||||
{
|
||||
StartConversation();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void OnEnable() => interactAction?.Enable();
|
||||
void OnDisable() => interactAction?.Disable();
|
||||
|
||||
void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (other.CompareTag("Player"))
|
||||
{
|
||||
playerInRange = true;
|
||||
}
|
||||
}
|
||||
|
||||
void OnTriggerExit(Collider other)
|
||||
{
|
||||
if (other.CompareTag("Player"))
|
||||
{
|
||||
playerInRange = false;
|
||||
}
|
||||
}
|
||||
|
||||
async void StartConversation()
|
||||
{
|
||||
// Player controls are locked by DialogueTransitionController off the
|
||||
// runner's onDialogueStart event — nothing to do for that here.
|
||||
if (DialogueUIVisibility.Show(dialogueUI))
|
||||
{
|
||||
// Only reached if the UI was found deactivated; give TMP a
|
||||
// frame to re-cache its Canvas in OnEnable before any text is
|
||||
// generated.
|
||||
await Awaitable.NextFrameAsync();
|
||||
}
|
||||
|
||||
await dialogueRunner.StartDialogue(yarnNodeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99afbbd28c8054d59a7a0dec94f5ec8f
|
||||
@@ -0,0 +1,85 @@
|
||||
using NightclubArcadia.UI;
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
namespace NightclubArcadia.Dialogue
|
||||
{
|
||||
/// <summary>
|
||||
/// Owns the hand-off between dialogue and the 3D environment: locks the
|
||||
/// player's controls for as long as a conversation is running, and registers
|
||||
/// the <<enter_environment>> Yarn command that hands control back.
|
||||
///
|
||||
/// The lock is driven by the DialogueRunner's own lifecycle events rather
|
||||
/// than by each interactable, so every entry point — auto-started nodes,
|
||||
/// NPCStandIn, DialogueInteractable — gets the same behaviour without
|
||||
/// having to remember to do it. Control locking is delegated to
|
||||
/// <see cref="PlayerControlLock"/> so the player menu can hold a second
|
||||
/// independent lock without re-enabling movement mid-conversation.
|
||||
/// </summary>
|
||||
public class DialogueTransitionController : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private DialogueRunner dialogueRunner;
|
||||
[SerializeField] private GameObject dialogueUI;
|
||||
[SerializeField] private GameObject playerArmature;
|
||||
[SerializeField] private PlayerControlLock controlLock;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (controlLock == null && playerArmature != null)
|
||||
{
|
||||
controlLock = playerArmature.GetComponent<PlayerControlLock>();
|
||||
}
|
||||
|
||||
// Subscribed in Awake rather than Start: the runner auto-starts its
|
||||
// first node from its own Start(), and script execution order
|
||||
// between the two is not guaranteed.
|
||||
dialogueRunner.onDialogueStart?.AddListener(OnDialogueStart);
|
||||
dialogueRunner.onDialogueComplete?.AddListener(OnDialogueComplete);
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (controlLock == null && playerArmature != null)
|
||||
{
|
||||
controlLock = playerArmature.GetComponent<PlayerControlLock>();
|
||||
}
|
||||
|
||||
// Dialogue is in progress as soon as this controller is active
|
||||
// (including auto-started nodes), so the player stays locked out
|
||||
// until <<enter_environment>>. The armature itself stays
|
||||
// active/visible — only its controls are disabled.
|
||||
controlLock?.Acquire(this);
|
||||
|
||||
dialogueRunner.AddCommandHandler("enter_environment", EnterEnvironment);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
dialogueRunner.onDialogueStart?.RemoveListener(OnDialogueStart);
|
||||
dialogueRunner.onDialogueComplete?.RemoveListener(OnDialogueComplete);
|
||||
}
|
||||
|
||||
void OnDialogueStart()
|
||||
{
|
||||
DialogueUIVisibility.Show(dialogueUI);
|
||||
UIStateController.Instance?.SetDialogueActive(true);
|
||||
controlLock?.Acquire(this);
|
||||
}
|
||||
|
||||
// Safety net: a node that ends without <<enter_environment>> must still
|
||||
// give the player their controls back.
|
||||
void OnDialogueComplete() => EnterEnvironment();
|
||||
|
||||
void EnterEnvironment()
|
||||
{
|
||||
// Hide, don't deactivate: deactivating the Canvas breaks TMP's
|
||||
// cached Canvas reference and makes the next conversation throw.
|
||||
// See DialogueUIVisibility / PanelVisibility.
|
||||
DialogueUIVisibility.Hide(dialogueUI);
|
||||
UIStateController.Instance?.SetDialogueActive(false);
|
||||
// Release is idempotent on a HashSet — safe when both
|
||||
// <<enter_environment>> and onDialogueComplete fire.
|
||||
controlLock?.Release(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc43c99ef338a41ea8f7a18c283fe6df
|
||||
@@ -0,0 +1,28 @@
|
||||
using NightclubArcadia.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Dialogue
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows and hides the dialogue UI *without* deactivating its GameObject.
|
||||
/// Forwards to <see cref="PanelVisibility"/> — kept as a thin wrapper so
|
||||
/// existing call sites (NPCStandIn, DialogueInteractable,
|
||||
/// DialogueTransitionController) continue to compile unchanged.
|
||||
/// </summary>
|
||||
public static class DialogueUIVisibility
|
||||
{
|
||||
/// <summary>
|
||||
/// Makes the dialogue UI visible and interactive. Returns true if the
|
||||
/// GameObject had to be re-activated (legacy scene state), in which
|
||||
/// case the caller must wait one frame before rendering text so that
|
||||
/// TMP's OnEnable can re-cache its Canvas.
|
||||
/// </summary>
|
||||
public static bool Show(GameObject dialogueUI) => PanelVisibility.Show(dialogueUI);
|
||||
|
||||
/// <summary>
|
||||
/// Hides the dialogue UI, leaving the hierarchy active. See
|
||||
/// <see cref="PanelVisibility"/>.
|
||||
/// </summary>
|
||||
public static void Hide(GameObject dialogueUI) => PanelVisibility.Hide(dialogueUI);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad5dcf93105bd49b287dbd19bc42cef7
|
||||
@@ -0,0 +1,13 @@
|
||||
using UnityEngine;
|
||||
using Yarn.Unity;
|
||||
|
||||
public class SkillFunctions : MonoBehaviour
|
||||
{
|
||||
[YarnFunction("top_skill")]
|
||||
public static string TopSkill(float a, string aName, float b, string bName, float c, string cName)
|
||||
{
|
||||
if (a >= b && a >= c) return aName;
|
||||
if (b >= a && b >= c) return bName;
|
||||
return cName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7e92eaa5873f456281db864a1a7871b
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97642050992484049b6c021481f2baf2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Interaction
|
||||
{
|
||||
/// <summary>
|
||||
/// Adapts NPCStandIn to the click-to-interact pipeline without modifying
|
||||
/// the existing proximity + keypress path.
|
||||
/// </summary>
|
||||
public sealed class ClickInteractableBridge : MonoBehaviour, IClickInteractable
|
||||
{
|
||||
[SerializeField] NPCStandIn npc;
|
||||
|
||||
public Transform ApproachPoint => transform;
|
||||
public float ApproachRadius => npc != null ? Mathf.Max(0.15f, npc.interactionRange - 0.5f) : 0.15f;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (npc == null)
|
||||
{
|
||||
npc = GetComponent<NPCStandIn>();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnApproached()
|
||||
{
|
||||
npc?.Interact();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5257f07d188de44eb9a04ba4d3a65fec
|
||||
@@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Interaction
|
||||
{
|
||||
public interface IClickInteractable
|
||||
{
|
||||
Transform ApproachPoint { get; }
|
||||
float ApproachRadius { get; }
|
||||
void OnApproached();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4812c7fb9cf2d41c28966640827dd0c8
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2216657f3a0224501bcfa09add14f689
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.InputSystem.LowLevel;
|
||||
|
||||
/// <summary>
|
||||
/// Tracks which input device was most recently active, globally, across the whole game.
|
||||
/// NPCStandIn (and any other UI that shows button prompts) reads InputDeviceTracker.Current
|
||||
/// to decide whether to show "[F]", "(X)", "(✕)", etc.
|
||||
/// Requires the Input System package (Window > Package Manager > Input System),
|
||||
/// and Project Settings > Player > Active Input Handling set to
|
||||
/// "Input System Package (New)" or "Both".
|
||||
/// </summary>
|
||||
public static class InputDeviceTracker
|
||||
{
|
||||
public enum DeviceType { Keyboard, Xbox, PlayStation, Generic }
|
||||
|
||||
public static DeviceType Current { get; private set; } = DeviceType.Keyboard;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod]
|
||||
static void Init()
|
||||
{
|
||||
InputSystem.onEvent += OnEvent;
|
||||
}
|
||||
|
||||
static void OnEvent(InputEventPtr eventPtr, InputDevice device)
|
||||
{
|
||||
// Only care about actual state changes (button/stick/key presses), not noise.
|
||||
if (!eventPtr.IsA<StateEvent>() && !eventPtr.IsA<DeltaStateEvent>()) return;
|
||||
|
||||
switch (device)
|
||||
{
|
||||
case Keyboard:
|
||||
case Mouse:
|
||||
Current = DeviceType.Keyboard;
|
||||
break;
|
||||
|
||||
case Gamepad gp:
|
||||
string n = gp.displayName.ToLowerInvariant();
|
||||
if (n.Contains("dualshock") || n.Contains("dualsense") || n.Contains("playstation"))
|
||||
Current = DeviceType.PlayStation;
|
||||
else if (n.Contains("xbox") || n.Contains("xinput"))
|
||||
Current = DeviceType.Xbox;
|
||||
else
|
||||
Current = DeviceType.Generic;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 941f7ff9039984f729ceddebd57d4159
|
||||
@@ -0,0 +1,205 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using TMPro;
|
||||
using Yarn.Unity;
|
||||
using NightclubArcadia.Dialogue;
|
||||
using NightclubArcadia.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Drop this on a sphere primitive to use it as a placeholder NPC:
|
||||
/// - Sets sphere color per-instance
|
||||
/// - Spawns a floating TextMeshPro name label that billboards to face the camera
|
||||
/// - Shows a proximity interaction prompt ("[F]", "(X)", "(✕)") that swaps based on
|
||||
/// the last input device used, via InputDeviceTracker
|
||||
/// - Press the interact button while in range to start a Yarn Spinner dialogue node
|
||||
/// Requires: TextMeshPro Essentials imported, Input System package installed,
|
||||
/// InputDeviceTracker.cs in the project, and a "Player" tag on your player object
|
||||
/// (or assign the Player field manually in the Inspector).
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(SphereCollider))]
|
||||
public class NPCStandIn : MonoBehaviour
|
||||
{
|
||||
[Header("Identity")]
|
||||
public string npcName = "Unnamed NPC";
|
||||
public Color npcColor = Color.white;
|
||||
|
||||
[Header("Dialogue")]
|
||||
public DialogueRunner dialogueRunner;
|
||||
public string yarnStartNode = "Start";
|
||||
|
||||
[Tooltip("Optional. Left empty, the Canvas under the DialogueRunner is used.")]
|
||||
public GameObject dialogueUI;
|
||||
|
||||
[Header("Label")]
|
||||
public float labelHeight = 1.2f;
|
||||
public float labelFontSize = 4f;
|
||||
public Color labelColor = Color.white;
|
||||
|
||||
[Header("Interaction Prompt")]
|
||||
public Transform player; // auto-found by "Player" tag if left empty
|
||||
public float interactionRange = 3f;
|
||||
public float promptHeight = 0.7f;
|
||||
public float promptFontSize = 3f;
|
||||
|
||||
private TextMeshPro labelText;
|
||||
private TextMeshPro promptText;
|
||||
private Renderer rend;
|
||||
private Camera mainCam;
|
||||
private InputAction interactAction;
|
||||
private bool playerInRange;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
rend = GetComponent<Renderer>();
|
||||
rend.material.color = npcColor;
|
||||
|
||||
mainCam = Camera.main;
|
||||
|
||||
if (player == null)
|
||||
{
|
||||
GameObject found = GameObject.FindGameObjectWithTag("Player");
|
||||
if (found != null) player = found.transform;
|
||||
}
|
||||
|
||||
CreateLabel();
|
||||
CreatePrompt();
|
||||
|
||||
interactAction = new InputAction("Interact");
|
||||
interactAction.AddBinding("<Keyboard>/f");
|
||||
interactAction.AddBinding("<Gamepad>/buttonSouth");
|
||||
interactAction.performed += ctx =>
|
||||
{
|
||||
if (playerInRange) Interact();
|
||||
};
|
||||
}
|
||||
|
||||
void OnEnable() => interactAction?.Enable();
|
||||
void OnDisable() => interactAction?.Disable();
|
||||
|
||||
void CreateLabel()
|
||||
{
|
||||
GameObject labelObj = new GameObject($"{npcName}_Label");
|
||||
labelObj.transform.SetParent(transform);
|
||||
labelObj.transform.localPosition = Vector3.up * labelHeight;
|
||||
|
||||
labelText = labelObj.AddComponent<TextMeshPro>();
|
||||
labelText.text = npcName;
|
||||
labelText.fontSize = labelFontSize;
|
||||
labelText.color = labelColor;
|
||||
labelText.alignment = TextAlignmentOptions.Center;
|
||||
labelText.rectTransform.sizeDelta = new Vector2(2f, 0.5f);
|
||||
}
|
||||
|
||||
void CreatePrompt()
|
||||
{
|
||||
GameObject promptObj = new GameObject($"{npcName}_Prompt");
|
||||
promptObj.transform.SetParent(transform);
|
||||
promptObj.transform.localPosition = Vector3.up * promptHeight;
|
||||
|
||||
promptText = promptObj.AddComponent<TextMeshPro>();
|
||||
promptText.fontSize = promptFontSize;
|
||||
promptText.color = Color.yellow;
|
||||
promptText.alignment = TextAlignmentOptions.Center;
|
||||
promptText.rectTransform.sizeDelta = new Vector2(1.5f, 0.4f);
|
||||
promptObj.SetActive(false); // hidden until player is in range
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (player == null) return;
|
||||
|
||||
float dist = Vector3.Distance(transform.position, player.position);
|
||||
bool inRangeNow = dist <= interactionRange;
|
||||
|
||||
if (inRangeNow != playerInRange)
|
||||
{
|
||||
playerInRange = inRangeNow;
|
||||
promptText.gameObject.SetActive(playerInRange);
|
||||
}
|
||||
|
||||
if (playerInRange)
|
||||
{
|
||||
promptText.text = GlyphFor(InputDeviceTracker.Current);
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (mainCam == null) return;
|
||||
|
||||
if (labelText != null)
|
||||
labelText.transform.rotation = Quaternion.LookRotation(
|
||||
labelText.transform.position - mainCam.transform.position);
|
||||
|
||||
if (promptText != null)
|
||||
promptText.transform.rotation = Quaternion.LookRotation(
|
||||
promptText.transform.position - mainCam.transform.position);
|
||||
}
|
||||
|
||||
static string GlyphFor(InputDeviceTracker.DeviceType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case InputDeviceTracker.DeviceType.Xbox: return "(X)";
|
||||
case InputDeviceTracker.DeviceType.PlayStation: return "(\u2715)"; // Cross button
|
||||
default: return "[F]";
|
||||
}
|
||||
}
|
||||
|
||||
public void Interact()
|
||||
{
|
||||
if (dialogueRunner == null)
|
||||
{
|
||||
Debug.LogWarning($"[NPCStandIn] No DialogueRunner assigned on {npcName}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (UIStateController.Instance != null && UIStateController.Instance.IsMenuOpen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dialogueRunner.IsDialogueRunning)
|
||||
{
|
||||
StartDialogueAsync();
|
||||
}
|
||||
}
|
||||
|
||||
async void StartDialogueAsync()
|
||||
{
|
||||
// The dialogue UI is hidden when the player leaves a conversation via
|
||||
// <<enter_environment>>. Make it visible again before the runner
|
||||
// renders its first line.
|
||||
if (DialogueUIVisibility.Show(ResolveDialogueUI()))
|
||||
{
|
||||
// Only reached if the UI was found deactivated; give TMP a frame
|
||||
// to re-cache its Canvas in OnEnable before any text is generated.
|
||||
await Awaitable.NextFrameAsync();
|
||||
}
|
||||
|
||||
await dialogueRunner.StartDialogue(yarnStartNode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Canvas under the DialogueRunner, unless one was assigned explicitly.
|
||||
/// Resolved at call time (including inactive children) so this works
|
||||
/// without any per-NPC Inspector wiring.
|
||||
/// </summary>
|
||||
GameObject ResolveDialogueUI()
|
||||
{
|
||||
if (dialogueUI != null)
|
||||
{
|
||||
return dialogueUI;
|
||||
}
|
||||
|
||||
var canvas = dialogueRunner.GetComponentInChildren<Canvas>(true);
|
||||
if (canvas == null)
|
||||
{
|
||||
Debug.LogWarning($"[NPCStandIn] No Canvas found under {dialogueRunner.name} for {npcName}");
|
||||
return null;
|
||||
}
|
||||
|
||||
dialogueUI = canvas.gameObject;
|
||||
return dialogueUI;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23d0ac85377c640a1900cfd13e89c389
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 381786de30b3e49e7a693028cc2127f5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,234 @@
|
||||
using System;
|
||||
using NightclubArcadia.Interaction;
|
||||
using NightclubArcadia.Player.Math;
|
||||
using StarterAssets;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
namespace NightclubArcadia.Player
|
||||
{
|
||||
/// <summary>
|
||||
/// NavMeshAgent in oracle mode: computes desired move input for the arbiter
|
||||
/// without moving the CharacterController directly.
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(-60)]
|
||||
[RequireComponent(typeof(NavMeshAgent))]
|
||||
public sealed class ClickToMoveController : MonoBehaviour
|
||||
{
|
||||
const float SampleRadius = 1.5f;
|
||||
const float StallWindow = 0.4f;
|
||||
const float StallDistance = 0.05f;
|
||||
|
||||
[SerializeField] Camera brainCamera;
|
||||
|
||||
NavMeshAgent agent;
|
||||
ThirdPersonController locomotion;
|
||||
IClickInteractable pendingInteractable;
|
||||
|
||||
bool forceRunForPath;
|
||||
[SerializeField] float runDistanceThreshold = 6f;
|
||||
Vector3 lastPosition;
|
||||
float stallTimer;
|
||||
bool hasPath;
|
||||
|
||||
public bool HasPath => hasPath;
|
||||
public Vector3 Destination { get; private set; }
|
||||
public Vector2 DesiredMoveInput { get; private set; }
|
||||
public float RemainingDistance => agent != null ? agent.remainingDistance : 0f;
|
||||
public bool WantsSprint => hasPath && (forceRunForPath || agent.remainingDistance > runDistanceThreshold);
|
||||
|
||||
public event Action<bool> PathFinished;
|
||||
public event Action RunRequested;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
agent = GetComponent<NavMeshAgent>();
|
||||
locomotion = GetComponent<ThirdPersonController>();
|
||||
|
||||
agent.updatePosition = false;
|
||||
agent.updateRotation = false;
|
||||
agent.updateUpAxis = false;
|
||||
agent.angularSpeed = 0f;
|
||||
agent.acceleration = 1000f;
|
||||
agent.autoBraking = true;
|
||||
agent.stoppingDistance = 0.15f;
|
||||
agent.radius = 0.3f;
|
||||
agent.height = 1.8f;
|
||||
|
||||
if (brainCamera == null)
|
||||
{
|
||||
brainCamera = Camera.main;
|
||||
}
|
||||
|
||||
SyncAgentSpeed(false);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!hasPath)
|
||||
{
|
||||
DesiredMoveInput = Vector2.zero;
|
||||
return;
|
||||
}
|
||||
|
||||
SyncAgentSpeed(forceRunForPath || agent.remainingDistance > runDistanceThreshold);
|
||||
|
||||
if (brainCamera == null)
|
||||
{
|
||||
brainCamera = Camera.main;
|
||||
}
|
||||
|
||||
var cameraYaw = brainCamera != null ? brainCamera.transform.eulerAngles.y : 0f;
|
||||
DesiredMoveInput = MotionInputMath.WorldToCameraRelativeInput(
|
||||
agent.desiredVelocity,
|
||||
agent.speed,
|
||||
cameraYaw);
|
||||
|
||||
CheckStall();
|
||||
CheckArrival();
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (agent != null)
|
||||
{
|
||||
agent.nextPosition = transform.position;
|
||||
}
|
||||
}
|
||||
|
||||
public void RequestRun()
|
||||
{
|
||||
forceRunForPath = true;
|
||||
RunRequested?.Invoke();
|
||||
}
|
||||
|
||||
public bool SetDestination(Vector3 worldPoint)
|
||||
{
|
||||
pendingInteractable = null;
|
||||
|
||||
if (!TrySampleNavMesh(worldPoint, out var hit))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
agent.stoppingDistance = 0.15f;
|
||||
agent.isStopped = false;
|
||||
agent.SetDestination(hit.position);
|
||||
Destination = hit.position;
|
||||
hasPath = true;
|
||||
ResetStallTracking();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetInteractionTarget(IClickInteractable interactable)
|
||||
{
|
||||
if (interactable == null || interactable.ApproachPoint == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
pendingInteractable = interactable;
|
||||
var approach = interactable.ApproachPoint.position;
|
||||
|
||||
if (!TrySampleNavMesh(approach, out var hit))
|
||||
{
|
||||
pendingInteractable = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
agent.stoppingDistance = Mathf.Max(0.15f, interactable.ApproachRadius);
|
||||
agent.isStopped = false;
|
||||
agent.SetDestination(hit.position);
|
||||
Destination = hit.position;
|
||||
hasPath = true;
|
||||
ResetStallTracking();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
if (agent != null)
|
||||
{
|
||||
agent.ResetPath();
|
||||
agent.isStopped = true;
|
||||
}
|
||||
|
||||
hasPath = false;
|
||||
forceRunForPath = false;
|
||||
pendingInteractable = null;
|
||||
DesiredMoveInput = Vector2.zero;
|
||||
ResetStallTracking();
|
||||
}
|
||||
|
||||
bool TrySampleNavMesh(Vector3 point, out NavMeshHit hit)
|
||||
{
|
||||
return NavMesh.SamplePosition(point, out hit, SampleRadius, NavMesh.AllAreas);
|
||||
}
|
||||
|
||||
void CheckArrival()
|
||||
{
|
||||
if (!hasPath || agent.pathPending)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (agent.remainingDistance > agent.stoppingDistance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var success = agent.pathStatus != NavMeshPathStatus.PathInvalid;
|
||||
hasPath = false;
|
||||
agent.ResetPath();
|
||||
|
||||
var interactable = pendingInteractable;
|
||||
pendingInteractable = null;
|
||||
|
||||
PathFinished?.Invoke(success);
|
||||
|
||||
if (success && interactable != null)
|
||||
{
|
||||
interactable.OnApproached();
|
||||
}
|
||||
}
|
||||
|
||||
void CheckStall()
|
||||
{
|
||||
var displacement = Vector3.Distance(
|
||||
new Vector3(transform.position.x, 0f, transform.position.z),
|
||||
new Vector3(lastPosition.x, 0f, lastPosition.z));
|
||||
|
||||
if (displacement < StallDistance)
|
||||
{
|
||||
stallTimer += Time.deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
stallTimer = 0f;
|
||||
lastPosition = transform.position;
|
||||
}
|
||||
|
||||
if (stallTimer >= StallWindow && agent.remainingDistance > agent.stoppingDistance)
|
||||
{
|
||||
Cancel();
|
||||
PathFinished?.Invoke(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ResetStallTracking()
|
||||
{
|
||||
lastPosition = transform.position;
|
||||
stallTimer = 0f;
|
||||
}
|
||||
|
||||
void SyncAgentSpeed(bool sprint)
|
||||
{
|
||||
if (locomotion == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
agent.speed = sprint ? locomotion.SprintSpeed : locomotion.MoveSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2762b30721644611b9672bd4781cf15
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c32faf711a4044ed88ff1be2790915f7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,42 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Player.Math
|
||||
{
|
||||
/// <summary>
|
||||
/// Pure math helpers shared by click-to-move and camera pan.
|
||||
/// </summary>
|
||||
public static class MotionInputMath
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a NavMeshAgent desired velocity into the camera-relative
|
||||
/// Vector2 that ThirdPersonController expects on StarterAssetsInputs.move.
|
||||
/// </summary>
|
||||
public static Vector2 WorldToCameraRelativeInput(Vector3 worldVelocity, float agentSpeed, float cameraYaw)
|
||||
{
|
||||
if (worldVelocity.sqrMagnitude < 0.0001f || agentSpeed <= 0f)
|
||||
{
|
||||
return Vector2.zero;
|
||||
}
|
||||
|
||||
var horizontal = new Vector3(worldVelocity.x, 0f, worldVelocity.z);
|
||||
var magnitude = horizontal.magnitude;
|
||||
var fraction = Mathf.Clamp01(magnitude / agentSpeed);
|
||||
var local = Quaternion.Euler(0f, -cameraYaw, 0f) * horizontal.normalized;
|
||||
return new Vector2(local.x, local.z) * fraction;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts screen-space pointer delta into a world-plane pan offset.
|
||||
/// Drag direction is inverted so the world follows the cursor.
|
||||
/// </summary>
|
||||
public static Vector3 ScreenDeltaToWorldPan(
|
||||
Vector2 pixelDelta,
|
||||
Vector3 camRight,
|
||||
Vector3 camForward,
|
||||
float metresPerPixel)
|
||||
{
|
||||
var forward = Vector3.ProjectOnPlane(camForward, Vector3.up).normalized;
|
||||
return (-pixelDelta.x * camRight + -pixelDelta.y * forward) * metresPerPixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9af00d68e15e24c02811500cdf0dd2d4
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "NightclubArcadia.Locomotion.Math",
|
||||
"rootNamespace": "NightclubArcadia.Player.Math",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12491a5edc87346d28ffc48f9ab6562c
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,114 @@
|
||||
using NightclubArcadia.Interaction;
|
||||
using NightclubArcadia.UI;
|
||||
using StarterAssets;
|
||||
using UnityEngine;
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
using UnityEngine.InputSystem;
|
||||
#endif
|
||||
|
||||
namespace NightclubArcadia.Player
|
||||
{
|
||||
public enum MotionSource
|
||||
{
|
||||
None,
|
||||
Direct,
|
||||
Navigation
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sole writer of StarterAssetsInputs move/sprint. Picks one input source
|
||||
/// per frame: direct keyboard/gamepad or click-to-move navigation.
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(-50)]
|
||||
public sealed class PlayerMotionArbiter : MonoBehaviour
|
||||
{
|
||||
[SerializeField] float directInputCancelThreshold = 0.15f;
|
||||
[SerializeField] float runDistanceThreshold = 6f;
|
||||
|
||||
StarterAssetsInputs playerInputs;
|
||||
PlayerControlLock controlLock;
|
||||
ClickToMoveController clickToMove;
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
PlayerInput playerInput;
|
||||
#endif
|
||||
|
||||
public MotionSource ActiveSource { get; private set; }
|
||||
|
||||
void Awake()
|
||||
{
|
||||
playerInputs = GetComponent<StarterAssetsInputs>();
|
||||
controlLock = GetComponent<PlayerControlLock>();
|
||||
clickToMove = GetComponent<ClickToMoveController>();
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
playerInput = GetComponent<PlayerInput>();
|
||||
#endif
|
||||
}
|
||||
|
||||
public void ResetState()
|
||||
{
|
||||
ActiveSource = MotionSource.None;
|
||||
clickToMove?.Cancel();
|
||||
WriteInput(Vector2.zero, false);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (controlLock != null && controlLock.IsLocked)
|
||||
{
|
||||
clickToMove?.Cancel();
|
||||
ActiveSource = MotionSource.None;
|
||||
WriteInput(Vector2.zero, false);
|
||||
return;
|
||||
}
|
||||
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
var raw = playerInput.actions["Move"].ReadValue<Vector2>();
|
||||
#else
|
||||
var raw = Vector2.zero;
|
||||
#endif
|
||||
|
||||
if (raw.sqrMagnitude > directInputCancelThreshold * directInputCancelThreshold)
|
||||
{
|
||||
clickToMove?.Cancel();
|
||||
ActiveSource = MotionSource.Direct;
|
||||
WriteInput(raw, ReadDirectSprint());
|
||||
return;
|
||||
}
|
||||
|
||||
if (clickToMove != null && clickToMove.HasPath)
|
||||
{
|
||||
ActiveSource = MotionSource.Navigation;
|
||||
WriteInput(clickToMove.DesiredMoveInput, ShouldNavigationSprint());
|
||||
return;
|
||||
}
|
||||
|
||||
ActiveSource = MotionSource.None;
|
||||
WriteInput(Vector2.zero, false);
|
||||
}
|
||||
|
||||
bool ReadDirectSprint()
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
return playerInput.actions["Sprint"].IsPressed();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ShouldNavigationSprint()
|
||||
{
|
||||
return clickToMove != null && clickToMove.WantsSprint;
|
||||
}
|
||||
|
||||
void WriteInput(Vector2 move, bool sprint)
|
||||
{
|
||||
if (playerInputs == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
playerInputs.MoveInput(move);
|
||||
playerInputs.SprintInput(sprint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91bf24256c6694185b4247a736593727
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
using UnityEngine.InputSystem;
|
||||
#endif
|
||||
|
||||
namespace NightclubArcadia.Player
|
||||
{
|
||||
/// <summary>
|
||||
/// Receives pointer and camera-pan SendMessages from PlayerInput and
|
||||
/// exposes them as C# events for navigation and camera systems.
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(-100)]
|
||||
public sealed class PlayerPointerInput : MonoBehaviour
|
||||
{
|
||||
public Vector2 ScreenPosition { get; private set; }
|
||||
public bool IsPanning { get; private set; }
|
||||
|
||||
public event Action Clicked;
|
||||
public event Action PanStarted;
|
||||
public event Action<Vector2> PanDelta;
|
||||
public event Action PanEnded;
|
||||
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
void OnPoint(InputValue value)
|
||||
{
|
||||
ScreenPosition = value.Get<Vector2>();
|
||||
}
|
||||
|
||||
void OnClick(InputValue value)
|
||||
{
|
||||
if (value.isPressed)
|
||||
{
|
||||
Clicked?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
void OnCameraPan(InputValue value)
|
||||
{
|
||||
if (value.isPressed && !IsPanning)
|
||||
{
|
||||
IsPanning = true;
|
||||
PanStarted?.Invoke();
|
||||
}
|
||||
else if (!value.isPressed && IsPanning)
|
||||
{
|
||||
IsPanning = false;
|
||||
PanEnded?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
void OnPointerDelta(InputValue value)
|
||||
{
|
||||
if (IsPanning)
|
||||
{
|
||||
PanDelta?.Invoke(value.Get<Vector2>());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff77faf7e79154095ad57ad50df8c605
|
||||
@@ -0,0 +1,203 @@
|
||||
using System;
|
||||
using NightclubArcadia.Interaction;
|
||||
using NightclubArcadia.UI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace NightclubArcadia.Player
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts pointer clicks into click-to-move destinations or interactable
|
||||
/// approach targets.
|
||||
/// </summary>
|
||||
public sealed class PointerNavigationInput : MonoBehaviour
|
||||
{
|
||||
const float DoubleClickWindow = 0.35f;
|
||||
const float DoubleClickPixelThreshold = 40f;
|
||||
|
||||
[SerializeField] Camera brainCamera;
|
||||
[SerializeField] LayerMask clickMask = ~0;
|
||||
[SerializeField] PlayerPointerInput pointerInput;
|
||||
[SerializeField] ClickToMoveController clickToMove;
|
||||
[SerializeField] PlayerMotionArbiter motionArbiter;
|
||||
|
||||
float lastClickTime = -1f;
|
||||
Vector2 lastClickPosition;
|
||||
bool pendingClick;
|
||||
Vector2 pendingClickPosition;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (pointerInput == null)
|
||||
{
|
||||
pointerInput = GetComponent<PlayerPointerInput>();
|
||||
}
|
||||
|
||||
if (clickToMove == null)
|
||||
{
|
||||
clickToMove = GetComponent<ClickToMoveController>();
|
||||
}
|
||||
|
||||
if (motionArbiter == null)
|
||||
{
|
||||
motionArbiter = GetComponent<PlayerMotionArbiter>();
|
||||
}
|
||||
|
||||
if (brainCamera == null)
|
||||
{
|
||||
brainCamera = Camera.main;
|
||||
}
|
||||
|
||||
if (clickMask.value == ~0)
|
||||
{
|
||||
clickMask = LayerMask.GetMask("Default", "Ground", "Interactable");
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
if (pointerInput != null)
|
||||
{
|
||||
pointerInput.Clicked += OnClicked;
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (pointerInput != null)
|
||||
{
|
||||
pointerInput.Clicked -= OnClicked;
|
||||
}
|
||||
|
||||
pendingClick = false;
|
||||
}
|
||||
|
||||
// Input System callbacks fire during event processing, where
|
||||
// IsPointerOverGameObject() is invalid (queries last frame's UI).
|
||||
// Queue the click and resolve it in Update instead.
|
||||
void OnClicked()
|
||||
{
|
||||
if (pointerInput == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pendingClick = true;
|
||||
pendingClickPosition = pointerInput.ScreenPosition;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!pendingClick)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pendingClick = false;
|
||||
ProcessClick(pendingClickPosition);
|
||||
}
|
||||
|
||||
void ProcessClick(Vector2 screenPos)
|
||||
{
|
||||
if (!CanNavigate())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (EventSystem.current != null && EventSystem.current.IsPointerOverGameObject())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (brainCamera == null)
|
||||
{
|
||||
brainCamera = Camera.main;
|
||||
}
|
||||
|
||||
if (brainCamera == null || clickToMove == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var ray = brainCamera.ScreenPointToRay(screenPos);
|
||||
var hits = Physics.RaycastAll(ray, 200f, clickMask, QueryTriggerInteraction.Collide);
|
||||
Array.Sort(hits, (a, b) => a.distance.CompareTo(b.distance));
|
||||
|
||||
var isDoubleClick = IsDoubleClick(screenPos);
|
||||
lastClickTime = Time.unscaledTime;
|
||||
lastClickPosition = screenPos;
|
||||
|
||||
foreach (var hit in hits)
|
||||
{
|
||||
var interactable = FindInteractable(hit.collider);
|
||||
if (interactable != null)
|
||||
{
|
||||
if (isDoubleClick)
|
||||
{
|
||||
clickToMove.RequestRun();
|
||||
}
|
||||
|
||||
if (clickToMove.SetInteractionTarget(interactable))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var hit in hits)
|
||||
{
|
||||
if (isDoubleClick)
|
||||
{
|
||||
clickToMove.RequestRun();
|
||||
}
|
||||
|
||||
if (clickToMove.SetDestination(hit.point))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CanNavigate()
|
||||
{
|
||||
if (GetComponent<PlayerControlLock>() is { IsLocked: true })
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (UIStateController.Instance == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return !UIStateController.Instance.IsDialogueActive
|
||||
&& !UIStateController.Instance.IsMenuOpen;
|
||||
}
|
||||
|
||||
bool IsDoubleClick(Vector2 screenPos)
|
||||
{
|
||||
if (lastClickTime < 0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var withinTime = Time.unscaledTime - lastClickTime <= DoubleClickWindow;
|
||||
var withinDistance = Vector2.Distance(screenPos, lastClickPosition) <= DoubleClickPixelThreshold;
|
||||
return withinTime && withinDistance;
|
||||
}
|
||||
|
||||
static IClickInteractable FindInteractable(Collider collider)
|
||||
{
|
||||
var behaviours = collider.GetComponentsInParent<MonoBehaviour>();
|
||||
foreach (var behaviour in behaviours)
|
||||
{
|
||||
if (behaviour is IClickInteractable interactable)
|
||||
{
|
||||
return interactable;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f62460e35fda4829bd6ffeffe633a7e
|
||||
@@ -3,7 +3,8 @@
|
||||
"rootNamespace": "NightclubArcadia.Skills",
|
||||
"references": [
|
||||
"YarnSpinner.Unity",
|
||||
"Unity.TextMeshPro"
|
||||
"Unity.TextMeshPro",
|
||||
"UnityEngine.UI"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace NightclubArcadia.Skills
|
||||
{
|
||||
/// <summary>
|
||||
/// One skill row: name, numeric rank, and accent-tinted fill bar.
|
||||
/// </summary>
|
||||
public sealed class SkillRowView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] TMP_Text nameLabel;
|
||||
[SerializeField] TMP_Text rankLabel;
|
||||
[SerializeField] Image barFill;
|
||||
[SerializeField] Image accentStripe;
|
||||
|
||||
public void Bind(SkillDefinition def, int rank, int displayMaxRank)
|
||||
{
|
||||
if (def == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (nameLabel != null)
|
||||
{
|
||||
nameLabel.text = string.IsNullOrEmpty(def.DisplayName)
|
||||
? def.Id.ToUpperInvariant()
|
||||
: def.DisplayName;
|
||||
nameLabel.color = def.AccentColor;
|
||||
}
|
||||
|
||||
if (rankLabel != null)
|
||||
{
|
||||
rankLabel.text = rank.ToString();
|
||||
}
|
||||
|
||||
if (barFill != null)
|
||||
{
|
||||
var max = Mathf.Max(1, displayMaxRank);
|
||||
barFill.fillAmount = Mathf.Clamp01(rank / (float)max);
|
||||
barFill.color = def.AccentColor;
|
||||
}
|
||||
|
||||
if (accentStripe != null)
|
||||
{
|
||||
accentStripe.color = def.AccentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ccda37aee7e42b09a0628f8a5729060
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,88 @@
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NightclubArcadia.Skills
|
||||
{
|
||||
/// <summary>
|
||||
/// Skills tab content. Rebuilds the list from SkillDatabase.All +
|
||||
/// PlayerSkills.GetRank on each show. No change event on PlayerSkills —
|
||||
/// refresh on show is deliberate (menu is modal; ranks cannot change while open).
|
||||
/// </summary>
|
||||
public sealed class SkillsPanelView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] RectTransform contentRoot;
|
||||
[SerializeField] SkillRowView rowPrefab;
|
||||
[SerializeField] TMP_Text axisHeaderPrefab;
|
||||
[SerializeField] int displayMaxRank = 6;
|
||||
|
||||
readonly List<GameObject> spawned = new List<GameObject>();
|
||||
|
||||
/// <summary>
|
||||
/// Wired from MenuTabBar TabEntry.onShown in the Inspector.
|
||||
/// </summary>
|
||||
public void Refresh()
|
||||
{
|
||||
Clear();
|
||||
|
||||
var runtime = SkillRuntime.Instance;
|
||||
if (runtime == null || runtime.Database == null || runtime.Skills == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (contentRoot == null || rowPrefab == null)
|
||||
{
|
||||
Debug.LogWarning($"[{nameof(SkillsPanelView)}] Missing contentRoot or rowPrefab.", this);
|
||||
return;
|
||||
}
|
||||
|
||||
SkillAxis? currentAxis = null;
|
||||
foreach (var def in runtime.Database.All)
|
||||
{
|
||||
if (def == null || string.IsNullOrEmpty(def.Id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentAxis == null || currentAxis.Value != def.Axis)
|
||||
{
|
||||
currentAxis = def.Axis;
|
||||
SpawnAxisHeader(def.Axis);
|
||||
}
|
||||
|
||||
var rank = runtime.Skills.GetRank(def.Id);
|
||||
var row = Instantiate(rowPrefab, contentRoot);
|
||||
row.gameObject.SetActive(true);
|
||||
row.Bind(def, rank, displayMaxRank);
|
||||
spawned.Add(row.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnAxisHeader(SkillAxis axis)
|
||||
{
|
||||
if (axisHeaderPrefab == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var header = Instantiate(axisHeaderPrefab, contentRoot);
|
||||
header.gameObject.SetActive(true);
|
||||
header.text = axis.ToString().ToUpperInvariant();
|
||||
spawned.Add(header.gameObject);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for (var i = 0; i < spawned.Count; i++)
|
||||
{
|
||||
if (spawned[i] != null)
|
||||
{
|
||||
Destroy(spawned[i]);
|
||||
}
|
||||
}
|
||||
|
||||
spawned.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user