Merge all of micycle's changes
Squashed commit of the following: commit 9005b2b7b43ffe0b07fafa67f3d9f82cd26d110c Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 19:59:20 2023 -0400 fix crash on client disconnect commit 3105e82ac2d688e8c3e9461d4235d9dbde300379 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 16:56:36 2023 -0400 fix uncaught fallthrough in GetColor commit 030cc459d78988abdca702b8000b5ad7e282dab3 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 16:31:27 2023 -0400 add the license text for CC-BY-NC-SA-4 from the license on gamebanana commit 38c403f662a78ebb3cf0d093e0e4356ee31f4474 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 16:23:52 2023 -0400 build commit 61af7e666aac2c8a6099c3e95fe48fda0a082038 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 16:23:25 2023 -0400 we no longer need reloads or deaths when enabling commit de509fc32d151e70e93514ffe10bf10388c21c4b Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 16:21:08 2023 -0400 add strip target in phony just in case commit 44d8e87eb9ba4252f9c283f285d9757243a551da Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 16:20:19 2023 -0400 convert crlf newlines to lf and remove utf8-bom commit 02c4ef754a1b22687ad84ba83c2b14ef9a8fc376 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 16:17:01 2023 -0400 strip our reference assemblies to reduce file size commit 1af89ed351e95e49712921df4d06799f0823aafa Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 15:58:00 2023 -0400 fix regression for playback entities and other non-ghost player sprites commit 157bbadde5365822f38daa885b29cd19f30990c2 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 05:33:08 2023 -0400 polish commit 4629793c530ecac41ca4d4e1376037973f554c90 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 05:19:44 2023 -0400 reword commit 998e4e91f215795d09c2d84ba95fc5dbaf60db5e Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 05:18:44 2023 -0400 build commit 1ff0b69c9dc9a1c5728a3919fc4f4bff4dfd24c5 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 05:18:31 2023 -0400 remove bullshit note commit ad799e4e52efd1343c1c3d29380043fbc24e2ff8 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 04:56:46 2023 -0400 add note about disabling hair mods commit a78de6b6780aa3d035cb422f307050d741ee5587 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 04:39:25 2023 -0400 build commit f605307da9303e0529923a4b6f8767f2991df0d0 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 04:39:20 2023 -0400 fix crash w/o celestenet & make note a header (disabled notes can't be viewed) commit 8b297426fcbe01cbddfc4ee4289f90b3160e4f87 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 04:11:25 2023 -0400 unused commit fd69e4c918b41149ce0399e5fc75139a6280f571 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 04:11:11 2023 -0400 move colorutil into misc commit 6522db9f06e7e461098fc13705f04b02542a52a9 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 03:59:18 2023 -0400 build commit 3d57982539e8b734099bd24dce765dcaedc7e5a7 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 03:59:13 2023 -0400 reword some more text commit a87e853d44f98b09c95308a1f13683188da612fd Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 03:50:06 2023 -0400 disable celestenet settings when not installed + reword some text commit 50ed0542decf3219275813d4873c613f620e8b28 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 03:48:34 2023 -0400 Revert "dependency downloader for celestenet" This reverts commit 6c896eaee60d22944e679352e7de74b6ead36aa8. commit 6c896eaee60d22944e679352e7de74b6ead36aa8 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 03:47:50 2023 -0400 dependency downloader for celestenet commit f4f280230500611cf6ae0269e116c63ff420b1d1 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 03:17:14 2023 -0400 build actually done wtf? commit 8e003342720efcd213db75502e6acbea61b76304 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 02:52:34 2023 -0400 rewrite commit c601079e66e44c72ea50e818856b829a0328ac17 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 02:52:11 2023 -0400 fix dash trails but introduce a crash with players w/o mod commit 0b3b051292c10391eae73f23242de3179a8a9904 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 01:33:41 2023 -0400 well it does sync, but issues: - setting hair color conflicts with hyperline - hair direction doesn't update wtf? - dash trail is fucked commit da36686a4791d57dcb9a5cb8636005086a4d75e2 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun May 7 01:16:37 2023 -0400 fix celestenet onoffs not displaing the stored setting on first load commit 62a25a5e737c33a47f6f1c5f77037d7d681b4114 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sat May 6 20:28:28 2023 -0400 remove unneeded line in makefile commit 394a7cd49b64d071a8ab0276b6db19bb56de1579 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sat May 6 20:28:17 2023 -0400 refactor module to better support ghosts, and finish celestnet module commit 9f0f04a6d903ee760d556ba94b282b73083c6bae Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sat May 6 16:19:28 2023 -0400 fix makfile for hot reload commit c4316c1c7eb99f0d8080df01ff97bc89eb6f3076 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sat May 6 02:58:44 2023 -0400 start proper celestenet module commit 96a21fac816fb30a3710837571e1d683ea39645e Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Mon Apr 24 15:26:36 2023 -0400 fix settings crash commit a66cf51ed1d2a2e6d0fc36b46ab587d51bc88e4e Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Mon Apr 24 15:01:25 2023 -0400 add celeste menu options commit c095747458f8abd904e21d19742c97e44907f0eb Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun Apr 23 14:45:44 2023 -0400 fix crash with ghosts not having a scene set??!? commit bcea0f41e5b0dace8e61bf112ec5fc47679ceffc Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun Apr 23 03:36:33 2023 -0400 Settings.enabled and player != null guards commit 3cecaa2a6b6adcfcd96790e4e2f36fef0200e922 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun Apr 23 03:19:45 2023 -0400 quick fix for null ghost hair commit cedb0c55b38405abcb901c94203e4bea1dcd1e65 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun Apr 23 02:40:21 2023 -0400 unload the celestenet hook commit 486d09221566d7de3b2c8f739710800536be6f74 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun Apr 23 02:38:34 2023 -0400 fix up makefile commit 68e99cf0c4898e399c093a7aa60b87c6e1db98ac Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun Apr 23 02:26:30 2023 -0400 rm old dll commit eb6006e6f5afec3b281469ec3cfa56e732ecf7e4 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun Apr 23 02:26:14 2023 -0400 code rebuild commit 05441fcd3ab35ac76a50bea744259b0704794bbe Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun Apr 23 02:17:19 2023 -0400 clean up :3 commit 831dd6775cf585ab0feb202fc27e66b36e033c6d Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sun Apr 23 01:51:04 2023 -0400 add in CelesteNet ghost support :) commit 7e8bcac717e294f88b097ec6c60eb128a521d605 Author: micycle <5301938-bit_network@users.noreply.gitlab.com> Date: Sat Apr 22 23:42:58 2023 -0400 initial commit (should have starting tracking a while ago)
This commit is contained in:
parent
867fd9a438
commit
cf5efcbdbc
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -1,10 +1,41 @@
|
|||
AVALI_SKIN_TITLE= Avali Skin
|
||||
AVALI_SKIN_COLORONE= Color One
|
||||
AVALI_SKIN_COLORTWO= Color Two
|
||||
AVALI_SKIN_MARKING_COLORS= Marking Colors
|
||||
AVALI_SKIN_ZERODASH= Zero Dashes
|
||||
AVALI_SKIN_ONEDASH= One Dash
|
||||
AVALI_SKIN_TWODASH= Two Dashes
|
||||
AVALI_SKIN_THREEDASH= Three Dashes
|
||||
AVALI_SKIN_FOURDASH= Four Dashes
|
||||
AVALI_SKIN_FIVEDASH= Five+ Dashes
|
||||
|
||||
modoptions_avaliskin_colormodeopt=Dash color mode
|
||||
modoptions_avaliskin_colormodeopt_ExternalDash=Use hair color
|
||||
modoptions_avaliskin_colormodeopt_ManualPreset=Select color preset
|
||||
modoptions_avaliskin_colormodeopt_ManualPreset_note=Selects hair color from color presets
|
||||
Make sure to disable other hair color mods.
|
||||
modoptions_avaliskin_colormodeopt_ManualRGB=Select RGB color
|
||||
modoptions_avaliskin_colormodeopt_ManualRGB_note=Selects hair color from RGB values.
|
||||
Make sure to disable other hair color mods.
|
||||
modoptions_avaliskin_colormodeopt_ExternalDash_note=Uses hair color from vanilla
|
||||
or from other mods (e.g., Hyperline, Prideline)
|
||||
|
||||
AVALI_SKIN_COLORS=Dash colors
|
||||
AVALI_SKIN_DASH0=Zero Dashes
|
||||
AVALI_SKIN_DASH1=One Dash
|
||||
AVALI_SKIN_DASH2=Two Dashes
|
||||
AVALI_SKIN_DASH3=Three Dashes
|
||||
AVALI_SKIN_DASH4=Four Dashes
|
||||
AVALI_SKIN_DASH5=Five+ Dashes
|
||||
|
||||
AVALI_SKIN_RED=Red
|
||||
AVALI_SKIN_GREEN=Green
|
||||
AVALI_SKIN_BLUE=Blue
|
||||
AVALI_SKIN_COLOR=Color
|
||||
|
||||
modoptions_avaliskin_celestenet_header=CelesteNet support
|
||||
modoptions_avaliskin_celestenet=Enable CelesteNet support
|
||||
modoptions_avaliskin_celestenet_nocelestenet=CelesteNet is not installed. Optional.
|
||||
|
||||
modoptions_avaliskin_celestenetsync=CelesteNet skin sync
|
||||
modoptions_avaliskin_celestenetsync_SendReceive=Send/Receive
|
||||
modoptions_avaliskin_celestenetsync_Send=Send only
|
||||
modoptions_avaliskin_celestenetsync_Receive=Receive only
|
||||
modoptions_avaliskin_celestenetsync_None=Disable
|
||||
modoptions_avaliskin_celestenetsync_note=Synchronizes skins for other CelesteNet
|
||||
players if they also have this mod
|
||||
|
||||
modoptions_avaliskin_celesteneteveryonehasskin=Everyone is an Avali
|
||||
modoptions_avaliskin_celesteneteveryonehasskin_note=Renders all CelesteNet players
|
||||
as Avalis, regardless of their skin
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// Compile with fxc.exe AvaliRecolor.fx /T fx_2_0 /O3
|
||||
|
||||
// Creates a texture at a given texture index
|
||||
#define DECLARE_TEXTURE(Name, index) \
|
||||
texture Name: register(t##index); \
|
||||
sampler Name##Sampler: register(s##index)
|
||||
|
||||
// Samples the texture and returns a color
|
||||
#define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name##Sampler, texCoord)
|
||||
|
||||
|
||||
DECLARE_TEXTURE(text, 0); // The texture to be recolored
|
||||
|
||||
uniform float4 color_replace_from; // #1ad589
|
||||
uniform float4 color_replace_to;
|
||||
uniform float threshold; // 0.01
|
||||
|
||||
|
||||
// hsls provides distance instead of this...
|
||||
// float fast_distance4(float4 a, float4 b) {
|
||||
// float4 diff = a - b;
|
||||
// return diff.x * diff.x + diff.y * diff.y + diff.z * diff.z + diff.w * diff.w;
|
||||
// }
|
||||
|
||||
|
||||
float4 ps_recolor(float4 pos: SV_Position, float4 in_color: COLOR0, float2 uv: TEXCOORD0): COLOR {
|
||||
float4 color = SAMPLE_TEXTURE(text, uv);
|
||||
return (distance(color, color_replace_from) < threshold ? color_replace_to : color) * in_color;
|
||||
}
|
||||
|
||||
technique Recolor {
|
||||
pass {
|
||||
PixelShader = compile ps_2_0 ps_recolor();
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,192 +1,192 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Sprites>
|
||||
|
||||
<player_avali path="characters/Avali/" start="idle">
|
||||
<Origin x="16" y="32" />
|
||||
|
||||
<Loop id="idle_carry" path="idle_carry" delay="0.15" />
|
||||
<Anim id="runSlow_carry" path="run_carry" delay="0.07" />
|
||||
<Loop id="jumpSlow_carry" path="jump_carry" delay="0.1" frames="0,1" />
|
||||
<Anim id="fallSlow_carry" path="jump_carry" delay="0.1" frames="2,3" />
|
||||
<Anim id="pickUp" path="pickup" delay="0.06" />
|
||||
<Anim id="throw" path="throw" delay="0.06" goto="idle" />
|
||||
|
||||
<Anim id="idle" path="idle" delay="0.15" goto="idle"/>
|
||||
|
||||
<Anim id="idleA" path="idleA" delay="0.12" goto="idle"/>
|
||||
<Anim id="idleB" path="idleB" delay="0.16" goto="idle"/>
|
||||
<Anim id="idleC" path="idleC" delay="0.12" goto="idle"/>
|
||||
|
||||
<Anim id="lookUp" path="lookUp" delay="0.15" />
|
||||
<Loop id="walk" path="walk" delay="0.06" />
|
||||
<Loop id="push" path="push" delay="0.1" />
|
||||
<Anim id="runSlow" path="runSlow" delay="0.07" goto="runFast" />
|
||||
<Loop id="runFast" path="runFast" delay="0.05" />
|
||||
<Anim id="runStumble" path="runStumble" delay="0.05" frames="10-11,0-11" goto="runFast"/>
|
||||
<Loop id="runWind" path="run_wind" delay="0.095" frames="0-11"/>
|
||||
<Loop id="dash" path="dash" delay="0.09" />
|
||||
<Anim id="dreamDashIn" path="dreamDash" frames="0-3" delay="0.04" goto="dreamDashLoop"/>
|
||||
<Loop id="dreamDashLoop" path="dreamDash" frames="4-16" delay="0.03" />
|
||||
<Anim id="dreamDashOut" path="dreamDash" frames="17-20" delay="0.04" />
|
||||
<Loop id="slide" path="slide" delay="0.03" />
|
||||
<Loop id="jumpSlow" path="jumpSlow" delay="0.1" frames="0,1" />
|
||||
<Loop id="jumpFast" path="jumpFast" delay="0.1" frames="0,1" />
|
||||
<Anim id="fallSlow" path="jumpSlow" delay="0.1" frames="2,3" />
|
||||
<Anim id="fallFast" path="jumpFast" delay="0.1" frames="2,3" />
|
||||
<Loop id="tired" path="tired" delay="0.4" />
|
||||
<Anim id="tiredStill" path="tired" frames="0" />
|
||||
<Loop id="wallslide" path="climb" frames="0" />
|
||||
<Anim id="climbLookBackStart" path="climb" delay="0.08" frames="6,7,8" goto="climbLookBack" />
|
||||
<Loop id="climbLookBack" path="climb" frames="8" />
|
||||
<Loop id="climbup" path="climb" delay="0.08" frames="0-5" />
|
||||
<Anim id="climbPush" path="climb" delay="0.04" frames="0,9-11" />
|
||||
<Anim id="climbPull" path="climb" delay="0.04" frames="0,12-14" />
|
||||
<Loop id="duck" path="duck" delay="0" frames="0" />
|
||||
<Anim id="fallPose" path="fallPose" delay="0.1" frames="0-10" goto="idle"/>
|
||||
<Loop id="edge" path="edge" delay="0.25" frames="0-13" />
|
||||
<Loop id="edgeBack" path="edge_back" delay="0.25"/>
|
||||
<Anim id="faint" path="faint" delay="0.1" frames="0-10" goto="fainted" />
|
||||
<Loop id="fainted" path="faint" delay="0.1" frames="10" />
|
||||
<Anim id="flip" path="flip" delay="0.04" frames="0-7" goto="runFast"/>
|
||||
<Loop id="skid" path="flip" delay="0.04" frames="8"/>
|
||||
<Loop id="dangling" path="dangling" delay="0.11" frames="0-9" />
|
||||
<Anim id="deadside" path="death_h" delay="0.02" frames="0-12" />
|
||||
<Anim id="deadup" path="death_h" delay="0.02" frames="0-12" />
|
||||
<Anim id="deaddown" path="death_h" delay="0.02" frames="0-12" />
|
||||
|
||||
<Loop id="swimIdle" path="swim" frames="0-5" delay="0.3" />
|
||||
<Loop id="swimUp" path="swim" frames="6-11" delay="0.1" />
|
||||
<Loop id="swimDown" path="swim" frames="12-17" delay="0.15" />
|
||||
|
||||
<Anim id="startStarFly" path="startStarFly" delay="0.08" goto="starFly"/>
|
||||
<Loop id="starFly" path="starFly" delay="0.08"/>
|
||||
<Loop id="bubble" path="bubble" delay="0.08"/>
|
||||
|
||||
<Anim id="fall" path="fall" delay="0.06" frames="0-7" />
|
||||
<Loop id="bigFall" path="bigFall" frames="0-3" delay="0.06"/>
|
||||
<Anim id="bigFallRecover" path="bigFall" frames="4*3,5*3,6*3,7*2,8,8,9,10" delay="0.08" goto="swimIdle"/>
|
||||
|
||||
<Anim id="sleep" path="sleep" delay="0.1" frames="0,1*2,2,3*2,4*2,5*2,6*2,7*2,8*2,9*3,10*3,11-19" />
|
||||
<Anim id="bagdown" path="sleep" delay="0.1" frames="0,1*2,2*2,3*2,4*2,5*2,6*2,7*2,8*2,9*3,10*3,11" />
|
||||
<Anim id="asleep" path="wakeUp/" frames="0" />
|
||||
<Anim id="wakeUp" path="wakeUp/" delay=".16" frames="0*4,1,2*8,3*2,4-13" />
|
||||
<Anim id="halfWakeUp" path="wakeUp/" delay=".16" frames="13" />
|
||||
|
||||
<Loop id="spin" path="spin" delay="0.1" />
|
||||
<Loop id="shaking" path="shaking" delay="0.1" />
|
||||
<Loop id="hug" path="hug" delay="0.08"/>
|
||||
|
||||
<Anim id="starMorph" path="starMorph" delay="0.06" frames="0-9" goto="starMorphIdle"/>
|
||||
<Loop id="starMorphIdle" path="starMorph" frames="10" delay="0.06"/>
|
||||
|
||||
<Loop id="carryTheoWalk" path="walk_carry_theo" frames="0-11" delay="0.06"/>
|
||||
<Anim id="carryTheoCollapse" path="walk_carry_theo" frames="12-18" delay="0.06"/>
|
||||
|
||||
<Anim id="tentacle_grab" path="tentacle/grab" delay="0.06" frames="0-14" goto="tentacle_grabbed"/>
|
||||
<Loop id="tentacle_grabbed" path="tentacle/grab" delay="0.1" frames="15-23"/>
|
||||
<Loop id="tentacle_pull" path="tentacle/grab" frames="24" delay="0.1"/>
|
||||
<Loop id="tentacle_dangling" path="tentacle/grab" frames="25" delay="0.1"/>
|
||||
|
||||
<Anim id="sitDown" path="sitDown" delay="0.1" frames="0,1*2,2,3*2,4*2,5*2,6*2,7*2,8*2,9*2,10*2,11-13"/>
|
||||
|
||||
<Loop id="launch" path="launch" delay="0.1" />
|
||||
<Anim id="launchRecover" path="launchRecover" delay="0.09" />
|
||||
|
||||
<Metadata>
|
||||
<Frames path="starFly" hair="0,3"/>
|
||||
</Metadata>
|
||||
</player_avali>
|
||||
|
||||
<player_avali_no_backpack copy="player_avali" path="characters/Avali_nb/">
|
||||
<Anim id="idle" path="idle" delay="0.15" goto="idle"/>
|
||||
<Anim id="idleA" path="idleA" delay="0.12" goto="idle"/>
|
||||
<Anim id="idleB" path="idleB" delay="0.12" goto="idle"/>
|
||||
<Anim id="idleC" path="idleC" delay="0.16" goto="idle"/>
|
||||
|
||||
<Anim id="roll" path="roll" frames="0-12" delay="0.05"/>
|
||||
<Anim id="rollGetUp" path="roll" frames="13-16" delay=".1" goto="downed"/>
|
||||
<Loop id="downed" path="roll" delay="0.8" frames="17"/>
|
||||
|
||||
</player_avali_no_backpack>
|
||||
|
||||
<player_sweat path="characters/Avali/sweat/" start="idle">
|
||||
<Justify x=".55" y="1.05" />
|
||||
|
||||
<Loop id="idle" path="idle" />
|
||||
<Anim id="climb" path="climb" frames="0,1" delay=".1" goto="climbLoop" />
|
||||
<Loop id="climbLoop" path="climb" frames="2-7" delay=".1" />
|
||||
<Loop id="still" path="still" delay=".1" />
|
||||
<Anim id="jump" path="jump" delay=".1" goto="idle" />
|
||||
<Loop id="danger" path="danger" delay=".05" />
|
||||
</player_sweat>
|
||||
|
||||
<player_avali_playback copy="player_avali" path="characters/Avali_playback/">
|
||||
<Anim id="idle" path="idle" delay="0.15" goto="idle"/>
|
||||
<Anim id="idleA" path="idleA" delay="0.12" goto="idle"/>
|
||||
<Anim id="idleB" path="idleB" delay="0.16" goto="idle"/>
|
||||
<Anim id="idleC" path="idleC" delay="0.12" goto="idle"/>
|
||||
|
||||
<Anim id="roll" path="roll" frames="0-12" delay="0.05"/>
|
||||
<Anim id="rollGetUp" path="roll" frames="13-16" delay=".1" goto="downed"/>
|
||||
<Loop id="downed" path="roll" delay="0.8" frames="17"/>
|
||||
</player_avali_playback>
|
||||
|
||||
<!-- Objects -->
|
||||
|
||||
<payphone_avali path="cutscenes/Avali/payphone/" start="idle">
|
||||
<Justify x=".5" y="1" />
|
||||
|
||||
<Loop id="idle" path="phone" delay="0.1" frames="0"/>
|
||||
<Anim id="pickUp" path="phone" delay="0.08" frames="1-11"/>
|
||||
<Loop id="talkPhone" path="phone" delay="0.08" frames="11"/>
|
||||
<Anim id="jumpBack" path="phone" delay="0.08" frames="12-17"/>
|
||||
<Anim id="scare" path="phone" delay="0.08" frames="18-21"/>
|
||||
<Anim id="transform" path="phone" delay="0.08" frames="22-45" />
|
||||
<Anim id="eat" path="phone" delay="0.08" frames="46-73,83*2,84*2,85*2,86*2,87*2,74-82"/>
|
||||
<Loop id="monsterIdle" path="phone" delay="0.2" frames="83-87"/>
|
||||
</payphone_avali>
|
||||
|
||||
<lookout_avali path="objects/Avali/lookout/" start="idle">
|
||||
<Justify x=".5" y="1" />
|
||||
|
||||
<Loop id="idle" path="lookout" delay="0.1" frames="0*9,1-4"/>
|
||||
<Anim id="lookRight" path="lookout" delay="0.08" frames="5-7,9" goto="looking"/>
|
||||
<Anim id="lookLeft" path="lookout" delay="0.08" frames="18-20,8,9" goto="looking"/>
|
||||
<Loop id="looking" path="lookout" delay="0.08" frames="9"/>
|
||||
<Loop id="lookingUp" path="lookout" frames="10"/>
|
||||
<Loop id="lookingUpRight" path="lookout" frames="11"/>
|
||||
<Loop id="lookingRight" path="lookout" frames="12"/>
|
||||
<Loop id="lookingDownRight" path="lookout" frames="13"/>
|
||||
<Loop id="lookingDown" path="lookout" frames="14"/>
|
||||
<Loop id="lookingDownLeft" path="lookout" frames="15"/>
|
||||
<Loop id="lookingLeft" path="lookout" frames="16"/>
|
||||
<Loop id="lookingUpLeft" path="lookout" frames="17"/>
|
||||
|
||||
<Loop id="badeline_idle" path="badeline" delay="0.1" frames="5*9,6"/>
|
||||
<Anim id="badeline_lookRight" path="badeline" delay="0.08" frames="0-4" goto="badeline_looking"/>
|
||||
<Anim id="badeline_lookLeft" path="badeline" delay="0.08" frames="15-17,3,4" goto="badeline_looking"/>
|
||||
<Loop id="badeline_looking" path="badeline" delay="0.08" frames="4"/>
|
||||
<Loop id="badeline_lookingUp" path="badeline" frames="7"/>
|
||||
<Loop id="badeline_lookingUpRight" path="badeline" frames="8"/>
|
||||
<Loop id="badeline_lookingRight" path="badeline" frames="9"/>
|
||||
<Loop id="badeline_lookingDownRight" path="badeline" frames="10"/>
|
||||
<Loop id="badeline_lookingDown" path="badeline" frames="11"/>
|
||||
<Loop id="badeline_lookingDownLeft" path="badeline" frames="12"/>
|
||||
<Loop id="badeline_lookingLeft" path="badeline" frames="13"/>
|
||||
<Loop id="badeline_lookingUpLeft" path="badeline" frames="14"/>
|
||||
|
||||
<Loop id="nobackpack_idle" path="lookout" delay="0.1" frames="0*9,1-4"/>
|
||||
<Anim id="nobackpack_lookRight" path="lookout" delay="0.08" frames="5-7,9" goto="nobackpack_looking"/>
|
||||
<Anim id="nobackpack_lookLeft" path="lookout" delay="0.08" frames="18-20,8,9" goto="nobackpack_looking"/>
|
||||
<Loop id="nobackpack_looking" path="lookout" delay="0.08" frames="9"/>
|
||||
<Loop id="nobackpack_lookingUp" path="lookout" frames="10"/>
|
||||
<Loop id="nobackpack_lookingUpRight" path="lookout" frames="11"/>
|
||||
<Loop id="nobackpack_lookingRight" path="lookout" frames="12"/>
|
||||
<Loop id="nobackpack_lookingDownRight" path="lookout" frames="13"/>
|
||||
<Loop id="nobackpack_lookingDown" path="lookout" frames="14"/>
|
||||
<Loop id="nobackpack_lookingDownLeft" path="lookout" frames="15"/>
|
||||
<Loop id="nobackpack_lookingLeft" path="lookout" frames="16"/>
|
||||
<Loop id="nobackpack_lookingUpLeft" path="lookout" frames="17"/>
|
||||
</lookout_avali>
|
||||
|
||||
</Sprites>
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Sprites>
|
||||
|
||||
<player_avali path="characters/Avali/" start="idle">
|
||||
<Origin x="16" y="32" />
|
||||
|
||||
<Loop id="idle_carry" path="idle_carry" delay="0.15" />
|
||||
<Anim id="runSlow_carry" path="run_carry" delay="0.07" />
|
||||
<Loop id="jumpSlow_carry" path="jump_carry" delay="0.1" frames="0,1" />
|
||||
<Anim id="fallSlow_carry" path="jump_carry" delay="0.1" frames="2,3" />
|
||||
<Anim id="pickUp" path="pickup" delay="0.06" />
|
||||
<Anim id="throw" path="throw" delay="0.06" goto="idle" />
|
||||
|
||||
<Anim id="idle" path="idle" delay="0.15" goto="idle"/>
|
||||
|
||||
<Anim id="idleA" path="idleA" delay="0.12" goto="idle"/>
|
||||
<Anim id="idleB" path="idleB" delay="0.16" goto="idle"/>
|
||||
<Anim id="idleC" path="idleC" delay="0.12" goto="idle"/>
|
||||
|
||||
<Anim id="lookUp" path="lookUp" delay="0.15" />
|
||||
<Loop id="walk" path="walk" delay="0.06" />
|
||||
<Loop id="push" path="push" delay="0.1" />
|
||||
<Anim id="runSlow" path="runSlow" delay="0.07" goto="runFast" />
|
||||
<Loop id="runFast" path="runFast" delay="0.05" />
|
||||
<Anim id="runStumble" path="runStumble" delay="0.05" frames="10-11,0-11" goto="runFast"/>
|
||||
<Loop id="runWind" path="run_wind" delay="0.095" frames="0-11"/>
|
||||
<Loop id="dash" path="dash" delay="0.09" />
|
||||
<Anim id="dreamDashIn" path="dreamDash" frames="0-3" delay="0.04" goto="dreamDashLoop"/>
|
||||
<Loop id="dreamDashLoop" path="dreamDash" frames="4-16" delay="0.03" />
|
||||
<Anim id="dreamDashOut" path="dreamDash" frames="17-20" delay="0.04" />
|
||||
<Loop id="slide" path="slide" delay="0.03" />
|
||||
<Loop id="jumpSlow" path="jumpSlow" delay="0.1" frames="0,1" />
|
||||
<Loop id="jumpFast" path="jumpFast" delay="0.1" frames="0,1" />
|
||||
<Anim id="fallSlow" path="jumpSlow" delay="0.1" frames="2,3" />
|
||||
<Anim id="fallFast" path="jumpFast" delay="0.1" frames="2,3" />
|
||||
<Loop id="tired" path="tired" delay="0.4" />
|
||||
<Anim id="tiredStill" path="tired" frames="0" />
|
||||
<Loop id="wallslide" path="climb" frames="0" />
|
||||
<Anim id="climbLookBackStart" path="climb" delay="0.08" frames="6,7,8" goto="climbLookBack" />
|
||||
<Loop id="climbLookBack" path="climb" frames="8" />
|
||||
<Loop id="climbup" path="climb" delay="0.08" frames="0-5" />
|
||||
<Anim id="climbPush" path="climb" delay="0.04" frames="0,9-11" />
|
||||
<Anim id="climbPull" path="climb" delay="0.04" frames="0,12-14" />
|
||||
<Loop id="duck" path="duck" delay="0" frames="0" />
|
||||
<Anim id="fallPose" path="fallPose" delay="0.1" frames="0-10" goto="idle"/>
|
||||
<Loop id="edge" path="edge" delay="0.25" frames="0-13" />
|
||||
<Loop id="edgeBack" path="edge_back" delay="0.25"/>
|
||||
<Anim id="faint" path="faint" delay="0.1" frames="0-10" goto="fainted" />
|
||||
<Loop id="fainted" path="faint" delay="0.1" frames="10" />
|
||||
<Anim id="flip" path="flip" delay="0.04" frames="0-7" goto="runFast"/>
|
||||
<Loop id="skid" path="flip" delay="0.04" frames="8"/>
|
||||
<Loop id="dangling" path="dangling" delay="0.11" frames="0-9" />
|
||||
<Anim id="deadside" path="death_h" delay="0.02" frames="0-12" />
|
||||
<Anim id="deadup" path="death_h" delay="0.02" frames="0-12" />
|
||||
<Anim id="deaddown" path="death_h" delay="0.02" frames="0-12" />
|
||||
|
||||
<Loop id="swimIdle" path="swim" frames="0-5" delay="0.3" />
|
||||
<Loop id="swimUp" path="swim" frames="6-11" delay="0.1" />
|
||||
<Loop id="swimDown" path="swim" frames="12-17" delay="0.15" />
|
||||
|
||||
<Anim id="startStarFly" path="startStarFly" delay="0.08" goto="starFly"/>
|
||||
<Loop id="starFly" path="starFly" delay="0.08"/>
|
||||
<Loop id="bubble" path="bubble" delay="0.08"/>
|
||||
|
||||
<Anim id="fall" path="fall" delay="0.06" frames="0-7" />
|
||||
<Loop id="bigFall" path="bigFall" frames="0-3" delay="0.06"/>
|
||||
<Anim id="bigFallRecover" path="bigFall" frames="4*3,5*3,6*3,7*2,8,8,9,10" delay="0.08" goto="swimIdle"/>
|
||||
|
||||
<Anim id="sleep" path="sleep" delay="0.1" frames="0,1*2,2,3*2,4*2,5*2,6*2,7*2,8*2,9*3,10*3,11-19" />
|
||||
<Anim id="bagdown" path="sleep" delay="0.1" frames="0,1*2,2*2,3*2,4*2,5*2,6*2,7*2,8*2,9*3,10*3,11" />
|
||||
<Anim id="asleep" path="wakeUp/" frames="0" />
|
||||
<Anim id="wakeUp" path="wakeUp/" delay=".16" frames="0*4,1,2*8,3*2,4-13" />
|
||||
<Anim id="halfWakeUp" path="wakeUp/" delay=".16" frames="13" />
|
||||
|
||||
<Loop id="spin" path="spin" delay="0.1" />
|
||||
<Loop id="shaking" path="shaking" delay="0.1" />
|
||||
<Loop id="hug" path="hug" delay="0.08"/>
|
||||
|
||||
<Anim id="starMorph" path="starMorph" delay="0.06" frames="0-9" goto="starMorphIdle"/>
|
||||
<Loop id="starMorphIdle" path="starMorph" frames="10" delay="0.06"/>
|
||||
|
||||
<Loop id="carryTheoWalk" path="walk_carry_theo" frames="0-11" delay="0.06"/>
|
||||
<Anim id="carryTheoCollapse" path="walk_carry_theo" frames="12-18" delay="0.06"/>
|
||||
|
||||
<Anim id="tentacle_grab" path="tentacle/grab" delay="0.06" frames="0-14" goto="tentacle_grabbed"/>
|
||||
<Loop id="tentacle_grabbed" path="tentacle/grab" delay="0.1" frames="15-23"/>
|
||||
<Loop id="tentacle_pull" path="tentacle/grab" frames="24" delay="0.1"/>
|
||||
<Loop id="tentacle_dangling" path="tentacle/grab" frames="25" delay="0.1"/>
|
||||
|
||||
<Anim id="sitDown" path="sitDown" delay="0.1" frames="0,1*2,2,3*2,4*2,5*2,6*2,7*2,8*2,9*2,10*2,11-13"/>
|
||||
|
||||
<Loop id="launch" path="launch" delay="0.1" />
|
||||
<Anim id="launchRecover" path="launchRecover" delay="0.09" />
|
||||
|
||||
<Metadata>
|
||||
<Frames path="starFly" hair="0,3"/>
|
||||
</Metadata>
|
||||
</player_avali>
|
||||
|
||||
<player_avali_no_backpack copy="player_avali" path="characters/Avali_nb/">
|
||||
<Anim id="idle" path="idle" delay="0.15" goto="idle"/>
|
||||
<Anim id="idleA" path="idleA" delay="0.12" goto="idle"/>
|
||||
<Anim id="idleB" path="idleB" delay="0.12" goto="idle"/>
|
||||
<Anim id="idleC" path="idleC" delay="0.16" goto="idle"/>
|
||||
|
||||
<Anim id="roll" path="roll" frames="0-12" delay="0.05"/>
|
||||
<Anim id="rollGetUp" path="roll" frames="13-16" delay=".1" goto="downed"/>
|
||||
<Loop id="downed" path="roll" delay="0.8" frames="17"/>
|
||||
|
||||
</player_avali_no_backpack>
|
||||
|
||||
<player_sweat path="characters/Avali/sweat/" start="idle">
|
||||
<Justify x=".55" y="1.05" />
|
||||
|
||||
<Loop id="idle" path="idle" />
|
||||
<Anim id="climb" path="climb" frames="0,1" delay=".1" goto="climbLoop" />
|
||||
<Loop id="climbLoop" path="climb" frames="2-7" delay=".1" />
|
||||
<Loop id="still" path="still" delay=".1" />
|
||||
<Anim id="jump" path="jump" delay=".1" goto="idle" />
|
||||
<Loop id="danger" path="danger" delay=".05" />
|
||||
</player_sweat>
|
||||
|
||||
<player_avali_playback copy="player_avali" path="characters/Avali_playback/">
|
||||
<Anim id="idle" path="idle" delay="0.15" goto="idle"/>
|
||||
<Anim id="idleA" path="idleA" delay="0.12" goto="idle"/>
|
||||
<Anim id="idleB" path="idleB" delay="0.16" goto="idle"/>
|
||||
<Anim id="idleC" path="idleC" delay="0.12" goto="idle"/>
|
||||
|
||||
<Anim id="roll" path="roll" frames="0-12" delay="0.05"/>
|
||||
<Anim id="rollGetUp" path="roll" frames="13-16" delay=".1" goto="downed"/>
|
||||
<Loop id="downed" path="roll" delay="0.8" frames="17"/>
|
||||
</player_avali_playback>
|
||||
|
||||
<!-- Objects -->
|
||||
|
||||
<payphone_avali path="cutscenes/Avali/payphone/" start="idle">
|
||||
<Justify x=".5" y="1" />
|
||||
|
||||
<Loop id="idle" path="phone" delay="0.1" frames="0"/>
|
||||
<Anim id="pickUp" path="phone" delay="0.08" frames="1-11"/>
|
||||
<Loop id="talkPhone" path="phone" delay="0.08" frames="11"/>
|
||||
<Anim id="jumpBack" path="phone" delay="0.08" frames="12-17"/>
|
||||
<Anim id="scare" path="phone" delay="0.08" frames="18-21"/>
|
||||
<Anim id="transform" path="phone" delay="0.08" frames="22-45" />
|
||||
<Anim id="eat" path="phone" delay="0.08" frames="46-73,83*2,84*2,85*2,86*2,87*2,74-82"/>
|
||||
<Loop id="monsterIdle" path="phone" delay="0.2" frames="83-87"/>
|
||||
</payphone_avali>
|
||||
|
||||
<lookout_avali path="objects/Avali/lookout/" start="idle">
|
||||
<Justify x=".5" y="1" />
|
||||
|
||||
<Loop id="idle" path="lookout" delay="0.1" frames="0*9,1-4"/>
|
||||
<Anim id="lookRight" path="lookout" delay="0.08" frames="5-7,9" goto="looking"/>
|
||||
<Anim id="lookLeft" path="lookout" delay="0.08" frames="18-20,8,9" goto="looking"/>
|
||||
<Loop id="looking" path="lookout" delay="0.08" frames="9"/>
|
||||
<Loop id="lookingUp" path="lookout" frames="10"/>
|
||||
<Loop id="lookingUpRight" path="lookout" frames="11"/>
|
||||
<Loop id="lookingRight" path="lookout" frames="12"/>
|
||||
<Loop id="lookingDownRight" path="lookout" frames="13"/>
|
||||
<Loop id="lookingDown" path="lookout" frames="14"/>
|
||||
<Loop id="lookingDownLeft" path="lookout" frames="15"/>
|
||||
<Loop id="lookingLeft" path="lookout" frames="16"/>
|
||||
<Loop id="lookingUpLeft" path="lookout" frames="17"/>
|
||||
|
||||
<Loop id="badeline_idle" path="badeline" delay="0.1" frames="5*9,6"/>
|
||||
<Anim id="badeline_lookRight" path="badeline" delay="0.08" frames="0-4" goto="badeline_looking"/>
|
||||
<Anim id="badeline_lookLeft" path="badeline" delay="0.08" frames="15-17,3,4" goto="badeline_looking"/>
|
||||
<Loop id="badeline_looking" path="badeline" delay="0.08" frames="4"/>
|
||||
<Loop id="badeline_lookingUp" path="badeline" frames="7"/>
|
||||
<Loop id="badeline_lookingUpRight" path="badeline" frames="8"/>
|
||||
<Loop id="badeline_lookingRight" path="badeline" frames="9"/>
|
||||
<Loop id="badeline_lookingDownRight" path="badeline" frames="10"/>
|
||||
<Loop id="badeline_lookingDown" path="badeline" frames="11"/>
|
||||
<Loop id="badeline_lookingDownLeft" path="badeline" frames="12"/>
|
||||
<Loop id="badeline_lookingLeft" path="badeline" frames="13"/>
|
||||
<Loop id="badeline_lookingUpLeft" path="badeline" frames="14"/>
|
||||
|
||||
<Loop id="nobackpack_idle" path="lookout" delay="0.1" frames="0*9,1-4"/>
|
||||
<Anim id="nobackpack_lookRight" path="lookout" delay="0.08" frames="5-7,9" goto="nobackpack_looking"/>
|
||||
<Anim id="nobackpack_lookLeft" path="lookout" delay="0.08" frames="18-20,8,9" goto="nobackpack_looking"/>
|
||||
<Loop id="nobackpack_looking" path="lookout" delay="0.08" frames="9"/>
|
||||
<Loop id="nobackpack_lookingUp" path="lookout" frames="10"/>
|
||||
<Loop id="nobackpack_lookingUpRight" path="lookout" frames="11"/>
|
||||
<Loop id="nobackpack_lookingRight" path="lookout" frames="12"/>
|
||||
<Loop id="nobackpack_lookingDownRight" path="lookout" frames="13"/>
|
||||
<Loop id="nobackpack_lookingDown" path="lookout" frames="14"/>
|
||||
<Loop id="nobackpack_lookingDownLeft" path="lookout" frames="15"/>
|
||||
<Loop id="nobackpack_lookingLeft" path="lookout" frames="16"/>
|
||||
<Loop id="nobackpack_lookingUpLeft" path="lookout" frames="17"/>
|
||||
</lookout_avali>
|
||||
|
||||
</Sprites>
|
||||
|
|
|
@ -0,0 +1,437 @@
|
|||
Attribution-NonCommercial-ShareAlike 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
|
||||
Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution-NonCommercial-ShareAlike 4.0 International Public License
|
||||
("Public License"). To the extent this Public License may be
|
||||
interpreted as a contract, You are granted the Licensed Rights in
|
||||
consideration of Your acceptance of these terms and conditions, and the
|
||||
Licensor grants You such rights in consideration of benefits the
|
||||
Licensor receives from making the Licensed Material available under
|
||||
these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. BY-NC-SA Compatible License means a license listed at
|
||||
creativecommons.org/compatiblelicenses, approved by Creative
|
||||
Commons as essentially the equivalent of this Public License.
|
||||
|
||||
d. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
e. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
f. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
g. License Elements means the license attributes listed in the name
|
||||
of a Creative Commons Public License. The License Elements of this
|
||||
Public License are Attribution, NonCommercial, and ShareAlike.
|
||||
|
||||
h. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
i. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
j. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
k. NonCommercial means not primarily intended for or directed towards
|
||||
commercial advantage or monetary compensation. For purposes of
|
||||
this Public License, the exchange of the Licensed Material for
|
||||
other material subject to Copyright and Similar Rights by digital
|
||||
file-sharing or similar means is NonCommercial provided there is
|
||||
no payment of monetary compensation in connection with the
|
||||
exchange.
|
||||
|
||||
l. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
m. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
n. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part, for NonCommercial purposes only; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material for
|
||||
NonCommercial purposes only.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. Additional offer from the Licensor -- Adapted Material.
|
||||
Every recipient of Adapted Material from You
|
||||
automatically receives an offer from the Licensor to
|
||||
exercise the Licensed Rights in the Adapted Material
|
||||
under the conditions of the Adapter's License You apply.
|
||||
|
||||
c. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties, including when
|
||||
the Licensed Material is used other than for NonCommercial
|
||||
purposes.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
b. ShareAlike.
|
||||
|
||||
In addition to the conditions in Section 3(a), if You Share
|
||||
Adapted Material You produce, the following conditions also apply.
|
||||
|
||||
1. The Adapter's License You apply must be a Creative Commons
|
||||
license with the same License Elements, this version or
|
||||
later, or a BY-NC-SA Compatible License.
|
||||
|
||||
2. You must include the text of, or the URI or hyperlink to, the
|
||||
Adapter's License You apply. You may satisfy this condition
|
||||
in any reasonable manner based on the medium, means, and
|
||||
context in which You Share Adapted Material.
|
||||
|
||||
3. You may not offer or impose any additional or different terms
|
||||
or conditions on, or apply any Effective Technological
|
||||
Measures to, Adapted Material that restrict exercise of the
|
||||
rights granted under the Adapter's License You apply.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database for NonCommercial purposes
|
||||
only;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material,
|
||||
including for purposes of Section 3(b); and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the
|
||||
public licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
|
@ -1,278 +1,429 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Monocle;
|
||||
using System;
|
||||
using MonoMod.Cil;
|
||||
using MonoMod.Utils;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Celeste.Mod.AvaliSkin {
|
||||
// This code was built off of max480's code for the Pro Banana Skin.
|
||||
// Other mods I referenced include SkinModHelper and Kayden Fox skin.
|
||||
public class AvaliSkinModule : EverestModule {
|
||||
public static AvaliSkinModule Instance;
|
||||
public override Type SettingsType => typeof(AvaliSkinSettings);
|
||||
public static AvaliSkinSettings Settings => (AvaliSkinSettings) Instance._Settings;
|
||||
public static SpriteBank AvaliSpriteBank;
|
||||
|
||||
// the dash colors, tbr
|
||||
private static Color ZeroDashColor;
|
||||
private static Color OneDashColor;
|
||||
private static Color TwoDashColor;
|
||||
private static Color ThreeDashColor;
|
||||
private static Color FourDashColor;
|
||||
private static Color FiveDashColor;
|
||||
|
||||
// recolored dash particles (A = 0-dash, B = 1-dash, C = 2-dash)
|
||||
private static ParticleType P_DashA;
|
||||
private static ParticleType P_DashB;
|
||||
private static ParticleType P_DashC;
|
||||
|
||||
// Atlas for Color1 and Color2; we'll see if we need these later.
|
||||
// private static Atlas Col1Atlas;
|
||||
// private static Atlas Col2Atlas;
|
||||
|
||||
// Color Grade IDs
|
||||
private static string dashGID;
|
||||
// private static string col1GID;
|
||||
// private static string col2GID;
|
||||
|
||||
public AvaliSkinModule() {
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public override void Load() {
|
||||
On.Celeste.PlayerSprite.ctor += onPlayerSpriteConstructor;
|
||||
On.Celeste.Player.Render += onPlayerRender;
|
||||
On.Celeste.Player.GetCurrentTrailColor += onPlayerGetTrailColor;
|
||||
On.Celeste.Player.UpdateHair += onPlayerUpdateHair;
|
||||
On.Celeste.Player.DashUpdate += onPlayerDashUpdate;
|
||||
IL.Celeste.DeathEffect.Draw += DeathEffectDrawHook;
|
||||
On.Celeste.Payphone.ctor += onPayphoneConstructor;
|
||||
On.Celeste.Lookout.ctor += onLookoutConstructor;
|
||||
}
|
||||
|
||||
public override void LoadContent(bool firstLoad) {
|
||||
base.LoadContent(firstLoad);
|
||||
}
|
||||
|
||||
public override void Unload() {
|
||||
On.Celeste.PlayerSprite.ctor -= onPlayerSpriteConstructor;
|
||||
On.Celeste.Player.Render -= onPlayerRender;
|
||||
On.Celeste.Player.GetCurrentTrailColor -= onPlayerGetTrailColor;
|
||||
On.Celeste.Player.UpdateHair -= onPlayerUpdateHair;
|
||||
On.Celeste.Player.DashUpdate -= onPlayerDashUpdate;
|
||||
IL.Celeste.DeathEffect.Draw -= DeathEffectDrawHook;
|
||||
On.Celeste.Payphone.ctor -= onPayphoneConstructor;
|
||||
On.Celeste.Lookout.ctor -= onLookoutConstructor;
|
||||
}
|
||||
|
||||
private void onPlayerSpriteConstructor(On.Celeste.PlayerSprite.orig_ctor orig, PlayerSprite self, PlayerSpriteMode mode) {
|
||||
orig(self, mode);
|
||||
|
||||
if (Settings.Enabled) {
|
||||
// set the dash colors
|
||||
ZeroDashColor = ColorsToHex.SettingToColor(Settings.ZeroDash);
|
||||
OneDashColor = ColorsToHex.SettingToColor(Settings.OneDash);
|
||||
TwoDashColor = ColorsToHex.SettingToColor(Settings.TwoDash);
|
||||
ThreeDashColor = ColorsToHex.SettingToColor(Settings.ThreeDash);
|
||||
FourDashColor = ColorsToHex.SettingToColor(Settings.FourDash);
|
||||
FiveDashColor = ColorsToHex.SettingToColor(Settings.FiveDash);
|
||||
|
||||
// build the small dash particles
|
||||
P_DashA = new ParticleType(Player.P_DashA)
|
||||
{
|
||||
Color = ZeroDashColor,
|
||||
Color2 = OneDashColor,
|
||||
};
|
||||
P_DashB = new ParticleType(Player.P_DashA)
|
||||
{
|
||||
Color = OneDashColor,
|
||||
Color2 = TwoDashColor,
|
||||
};
|
||||
P_DashC = new ParticleType(Player.P_DashA)
|
||||
{
|
||||
Color = TwoDashColor,
|
||||
Color2 = TwoDashColor,
|
||||
};
|
||||
|
||||
if (self.Mode == PlayerSpriteMode.Madeline || self.Mode == PlayerSpriteMode.MadelineNoBackpack || self.Mode == PlayerSpriteMode.Playback)
|
||||
{
|
||||
string sprID = "";
|
||||
switch (self.Mode)
|
||||
{
|
||||
case PlayerSpriteMode.Madeline:
|
||||
sprID = "player_avali"; break;
|
||||
case PlayerSpriteMode.MadelineNoBackpack:
|
||||
sprID = "player_avali_no_backpack"; break;
|
||||
case PlayerSpriteMode.Playback:
|
||||
sprID = "player_avali_playback"; break;
|
||||
}
|
||||
PlayerSprite.CreateFramesMetadata(sprID);
|
||||
GFX.SpriteBank.CreateOn(self, sprID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onPlayerRender(On.Celeste.Player.orig_Render orig, Player self) {
|
||||
if (Settings.Enabled) {
|
||||
// we are going to apply a color grade to the Avali using the colors set in settings
|
||||
// get the dash texture ID
|
||||
switch (self.Dashes) {
|
||||
case 0:
|
||||
dashGID = "mcol_" + Settings.ZeroDash; break;
|
||||
case 1:
|
||||
dashGID = "mcol_" + Settings.OneDash; break;
|
||||
case 2:
|
||||
dashGID = "mcol_" + Settings.TwoDash; break;
|
||||
case 3:
|
||||
dashGID = "mcol_" + Settings.ThreeDash; break;
|
||||
case 4:
|
||||
dashGID = "mcol_" + Settings.FourDash; break;
|
||||
default:
|
||||
dashGID = "mcol_" + Settings.FiveDash; break;
|
||||
}
|
||||
|
||||
/* get the color1 and color2 grade IDS
|
||||
col1GID = "col1_" + Settings.ColorOne;
|
||||
col2GID = "col2_" + Settings.ColorTwo;
|
||||
|
||||
This is where code to apply custom color1 and color2 would go, but I've learned that using colorgrades themselves is *not* a viable option, so I have not currently implemented it.
|
||||
I might need a custom effect.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// apply the colorgrade to the player
|
||||
Effect fxColorGrading = GFX.FxColorGrading;
|
||||
fxColorGrading.CurrentTechnique = fxColorGrading.Techniques["ColorGradeSingle"];
|
||||
Engine.Graphics.GraphicsDevice.Textures[1] = GFX.ColorGrades[dashGID].Texture.Texture_Safe;
|
||||
Draw.SpriteBatch.End();
|
||||
Draw.SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.None, RasterizerState.CullNone, fxColorGrading, (self.Scene as Level).GameplayRenderer.Camera.Matrix);
|
||||
|
||||
// render Avali...
|
||||
orig(self);
|
||||
|
||||
// ... and reset rendering to stop using the color grade.
|
||||
Draw.SpriteBatch.End();
|
||||
Draw.SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.None, RasterizerState.CullNone, null, (self.Scene as Level).GameplayRenderer.Camera.Matrix);
|
||||
} else {
|
||||
// skin disabled, just render Maddy
|
||||
orig(self);
|
||||
}
|
||||
}
|
||||
private void DeathEffectDrawHook(ILContext il)
|
||||
{
|
||||
// replace death particle, just like SkinModHelper
|
||||
ILCursor cursor = new ILCursor(il);
|
||||
while (cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdstr("characters/player/hair00"))) {
|
||||
cursor.EmitDelegate<Func<string, string>>(ReplaceDeathParticle);
|
||||
}
|
||||
}
|
||||
private static string ReplaceDeathParticle(string deathParticle)
|
||||
{
|
||||
if (Settings.Enabled) {
|
||||
string newDeathParticle = "characters/Avali/death_particle";
|
||||
return newDeathParticle;
|
||||
}
|
||||
return deathParticle;
|
||||
}
|
||||
private Color onPlayerGetTrailColor(On.Celeste.Player.orig_GetCurrentTrailColor orig, Player self) {
|
||||
if (Settings.Enabled) {
|
||||
// replace trail colors with marking colors
|
||||
int dashCount = self.Dashes;
|
||||
switch (dashCount) {
|
||||
case 0:
|
||||
return ZeroDashColor;
|
||||
case 1:
|
||||
return OneDashColor;
|
||||
case 2:
|
||||
return TwoDashColor;
|
||||
case 3:
|
||||
return ThreeDashColor;
|
||||
case 4:
|
||||
return FourDashColor;
|
||||
default:
|
||||
return FiveDashColor;
|
||||
}
|
||||
}
|
||||
|
||||
// skin disabled, keep original colors
|
||||
return orig(self);
|
||||
}
|
||||
|
||||
private void onPlayerUpdateHair(On.Celeste.Player.orig_UpdateHair orig, Player self, bool applyGravity) {
|
||||
orig(self, applyGravity);
|
||||
|
||||
if (Settings.Enabled) {
|
||||
// change player hair color to match dash colors.
|
||||
// (hair is invisible, but that influences other things like the orbs when the Avali dies and respawns)
|
||||
int dashCount = self.Dashes;
|
||||
switch (dashCount)
|
||||
{
|
||||
case 0:
|
||||
self.Hair.Color = ZeroDashColor; break;
|
||||
case 1:
|
||||
self.Hair.Color = OneDashColor; break;
|
||||
case 2:
|
||||
self.Hair.Color = TwoDashColor; break;
|
||||
case 3:
|
||||
self.Hair.Color = ThreeDashColor; break;
|
||||
case 4:
|
||||
self.Hair.Color = FourDashColor; break;
|
||||
default:
|
||||
self.Hair.Color = FiveDashColor; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int onPlayerDashUpdate(On.Celeste.Player.orig_DashUpdate orig, Player self) {
|
||||
if (!Settings.Enabled) {
|
||||
// skin disabled: just run vanilla code
|
||||
return orig(self);
|
||||
}
|
||||
|
||||
// back up vanilla particles
|
||||
ParticleType bakDashA = Player.P_DashA;
|
||||
ParticleType bakDashB = Player.P_DashB;
|
||||
ParticleType bakDashBadB = Player.P_DashBadB;
|
||||
|
||||
// replace them with recolored ones
|
||||
Player.P_DashA = P_DashA;
|
||||
Player.P_DashB = P_DashB;
|
||||
Player.P_DashBadB = P_DashB;
|
||||
|
||||
// run vanilla code: if it emits particles, it will use recolored ones.
|
||||
int result = orig(self);
|
||||
|
||||
// restore vanilla particles
|
||||
Player.P_DashA = bakDashA;
|
||||
Player.P_DashB = bakDashB;
|
||||
Player.P_DashBadB = bakDashBadB;
|
||||
|
||||
return result;
|
||||
}
|
||||
private void onPayphoneConstructor(On.Celeste.Payphone.orig_ctor orig, Payphone self, Vector2 pos)
|
||||
{
|
||||
orig(self, pos);
|
||||
if (Settings.Enabled)
|
||||
{
|
||||
// replace payphone sprites
|
||||
self.Remove(self.Sprite);
|
||||
self.Add(self.Sprite = GFX.SpriteBank.Create("payphone_avali"));
|
||||
self.Sprite.Play("idle");
|
||||
}
|
||||
}
|
||||
|
||||
private void onLookoutConstructor(On.Celeste.Lookout.orig_ctor orig, Lookout self, EntityData data, Vector2 pos)
|
||||
{
|
||||
orig(self, data, pos);
|
||||
if (Settings.Enabled) {
|
||||
// replace lookout (binoculars) sprites
|
||||
DynamicData lookoutData = new DynamicData(self);
|
||||
Sprite origSpr = lookoutData.Get<Sprite>("sprite");
|
||||
GFX.SpriteBank.CreateOn(origSpr, "lookout_avali");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Monocle;
|
||||
using MonoMod.Cil;
|
||||
using MonoMod.Utils;
|
||||
using MonoMod.RuntimeDetour;
|
||||
|
||||
using Celeste.Mod.CelesteNet.Client;
|
||||
using Celeste.Mod.CelesteNet.Client.Entities;
|
||||
using Celeste.Mod.CelesteNet.DataTypes;
|
||||
|
||||
using ColorChoice = Celeste.Mod.AvaliSkin.AvaliSkinSettings.ColorChoice;
|
||||
using ColorMode = Celeste.Mod.AvaliSkin.AvaliSkinSettings.ColorMode;
|
||||
|
||||
|
||||
namespace Celeste.Mod.AvaliSkin {
|
||||
// This code was built off of max480's code for the Pro Banana Skin.
|
||||
// Other mods I referenced include SkinModHelper, Hyperline, Styleline, and Kayden Fox skin.
|
||||
public class AvaliSkinModule : EverestModule {
|
||||
public static AvaliSkinModule Instance;
|
||||
public override Type SettingsType => typeof(AvaliSkinSettings);
|
||||
public static AvaliSkinSettings Settings => (AvaliSkinSettings) Instance._Settings;
|
||||
|
||||
public static AvaliConfig PlayerConfig {
|
||||
get => new AvaliConfig {
|
||||
Enabled = Settings.Enabled,
|
||||
ColorMode = Settings.ColorModeOpt,
|
||||
ManualPreset = Settings.DashPreset,
|
||||
ManualRGB = Settings.DashRGBColor
|
||||
};
|
||||
}
|
||||
private static Effect FxRecolor;
|
||||
|
||||
public static EverestModuleMetadata CelesteNetMeta = new EverestModuleMetadata() {
|
||||
Name = "CelesteNet.Client",
|
||||
Version = new Version(2, 0, 0)
|
||||
};
|
||||
|
||||
public AvaliSkinModule() => Instance = this;
|
||||
|
||||
|
||||
public override void Load() {
|
||||
Logger.Log(LogLevel.Info, "AvaliSkin", $"Hooking stuff...");
|
||||
|
||||
On.Celeste.LevelLoader.ctor += onLevelLoaderctor;
|
||||
On.Celeste.Player.Render += onPlayerRender;
|
||||
|
||||
if (Everest.Loader.DependencyLoaded(CelesteNetMeta)) {
|
||||
Logger.Log(LogLevel.Info, "AvaliSkin", $"Hooking for CelesteNet...");
|
||||
On.Celeste.PlayerSprite.Render += onPlayerSpriteRenderCelestenet;
|
||||
On.Celeste.PlayerSprite.Render += onPlayerSpriteRenderCelestenetMisc;
|
||||
} else {
|
||||
On.Celeste.PlayerSprite.Render += onPlayerSpriteRenderMisc;
|
||||
}
|
||||
|
||||
using (new DetourContext("AvaliSkinModule") {
|
||||
After = { "Hyperline" }
|
||||
}) {
|
||||
On.Celeste.Player.GetCurrentTrailColor += onPlayerGetTrailColor;
|
||||
On.Celeste.Player.UpdateHair += onPlayerUpdateHair;
|
||||
On.Celeste.Player.DashUpdate += onPlayerDashUpdate;
|
||||
}
|
||||
|
||||
IL.Celeste.DeathEffect.Draw += DeathEffectDrawHook;
|
||||
On.Celeste.Payphone.ctor += onPayphoneConstructor;
|
||||
On.Celeste.Lookout.ctor += onLookoutConstructor;
|
||||
}
|
||||
|
||||
|
||||
public override void LoadContent(bool firstLoad) {
|
||||
base.LoadContent(firstLoad);
|
||||
|
||||
IGraphicsDeviceService graphicsDeviceService =
|
||||
Engine.Instance.Content.ServiceProvider
|
||||
.GetService(typeof(IGraphicsDeviceService))
|
||||
as IGraphicsDeviceService;
|
||||
|
||||
ModAsset asset = Everest.Content.Get("Effects/AvaliRecolor.o", true);
|
||||
FxRecolor = new Effect(graphicsDeviceService.GraphicsDevice, asset.Data);
|
||||
}
|
||||
|
||||
|
||||
public override void Unload() {
|
||||
Logger.Log(LogLevel.Info, "AvaliSkin", $"Unhooking stuff...");
|
||||
|
||||
On.Celeste.LevelLoader.ctor -= onLevelLoaderctor;
|
||||
On.Celeste.Player.Render -= onPlayerRender;
|
||||
|
||||
if (Everest.Loader.DependencyLoaded(CelesteNetMeta)) {
|
||||
Logger.Log(LogLevel.Info, "AvaliSkin", $"Unhooking hooks for CelesteNet...");
|
||||
On.Celeste.PlayerSprite.Render -= onPlayerSpriteRenderCelestenet;
|
||||
On.Celeste.PlayerSprite.Render -= onPlayerSpriteRenderCelestenetMisc;
|
||||
} else {
|
||||
On.Celeste.PlayerSprite.Render -= onPlayerSpriteRenderMisc;
|
||||
}
|
||||
|
||||
using (new DetourContext("AvaliSkinModule") {
|
||||
After = { "Hyperline" }
|
||||
}) {
|
||||
On.Celeste.Player.GetCurrentTrailColor -= onPlayerGetTrailColor;
|
||||
On.Celeste.Player.UpdateHair -= onPlayerUpdateHair;
|
||||
On.Celeste.Player.DashUpdate -= onPlayerDashUpdate;
|
||||
}
|
||||
|
||||
IL.Celeste.DeathEffect.Draw -= DeathEffectDrawHook;
|
||||
On.Celeste.Payphone.ctor -= onPayphoneConstructor;
|
||||
On.Celeste.Lookout.ctor -= onLookoutConstructor;
|
||||
|
||||
FxRecolor.Dispose();
|
||||
}
|
||||
|
||||
|
||||
private void trySpriteSwap(PlayerSprite sprite, bool enabled) {
|
||||
DynamicData dd = DynamicData.For(sprite);
|
||||
bool oldEnabled = false;
|
||||
// TryGet crashes with value types (of course; obviously!)
|
||||
// So we use a object type with the nullable bool... this is a bug in monomod?
|
||||
if (dd.TryGet<bool?>("avaliskin_enabled", out bool? ddoldEnabled)) {
|
||||
oldEnabled = (bool) ddoldEnabled;
|
||||
}
|
||||
|
||||
if (oldEnabled != enabled) {
|
||||
string spriteID = "";
|
||||
switch (sprite.Mode) {
|
||||
case PlayerSpriteMode.Madeline:
|
||||
spriteID = enabled ? "player_avali" : "player"; break;
|
||||
case PlayerSpriteMode.MadelineNoBackpack:
|
||||
spriteID = enabled ? "player_avali_no_backpack" : "player_no_backpack"; break;
|
||||
case PlayerSpriteMode.Playback:
|
||||
spriteID = enabled ? "player_avali_playback" : "player_playback"; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
dd.Set("avaliskin_enabled", (bool?) enabled);
|
||||
Vector2 pos = sprite.RenderPosition;
|
||||
GFX.SpriteBank.CreateOn(sprite, spriteID);
|
||||
sprite.RenderPosition = pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onLevelLoaderctor(
|
||||
On.Celeste.LevelLoader.orig_ctor orig, LevelLoader self,
|
||||
Session session, Vector2? startPosition = null
|
||||
) {
|
||||
orig(self, session, startPosition);
|
||||
|
||||
// This only needs to be ran once, but we can't run this in LoadContent
|
||||
// because the sprites are not loaded yet... see the original Everest
|
||||
// source for this function
|
||||
PlayerSprite.CreateFramesMetadata("player_avali");
|
||||
PlayerSprite.CreateFramesMetadata("player_avali_no_backpack");
|
||||
PlayerSprite.CreateFramesMetadata("player_avali_playback");
|
||||
}
|
||||
|
||||
|
||||
private void onPlayerRender(On.Celeste.Player.orig_Render orig, Player self) {
|
||||
PlayerSprite sprite = self.Sprite;
|
||||
if (sprite.Scene != null && PlayerConfig.IsEnabled(self)) {
|
||||
// swap out the player's spritebank if the enabled state changed
|
||||
trySpriteSwap(sprite, true);
|
||||
Color color = PlayerConfig.GetColor(self);
|
||||
|
||||
// apply the recolor effect to the player:
|
||||
// replace the color #1ud589 in the sprite with color
|
||||
FxRecolor.Parameters["threshold"].SetValue(0.01f);
|
||||
FxRecolor.Parameters["color_replace_from"].SetValue(
|
||||
(new Color((byte) 0x1u, 0xd5, 0x89, 0xff)).ToVector4()
|
||||
);
|
||||
FxRecolor.Parameters["color_replace_to"].SetValue(color.ToVector4());
|
||||
FxRecolor.CurrentTechnique = FxRecolor.Techniques["Recolor"];
|
||||
|
||||
Draw.SpriteBatch.End();
|
||||
Draw.SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.None, RasterizerState.CullNone, FxRecolor, (self.Scene as Level).GameplayRenderer.Camera.Matrix);
|
||||
|
||||
// render Avali...
|
||||
orig(self);
|
||||
|
||||
// ... and reset rendering to stop using the effect
|
||||
Draw.SpriteBatch.End();
|
||||
Draw.SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.None, RasterizerState.CullNone, null, (self.Scene as Level).GameplayRenderer.Camera.Matrix);
|
||||
} else if (self.Scene != null) {
|
||||
trySpriteSwap(sprite, false);
|
||||
orig(self);
|
||||
} else {
|
||||
orig(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onPlayerSpriteRenderMisc(On.Celeste.PlayerSprite.orig_Render orig, PlayerSprite self) {
|
||||
Player player = Engine.Scene.Tracker.GetEntity<Player>();
|
||||
if (player == null) {
|
||||
orig(self);
|
||||
return;
|
||||
}
|
||||
|
||||
// This handles rendering of misc instances of PlayerSprites:
|
||||
// usually player playback entities and the such.
|
||||
if (
|
||||
self.Scene != null
|
||||
&& (self.Entity == null || !(self.Entity is Player))
|
||||
) {
|
||||
if (PlayerConfig.IsEnabled(player)) {
|
||||
trySpriteSwap(self, true);
|
||||
Color color = PlayerConfig.GetColor(player);
|
||||
|
||||
// apply the recolor effect to the sprite
|
||||
// replace the color #1ud589 in the sprite with color
|
||||
FxRecolor.Parameters["threshold"].SetValue(0.01f);
|
||||
FxRecolor.Parameters["color_replace_from"].SetValue(
|
||||
(new Color((byte) 0x1u, 0xd5, 0x89, 0xff)).ToVector4()
|
||||
);
|
||||
FxRecolor.Parameters["color_replace_to"].SetValue(color.ToVector4());
|
||||
FxRecolor.CurrentTechnique = FxRecolor.Techniques["Recolor"];
|
||||
|
||||
Draw.SpriteBatch.End();
|
||||
Draw.SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.None, RasterizerState.CullNone, FxRecolor, (self.Scene as Level).GameplayRenderer.Camera.Matrix);
|
||||
|
||||
// render the sprite...
|
||||
orig(self);
|
||||
|
||||
// ... and reset rendering to stop using the effect
|
||||
Draw.SpriteBatch.End();
|
||||
Draw.SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.None, RasterizerState.CullNone, null, (self.Scene as Level).GameplayRenderer.Camera.Matrix);
|
||||
} else {
|
||||
trySpriteSwap(self, false);
|
||||
orig(self);
|
||||
}
|
||||
} else {
|
||||
orig(self);
|
||||
}
|
||||
}
|
||||
|
||||
private void onPlayerSpriteRenderCelestenetMisc(On.Celeste.PlayerSprite.orig_Render orig, PlayerSprite self) {
|
||||
// This handles rendering of misc instances of PlayerSprites:
|
||||
// usually player playback entities and the such.
|
||||
if (
|
||||
self.Scene != null && (
|
||||
self.Entity == null
|
||||
|| !(self.Entity is Player || self.Entity is Ghost)
|
||||
)
|
||||
) {
|
||||
onPlayerSpriteRenderMisc(orig, self);
|
||||
} else {
|
||||
orig(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// CelesteNet must be loaded when calling this function.
|
||||
private void onPlayerSpriteRenderCelestenet(On.Celeste.PlayerSprite.orig_Render orig, PlayerSprite self) {
|
||||
// CelesteNet players are not actually Player classes, but instead this custom Ghost class.
|
||||
// Ghosts have their own custom hair and sprite which we are able to recolor like the player.
|
||||
// We need to be really paranoid here cuz celestenet jank...
|
||||
CelesteNetClient client = CelesteNetClientModule.Instance.Client;
|
||||
AvaliConfig everyoneHasSkin = new AvaliConfig { Enabled = true, ColorMode = ColorMode.ExternalDash};
|
||||
Color color;
|
||||
Ghost ghost;
|
||||
if (
|
||||
self.Scene != null && self.Entity != null
|
||||
&& self.Entity is Ghost ghost2 && ghost2.PlayerInfo != null
|
||||
&& client != null
|
||||
&& client.Data.TryGetBoundRef<DataPlayerInfo, DataPlayerAvaliSkin>(
|
||||
ghost2.PlayerInfo.ID,
|
||||
out DataPlayerAvaliSkin data
|
||||
) && data != null
|
||||
&& data.Config.IsEnabled(ghost2)
|
||||
) {
|
||||
ghost = ghost2;
|
||||
color = data.Config.GetColor(ghost);
|
||||
} else if (
|
||||
Settings.CelesteNetEveryoneHasSkin
|
||||
&& self.Scene != null && self.Entity != null
|
||||
&& self.Entity is Ghost ghost3
|
||||
&& everyoneHasSkin.IsEnabled(ghost3)
|
||||
) {
|
||||
ghost = ghost3;
|
||||
color = everyoneHasSkin.GetColor(ghost);
|
||||
} else if (
|
||||
self.Scene != null && self.Entity != null
|
||||
&& self.Entity is Ghost _
|
||||
) {
|
||||
trySpriteSwap(self, false);
|
||||
orig(self);
|
||||
return;
|
||||
} else {
|
||||
orig(self);
|
||||
return;
|
||||
}
|
||||
|
||||
// swap out the ghost's spritebank if the enabled state changed
|
||||
trySpriteSwap(self, true);
|
||||
|
||||
// apply the recolor effect to the ghost:
|
||||
// replace the color #1ud589 in the sprite with color
|
||||
FxRecolor.Parameters["threshold"].SetValue(0.01f);
|
||||
FxRecolor.Parameters["color_replace_from"].SetValue(
|
||||
(new Color((byte) 0x1u, 0xd5, 0x89, 0xff)).ToVector4()
|
||||
);
|
||||
FxRecolor.Parameters["color_replace_to"].SetValue(color.ToVector4());
|
||||
FxRecolor.CurrentTechnique = FxRecolor.Techniques["Recolor"];
|
||||
|
||||
Draw.SpriteBatch.End();
|
||||
Draw.SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.None, RasterizerState.CullNone, FxRecolor, (self.Scene as Level).GameplayRenderer.Camera.Matrix);
|
||||
|
||||
// render the ghost...
|
||||
orig(self);
|
||||
|
||||
// ... and reset rendering to stop using the effect
|
||||
Draw.SpriteBatch.End();
|
||||
Draw.SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointWrap, DepthStencilState.None, RasterizerState.CullNone, null, (self.Scene as Level).GameplayRenderer.Camera.Matrix);
|
||||
}
|
||||
|
||||
|
||||
private void DeathEffectDrawHook(ILContext il) {
|
||||
// replace death particle, just like SkinModHelper
|
||||
ILCursor cursor = new ILCursor(il);
|
||||
while (cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdstr("characters/player/hair00"))) {
|
||||
cursor.EmitDelegate<Func<string, string>>(ReplaceDeathParticle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static string ReplaceDeathParticle(string deathParticle) {
|
||||
if (PlayerConfig.Enabled) {
|
||||
string newDeathParticle = "characters/Avali/death_particle";
|
||||
return newDeathParticle;
|
||||
}
|
||||
return deathParticle;
|
||||
}
|
||||
|
||||
|
||||
private Color onPlayerGetTrailColor(On.Celeste.Player.orig_GetCurrentTrailColor orig, Player self) {
|
||||
Color orig_color = orig(self);
|
||||
if (PlayerConfig.IsEnabled(self)) {
|
||||
// Don't change the trail color if another mod is in control of it!
|
||||
// The hair mod should do be doing that instead of us.
|
||||
// Furthermore: naively doing this will look strange because the white
|
||||
// hair flash right after dashing will be copied to the trail.
|
||||
if (PlayerConfig.ColorMode != ColorMode.ExternalDash) {
|
||||
// replace trail colors with marking colors
|
||||
return PlayerConfig.GetColor(self);
|
||||
}
|
||||
}
|
||||
|
||||
// skin disabled, keep original colors
|
||||
return orig_color;
|
||||
}
|
||||
|
||||
|
||||
private void onPlayerUpdateHair(On.Celeste.Player.orig_UpdateHair orig, Player self, bool applyGravity) {
|
||||
orig(self, applyGravity);
|
||||
|
||||
// Don't change the hair color if another mod is in control of it!
|
||||
if (PlayerConfig.IsEnabled(self) && PlayerConfig.ColorMode != ColorMode.ExternalDash) {
|
||||
// change player hair color to match dash colors.
|
||||
// (hair is invisible, but that influences other things like the orbs when the Avali dies and respawns)
|
||||
self.Hair.Color = PlayerConfig.GetColor(self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int onPlayerDashUpdate(On.Celeste.Player.orig_DashUpdate orig, Player self) {
|
||||
if (!(
|
||||
PlayerConfig.IsEnabled(self)
|
||||
// We can't exfiltrate a dash color in this mode because we can't extract that
|
||||
// without integrating with the dash color mod, and besides, whatever mod that
|
||||
// changed the dash color should have also changed these particles regardless.
|
||||
&& PlayerConfig.ColorMode != ColorMode.ExternalDash
|
||||
)) {
|
||||
// disabled, just run vanilla code
|
||||
return orig(self);
|
||||
}
|
||||
|
||||
Color color = PlayerConfig.GetColor(self);
|
||||
|
||||
// back up vanilla particles
|
||||
ParticleType bakDashA = Player.P_DashA;
|
||||
ParticleType bakDashB = Player.P_DashB;
|
||||
ParticleType bakDashBadB = Player.P_DashBadB;
|
||||
|
||||
// Replace them with recolored ones.
|
||||
// We need to generate these dash particles on the fly because multiple players may
|
||||
// have different colors (e.g. Celestenet).
|
||||
Player.P_DashA = new ParticleType(Player.P_DashA) {
|
||||
Color = color,
|
||||
Color2 = color,
|
||||
};
|
||||
Player.P_DashB = Player.P_DashA;
|
||||
Player.P_DashBadB = Player.P_DashA;
|
||||
|
||||
// run vanilla code: if it emits particles, it will use recolored ones.
|
||||
int result = orig(self);
|
||||
|
||||
// restore vanilla particles
|
||||
Player.P_DashA = bakDashA;
|
||||
Player.P_DashB = bakDashB;
|
||||
Player.P_DashBadB = bakDashBadB;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private void onPayphoneConstructor(On.Celeste.Payphone.orig_ctor orig, Payphone self, Vector2 pos) {
|
||||
orig(self, pos);
|
||||
if (Settings.Enabled) {
|
||||
// replace payphone sprites
|
||||
self.Remove(self.Sprite);
|
||||
self.Add(self.Sprite = GFX.SpriteBank.Create("payphone_avali"));
|
||||
self.Sprite.Play("idle");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void onLookoutConstructor(On.Celeste.Lookout.orig_ctor orig, Lookout self, EntityData data, Vector2 pos) {
|
||||
orig(self, data, pos);
|
||||
if (Settings.Enabled) {
|
||||
// replace lookout (binoculars) sprites
|
||||
DynamicData lookoutData = new DynamicData(self);
|
||||
Sprite origSpr = lookoutData.Get<Sprite>("sprite");
|
||||
GFX.SpriteBank.CreateOn(origSpr, "lookout_avali");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,94 +1,326 @@
|
|||
using Monocle;
|
||||
|
||||
namespace Celeste.Mod.AvaliSkin
|
||||
{
|
||||
[SettingName("AVALI_SKIN_TITLE")]
|
||||
public class AvaliSkinSettings : EverestModuleSettings
|
||||
{
|
||||
private bool enabled = true;
|
||||
|
||||
[SettingSubText("Note: Enabling/disabling in-game requires either\na reload or death before some things change")]
|
||||
public bool Enabled
|
||||
{
|
||||
get => enabled;
|
||||
set
|
||||
{
|
||||
enabled = value;
|
||||
|
||||
if (Engine.Scene is Level level)
|
||||
{
|
||||
// we're in a map: reset sprite the same way the Other Self toggle does.
|
||||
// the hook on PlayerSprite will decide if we should use the Avali skin or not.
|
||||
Player player = level.Tracker.GetEntity<Player>();
|
||||
if (player != null)
|
||||
{
|
||||
PlayerSpriteMode mode = (SaveData.Instance.Assists.PlayAsBadeline ? PlayerSpriteMode.MadelineAsBadeline : player.DefaultSpriteMode);
|
||||
if (player.Active)
|
||||
{
|
||||
player.ResetSpriteNextFrame(mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
player.ResetSprite(mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region AvaliColorSettings
|
||||
|
||||
/* For later
|
||||
|
||||
[SettingName("AVALI_SKIN_COLORONE")]
|
||||
public ColorChoice ColorOne { get; set; } = ColorChoice.Beige;
|
||||
|
||||
[SettingName("AVALI_SKIN_COLORTWO")]
|
||||
public ColorChoice ColorTwo { get; set; } = ColorChoice.GreyLight;
|
||||
|
||||
*/
|
||||
|
||||
[SettingName("AVALI_SKIN_ZERODASH")]
|
||||
[SettingSubText("Note: Changing colors in-game requires either\na reload or death before fully applying")]
|
||||
public ColorChoice ZeroDash { get; set; } = ColorChoice.BlueLight;
|
||||
|
||||
[SettingName("AVALI_SKIN_ONEDASH")]
|
||||
public ColorChoice OneDash { get; set; } = ColorChoice.Turquoise;
|
||||
|
||||
[SettingName("AVALI_SKIN_TWODASH")]
|
||||
public ColorChoice TwoDash { get; set; } = ColorChoice.Pink;
|
||||
|
||||
[SettingName("AVALI_SKIN_THREEDASH")]
|
||||
public ColorChoice ThreeDash { get; set; } = ColorChoice.BlueDark;
|
||||
|
||||
[SettingName("AVALI_SKIN_FOURDASH")]
|
||||
public ColorChoice FourDash { get; set; } = ColorChoice.Yellow;
|
||||
|
||||
[SettingName("AVALI_SKIN_FIVEDASH")]
|
||||
public ColorChoice FiveDash { get; set; } = ColorChoice.Red;
|
||||
|
||||
#endregion
|
||||
|
||||
public enum ColorChoice
|
||||
{
|
||||
Beige,
|
||||
Black,
|
||||
BlueDark,
|
||||
BlueLight,
|
||||
Brown,
|
||||
Cyan,
|
||||
GreenDark,
|
||||
GreenLight,
|
||||
GreyDark,
|
||||
GreyLight,
|
||||
Magenta,
|
||||
Orange,
|
||||
Pink,
|
||||
Purple,
|
||||
Red,
|
||||
Turquoise,
|
||||
White,
|
||||
Yellow,
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
using Monocle;
|
||||
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Celeste.Mod.AvaliSkin {
|
||||
[SettingName("AVALI_SKIN_TITLE")]
|
||||
public class AvaliSkinSettings : EverestModuleSettings {
|
||||
private void updateOptions() {
|
||||
bool loadedCelestenet = Everest.Loader.DependencyLoaded(AvaliSkinModule.CelesteNetMeta);
|
||||
|
||||
// send the new settings to other celestenet players if we're connected
|
||||
if (loadedCelestenet) { updateSkinCelestenet(); }
|
||||
|
||||
// menu is not loaded; don't bother
|
||||
if (ColorModeOptItem == null) { return; }
|
||||
|
||||
// disable all the normal options if the main toggle is disabled
|
||||
ColorModeOptItem.Disabled = !Enabled;
|
||||
ColorSubmenuItem.Disabled = !Enabled;
|
||||
|
||||
// change up the colormode note based on the selection
|
||||
string colorModeNote = "";
|
||||
switch (ColorModeOpt) {
|
||||
case ColorMode.ExternalDash: colorModeNote = "modoptions_avaliskin_colormodeopt_ExternalDash_note"; break;
|
||||
case ColorMode.ManualPreset: colorModeNote = "modoptions_avaliskin_colormodeopt_ManualPreset_note"; break;
|
||||
case ColorMode.ManualRGB: colorModeNote = "modoptions_avaliskin_colormodeopt_ManualRGB_note"; break;
|
||||
}
|
||||
ColorModeOptNote.Title = colorModeNote.DialogOrKey();
|
||||
|
||||
// no point in showing the submenu at all for externaldash; there's
|
||||
// nothing to configure!
|
||||
ColorSubmenuItem.Visible = ColorModeOpt != ColorMode.ExternalDash;
|
||||
|
||||
// disable and change item visibility based on main toggle or colormode
|
||||
foreach (var item in DashRGBItems) {
|
||||
item.Disabled = !Enabled;
|
||||
item.Visible = ColorModeOpt == ColorMode.ManualRGB;
|
||||
}
|
||||
|
||||
foreach (var item in DashPresetItems) {
|
||||
item.Disabled = !Enabled;
|
||||
item.Visible = ColorModeOpt == ColorMode.ManualPreset;
|
||||
}
|
||||
|
||||
|
||||
// Disable if Celestenet is not installed/enabled.
|
||||
EnableCelesteNetItem.Disabled = !loadedCelestenet;
|
||||
|
||||
// Independently disable the celestenet options
|
||||
// The user might want the skin disabled, but not for others!
|
||||
// Also disable these options if Celestenet is not installed/enabled.
|
||||
CelesteNetSyncItem.Disabled = !EnableCelesteNet || !loadedCelestenet;
|
||||
CelesteNetEveryoneHasSkinItem.Disabled = !EnableCelesteNet || !loadedCelestenet;
|
||||
}
|
||||
|
||||
// CelesteNet must be loaded when calling this function.
|
||||
private void updateSkinCelestenet() {
|
||||
// this needs to be in a seperate function because the entire component
|
||||
// relies on an assembly reference
|
||||
if (CelesteNetAvaliComponent.Instance != null) {
|
||||
CelesteNetAvaliComponent.Instance.SendAvaliSkin();
|
||||
}
|
||||
}
|
||||
|
||||
// note: YamlDotNet ignores all private member variables
|
||||
private bool enabled = true;
|
||||
public bool Enabled {
|
||||
get => enabled;
|
||||
set {
|
||||
enabled = value;
|
||||
|
||||
if (Engine.Scene is Level level) {
|
||||
// we're in a map: reset sprite the same way the Other Self toggle does.
|
||||
// the hook on PlayerSprite will decide if we should use the Avali skin or not.
|
||||
Player player = level.Tracker.GetEntity<Player>();
|
||||
if (player != null) {
|
||||
PlayerSpriteMode mode = (SaveData.Instance.Assists.PlayAsBadeline ? PlayerSpriteMode.MadelineAsBadeline : player.DefaultSpriteMode);
|
||||
if (player.Active) {
|
||||
player.ResetSpriteNextFrame(mode);
|
||||
} else {
|
||||
player.ResetSprite(mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateOptions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum ColorMode {
|
||||
ExternalDash,
|
||||
ManualPreset,
|
||||
ManualRGB
|
||||
}
|
||||
|
||||
public ColorMode ColorModeOpt { get; set; } = ColorMode.ExternalDash;
|
||||
private TextMenu.Item ColorModeOptItem;
|
||||
private TextMenu.SubHeader ColorModeOptNote;
|
||||
public void CreateColorModeOptEntry(TextMenu menu, bool inGame) {
|
||||
ColorModeOptItem = new TextMenuExt.EnumerableSlider<ColorMode>(
|
||||
"modoptions_avaliskin_colormodeopt".DialogOrKey(),
|
||||
// Enum.GetValues returns an Array, which is not enumerable.
|
||||
// However, normal object vectors are. So...
|
||||
((ColorMode[]) Enum.GetValues(typeof(ColorMode))).Select(
|
||||
variant => new KeyValuePair<ColorMode, string>(
|
||||
variant,
|
||||
$"modoptions_avaliskin_colormodeopt_{variant.ToString()}".DialogOrKey()
|
||||
)
|
||||
),
|
||||
ColorModeOpt
|
||||
).Change(opt => {
|
||||
ColorModeOpt = opt;
|
||||
updateOptions();
|
||||
});
|
||||
menu.Add(ColorModeOptItem);
|
||||
ColorModeOptItem.AddDescription(menu, "modoptions_avaliskin_colormodeopt_note".DialogOrKey());
|
||||
|
||||
List<TextMenu.Item> items = menu.GetItems();
|
||||
ColorModeOptNote = (TextMenu.SubHeader) items[items.IndexOf(ColorModeOptItem) + 1];
|
||||
}
|
||||
|
||||
#region AvaliColorSettings
|
||||
|
||||
// ColorSubmenu is a dummy setting that is only used to position the
|
||||
// Submenu. This setting is never used, hence why it is Void!
|
||||
[YamlIgnore]
|
||||
public Void ColorSubmenu { get; set; }
|
||||
private TextMenuExt.OptionSubMenu ColorSubmenuItem;
|
||||
public void CreateColorSubmenuEntry(TextMenu menu, bool inGame) {
|
||||
DashRGBItems.Clear();
|
||||
DashPresetItems.Clear();
|
||||
|
||||
ColorSubmenuItem = new TextMenuExt.OptionSubMenu(
|
||||
"AVALI_SKIN_COLORS".DialogOrKey()
|
||||
);
|
||||
|
||||
// This generates n submenus, one for each dash
|
||||
for (int i = 0; i < DashRGBColor.Count; i++) {
|
||||
TextMenuExt.IntSlider DashRItem, DashGItem, DashBItem;
|
||||
TextMenu.Option<ColorChoice> DashColorItem;
|
||||
|
||||
int j = i; // C# lambda are wierd: capturing i directly mutates the captured variable
|
||||
|
||||
ColorSubmenuItem.Add(
|
||||
$"AVALI_SKIN_DASH{i}".DialogOrKey(),
|
||||
new List<TextMenu.Item> {
|
||||
(DashRItem = new TextMenuExt.IntSlider(
|
||||
"AVALI_SKIN_RED".DialogOrKey(),
|
||||
0, 255, DashRGBColor[j].R
|
||||
).Change(
|
||||
// C# is stupidly pendatic and doesn't support property assignment in List elements
|
||||
// so we have to do this ugly shit to avoid breaking up this expression into two
|
||||
c => DashRGBColor[j] = new Color((byte) c, DashRGBColor[j].B, DashRGBColor[j].G)
|
||||
)),
|
||||
(DashGItem = new TextMenuExt.IntSlider(
|
||||
"AVALI_SKIN_BLUE".DialogOrKey(),
|
||||
0, 255, DashRGBColor[j].G
|
||||
).Change(
|
||||
c => DashRGBColor[j] = new Color(DashRGBColor[j].R, (byte) c, DashRGBColor[j].G)
|
||||
)),
|
||||
(DashBItem = new TextMenuExt.IntSlider(
|
||||
"AVALI_SKIN_GREEN".DialogOrKey(),
|
||||
0, 255, DashRGBColor[j].B
|
||||
).Change(
|
||||
c => DashRGBColor[j] = new Color(DashRGBColor[j].R, DashRGBColor[j].B, (byte) c)
|
||||
)),
|
||||
(DashColorItem = new TextMenuExt.EnumSlider<ColorChoice>(
|
||||
"AVALI_SKIN_COLOR".DialogOrKey(),
|
||||
DashPreset[j]
|
||||
).Change(c => DashPreset[j] = c)),
|
||||
}
|
||||
);
|
||||
|
||||
DashRGBItems.Add(DashRItem);
|
||||
DashRGBItems.Add(DashGItem);
|
||||
DashRGBItems.Add(DashBItem);
|
||||
DashPresetItems.Add(DashColorItem);
|
||||
}
|
||||
|
||||
menu.Add(ColorSubmenuItem);
|
||||
}
|
||||
|
||||
|
||||
// The following two settings DashRGB & DashPreset are not shown, but
|
||||
// stored. They are set in the above submenu.
|
||||
[SettingIgnore]
|
||||
[YamlIgnore]
|
||||
public List<Color> DashRGBColor { get; set; } = new List<Color> {
|
||||
ColorUtil.SettingToColor(ColorChoice.BlueLight),
|
||||
ColorUtil.SettingToColor(ColorChoice.Turquoise),
|
||||
ColorUtil.SettingToColor(ColorChoice.Pink),
|
||||
ColorUtil.SettingToColor(ColorChoice.BlueDark),
|
||||
ColorUtil.SettingToColor(ColorChoice.Yellow),
|
||||
ColorUtil.SettingToColor(ColorChoice.Red),
|
||||
};
|
||||
// this will get (de)serialized from/into a yaml list
|
||||
[SettingIgnore]
|
||||
public IEnumerable<string> DashRGB {
|
||||
get => DashRGBColor.Select(c => ColorUtil.ColorToHex(c));
|
||||
set {
|
||||
DashRGBColor = value.Select(c => ColorUtil.HexToColor(c)).ToList();
|
||||
}
|
||||
}
|
||||
// Stores submenu items that are enabled/disabled when colormode is RGB
|
||||
private List<TextMenuExt.IntSlider> DashRGBItems = new List<TextMenuExt.IntSlider>();
|
||||
|
||||
|
||||
[SettingIgnore]
|
||||
public List<ColorChoice> DashPreset { get; set; } = new List<ColorChoice> {
|
||||
ColorChoice.BlueLight,
|
||||
ColorChoice.Turquoise,
|
||||
ColorChoice.Pink,
|
||||
ColorChoice.BlueDark,
|
||||
ColorChoice.Yellow,
|
||||
ColorChoice.Red,
|
||||
};
|
||||
// Stores submenu items that are enabled/disabled when colormode is preset
|
||||
private List<TextMenu.Option<ColorChoice>> DashPresetItems = new List<TextMenu.Option<ColorChoice>>();
|
||||
|
||||
|
||||
|
||||
public bool EnableCelesteNet { get; set; } = true;
|
||||
[YamlIgnore]
|
||||
private TextMenu.Item EnableCelesteNetItem;
|
||||
public void CreateEnableCelesteNetEntry(TextMenu menu, bool inGame) {
|
||||
menu.Add(new TextMenu.SubHeader(
|
||||
"modoptions_avaliskin_celestenet_header".DialogOrKey(), false
|
||||
));
|
||||
|
||||
EnableCelesteNetItem = new TextMenu.OnOff(
|
||||
"modoptions_avaliskin_celestenet".DialogOrKey(),
|
||||
EnableCelesteNet
|
||||
).Change(enabled => {
|
||||
EnableCelesteNet = enabled;
|
||||
updateOptions();
|
||||
});
|
||||
menu.Add(EnableCelesteNetItem);
|
||||
|
||||
if (!Everest.Loader.DependencyLoaded(AvaliSkinModule.CelesteNetMeta)) {
|
||||
menu.Add(new TextMenu.SubHeader(
|
||||
"modoptions_avaliskin_celestenet_nocelestenet".DialogOrKey(), false
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum SendReceive {
|
||||
SendReceive,
|
||||
Send,
|
||||
Receive,
|
||||
None
|
||||
}
|
||||
|
||||
public SendReceive CelesteNetSync { get; set; } = SendReceive.SendReceive;
|
||||
[YamlIgnore]
|
||||
private TextMenu.Item CelesteNetSyncItem;
|
||||
public void CreateCelesteNetSyncEntry(TextMenu menu, bool inGame) {
|
||||
CelesteNetSyncItem = new TextMenuExt.EnumerableSlider<SendReceive>(
|
||||
"modoptions_avaliskin_celestenetsync".DialogOrKey(),
|
||||
((SendReceive[]) Enum.GetValues(typeof(SendReceive))).Select(
|
||||
variant => new KeyValuePair<SendReceive, string>(
|
||||
variant,
|
||||
$"modoptions_avaliskin_celestenetsync_{variant.ToString()}".DialogOrKey()
|
||||
)
|
||||
),
|
||||
CelesteNetSync
|
||||
).Change(opt => CelesteNetSync = opt);
|
||||
menu.Add(CelesteNetSyncItem);
|
||||
CelesteNetSyncItem.AddDescription(
|
||||
menu,
|
||||
"modoptions_avaliskin_celestenetsync_note".DialogOrKey()
|
||||
);
|
||||
}
|
||||
|
||||
public bool CelesteNetEveryoneHasSkin { get; set; } = false;
|
||||
[YamlIgnore]
|
||||
private TextMenu.Item CelesteNetEveryoneHasSkinItem;
|
||||
public void CreateCelesteNetEveryoneHasSkinEntry(TextMenu menu, bool inGame) {
|
||||
CelesteNetEveryoneHasSkinItem = new TextMenu.OnOff(
|
||||
"modoptions_avaliskin_celesteneteveryonehasskin".DialogOrKey(),
|
||||
CelesteNetEveryoneHasSkin
|
||||
).Change(enabled => CelesteNetEveryoneHasSkin = enabled);
|
||||
menu.Add(CelesteNetEveryoneHasSkinItem);
|
||||
CelesteNetEveryoneHasSkinItem.AddDescription(
|
||||
menu,
|
||||
"modoptions_avaliskin_celesteneteveryonehasskin_note".DialogOrKey()
|
||||
);
|
||||
|
||||
// call update options once the entire menu is loaded: this item is
|
||||
// added last
|
||||
updateOptions();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public enum ColorChoice
|
||||
{
|
||||
Beige,
|
||||
Black,
|
||||
BlueDark,
|
||||
BlueLight,
|
||||
Brown,
|
||||
Cyan,
|
||||
GreenDark,
|
||||
GreenLight,
|
||||
GreyDark,
|
||||
GreyLight,
|
||||
Magenta,
|
||||
Orange,
|
||||
Pink,
|
||||
Purple,
|
||||
Red,
|
||||
Turquoise,
|
||||
White,
|
||||
Yellow,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
|
||||
using Celeste.Mod.CelesteNet;
|
||||
using Celeste.Mod.CelesteNet.Client;
|
||||
using Celeste.Mod.CelesteNet.Client.Entities;
|
||||
using Celeste.Mod.CelesteNet.DataTypes;
|
||||
|
||||
using ColorChoice = Celeste.Mod.AvaliSkin.AvaliSkinSettings.ColorChoice;
|
||||
using ColorMode = Celeste.Mod.AvaliSkin.AvaliSkinSettings.ColorMode;
|
||||
using SendReceive = Celeste.Mod.AvaliSkin.AvaliSkinSettings.SendReceive;
|
||||
|
||||
|
||||
namespace Celeste.Mod.AvaliSkin {
|
||||
public class CelesteNetAvaliComponent : CelesteNetGameComponent {
|
||||
private static AvaliSkinSettings ModuleSettings => AvaliSkinModule.Settings;
|
||||
public static CelesteNetAvaliComponent Instance;
|
||||
|
||||
private CelesteNetClientContext Ctx;
|
||||
|
||||
public CelesteNetAvaliComponent(CelesteNetClientContext context, Game game) : base(context, game) {
|
||||
Instance = this;
|
||||
Ctx = context;
|
||||
}
|
||||
|
||||
public void Handle(CelesteNetConnection con, DataReady ready) {
|
||||
SendAvaliSkin();
|
||||
}
|
||||
|
||||
public void SendAvaliSkin() {
|
||||
if (Ctx.Client != null && Ctx.Client.PlayerInfo != null) {
|
||||
if (
|
||||
ModuleSettings.CelesteNetSync == SendReceive.SendReceive
|
||||
|| ModuleSettings.CelesteNetSync == SendReceive.Send
|
||||
) {
|
||||
Logger.Log(LogLevel.Info, "AvaliSkin", $"Sending updated DataPlayerAvaliSkin!");
|
||||
AvaliConfig config = AvaliSkinModule.PlayerConfig;
|
||||
Ctx.Client.Send(new DataPlayerAvaliSkin(Ctx.Client.PlayerInfo, config));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class DataPlayerAvaliSkin : DataType<DataPlayerAvaliSkin> {
|
||||
public AvaliConfig Config;
|
||||
public DataPlayerInfo Player;
|
||||
|
||||
static DataPlayerAvaliSkin() { DataID = "avaliskin_skinconfig"; }
|
||||
public DataPlayerAvaliSkin() {}
|
||||
public DataPlayerAvaliSkin(DataPlayerInfo player, AvaliConfig config) {
|
||||
this.Player = player;
|
||||
this.Config = config;
|
||||
}
|
||||
|
||||
public override MetaType[] GenerateMeta(DataContext ctx) => new MetaType[] {
|
||||
new MetaPlayerPrivateState(Player),
|
||||
new MetaBoundRef(DataType<DataPlayerInfo>.DataID, Player?.ID ?? uint.MaxValue, true)
|
||||
};
|
||||
|
||||
public override void FixupMeta(DataContext ctx) {
|
||||
Player = Get<MetaPlayerPrivateState>(ctx);
|
||||
Get<MetaBoundRef>(ctx).ID = Player?.ID ?? uint.MaxValue;
|
||||
}
|
||||
|
||||
protected override void Read(CelesteNetBinaryReader reader) {
|
||||
Config = new AvaliConfig {
|
||||
Enabled = reader.ReadBoolean(),
|
||||
ColorMode = ColorMode.ExternalDash
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Write(CelesteNetBinaryWriter writer) {
|
||||
writer.Write(Config.Enabled);
|
||||
if (Config.Enabled) {
|
||||
// byte lengthRGB = Math.Min(ManualRGB.Count, 5);
|
||||
// writer.Write((byte) ManualRGB.Count);
|
||||
// foreach (var color in ManualRGB) {
|
||||
// write.WriteNoA(color);
|
||||
// }
|
||||
|
||||
// byte lengthPreset = Math.Min(ManualPreset.Count, 5);
|
||||
// writer.Write((byte) ManualPreset.Count);
|
||||
// foreach (var color in ManualPreset) {
|
||||
// write.Write((byte) color);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
using Celeste.Mod.CelesteNet.Client;
|
||||
using Celeste.Mod.CelesteNet.Client.Entities;
|
||||
using Celeste.Mod.CelesteNet.DataTypes;
|
||||
|
||||
using ColorChoice = Celeste.Mod.AvaliSkin.AvaliSkinSettings.ColorChoice;
|
||||
using ColorMode = Celeste.Mod.AvaliSkin.AvaliSkinSettings.ColorMode;
|
||||
using SendReceive = Celeste.Mod.AvaliSkin.AvaliSkinSettings.SendReceive;
|
||||
|
||||
|
||||
namespace Celeste.Mod.AvaliSkin {
|
||||
public class AvaliConfig {
|
||||
private static AvaliSkinSettings Settings => AvaliSkinModule.Settings;
|
||||
|
||||
public bool Enabled;
|
||||
public ColorMode ColorMode;
|
||||
public List<ColorChoice> ManualPreset = new List<ColorChoice>();
|
||||
public List<Color> ManualRGB = new List<Color>();
|
||||
|
||||
|
||||
public bool IsEnabled(Player player) {
|
||||
return Enabled;
|
||||
}
|
||||
|
||||
public bool IsEnabled(Ghost ghost) {
|
||||
return Settings.EnableCelesteNet
|
||||
&& (
|
||||
(Enabled && (
|
||||
Settings.CelesteNetSync == SendReceive.SendReceive
|
||||
|| Settings.CelesteNetSync == SendReceive.Receive
|
||||
))
|
||||
|| Settings.CelesteNetEveryoneHasSkin
|
||||
);
|
||||
}
|
||||
|
||||
// Check sprite.Scene != null && sprite.Entity != null && sprite.Entity is Player player
|
||||
// before calling this
|
||||
public Color GetColor(Player player) {
|
||||
int dashes = player.Dashes;
|
||||
switch (this.ColorMode) {
|
||||
case ColorMode.ExternalDash:
|
||||
// Infrequently, it's possible for the player to momentarily have no hair.
|
||||
if (player.Hair != null && player.Sprite.HairCount > 0) {
|
||||
return player.Hair.GetHairColor(0);
|
||||
} else {
|
||||
// If the player does have no hair, then just default to
|
||||
// whatever preset... this only happens momentarily anyways
|
||||
return ColorUtil.SettingToColor(
|
||||
ManualPreset[Math.Min(dashes, ManualPreset.Count - 1)]
|
||||
);
|
||||
}
|
||||
|
||||
case ColorMode.ManualRGB:
|
||||
return ManualRGB[Math.Min(dashes, ManualRGB.Count - 1)];
|
||||
|
||||
case ColorMode.ManualPreset: default:
|
||||
return ColorUtil.SettingToColor(
|
||||
ManualPreset[Math.Min(dashes, ManualPreset.Count - 1)]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check sprite.Scene != null && sprite.Entity != null && sprite.Entity is Ghost
|
||||
// before calling this
|
||||
public Color GetColor(Ghost ghost) {
|
||||
// Infrequently, it's possible for the ghost to momentarily have no hair.
|
||||
if (ghost.Hair != null && ghost.Sprite.HairCount > 0) {
|
||||
return ghost.Hair.GetHairColor(0);
|
||||
} else {
|
||||
// todo: wtf???
|
||||
return new Color(0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,41 @@
|
|||
# run make release to compile everything on linux (and maybe on macos too who knows)
|
||||
|
||||
SHELL = /bin/bash
|
||||
# .ONESHELL:
|
||||
# .SHELLFLAGS=-ec
|
||||
|
||||
|
||||
LIBS = -pkg:dotnet -r:MonoMod.Utils.dll -r:MonoMod.RuntimeDetour.dll \
|
||||
-r:Celeste.exe -r:MMHOOK_Celeste.dll -r:FNA.dll -r:Mono.Cecil.dll -r:YamlDotNet.dll -r:CelesteNet.Client.dll -r:CelesteNet.Shared.dll
|
||||
# If this mod is setup in the Celeste/Mods/ directory, then we use the paths:
|
||||
# - ../../../, which should be the Celeste/ directory, which contains most dlls
|
||||
# - ./Libraries/, which contains the optional dependency CelesteNet.Client.dll
|
||||
LIB_PATH = -lib:../../../ -lib:./Libraries/
|
||||
|
||||
BINARY=AvaliSkin.dll
|
||||
|
||||
|
||||
.PHONY: default release strip
|
||||
default: release
|
||||
|
||||
# To compile code on linux you will need the mono runtime and mcs (the mono c# compiler), and that's it actually.
|
||||
release:
|
||||
mcs ${LIB_PATH} ${LIBS} *.cs -t:library -out:${BINARY} -optimize
|
||||
cat ${BINARY} > ../${BINARY}
|
||||
rm ${BINARY}
|
||||
|
||||
# This strips out code from reference assemblies so only the symbols are
|
||||
# present for linking.
|
||||
strip:
|
||||
for file in ./Libraries/*; do mono-cil-strip "$$file"; done
|
||||
|
||||
# To compile the shaders, you will need:
|
||||
# - wine64 to be installed,
|
||||
# - the June 2010 legacy DirectX SDK needs to be unzipped under wine
|
||||
# (download: https://www.microsoft.com/en-us/download/details.aspx?id=6812)
|
||||
# - and you will need D3DCompiler_43.dll which you can grab from winetricks or
|
||||
# if you have steam proton installed, you probably already have a copy of it
|
||||
# *somewhere* on your system.
|
||||
# Man microsoft software sucks... how is this company still alive
|
||||
shader_c:
|
||||
wine64 DXSDK/Utilities/bin/x64/fxc.exe "AvaliRecolor.fx" "/T" "fx_2_0" "/Fo" "AvaliRecolor.o" "/O3"
|
|
@ -0,0 +1,56 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
using Monocle;
|
||||
|
||||
using CC = Celeste.Mod.AvaliSkin.AvaliSkinSettings.ColorChoice;
|
||||
|
||||
|
||||
namespace Celeste.Mod.AvaliSkin {
|
||||
public static class Misc {
|
||||
public static string DialogOrKey(this string key, Language lang = null) {
|
||||
return key.DialogCleanOrNull(lang) ?? key;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This is a "never/empty type" in C#. It is impossible to construct.
|
||||
// Used in cases where a variable should never be initialized.
|
||||
public enum Void {}
|
||||
|
||||
|
||||
public class ColorUtil {
|
||||
public static Color SettingToColor(CC col) {
|
||||
switch (col) {
|
||||
case CC.Beige: return new Color(162, 133, 92);
|
||||
case CC.Black: return new Color(0, 0, 0);
|
||||
case CC.BlueDark: return new Color(22, 42, 162);
|
||||
case CC.BlueLight: return new Color(50, 151, 223);
|
||||
case CC.Brown: return new Color(98, 75, 33);
|
||||
case CC.Cyan: return new Color(26, 225, 225);
|
||||
case CC.GreenDark: return new Color(41, 132, 49);
|
||||
case CC.GreenLight: return new Color(59, 219, 47);
|
||||
case CC.GreyDark: return new Color(60, 60, 60);
|
||||
case CC.GreyLight: return new Color(168, 168, 168);
|
||||
case CC.Magenta: return new Color(228, 14, 155);
|
||||
case CC.Orange: return new Color(237, 147, 32);
|
||||
case CC.Pink: return new Color(233, 106, 252);
|
||||
case CC.Purple: return new Color(190, 23, 214);
|
||||
case CC.Red: return new Color(238, 17, 34);
|
||||
case CC.Turquoise: return new Color(26, 213, 137);
|
||||
case CC.White: return new Color(255, 255, 255);
|
||||
case CC.Yellow: return new Color(244, 226, 15);
|
||||
default: return new Color(26, 213, 137);
|
||||
}
|
||||
}
|
||||
|
||||
public static string ColorToHex(Color color) {
|
||||
return $"#{color.R:x2}{color.G:x2}{color.B:x2}";
|
||||
}
|
||||
|
||||
public static Color HexToColor(string hex) {
|
||||
return Monocle.Calc.HexToColor(hex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,4 +3,7 @@
|
|||
DLL: AvaliSkin.dll
|
||||
Dependencies:
|
||||
- Name: Everest
|
||||
Version: 1.3070.0
|
||||
Version: 1.3070.0
|
||||
OptionalDependencies:
|
||||
- Name: CelesteNet.Client
|
||||
Version: 2.0.0
|
||||
|
|
Loading…
Reference in New Issue