From 42b559b104207d0f4780a82f8da40acba1cc8e19 Mon Sep 17 00:00:00 2001
From: ClearZer0 <534310154@qq.com>
Date: Wed, 18 Dec 2024 02:39:14 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B5=8B=E8=AF=95=E5=9C=B0?=
=?UTF-8?q?=E5=9B=BE=20Loenn=E6=95=99=E7=A8=8B=E7=9B=AE=E5=BD=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/coding_challenges/simple_texturing.md | 22 ++---
docs/index.md | 3 +
docs/loenn/basic_configurations.md | 19 +++++
docs/loenn/effect_structs.md | 1 +
docs/loenn/entity_structs.md | 1 +
docs/loenn/folder_structure.md | 2 +
docs/loenn/nodes.md | 1 +
docs/loenn/rendering.md | 15 ++++
docs/loenn/trigger_structs.md | 1 +
docs/misc/change_log.md | 3 +
docs/misc/to_do_list.md | 3 +-
docs/resources/CelesteModTutorial.zip | Bin 0 -> 25568 bytes
mkdocs.yml | 8 ++
src/CelesteModTutorial/CelesteModTutorial.dll | Bin 0 -> 8192 bytes
src/CelesteModTutorial/Code/CelesteMod.props | 80 ++++++++++++++++++
.../Code/CelesteMod.targets | 54 ++++++++++++
.../Code/CelesteModTutorial.csproj | 19 +++++
.../Code/CelesteModTutorialModule.cs | 35 ++++++++
.../Code/CelesteModTutorialSaveData.cs | 11 +++
.../Code/CelesteModTutorialSession.cs | 11 +++
.../Code/CelesteModTutorialSettings.cs | 11 +++
src/CelesteModTutorial/Code/Common.props | 11 +++
.../Code/Entities/PassByRefill.cs | 52 ++++++++++++
.../Code/Entities/PassByRefillWithTexture.cs | 50 +++++++++++
.../Code/ModFolder/CelesteModTutorial.dll | Bin 0 -> 8192 bytes
.../Code/ModFolder/CelesteModTutorial.pdb | Bin 0 -> 4100 bytes
.../Triggers/SetPassByRefillDashesTrigger.cs | 40 +++++++++
src/CelesteModTutorial/Dialog/English.txt | 9 ++
.../Dialog/Simplified Chinese.txt | 9 ++
.../objects/PassByRefill/pass_by_refill.png | Bin 0 -> 736 bytes
.../Loenn/entities/PassByRefill.lua | 20 +++++
.../entities/PassByRefillWithTexture.lua | 21 +++++
src/CelesteModTutorial/Loenn/lang/en_gb.lang | 4 +
.../triggers/SetPassByRefillDashesTrigger.lua | 20 +++++
.../Maps/CelesteModTutorial/Test.bin | Bin 0 -> 790 bytes
src/CelesteModTutorial/everest.yaml | 7 ++
36 files changed, 532 insertions(+), 11 deletions(-)
create mode 100644 docs/loenn/basic_configurations.md
create mode 100644 docs/loenn/effect_structs.md
create mode 100644 docs/loenn/entity_structs.md
create mode 100644 docs/loenn/folder_structure.md
create mode 100644 docs/loenn/nodes.md
create mode 100644 docs/loenn/rendering.md
create mode 100644 docs/loenn/trigger_structs.md
create mode 100644 docs/resources/CelesteModTutorial.zip
create mode 100644 src/CelesteModTutorial/CelesteModTutorial.dll
create mode 100644 src/CelesteModTutorial/Code/CelesteMod.props
create mode 100644 src/CelesteModTutorial/Code/CelesteMod.targets
create mode 100644 src/CelesteModTutorial/Code/CelesteModTutorial.csproj
create mode 100644 src/CelesteModTutorial/Code/CelesteModTutorialModule.cs
create mode 100644 src/CelesteModTutorial/Code/CelesteModTutorialSaveData.cs
create mode 100644 src/CelesteModTutorial/Code/CelesteModTutorialSession.cs
create mode 100644 src/CelesteModTutorial/Code/CelesteModTutorialSettings.cs
create mode 100644 src/CelesteModTutorial/Code/Common.props
create mode 100644 src/CelesteModTutorial/Code/Entities/PassByRefill.cs
create mode 100644 src/CelesteModTutorial/Code/Entities/PassByRefillWithTexture.cs
create mode 100644 src/CelesteModTutorial/Code/ModFolder/CelesteModTutorial.dll
create mode 100644 src/CelesteModTutorial/Code/ModFolder/CelesteModTutorial.pdb
create mode 100644 src/CelesteModTutorial/Code/Triggers/SetPassByRefillDashesTrigger.cs
create mode 100644 src/CelesteModTutorial/Dialog/English.txt
create mode 100644 src/CelesteModTutorial/Dialog/Simplified Chinese.txt
create mode 100644 src/CelesteModTutorial/Graphics/Atlases/Gameplay/objects/PassByRefill/pass_by_refill.png
create mode 100644 src/CelesteModTutorial/Loenn/entities/PassByRefill.lua
create mode 100644 src/CelesteModTutorial/Loenn/entities/PassByRefillWithTexture.lua
create mode 100644 src/CelesteModTutorial/Loenn/lang/en_gb.lang
create mode 100644 src/CelesteModTutorial/Loenn/triggers/SetPassByRefillDashesTrigger.lua
create mode 100644 src/CelesteModTutorial/Maps/CelesteModTutorial/Test.bin
create mode 100644 src/CelesteModTutorial/everest.yaml
diff --git a/docs/coding_challenges/simple_texturing.md b/docs/coding_challenges/simple_texturing.md
index 3924257..d04952b 100644
--- a/docs/coding_challenges/simple_texturing.md
+++ b/docs/coding_challenges/simple_texturing.md
@@ -59,11 +59,12 @@ ok 那么现在我们该在代码这边来点贴图了, 这里我们会用到之
- Graphics
- Atlases
- Gameplay
- - `MyCelesteMod`
- - pass_by_refill.png
+ - objects
+ - PassByRefill
+ - pass_by_refill.png
`pass_by_refill.png` 即我们的贴图, 如果你同时也是一位 mapper 的话你一定很熟悉这个文件夹套套乐!
-在代码这边, 我们使用 `GFX.Game["MyCelesteMod/pass_by_refill"]` 来获取这个贴图, 它是一个 `MTexture` 类型的实例, 在获取到这个贴图后,
+在代码这边, 我们使用 `GFX.Game["objects/PassByRefill/pass_by_refill"]` 来获取这个贴图, 它是一个 `MTexture` 类型的实例, 在获取到这个贴图后,
我们 `new` 一个 `Monocle.Image`, 然后在构造函数中传入它, 然后使用 `this.Add` 函数挂载到我们的这个实体上, 总的代码应该是这样的:
```cs title="PassByRefill.cs"
public PassByRefill(Vector2 position, int dashes)
@@ -73,16 +74,17 @@ public PassByRefill(Vector2 position, int dashes)
Hitbox hitbox = new(64, 64);
Collider = hitbox;
- MTexture tex = GFX.Game["MyCelesteMod/pass_by_refill"];
+ MTexture tex = GFX.Game["objects/PassByRefill/pass_by_refill"];
Image image = new(tex);
this.Add(image);
}
```
!!! info
- `GFX` 是蔚蓝中的一个管理贴图的类, 我们用它获取到一个贴图组 `Game`, 然后向它检索一个名为 `MyCelesteMod/pass_by_refill` 的贴图, 你可能会疑惑为什么这里的路径只需要后半部分,
- 这是因为 `GFX.Game` 只会检索 `Atlases/Graphics/Gameplay` 中的内容.
- 同样的, `GFX.Portraits` 只会检索 `Atlases/Graphics/Portraits` 中的内容.
+ `GFX` 是蔚蓝中的一个管理贴图的类, 我们用它获取到一个贴图组 `Game`, 然后向它检索一个名为 `objects/PassByRefill/pass_by_refill` 的贴图, 你可能会疑惑为什么这里的路径只需要后半部分,
+
+ 这是因为 `GFX.Game` 只会检索 `Graphics/Atlases/Gameplay` 中的内容.
+ 同样的, `GFX.Portraits` 只会检索 `Graphics/Atlases/Portraits` 中的内容.
顺便记得删掉我们重写的 `Render` 函数, 我们不再需要它了. 总的类应该是这样的:
```cs title="PassByRefill.cs"
@@ -99,7 +101,7 @@ public class PassByRefill : Entity
Hitbox hitbox = new(64, 64);
Collider = hitbox;
- MTexture tex = GFX.Game["MyCelesteMod/pass_by_refill"];
+ MTexture tex = GFX.Game["objects/PassByRefill/pass_by_refill"];
Image image = new(tex);
this.Add(image);
}
@@ -171,7 +173,7 @@ public class PassByRefill : Entity
然后设置 entity 的 `texture` 属性, 这会让 Loenn 为其设置贴图:
```lua
-entity.texture = "MyCelesteMod/pass_by_refill"
+entity.texture = "objects/PassByRefill/pass_by_refill"
```
顺便设置贴图原点为左上角, 否则 Loenn 中的显示可能会与实际游戏中的不同:
```lua
@@ -197,7 +199,7 @@ entity.fieldInformation =
}
}
-entity.texture = "MyCelesteMod/pass_by_refill"
+entity.texture = "objects/PassByRefill/pass_by_refill"
entity.justification = { 0.0, 0.0 }
return entity
diff --git a/docs/index.md b/docs/index.md
index 95cfadf..23fd351 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -6,6 +6,9 @@
大部分文章可能会写的不明不白以至于需要频繁修改, 如果你有更好的修改建议的话欢迎来提 issue.
+实战部分附带一张测试地图供读者下载下来乱弄研究与测试,
+你可以在[这里](resources/CelesteModTutorial.zip)进行下载.
+
那么一切就绪, 可以开始阅读 入门-第一节 了:
[开始 - Celeste Everest MonoMod](basics/celeste_everest_monomod.md)
diff --git a/docs/loenn/basic_configurations.md b/docs/loenn/basic_configurations.md
new file mode 100644
index 0000000..921acee
--- /dev/null
+++ b/docs/loenn/basic_configurations.md
@@ -0,0 +1,19 @@
+# Loenn 基础配置
+
+## Lua
+
+## EntityData
+
+## 基础结构
+
+### placements
+
+### fieldInformation
+
+### fieldOrder
+
+## 基础函数
+
+### selection
+
+### sprite
diff --git a/docs/loenn/effect_structs.md b/docs/loenn/effect_structs.md
new file mode 100644
index 0000000..47a2f7b
--- /dev/null
+++ b/docs/loenn/effect_structs.md
@@ -0,0 +1 @@
+# Effect 结构
\ No newline at end of file
diff --git a/docs/loenn/entity_structs.md b/docs/loenn/entity_structs.md
new file mode 100644
index 0000000..185ea56
--- /dev/null
+++ b/docs/loenn/entity_structs.md
@@ -0,0 +1 @@
+# Entity 结构
\ No newline at end of file
diff --git a/docs/loenn/folder_structure.md b/docs/loenn/folder_structure.md
new file mode 100644
index 0000000..690f718
--- /dev/null
+++ b/docs/loenn/folder_structure.md
@@ -0,0 +1,2 @@
+# Loenn 目录结构
+
diff --git a/docs/loenn/nodes.md b/docs/loenn/nodes.md
new file mode 100644
index 0000000..be51292
--- /dev/null
+++ b/docs/loenn/nodes.md
@@ -0,0 +1 @@
+# Loenn 节点
\ No newline at end of file
diff --git a/docs/loenn/rendering.md b/docs/loenn/rendering.md
new file mode 100644
index 0000000..f332a58
--- /dev/null
+++ b/docs/loenn/rendering.md
@@ -0,0 +1,15 @@
+# Loenn 绘制
+
+## sprite 函数
+
+## Loenn 绘制相关插件
+
+### struct.drawable_line
+
+### struct.drawable_rectangle
+
+### struct.drawable_sprite
+
+### struct.drawable_nine_patch
+
+### struct.drawable_text
\ No newline at end of file
diff --git a/docs/loenn/trigger_structs.md b/docs/loenn/trigger_structs.md
new file mode 100644
index 0000000..7588be9
--- /dev/null
+++ b/docs/loenn/trigger_structs.md
@@ -0,0 +1 @@
+# Trigger 结构
\ No newline at end of file
diff --git a/docs/misc/change_log.md b/docs/misc/change_log.md
index 5403455..3aad0d2 100644
--- a/docs/misc/change_log.md
+++ b/docs/misc/change_log.md
@@ -23,3 +23,6 @@
### 2024.12.16
* 更新项目模板
* 添加跨 Mod 交互
+
+### 2024.12.18
+* 添加测试地图
diff --git a/docs/misc/to_do_list.md b/docs/misc/to_do_list.md
index eeddd79..6350dab 100644
--- a/docs/misc/to_do_list.md
+++ b/docs/misc/to_do_list.md
@@ -12,6 +12,7 @@
| ----------------------------- | ------ |
| 完善跨 mod 交互 | 进行中 |
| 添加测试地图 | 进行中 |
+| 分离 Loenn 节及补充 | 准备中 |
| 更新基础环境配置-模板使用 | 准备中 |
| everest 自带事件 | 计划中 |
| publicizer 的使用 | 计划中 |
@@ -20,6 +21,6 @@
| 重构 hook 节 | 计划中 |
| 分离 DynamicData 相关 | 计划中 |
| 完善 StateMachine | 计划中 |
-| 添加 Effext 相关 | 计划中 |
+| 添加 Effect 相关 | 计划中 |
| 添加 Collider 相关 | 计划中 |
diff --git a/docs/resources/CelesteModTutorial.zip b/docs/resources/CelesteModTutorial.zip
new file mode 100644
index 0000000000000000000000000000000000000000..1fa9ec0de51a96498e10689545b10a96bcd6322f
GIT binary patch
literal 25568
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
literal 0
HcmV?d00001
diff --git a/mkdocs.yml b/mkdocs.yml
index 9062e6f..a6daec4 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -70,6 +70,14 @@ nav:
- Session, Settings, SaveData: "basics/session_settings_savedata.md"
- 进阶:
- 跨 Mod 交互: "advanced/cross_mod_interactions.md"
+ # - Loenn:
+ # - Loenn 目录结构: "loenn/folder_structure.md"
+ # - Loenn 基础配置: "loenn/basic_configurations.md"
+ # - Loenn 节点: "loenn/nodes.md"
+ # - Loenn 绘制: "loenn/rendering.md"
+ # - Entity 结构: "loenn/entity_structs.md"
+ # - Trigger 结构: "loenn/trigger_structs.md"
+ # - Effect 结构: "loenn/effect_structs.md"
- 实战:
- 简单自定义实体: "coding_challenges/simple_entity.md"
- 简单自定义Trigger: "coding_challenges/simple_trigger.md"
diff --git a/src/CelesteModTutorial/CelesteModTutorial.dll b/src/CelesteModTutorial/CelesteModTutorial.dll
new file mode 100644
index 0000000000000000000000000000000000000000..31b13562c823603ef6139220095d6680bbffd329
GIT binary patch
literal 8192
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
+
+ Library
+
+ false
+ false
+ ModFolder
+ copy
+ false
+
+
+
+
+
+
+ net452
+ x86
+
+
+ net7.0
+
+
+
+ true
+ $(CelesteRootPath)
+ $(CelesteRootPath)/legacyRef
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(CelesteAssemblyPath)/Celeste.exe
+ False
+
+
+ $(CelesteAssemblyPath)/Celeste.dll
+ False
+
+
+ $(CelesteAssemblyPath)/FNA.dll
+ False
+
+
+ $(CelesteAssemblyPath)/MMHOOK_Celeste.dll
+ False
+
+
+ $(CelesteAssemblyPath)/YamlDotNet.dll
+ False
+
+
+ $(CelesteAssemblyPath)/MonoMod.Utils.dll
+ False
+
+
+ $(CelesteAssemblyPath)/Mono.Cecil.dll
+ False
+
+
+ $(CelesteAssemblyPath)/MonoMod.RuntimeDetour.dll
+ False
+
+
+
\ No newline at end of file
diff --git a/src/CelesteModTutorial/Code/CelesteMod.targets b/src/CelesteModTutorial/Code/CelesteMod.targets
new file mode 100644
index 0000000..40377d7
--- /dev/null
+++ b/src/CelesteModTutorial/Code/CelesteMod.targets
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/CelesteModTutorial/Code/CelesteModTutorial.csproj b/src/CelesteModTutorial/Code/CelesteModTutorial.csproj
new file mode 100644
index 0000000..666d231
--- /dev/null
+++ b/src/CelesteModTutorial/Code/CelesteModTutorial.csproj
@@ -0,0 +1,19 @@
+
+
+
+
+ $(AssemblyName)
+ preview
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/CelesteModTutorial/Code/CelesteModTutorialModule.cs b/src/CelesteModTutorial/Code/CelesteModTutorialModule.cs
new file mode 100644
index 0000000..b82a686
--- /dev/null
+++ b/src/CelesteModTutorial/Code/CelesteModTutorialModule.cs
@@ -0,0 +1,35 @@
+using MonoMod.ModInterop;
+using System.Reflection;
+
+namespace CelesteModTutorial;
+
+public class CelesteModTutorialModule : EverestModule
+{
+ public static CelesteModTutorialModule Instance { get; private set; }
+
+ public override Type SettingsType => typeof(CelesteModTutorialSettings);
+ public static CelesteModTutorialSettings Settings => (CelesteModTutorialSettings)Instance._Settings;
+
+ public override Type SessionType => typeof(CelesteModTutorialSession);
+ public static CelesteModTutorialSession Session => (CelesteModTutorialSession)Instance._Session;
+
+ public override Type SaveDataType => typeof(CelesteModTutorialSaveData);
+ public static CelesteModTutorialSaveData SaveData => (CelesteModTutorialSaveData)Instance._SaveData;
+
+
+
+ public override void LoadContent(bool firstLoad)
+ {
+ base.LoadContent(firstLoad);
+ }
+
+ public override void Load()
+ {
+ Instance = this;
+ }
+
+ public override void Unload()
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/src/CelesteModTutorial/Code/CelesteModTutorialSaveData.cs b/src/CelesteModTutorial/Code/CelesteModTutorialSaveData.cs
new file mode 100644
index 0000000..60fa5cd
--- /dev/null
+++ b/src/CelesteModTutorial/Code/CelesteModTutorialSaveData.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CelesteModTutorial;
+
+public class CelesteModTutorialSaveData : EverestModuleSaveData
+{
+}
diff --git a/src/CelesteModTutorial/Code/CelesteModTutorialSession.cs b/src/CelesteModTutorial/Code/CelesteModTutorialSession.cs
new file mode 100644
index 0000000..02d2781
--- /dev/null
+++ b/src/CelesteModTutorial/Code/CelesteModTutorialSession.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CelesteModTutorial;
+
+public class CelesteModTutorialSession : EverestModuleSession
+{
+}
diff --git a/src/CelesteModTutorial/Code/CelesteModTutorialSettings.cs b/src/CelesteModTutorial/Code/CelesteModTutorialSettings.cs
new file mode 100644
index 0000000..f4c0d17
--- /dev/null
+++ b/src/CelesteModTutorial/Code/CelesteModTutorialSettings.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CelesteModTutorial;
+
+public class CelesteModTutorialSettings : EverestModuleSettings
+{
+}
diff --git a/src/CelesteModTutorial/Code/Common.props b/src/CelesteModTutorial/Code/Common.props
new file mode 100644
index 0000000..6da7abf
--- /dev/null
+++ b/src/CelesteModTutorial/Code/Common.props
@@ -0,0 +1,11 @@
+
+
+ D:\Steam\steamapps\common\Celeste
+ true
+ true
+ ModFolder
+
+ copy
+ False
+
+
\ No newline at end of file
diff --git a/src/CelesteModTutorial/Code/Entities/PassByRefill.cs b/src/CelesteModTutorial/Code/Entities/PassByRefill.cs
new file mode 100644
index 0000000..84cda12
--- /dev/null
+++ b/src/CelesteModTutorial/Code/Entities/PassByRefill.cs
@@ -0,0 +1,52 @@
+using Celeste.Mod.Entities;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CelesteModTutorial.Entities;
+
+[Tracked]
+[CustomEntity("CelesteModTutorial/PassByRefill")]
+public class PassByRefill : Entity
+{
+ public int Dashes = 0;
+
+ public PassByRefill(Vector2 position, Vector2 size, int dashes)
+ {
+ Position = position;
+ Collider = new Hitbox(64f, 64f);
+ Dashes = dashes;
+ }
+
+ public PassByRefill(EntityData data, Vector2 offset)
+ : this(data.Position + offset, new Vector2(data.Width, data.Height), data.Int("dashes"))
+ {
+
+ }
+
+ public override void Update()
+ {
+ base.Update();
+
+ // 获取 Player 实例 (别害怕!)
+ var player = Scene.Tracker.GetEntity();
+
+ // 检测是否与玩家碰撞
+ if (player is not null && CollideCheck(player))
+ {
+ // 如果碰撞了, 那么设置它的冲刺数
+ player.Dashes = Dashes;
+ }
+ }
+
+ public override void Render()
+ {
+ base.Render();
+
+ Color c = Color.Red;
+ c.A = 127;
+ Draw.Rect(Position, Width, Height, c);
+ }
+}
diff --git a/src/CelesteModTutorial/Code/Entities/PassByRefillWithTexture.cs b/src/CelesteModTutorial/Code/Entities/PassByRefillWithTexture.cs
new file mode 100644
index 0000000..72c60ed
--- /dev/null
+++ b/src/CelesteModTutorial/Code/Entities/PassByRefillWithTexture.cs
@@ -0,0 +1,50 @@
+using Celeste.Mod.Entities;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CelesteModTutorial.Entities;
+
+[Tracked]
+[CustomEntity("CelesteModTutorial/PassByRefillWithTexture")]
+public class PassByRefillWithTexture : Entity
+{
+ public int Dashes = 0;
+
+ public PassByRefillWithTexture(Vector2 position, int dashes)
+ {
+ Position = position;
+ Collider = new Hitbox(64f, 64f);
+ Dashes = dashes;
+
+ // 获取材质
+ MTexture tex = GFX.Game["objects/PassByRefill/pass_by_refill"];
+
+ // 向实体添加 Image 组件
+ Image image = new(tex);
+ Add(image);
+ }
+
+ public PassByRefillWithTexture(EntityData data, Vector2 offset)
+ : this(data.Position + offset, data.Int("dashes"))
+ {
+
+ }
+
+ public override void Update()
+ {
+ base.Update();
+
+ // 获取 Player 实例 (别害怕!)
+ var player = Scene.Tracker.GetEntity();
+
+ // 检测是否与玩家碰撞
+ if (player is not null && CollideCheck(player))
+ {
+ // 如果碰撞了, 那么设置它的冲刺数
+ player.Dashes = Dashes;
+ }
+ }
+}
diff --git a/src/CelesteModTutorial/Code/ModFolder/CelesteModTutorial.dll b/src/CelesteModTutorial/Code/ModFolder/CelesteModTutorial.dll
new file mode 100644
index 0000000000000000000000000000000000000000..31b13562c823603ef6139220095d6680bbffd329
GIT binary patch
literal 8192
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
literal 0
HcmV?d00001
diff --git a/src/CelesteModTutorial/Code/Triggers/SetPassByRefillDashesTrigger.cs b/src/CelesteModTutorial/Code/Triggers/SetPassByRefillDashesTrigger.cs
new file mode 100644
index 0000000..c105db9
--- /dev/null
+++ b/src/CelesteModTutorial/Code/Triggers/SetPassByRefillDashesTrigger.cs
@@ -0,0 +1,40 @@
+using Celeste.Mod.Entities;
+using CelesteModTutorial.Entities;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CelesteModTutorial.Triggers;
+
+[CustomEntity("CelesteModTutorial/SetPassByRefillDashesTrigger")]
+public class SetPassByRefillDashesTrigger : Trigger
+{
+ public int Dashes;
+
+ public SetPassByRefillDashesTrigger(EntityData data, Vector2 offset)
+ : base(data, offset)
+ {
+ Dashes = data.Int("dashes");
+ }
+
+ public override void OnEnter(Player player)
+ {
+ base.OnEnter(player);
+
+ // 获取所有的 PassByRefill
+ var refills = Scene.Tracker.GetEntities().Cast();
+ foreach (var refill in refills)
+ {
+ refill.Dashes = Dashes;
+ }
+
+ // 获取所有的 PassByRefillWithTexture
+ var refillsWithTexture = Scene.Tracker.GetEntities().Cast();
+ foreach (var refillWithTexture in refillsWithTexture)
+ {
+ refillWithTexture.Dashes = Dashes;
+ }
+ }
+}
diff --git a/src/CelesteModTutorial/Dialog/English.txt b/src/CelesteModTutorial/Dialog/English.txt
new file mode 100644
index 0000000..c1782fc
--- /dev/null
+++ b/src/CelesteModTutorial/Dialog/English.txt
@@ -0,0 +1,9 @@
+# Inline Text Commands:
+# {~}wavy text{/~}
+# {!}impact text{/!}
+# {>> x}changes speed at which characters are displayed{>>}
+# {# 000000}this text is black{#} (uses HEX color values)
+# {+MENU_BEGIN} inserts the dialog from the MENU_BEGIN value (in English, "CLIMB")
+# {n} creates a newline, without a page break
+# {0.5} creates a 0.5 second pause
+# {big}this text is large{/big}
diff --git a/src/CelesteModTutorial/Dialog/Simplified Chinese.txt b/src/CelesteModTutorial/Dialog/Simplified Chinese.txt
new file mode 100644
index 0000000..c1782fc
--- /dev/null
+++ b/src/CelesteModTutorial/Dialog/Simplified Chinese.txt
@@ -0,0 +1,9 @@
+# Inline Text Commands:
+# {~}wavy text{/~}
+# {!}impact text{/!}
+# {>> x}changes speed at which characters are displayed{>>}
+# {# 000000}this text is black{#} (uses HEX color values)
+# {+MENU_BEGIN} inserts the dialog from the MENU_BEGIN value (in English, "CLIMB")
+# {n} creates a newline, without a page break
+# {0.5} creates a 0.5 second pause
+# {big}this text is large{/big}
diff --git a/src/CelesteModTutorial/Graphics/Atlases/Gameplay/objects/PassByRefill/pass_by_refill.png b/src/CelesteModTutorial/Graphics/Atlases/Gameplay/objects/PassByRefill/pass_by_refill.png
new file mode 100644
index 0000000000000000000000000000000000000000..575424216e02963e29f35131837428214350af16
GIT binary patch
literal 736
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|SkfJR9T^xl
z_H+M9WCij$3p^r=85sBugD~Uq{1qt-3{0h-E{-7;ac^gz%@%f)ICg(-&dShW7cNa(
z3F(ZrW>pdX6Qu-N{>dtRdvS2_@~V##A66**Q{-w5jj{=0Ef!$$)azPW*C3ypIlFXz
zdHQa{FS|C(v^lS6y!rfY?$77m?6GIk7P9SE*s}I(!QOhEi;sP$*Pgg6U#YmZ_apDd
zUDt19chpoRw{Og9%&t>0-+&cC)rxIQQR=`D%RNB1ZiTU2Ho>aM%X^?Le6_wJ2S
zVTa#2e~<62cM%SpMk8l%MvG`+ceT>eA3DhgJrC`PwsazT2X|KhJ&n
zbNkh`X~&Kp@)a$eDX>pq&Y81{qtq&YK9GB&
zricM5e#0VE@Kwn@J0N$$&nFB}@ePHml&-woQw!uOd_Ktt6;F5^;=1B;p5zSkyV%OSS}58zp9v7xVQSjS-#EvKbLmD
yJuM{_D0C%GM@89IR`_As_G4vFL-(yYY5&bG_1nuL?nS^<$>8bg=d#Wzp$P!dP)&LO
literal 0
HcmV?d00001
diff --git a/src/CelesteModTutorial/Loenn/entities/PassByRefill.lua b/src/CelesteModTutorial/Loenn/entities/PassByRefill.lua
new file mode 100644
index 0000000..17a48c2
--- /dev/null
+++ b/src/CelesteModTutorial/Loenn/entities/PassByRefill.lua
@@ -0,0 +1,20 @@
+local entity = {}
+
+entity.name = "CelesteModTutorial/PassByRefill"
+entity.placements = {
+ name = "normal",
+ data = {
+ width = 16,
+ height = 16,
+ dashes = 1
+ }
+}
+
+entity.fieldInformation =
+{
+ dashes = {
+ fieldType = "integer"
+ }
+}
+
+return entity
\ No newline at end of file
diff --git a/src/CelesteModTutorial/Loenn/entities/PassByRefillWithTexture.lua b/src/CelesteModTutorial/Loenn/entities/PassByRefillWithTexture.lua
new file mode 100644
index 0000000..fd67658
--- /dev/null
+++ b/src/CelesteModTutorial/Loenn/entities/PassByRefillWithTexture.lua
@@ -0,0 +1,21 @@
+local entity = {}
+
+entity.name = "CelesteModTutorial/PassByRefillWithTexture"
+entity.placements = {
+ name = "normal",
+ data = {
+ dashes = 1
+ }
+}
+
+entity.fieldInformation =
+{
+ dashes = {
+ fieldType = "integer"
+ }
+}
+
+entity.texture = "objects/PassByRefill/pass_by_refill"
+entity.justification = { 0.0, 0.0 }
+
+return entity
\ No newline at end of file
diff --git a/src/CelesteModTutorial/Loenn/lang/en_gb.lang b/src/CelesteModTutorial/Loenn/lang/en_gb.lang
new file mode 100644
index 0000000..373971e
--- /dev/null
+++ b/src/CelesteModTutorial/Loenn/lang/en_gb.lang
@@ -0,0 +1,4 @@
+entities.CelesteModTutorial/PassByRefill.placements.name.normal=PassByRefill
+entities.CelesteModTutorial/PassByRefillWithTexture.placements.name.normal=PassByRefillWithTexture
+
+triggers.CelesteModTutorial/SetPassByRefillDashesTrigger.placements.name.normal=SetPassByRefillDashesTrigger
\ No newline at end of file
diff --git a/src/CelesteModTutorial/Loenn/triggers/SetPassByRefillDashesTrigger.lua b/src/CelesteModTutorial/Loenn/triggers/SetPassByRefillDashesTrigger.lua
new file mode 100644
index 0000000..597c758
--- /dev/null
+++ b/src/CelesteModTutorial/Loenn/triggers/SetPassByRefillDashesTrigger.lua
@@ -0,0 +1,20 @@
+local trigger = {}
+
+trigger.name = "CelesteModTutorial/SetPassByRefillDashesTrigger"
+trigger.placements = {
+ name = "normal",
+ data = {
+ width = 16,
+ height = 16,
+ dashes = 2
+ }
+}
+
+trigger.fieldInformation =
+{
+ dashes = {
+ fieldType = "integer"
+ }
+}
+
+return trigger
\ No newline at end of file
diff --git a/src/CelesteModTutorial/Maps/CelesteModTutorial/Test.bin b/src/CelesteModTutorial/Maps/CelesteModTutorial/Test.bin
new file mode 100644
index 0000000000000000000000000000000000000000..8d4d121edd1bcbcedf32566a93da4b6799d53cf3
GIT binary patch
literal 790
zcmah`+j7$|5M4R8b1^9`G!U*W_fjt9_5rj_`qa=2@eJjuqu3i;6GhHQ3U2;}M?Qg1
z;xky8b|%a)!-Mund-kl(O3`8exIc>f+k^cfyar&)U}TpP+p~oc$xs)WMq>hr-%y5C
zH0yje7N`=uWW$u398GJXQq(24sKdGBOVpiI7(SNRD@qk>u8gpvP)(r}>KM;$lS_M6
zUF64T?A9Sl0vr@+ys(89T<#6IF$c@fI1y4tRq3(o{B~vkjwLIn_rBsY3`&vOd?o!M
zI^fAP(*>C{e#-T9BSkW~FYUlhdc;!W0-K%TSxZ%z1+CguH5gGMN~(r~aoxVdIR5DbN1q
zz6RCop(&(DO>|UfyqLuk>E1sKkI=3@U9b9~_|N5y%MYv#`1}>HClCO5E->(+d!JyP
z_8WxP2y2eH1?=Zd0O-~1Grr&ei3;}iW>EzB(?M4xzpZo;Ws^j$ddp7
literal 0
HcmV?d00001
diff --git a/src/CelesteModTutorial/everest.yaml b/src/CelesteModTutorial/everest.yaml
new file mode 100644
index 0000000..a98aa18
--- /dev/null
+++ b/src/CelesteModTutorial/everest.yaml
@@ -0,0 +1,7 @@
+- Name: CelesteModTutorial
+ Version: 0.0.1
+ DLL: CelesteModTutorial.dll
+ Dependencies:
+ - Name: Everest
+ Version: 1.4000.0
+