├── .gitattributes
├── .gitignore
├── .gitmodules
├── LICENSE
├── MMHOOK_Celeste.dll
├── README.md
├── RainbowMod.sln
├── RainbowMod
├── Content
│ ├── Dialog
│ │ └── English.txt
│ └── Graphics
│ │ └── Atlases
│ │ └── Gameplay
│ │ └── characters
│ │ └── player
│ │ ├── dab.png
│ │ ├── foxbangs00.png
│ │ ├── foxbangs01.png
│ │ ├── foxbangs02.png
│ │ ├── foxhair00.png
│ │ ├── foxhair01.png
│ │ └── skateboard.png
├── Properties
│ └── AssemblyInfo.cs
├── RainbowMod.csproj
├── RainbowModule.cs
├── RainbowModuleSettings.cs
├── everest.yaml
├── packages.config
└── settings.celeste
└── rainbowdeline.gif
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Windows Store app package directory
170 | AppPackages/
171 | BundleArtifacts/
172 |
173 | # Visual Studio cache files
174 | # files ending in .cache can be ignored
175 | *.[Cc]ache
176 | # but keep track of directories ending in .cache
177 | !*.[Cc]ache/
178 |
179 | # Others
180 | ClientBin/
181 | [Ss]tyle[Cc]op.*
182 | ~$*
183 | *~
184 | *.dbmdl
185 | *.dbproj.schemaview
186 | *.pfx
187 | *.publishsettings
188 | node_modules/
189 | orleans.codegen.cs
190 |
191 | # RIA/Silverlight projects
192 | Generated_Code/
193 |
194 | # Backup & report files from converting an old project file
195 | # to a newer Visual Studio version. Backup files are not needed,
196 | # because we have git ;-)
197 | _UpgradeReport_Files/
198 | Backup*/
199 | UpgradeLog*.XML
200 | UpgradeLog*.htm
201 |
202 | # SQL Server files
203 | *.mdf
204 | *.ldf
205 |
206 | # Business Intelligence projects
207 | *.rdl.data
208 | *.bim.layout
209 | *.bim_*.settings
210 |
211 | # Microsoft Fakes
212 | FakesAssemblies/
213 |
214 | # GhostDoc plugin setting file
215 | *.GhostDoc.xml
216 |
217 | # Node.js Tools for Visual Studio
218 | .ntvs_analysis.dat
219 |
220 | # Visual Studio 6 build log
221 | *.plg
222 |
223 | # Visual Studio 6 workspace options file
224 | *.opt
225 |
226 | # Visual Studio LightSwitch build output
227 | **/*.HTMLClient/GeneratedArtifacts
228 | **/*.DesktopClient/GeneratedArtifacts
229 | **/*.DesktopClient/ModelManifest.xml
230 | **/*.Server/GeneratedArtifacts
231 | **/*.Server/ModelManifest.xml
232 | _Pvt_Extensions
233 |
234 | # LightSwitch generated files
235 | GeneratedArtifacts/
236 | ModelManifest.xml
237 |
238 | # Paket dependency manager
239 | .paket/paket.exe
240 |
241 | # FAKE - F# Make
242 | .fake/
243 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "Everest"]
2 | path = Everest
3 | url = https://github.com/EverestAPI/Everest.git
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Everest Team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MMHOOK_Celeste.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EverestAPI/RainbowMod/HEAD/MMHOOK_Celeste.dll
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Everest RainbodMod
2 |
3 | ### License: MIT
4 |
5 | ----
6 |
7 | Sample mod - Make Madeline's hair and dash be rainbows.
8 |
9 | 
10 |
11 | [Install Everest](https://everestapi.github.io/), download the mod `.zip` [here](/releases) and place it in your `Mods` directory. Don't extract anything.
12 |
13 | For more information about mod _development_, read the [Everest README.md](https://github.com/EverestAPI/Everest/blob/master/README.md)
14 |
--------------------------------------------------------------------------------
/RainbowMod.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RainbowMod", "RainbowMod\RainbowMod.csproj", "{8CBA6958-CD94-44B4-970B-5FC3DBE6B019}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Celeste.Mod.mm", "Everest\Celeste.Mod.mm\Celeste.Mod.mm.csproj", "{D5D0239D-FF95-4897-9484-1898AB7E82F5}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {8CBA6958-CD94-44B4-970B-5FC3DBE6B019}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {8CBA6958-CD94-44B4-970B-5FC3DBE6B019}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {8CBA6958-CD94-44B4-970B-5FC3DBE6B019}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {8CBA6958-CD94-44B4-970B-5FC3DBE6B019}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {D5D0239D-FF95-4897-9484-1898AB7E82F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {D5D0239D-FF95-4897-9484-1898AB7E82F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {D5D0239D-FF95-4897-9484-1898AB7E82F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {D5D0239D-FF95-4897-9484-1898AB7E82F5}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/RainbowMod/Content/Dialog/English.txt:
--------------------------------------------------------------------------------
1 | # NOTES:
2 | # The # Symbol at the start of a line counts as a Comment. To include in dialog, use a \#
3 | # The . Symbol will cause a pause unless escaped with \. (ex: Mr. Oshiro has a pause, Mr\. Oshiro does not)
4 | # Newlines automatically create a Page Break, unless there is an {n} command on the previous line
5 | # Commands: Anything inside of curly braces {...} is a command and should not be translated.
6 |
7 | # Inline Text Commands:
8 | # {~}wavy text{/~}
9 | # {!}impact text{/!}
10 | # {>> x}changes speed at which characters are displayed{>>}
11 | # {# 000000}this text is black{#} (uses HEX color values)
12 | # {+MENU_BEGIN} inserts the dialog from the MENU_BEGIN value (in English, "CLIMB")
13 | # {n} creates a newline, without a page break
14 | # {0.5} creates a 0.5 second pause
15 | # {big}this text is large{/big}
16 |
17 | # Gameplay Control Commands (should never change)
18 | # {trigger x} this triggers an in-game event
19 | # {anchor} controls the visual position of the textbox in-game
20 |
21 | # Rainbow Module Options
22 | MODOPTIONS_RAINBOWMODULE_TITLE= Fabeline
23 | MODOPTIONS_RAINBOWMODULE_ENABLED= Enabled
24 | MODOPTIONS_RAINBOWMODULE_SPEED= Speed
25 | MODOPTIONS_RAINBOWMODULE_RELOADCOLORS= Reload Color Settings
26 |
--------------------------------------------------------------------------------
/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/dab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EverestAPI/RainbowMod/HEAD/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/dab.png
--------------------------------------------------------------------------------
/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/foxbangs00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EverestAPI/RainbowMod/HEAD/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/foxbangs00.png
--------------------------------------------------------------------------------
/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/foxbangs01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EverestAPI/RainbowMod/HEAD/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/foxbangs01.png
--------------------------------------------------------------------------------
/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/foxbangs02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EverestAPI/RainbowMod/HEAD/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/foxbangs02.png
--------------------------------------------------------------------------------
/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/foxhair00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EverestAPI/RainbowMod/HEAD/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/foxhair00.png
--------------------------------------------------------------------------------
/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/foxhair01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EverestAPI/RainbowMod/HEAD/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/foxhair01.png
--------------------------------------------------------------------------------
/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/skateboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EverestAPI/RainbowMod/HEAD/RainbowMod/Content/Graphics/Atlases/Gameplay/characters/player/skateboard.png
--------------------------------------------------------------------------------
/RainbowMod/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("RainbowMod")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("RainbowMod")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("8cba6958-cd94-44b4-970b-5fc3dbe6b019")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/RainbowMod/RainbowMod.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {8CBA6958-CD94-44B4-970B-5FC3DBE6B019}
7 | Library
8 | Properties
9 | Celeste.Mod.Rainbow
10 | RainbowMod
11 | v4.5.2
12 | 512
13 | Artifact\
14 |
15 |
16 |
17 |
18 | true
19 | bin\Debug\
20 | DEBUG;TRACE
21 | true
22 | full
23 | AnyCPU
24 | prompt
25 | 4
26 |
27 |
28 | bin\Release\
29 | TRACE
30 | true
31 | true
32 | pdbonly
33 | AnyCPU
34 | prompt
35 | 4
36 |
37 |
38 |
39 | ..\Everest\lib-stripped\Celeste.exe
40 | False
41 |
42 |
43 | ..\Everest\lib-stripped\FNA.dll
44 | False
45 |
46 |
47 | ..\MMHOOK_Celeste.dll
48 | False
49 |
50 |
51 | ..\packages\Mono.Cecil.0.10.0\lib\net40\Mono.Cecil.dll
52 | False
53 |
54 |
55 | ..\packages\Mono.Cecil.0.10.0\lib\net40\Mono.Cecil.Mdb.dll
56 | False
57 |
58 |
59 | ..\packages\Mono.Cecil.0.10.0\lib\net40\Mono.Cecil.Pdb.dll
60 | False
61 |
62 |
63 | ..\packages\Mono.Cecil.0.10.0\lib\net40\Mono.Cecil.Rocks.dll
64 | False
65 |
66 |
67 | ..\Everest\lib-stripped\Steamworks.NET.dll
68 | False
69 |
70 |
71 |
72 |
73 | ..\Everest\lib\YamlDotNet.dll
74 | False
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | {d5d0239d-ff95-4897-9484-1898ab7e82f5}
85 | Celeste.Mod.mm
86 | False
87 |
88 |
89 |
90 |
91 | PreserveNewest
92 |
93 |
94 |
95 |
96 |
97 | Content\Dialog\English.txt
98 |
99 |
100 | Content\Graphics\Atlases\Gameplay\characters\player\foxbangs00.png
101 |
102 |
103 | Content\Graphics\Atlases\Gameplay\characters\player\foxbangs01.png
104 |
105 |
106 | Content\Graphics\Atlases\Gameplay\characters\player\foxbangs02.png
107 |
108 |
109 | Content\Graphics\Atlases\Gameplay\characters\player\foxhair00.png
110 |
111 |
112 | Content\Graphics\Atlases\Gameplay\characters\player\foxhair01.png
113 |
114 |
115 | Content\Graphics\Atlases\Gameplay\characters\player\skateboard.png
116 |
117 |
118 | Content\Graphics\Atlases\Gameplay\characters\player\dab.png
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/RainbowMod/RainbowModule.cs:
--------------------------------------------------------------------------------
1 | using Celeste.Mod;
2 | using FMOD.Studio;
3 | using Microsoft.Xna.Framework;
4 | using Monocle;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Reflection;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using On.Celeste;
12 | using Mono.Cecil.Cil;
13 |
14 | namespace Celeste.Mod.Rainbow {
15 | public class RainbowModule : EverestModule {
16 |
17 | public static RainbowModule Instance;
18 |
19 | public override Type SettingsType => typeof(RainbowModuleSettings);
20 | public static RainbowModuleSettings Settings => (RainbowModuleSettings) Instance._Settings;
21 |
22 | private static int trailIndex = 0;
23 |
24 | private static List FoxBangs;
25 | private static List FoxHair;
26 |
27 | private static MTexture Skateboard;
28 | private readonly static Vector2 SkateboardPlayerOffset = new Vector2(0, -3);
29 |
30 | private static MTexture Dab;
31 | private readonly static Vector2 DabPlayerOffset = new Vector2(0, -5);
32 |
33 | public RainbowModule() {
34 | Instance = this;
35 | }
36 |
37 | public override void LoadSettings() {
38 | base.LoadSettings();
39 |
40 | bool updated = false;
41 |
42 | if (Settings.FoxColorLight.A == 0) {
43 | Settings.FoxColorLight = new Color(0.8f, 0.5f, 0.05f, 1f);
44 | updated = true;
45 | }
46 | if (Settings.FoxColorDark.A == 0) {
47 | Settings.FoxColorDark = new Color(0.1f, 0.05f, 0f, 1f);
48 | updated = true;
49 | }
50 |
51 | if (updated) {
52 | SaveSettings();
53 | }
54 | }
55 |
56 | public override void Load() {
57 | // This is a runtime mod, but we can still manipulate the game.
58 |
59 | #if false // Set this to true if you want to demo new HookGen features.
60 |
61 | // Let's hook Celeste.Player.GetTrailColor
62 | On.Celeste.Player.GetTrailColor += (orig, player, wasDashB) => {
63 | Console.WriteLine("1 - Hello, World!");
64 |
65 | // Get the "original" color and manipulate it.
66 | // This step is optional - we can return anything we want.
67 | // We can also pass anything to the orig method.
68 | Color color = orig(player, wasDashB);
69 |
70 | // If the player is facing left, display a modified color.
71 | if (player.Facing == Facings.Left)
72 | return new Color(0xFF, color.G, color.B, color.A);
73 |
74 | return color;
75 | };
76 |
77 | IL.Celeste.Player.GetTrailColor += (body, il) => {
78 | // Let'd dump the method before manipulating it.
79 | Console.WriteLine("MANIPULATING " + body.Method);
80 | foreach (Instruction i in body.Instructions)
81 | Console.WriteLine(i);
82 |
83 | int index = 0;
84 |
85 | // Insert Console.WriteLine(...) at the beginning.
86 | il.Emit(ref index, OpCodes.Ldstr, "2 - Hello, IL manipulation!");
87 | il.Emit(ref index, OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
88 |
89 | // After that, emit an inline delegate call.
90 | il.EmitDelegateCall(ref index, () => {
91 | Console.WriteLine("3 - Hello, C# code in IL!");
92 | });
93 |
94 | // Note that we can also insert any arbitrary delegate anywhere.
95 | // We know that the original method ends with ldloc.0, then ret
96 | // Let's wrap ldloc.0 with a delegate call, then invoke it before ret.
97 | if (il.GotoNext(ref index, (instrs, i) =>
98 | instrs[i + 0].OpCode == OpCodes.Ldloc_0 &&
99 | instrs[i + 1].OpCode == OpCodes.Ret
100 | )) {
101 | // Note that we also need to update any branches pointing towards ldloc.0
102 | // We only need to do this because we know that there's at least one jump to ldloc.0
103 | int indexPush = index;
104 | int delegateID = il.EmitDelegatePush>(ref index, color => {
105 | Console.WriteLine("4 - Hello, arbitrary C# code in IL!");
106 | color.G = 0xFF;
107 | return color;
108 | });
109 | il.UpdateBranches(index, indexPush);
110 |
111 | index += 1; // Skip ldloc.0
112 |
113 | il.EmitDelegateInvoke(ref index, delegateID);
114 | // The delegate returns a modified color, which gets returned by the following ret instruction.
115 |
116 | } else {
117 | // If we know that there are multiple versions, we could chain them via else-ifs.
118 | // Otherwise, do nothing (or throw an exception).
119 | }
120 |
121 | // Leave the rest of the method unmodified.
122 | };
123 |
124 | #endif
125 |
126 | On.Celeste.PlayerHair.GetHairColor += GetHairColor;
127 | On.Celeste.Player.GetTrailColor += GetTrailColor;
128 | On.Celeste.PlayerHair.GetHairTexture += GetHairTexture;
129 | On.Celeste.PlayerHair.Render += RenderHair;
130 | On.Celeste.Player.Render += RenderPlayer;
131 | On.Celeste.PlayerSprite.Render += RenderPlayerSprite;
132 | }
133 |
134 | public override void LoadContent(bool firstLoad) {
135 | FoxBangs = GFX.Game.GetAtlasSubtextures("characters/player/foxbangs");
136 | FoxHair = GFX.Game.GetAtlasSubtextures("characters/player/foxhair");
137 | Skateboard = GFX.Game["characters/player/skateboard"];
138 | Dab = GFX.Game["characters/player/dab"];
139 | }
140 |
141 | public override void Unload() {
142 | On.Celeste.PlayerHair.GetHairColor -= GetHairColor;
143 | On.Celeste.Player.GetTrailColor -= GetTrailColor;
144 | On.Celeste.PlayerHair.GetHairTexture -= GetHairTexture;
145 | On.Celeste.PlayerHair.Render -= RenderHair;
146 | On.Celeste.Player.Render -= RenderPlayer;
147 | On.Celeste.PlayerSprite.Render -= RenderPlayerSprite;
148 | }
149 |
150 | public override void CreateModMenuSection(TextMenu menu, bool inGame, EventInstance snapshot) {
151 | base.CreateModMenuSection(menu, inGame, snapshot);
152 |
153 | if (inGame) {
154 | menu.Add(new TextMenu.Button(Dialog.Clean("modoptions_rainbowmodule_reloadcolors")).Pressed(() => {
155 | // Temporarily store current settings, load new settings and replace colors.
156 | RainbowModuleSettings settings = Settings;
157 | LoadSettings();
158 | settings.FoxColorLight = Settings.FoxColorLight;
159 | settings.FoxColorDark = Settings.FoxColorDark;
160 | _Settings = settings;
161 | }));
162 | }
163 | }
164 |
165 | public static Color GetHairColor(On.Celeste.PlayerHair.orig_GetHairColor orig, PlayerHair self, int index) {
166 | Color colorOrig = orig(self, index);
167 | if (!(self.Entity is Player) || self.GetSprite().Mode == PlayerSpriteMode.Badeline)
168 | return colorOrig;
169 |
170 | Color color = colorOrig;
171 |
172 | if (Settings.FoxEnabled) {
173 | Color colorFox;
174 | if (index % 2 == 0) {
175 | colorFox = Settings.FoxColorLight;
176 | color = new Color(
177 | (color.R / 255f) * 0.1f + (colorFox.R / 255f) * 0.9f,
178 | (color.G / 255f) * 0.05f + (colorFox.G / 255f) * 0.95f,
179 | (color.B / 255f) * 0.2f + (colorFox.B / 255f) * 0.8f,
180 | color.A
181 | );
182 | } else {
183 | colorFox = Settings.FoxColorDark;
184 | color = new Color(
185 | (color.R / 255f) * 0.1f + (colorFox.R / 255f) * 0.7f,
186 | (color.G / 255f) * 0.1f + (colorFox.G / 255f) * 0.7f,
187 | (color.B / 255f) * 0.1f + (colorFox.B / 255f) * 0.7f,
188 | color.A
189 | );
190 | }
191 | }
192 |
193 | if (Settings.RainbowEnabled) {
194 | float wave = self.GetWave() * 60f;
195 | wave *= Settings.RainbowSpeedFactor;
196 | Color colorRainbow = ColorFromHSV((index / (float) self.GetSprite().HairCount) * 180f + wave, 0.6f, 1.0f);
197 | color = new Color(
198 | (color.R / 255f) * 0.3f + (colorRainbow.R / 255f) * 0.7f,
199 | (color.G / 255f) * 0.3f + (colorRainbow.G / 255f) * 0.7f,
200 | (color.B / 255f) * 0.3f + (colorRainbow.B / 255f) * 0.7f,
201 | color.A
202 | );
203 | }
204 |
205 | color.A = colorOrig.A;
206 | return color;
207 | }
208 |
209 | public static Color GetTrailColor(On.Celeste.Player.orig_GetTrailColor orig, Player self, bool wasDashB) {
210 | if (!Settings.RainbowEnabled || self.Sprite.Mode == PlayerSpriteMode.Badeline || self.Hair == null)
211 | return orig(self, wasDashB);
212 |
213 | return self.Hair.GetHairColor((trailIndex++) % self.Hair.GetSprite().HairCount);
214 | }
215 |
216 | public static MTexture GetHairTexture(On.Celeste.PlayerHair.orig_GetHairTexture orig, PlayerHair self, int index) {
217 | if (!(self.Entity is Player) || self.GetSprite().Mode == PlayerSpriteMode.Badeline)
218 | return orig(self, index);
219 |
220 | if (Settings.FoxEnabled) {
221 | if (index == 0)
222 | return FoxBangs[self.GetSprite().HairFrame];
223 | return FoxHair[index % FoxHair.Count];
224 | }
225 |
226 | return orig(self, index);
227 | }
228 |
229 | public static void RenderHair(On.Celeste.PlayerHair.orig_Render orig, PlayerHair self) {
230 | if (Settings.BaldelineEnabled) return;
231 | Player player = self.Entity as Player;
232 | if (player == null || self.GetSprite().Mode == PlayerSpriteMode.Badeline) {
233 | orig(self);
234 | return;
235 | }
236 |
237 | if (Settings.SkateboardEnabled)
238 | for (int i = 0; i < self.Nodes.Count; i++)
239 | self.Nodes[i] = self.Nodes[i] + SkateboardPlayerOffset;
240 | if (Settings.DuckToDabEnabled && player.Ducking)
241 | for (int i = 0; i < self.Nodes.Count; i++)
242 | self.Nodes[i] = self.Nodes[i] + DabPlayerOffset;
243 |
244 | if (Settings.WoomyEnabled) {
245 | PlayerSprite sprite = self.GetSprite();
246 | if (!sprite.HasHair)
247 | return;
248 |
249 | const float woomyOffs = 3f;
250 | Vector2 woomyScaleMul = new Vector2(0.7f, 0.7f);
251 | Vector2 woomyScaleOffs = new Vector2(-0.2f, -0.2f);
252 |
253 | Vector2 origin = new Vector2(5f, 5f);
254 | Color colorBorder = self.Border * self.Alpha;
255 |
256 | RenderHairPlayerOutline(self);
257 |
258 | Vector2 pos;
259 | MTexture tex;
260 | Color color;
261 | Vector2 scale;
262 |
263 | self.Nodes[0] = self.Nodes[0].Floor();
264 |
265 | if (colorBorder.A > 0) {
266 | tex = self.GetHairTexture(0);
267 | scale = self.GetHairScale(0);
268 | pos = self.Nodes[0];
269 | tex.Draw(pos + new Vector2(-1f, 0f), origin, colorBorder, scale);
270 | tex.Draw(pos + new Vector2( 1f, 0f), origin, colorBorder, scale);
271 | tex.Draw(pos + new Vector2(0f, -1f), origin, colorBorder, scale);
272 | tex.Draw(pos + new Vector2( 0f, 1f), origin, colorBorder, scale);
273 |
274 | tex = self.GetHairTexture(2);
275 | scale = self.GetHairScale(sprite.HairCount - 2) * woomyScaleMul + woomyScaleOffs;
276 | pos = self.Nodes[0];
277 | tex.Draw(pos + new Vector2(-1f - woomyOffs, 0f), origin, colorBorder, scale);
278 | tex.Draw(pos + new Vector2( 1f - woomyOffs, 0f), origin, colorBorder, scale);
279 | tex.Draw(pos + new Vector2( 0f - woomyOffs, -1f), origin, colorBorder, scale);
280 | tex.Draw(pos + new Vector2( 0f - woomyOffs, 1f), origin, colorBorder, scale);
281 | tex.Draw(pos + new Vector2(-1f + woomyOffs, 0f), origin, colorBorder, scale);
282 | tex.Draw(pos + new Vector2( 1f + woomyOffs, 0f), origin, colorBorder, scale);
283 | tex.Draw(pos + new Vector2( 0f + woomyOffs, -1f), origin, colorBorder, scale);
284 | tex.Draw(pos + new Vector2( 0f + woomyOffs, 1f), origin, colorBorder, scale);
285 |
286 | for (int i = 1; i < sprite.HairCount; i++) {
287 | tex = self.GetHairTexture(i);
288 | scale = self.GetHairScale(sprite.HairCount - i - 1) * woomyScaleMul + woomyScaleOffs;
289 | pos = self.Nodes[i];
290 | tex.Draw(pos + new Vector2(-1f - woomyOffs, 0f), origin, colorBorder, scale);
291 | tex.Draw(pos + new Vector2( 1f - woomyOffs, 0f), origin, colorBorder, scale);
292 | tex.Draw(pos + new Vector2( 0f - woomyOffs, -1f), origin, colorBorder, scale);
293 | tex.Draw(pos + new Vector2( 0f - woomyOffs, 1f), origin, colorBorder, scale);
294 | tex.Draw(pos + new Vector2(-1f + woomyOffs, 0f), origin, colorBorder, scale);
295 | tex.Draw(pos + new Vector2( 1f + woomyOffs, 0f), origin, colorBorder, scale);
296 | tex.Draw(pos + new Vector2( 0f + woomyOffs, -1f), origin, colorBorder, scale);
297 | tex.Draw(pos + new Vector2( 0f + woomyOffs, 1f), origin, colorBorder, scale);
298 | }
299 | }
300 |
301 | tex = self.GetHairTexture(0);
302 | color = self.GetHairColor(0);
303 | scale = self.GetHairScale(0);
304 | tex.Draw(self.Nodes[0], origin, color, scale);
305 |
306 | tex = self.GetHairTexture(2);
307 | color = self.GetHairColor(0);
308 | scale = self.GetHairScale(sprite.HairCount - 2) * woomyScaleMul + woomyScaleOffs;
309 | tex.Draw(self.Nodes[0] + new Vector2(-woomyOffs, 0f), origin, color, scale);
310 | tex.Draw(self.Nodes[0] + new Vector2( woomyOffs, 0f), origin, color, scale);
311 |
312 | for (int i = sprite.HairCount - 1; i >= 1; i--) {
313 | tex = self.GetHairTexture(i);
314 | color = self.GetHairColor(i);
315 | scale = self.GetHairScale(sprite.HairCount - i - 1) * woomyScaleMul + woomyScaleOffs;
316 | tex.Draw(self.Nodes[i] + new Vector2(-woomyOffs, 0f), origin, color, scale);
317 | tex.Draw(self.Nodes[i] + new Vector2( woomyOffs, 0f), origin, color, scale);
318 | }
319 |
320 | goto End;
321 | }
322 |
323 | orig(self);
324 |
325 | End:
326 | if (Settings.SkateboardEnabled)
327 | for (int i = 0; i < self.Nodes.Count; i++)
328 | self.Nodes[i] = self.Nodes[i] - SkateboardPlayerOffset;
329 | if (Settings.DuckToDabEnabled && player.Ducking)
330 | for (int i = 0; i < self.Nodes.Count; i++)
331 | self.Nodes[i] = self.Nodes[i] - DabPlayerOffset;
332 | }
333 |
334 | private static void RenderHairPlayerOutline(PlayerHair self) {
335 | PlayerSprite sprite = self.GetSprite();
336 | if (!self.DrawPlayerSpriteOutline)
337 | return;
338 |
339 | Vector2 origin = sprite.Position;
340 | Color color = sprite.Color;
341 |
342 | sprite.Color = self.Border * self.Alpha;
343 |
344 | sprite.Position = origin + new Vector2(0f, -1f);
345 | sprite.Render();
346 | sprite.Position = origin + new Vector2(0f, 1f);
347 | sprite.Render();
348 | sprite.Position = origin + new Vector2(-1f, 0f);
349 | sprite.Render();
350 | sprite.Position = origin + new Vector2(1f, 0f);
351 | sprite.Render();
352 |
353 | sprite.Color = color;
354 | sprite.Position = origin;
355 | }
356 |
357 | public static void RenderPlayer(On.Celeste.Player.orig_Render orig, Player self) {
358 | Vector2 renderPos = self.Sprite.RenderPosition;
359 |
360 | if (Settings.SkateboardEnabled)
361 | self.Sprite.RenderPosition += SkateboardPlayerOffset;
362 | if (Settings.DuckToDabEnabled && self.Ducking)
363 | self.Sprite.RenderPosition += DabPlayerOffset;
364 |
365 | orig(self);
366 |
367 | if (Settings.SkateboardEnabled) {
368 | Skateboard.Draw(
369 | renderPos.Floor() + new Vector2(self.Facing == Facings.Left ? 9 : -8, -4),
370 | Vector2.Zero, Color.White,
371 | new Vector2(self.Facing == Facings.Left ? -1 : 1, 1)
372 | );
373 | }
374 |
375 | if (Settings.SkateboardEnabled)
376 | self.Sprite.RenderPosition -= SkateboardPlayerOffset;
377 | if (Settings.DuckToDabEnabled && self.Ducking)
378 | self.Sprite.RenderPosition -= DabPlayerOffset;
379 | }
380 |
381 | public static void RenderPlayerSprite(On.Celeste.PlayerSprite.orig_Render orig, PlayerSprite self) {
382 | Player player = self.Entity as Player;
383 | if (player == null || self.Mode == PlayerSpriteMode.Badeline) {
384 | orig(self);
385 | return;
386 | }
387 |
388 | if (Settings.DuckToDabEnabled && player.Ducking) {
389 | Dab.Draw(
390 | self.RenderPosition.Floor() + new Vector2(player.Facing == Facings.Left ? 6 : -6, -7),
391 | Vector2.Zero, Color.White,
392 | self.Scale
393 | );
394 | return;
395 | }
396 |
397 | orig(self);
398 | }
399 |
400 | // Conversion algorithms found randomly on the net - best source for HSV <-> RGB ever:tm:
401 |
402 | private static void ColorToHSV(Color c, out float h, out float s, out float v) {
403 | float r = c.R / 255f;
404 | float g = c.G / 255f;
405 | float b = c.B / 255f;
406 | float min, max, delta;
407 | min = Math.Min(Math.Min(r, g), b);
408 | max = Math.Max(Math.Max(r, g), b);
409 | v = max;
410 | delta = max - min;
411 | if (max != 0) {
412 | s = delta / max;
413 |
414 | if (r == max)
415 | h = (g - b) / delta;
416 | else if (g == max)
417 | h = 2 + (b - r) / delta;
418 | else
419 | h = 4 + (r - g) / delta;
420 | h *= 60f;
421 | if (h < 0)
422 | h += 360f;
423 | } else {
424 | s = 0f;
425 | h = 0f;
426 | }
427 | }
428 |
429 | private static Color ColorFromHSV(float hue, float saturation, float value) {
430 | int hi = (int) (Math.Floor(hue / 60f)) % 6;
431 | float f = hue / 60f - (float) Math.Floor(hue / 60f);
432 |
433 | value = value * 255;
434 | int v = (int) Math.Round(value);
435 | int p = (int) Math.Round(value * (1 - saturation));
436 | int q = (int) Math.Round(value * (1 - f * saturation));
437 | int t = (int) Math.Round(value * (1 - (1 - f) * saturation));
438 |
439 | if (hi == 0)
440 | return new Color(v, t, p, 255);
441 | else if (hi == 1)
442 | return new Color(q, v, p, 255);
443 | else if (hi == 2)
444 | return new Color(p, v, t, 255);
445 | else if (hi == 3)
446 | return new Color(p, q, v, 255);
447 | else if (hi == 4)
448 | return new Color(t, p, v, 255);
449 | else
450 | return new Color(v, p, q, 255);
451 | }
452 |
453 | }
454 | }
455 |
--------------------------------------------------------------------------------
/RainbowMod/RainbowModuleSettings.cs:
--------------------------------------------------------------------------------
1 | using FMOD.Studio;
2 | using Microsoft.Xna.Framework;
3 | using Monocle;
4 | using System;
5 | using System.Collections;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using YamlDotNet.Serialization;
11 |
12 | namespace Celeste.Mod.Rainbow {
13 | public class RainbowModuleSettings : EverestModuleSettings {
14 | public bool RainbowEnabled { get; set; }
15 |
16 | [SettingRange(0, 20)]
17 | public int RainbowSpeed { get; set; } = 10;
18 | [YamlIgnore]
19 | [SettingIgnore]
20 | public float RainbowSpeedFactor => RainbowSpeed / 20f;
21 |
22 | public bool FoxEnabled { get; set; }
23 |
24 | [YamlMember(Alias = "FoxColorLight")]
25 | [SettingIgnore]
26 | public string FoxColorLightHex {
27 | get {
28 | return FoxColorLight.R.ToString("X2") + FoxColorLight.G.ToString("X2") + FoxColorLight.B.ToString("X2");
29 | }
30 | set {
31 | if (string.IsNullOrEmpty(value))
32 | return;
33 | try {
34 | FoxColorLight = Calc.HexToColor(value);
35 | } catch (Exception e) {
36 | Logger.Log(LogLevel.Warn, "rainbowmod", "Invalid FoxColorLight!");
37 | e.LogDetailed();
38 | }
39 | }
40 | }
41 | [YamlIgnore]
42 | [SettingIgnore]
43 | public Color FoxColorLight { get; set; }
44 |
45 | [YamlMember(Alias = "FoxColorDark")]
46 | [SettingIgnore]
47 | public string FoxColorDarkHex {
48 | get {
49 | return FoxColorDark.R.ToString("X2") + FoxColorDark.G.ToString("X2") + FoxColorDark.B.ToString("X2");
50 | }
51 | set {
52 | if (string.IsNullOrEmpty(value))
53 | return;
54 | try {
55 | FoxColorDark = Calc.HexToColor(value);
56 | } catch (Exception e) {
57 | Logger.Log(LogLevel.Warn, "rainbowmod", "Invalid FoxColorDark!");
58 | e.LogDetailed();
59 | }
60 | }
61 | }
62 | [YamlIgnore]
63 | [SettingIgnore]
64 | public Color FoxColorDark { get; set; }
65 |
66 | public bool WoomyEnabled { get; set; }
67 |
68 | public bool SkateboardEnabled { get; set; }
69 |
70 | public bool DuckToDabEnabled { get; set; }
71 |
72 | public bool DuckToSneezeEnabled { get; set; }
73 |
74 | public bool BaldelineEnabled { get; set; }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/RainbowMod/everest.yaml:
--------------------------------------------------------------------------------
1 | - Name: RainbowMod
2 | Version: 3.2.0
3 | DLL: RainbowMod.dll
4 | Dependencies:
5 | - Name: Everest
6 | Version: 1.0.0
7 |
--------------------------------------------------------------------------------
/RainbowMod/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/RainbowMod/settings.celeste:
--------------------------------------------------------------------------------
1 |
2 |
3 | true
4 | 3
5 | 0
6 | true
7 | false
8 | false
9 | true
10 | 10
11 | 10
12 | true
13 | 0
14 | english
15 | true
16 | false
17 | Left
18 | Right
19 | Down
20 | Up
21 |
22 | Z
23 | V
24 | LeftShift
25 |
26 |
27 | C
28 |
29 |
30 | X
31 |
32 |
33 | X
34 |
35 |
36 |
37 | C
38 | Enter
39 |
40 |
41 | X
42 |
43 |
44 | Tab
45 |
46 |
47 | R
48 |
49 |
50 | LeftTrigger
51 | RightTrigger
52 | LeftShoulder
53 | RightShoulder
54 |
55 |
56 | A
57 | Y
58 |
59 |
60 | X
61 | B
62 |
63 |
64 | B
65 |
66 |
67 | false
68 |
--------------------------------------------------------------------------------
/rainbowdeline.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EverestAPI/RainbowMod/HEAD/rainbowdeline.gif
--------------------------------------------------------------------------------