diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9d32842 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,223 @@ +# Remove the line below if you want to inherit .editorconfig settings from higher directories +root = true + +# C# files +[*.cs] + +#### Core EditorConfig Options #### + +# Indentation and spacing +indent_size = 4 +indent_style = space +tab_width = 4 + +# New line preferences +end_of_line = crlf +insert_final_newline = false + +#### .NET Coding Conventions #### + +# Organize usings +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false +dotnet_style_qualification_for_field = false +dotnet_style_qualification_for_method = false +dotnet_style_qualification_for_property = false + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true +dotnet_style_predefined_type_for_member_access = true + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members + +# Expression-level preferences +dotnet_style_coalesce_expression = true +dotnet_style_collection_initializer = true +dotnet_style_explicit_tuple_names = true +dotnet_style_namespace_match_folder = false +dotnet_style_null_propagation = true +dotnet_style_object_initializer = true +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true +dotnet_style_prefer_compound_assignment = true +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_style_prefer_inferred_anonymous_type_member_names = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +dotnet_style_prefer_simplified_boolean_expressions = true +dotnet_style_prefer_simplified_interpolation = true + +# Field preferences +dotnet_style_readonly_field = true + +# Parameter preferences +dotnet_code_quality_unused_parameters = all + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +# New line preferences +dotnet_style_allow_multiple_blank_lines_experimental = false +dotnet_style_allow_statement_immediately_after_block_experimental = false + +#### C# Coding Conventions #### + +# var preferences +csharp_style_var_elsewhere = false +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = false + +# Expression-bodied members +csharp_style_expression_bodied_accessors = true +csharp_style_expression_bodied_constructors = false +csharp_style_expression_bodied_indexers = true +csharp_style_expression_bodied_lambdas = true +csharp_style_expression_bodied_local_functions = false +csharp_style_expression_bodied_methods = false +csharp_style_expression_bodied_operators = false +csharp_style_expression_bodied_properties = true + +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_extended_property_pattern = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_pattern_matching = true +csharp_style_prefer_switch_expression = true + +# Null-checking preferences +csharp_style_conditional_delegate_call = true +csharp_style_prefer_parameter_null_checking = true + +# Modifier preferences +csharp_prefer_static_local_function = true +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async + +# Code-block preferences +csharp_prefer_braces = true +csharp_prefer_simple_using_statement = true +csharp_style_namespace_declarations = block_scoped +csharp_style_prefer_method_group_conversion = true + +# Expression-level preferences +csharp_prefer_simple_default_expression = true +csharp_style_deconstructed_variable_declaration = true +csharp_style_implicit_object_creation_when_type_is_apparent = true +csharp_style_inlined_variable_declaration = true +csharp_style_prefer_index_operator = false +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_prefer_range_operator = false +csharp_style_prefer_tuple_swap = true +csharp_style_throw_expression = true +csharp_style_unused_value_assignment_preference = discard_variable +csharp_style_unused_value_expression_statement_preference = discard_variable + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace + +# New line preferences +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false +csharp_style_allow_embedded_statements_on_same_line_experimental = false + +#### C# Formatting Rules #### + +# New line preferences +csharp_new_line_before_catch = false +csharp_new_line_before_else = false +csharp_new_line_before_finally = false +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = none +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = false + +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case diff --git a/.github/ISSUE_TEMPLATE/BUG-REPORT.yml b/.github/ISSUE_TEMPLATE/BUG-REPORT.yml new file mode 100644 index 0000000..c59f025 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG-REPORT.yml @@ -0,0 +1,53 @@ +name: Bug Report +description: File a bug report +title: "[Bug]: " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + + - type: checkboxes + id: before + attributes: + label: Before You Report + description: Following these steps first gives us the best chance of fixing your problem. + options: + - label: My mods and Everest install are up to date. + required: false + - label: I have recreated the bug with a minimum number of mods installed. + required: false + + - type: input + id: platform + attributes: + label: What platform are you playing on? + description: e.g. Windows 10 FNA, Mac, Linux, etc. + validations: + required: true + + - type: textarea + id: problem + attributes: + label: Bug Description + description: What happened? And what did you expect to happen? + value: "Please give a clear and concise description of the bug." + validations: + required: true + + - type: textarea + id: reproduction + attributes: + label: Steps to Reproduce + description: How do we trigger this bug ourselves? + value: "Attach screenshots, video, a map, etc. as needed." + validations: + required: true + + - type: textarea + id: log + attributes: + label: Log Output + description: Please copy and paste any relevant log output. + render: shell diff --git a/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml new file mode 100644 index 0000000..299a4f9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml @@ -0,0 +1,22 @@ +name: Feature Request +description: Suggest a feature for the mod +title: "[Feature]: " +labels: ["enhancement"] +body: + - type: textarea + id: request + attributes: + label: Request Description + description: Please describe your request. + value: "Attach screenshots, concept art, etc. as needed." + validations: + required: true + + - type: input + id: deadline + attributes: + label: Target Date + description: If you have a time requirement, e.g. for a contest, list it here. + placeholder: Filling this out does not guarantee we can fulfill the request. + validations: + required: false diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..9ea2370 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,42 @@ +name: Build + +on: + push: + branches: [ dev ] + pull_request: + branches: [ dev ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Download Everest stripped lib + uses: robinraju/release-downloader@v1.5 + with: + repository: EverestAPI/Everest + latest: true + fileName: lib-stripped.zip + + - name: Extract lib-stripped.zip + run: unzip lib-stripped.zip + + - name: Setup .NET Core + uses: actions/setup-dotnet@v2 + with: + dotnet-version: 5.0.x + + - name: Install dependencies + run: dotnet restore + + - name: Build with .NET Core + run: dotnet build --configuration Debug --no-restore + env: + CELESTEPREFIX: ${{ github.workspace }}/lib-stripped + + - name: Upload build + uses: actions/upload-artifact@v3 + with: + name: bin + path: Code/bin/Debug/net452 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..39d02b0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,49 @@ +name: Release + +on: + workflow_dispatch: + push: + branches: [ dev ] + paths: + - 'everest.yaml' + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Download Everest stripped lib + uses: robinraju/release-downloader@v1.5 + with: + repository: EverestAPI/Everest + latest: true + fileName: lib-stripped.zip + + - name: Extract lib-stripped.zip + run: unzip lib-stripped.zip + + - name: Setup .NET Core + uses: actions/setup-dotnet@v2 + with: + dotnet-version: 5.0.x + + - name: Install dependencies + run: dotnet restore + + - name: Build with .NET Core + run: dotnet build --configuration Debug --no-restore + env: + CELESTEPREFIX: ${{ github.workspace }}/lib-stripped + + - name: Upload ZIP + uses: actions/upload-artifact@v3 + with: + name: CrystallineHelper + path: | + Ahorn + Code/bin + Graphics + Loenn + everest.yaml + !Code/bin/Debug \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fefa62b --- /dev/null +++ b/.gitignore @@ -0,0 +1,354 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# JetBrains Rider +.idea + diff --git a/Ahorn/effects/customWindSnow.jl b/Ahorn/effects/customWindSnow.jl new file mode 100644 index 0000000..c558aa4 --- /dev/null +++ b/Ahorn/effects/customWindSnow.jl @@ -0,0 +1,15 @@ +module CustomWindSnow + +using ..Ahorn, Maple + +@mapdef Effect "CrystallineHelper/CustomWindSnow" Snow(only::String="*", exclude::String="", colors::String="FFFFFF", alphas::String="1", amount::Integer=240, speedX::Number=0.0, speedY::Number=0.0, ignoreWind::Bool=false) + +placements = Snow + +Ahorn.editingOrder(entity::Snow) = ["name", "only", "exclude", "tag", "flag", "notflag", "colors", "alphas", "speedX", "speedY", "amount", "fg", "ignoreWind"] + +function Ahorn.canFgBg(effect::Snow) + return true, true +end + +end \ No newline at end of file diff --git a/Ahorn/entities/boostBumper.jl b/Ahorn/entities/boostBumper.jl new file mode 100644 index 0000000..f3dd7da --- /dev/null +++ b/Ahorn/entities/boostBumper.jl @@ -0,0 +1,21 @@ +module BoostBumper + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/boostbumper" Booster(x::Integer, y::Integer) + +const placements = Ahorn.PlacementDict( + "Bumper Booster (Crystalline)" => Ahorn.EntityPlacement( + Booster + ) +) + +function Ahorn.selection(entity::Booster) + x, y = Ahorn.position(entity) + + return Ahorn.Rectangle(x-9, y-9, 18, 18) +end + +Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::Booster) = Ahorn.drawSprite(ctx, "objects/boostBumper/booster00.png", 0, 0, jx=0.5, jy=0.5) + +end \ No newline at end of file diff --git a/Ahorn/entities/customPrologueBridge.jl b/Ahorn/entities/customPrologueBridge.jl new file mode 100644 index 0000000..49f4a79 --- /dev/null +++ b/Ahorn/entities/customPrologueBridge.jl @@ -0,0 +1,33 @@ +module CustomIntroBridge + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/customprologuebridge" Bridge(x::Integer, y::Integer, width::Integer=8, flag::String="", activationID::String="", activationIndex::Integer=0, left::Bool=false, delay::Number=0.2, speed::Number=0.8) + +const placements = Ahorn.PlacementDict( + "Custom Prologue Bridge (Crystalline)" => Ahorn.EntityPlacement( + Bridge, + "rectangle" + ) +) + +Ahorn.editingOrder(entity::Bridge) = String["x", "y", "width", "activationID", "activationIndex", "delay", "speed", "flag", "left"] +Ahorn.editingIgnored(entity::Bridge, multiple::Bool=false) = multiple ? String["x", "y", "width", "activationIndex", "left"] : String[] +Ahorn.minimumSize(entity::Bridge) = 8, 8 +Ahorn.resizable(entity::Bridge) = true, false + +function Ahorn.selection(entity::Bridge) + x, y = Ahorn.position(entity) + width = Int(get(entity.data, "width", 8)) + + return Ahorn.Rectangle(x, y, width, 8) +end + +function Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::Bridge) + width = Int(get(entity.data, "width", 8)) + for i = 0:(width / 8) - 1 + Ahorn.drawSprite(ctx, "objects/customBridge/tile" * string(Int(i % 6 + 3)) * ".png", i * 8, 0, jx=0, jy=0) + end +end + +end \ No newline at end of file diff --git a/Ahorn/entities/fillCrystal.jl b/Ahorn/entities/fillCrystal.jl new file mode 100644 index 0000000..e0b143b --- /dev/null +++ b/Ahorn/entities/fillCrystal.jl @@ -0,0 +1,21 @@ +module FillCrystal + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/fillcrystal" Crystal(x::Integer, y::Integer, oneUse::Bool=false, respawnTime::Number=2.5) + +const placements = Ahorn.PlacementDict( + "Fill Crystal (Crystalline)" => Ahorn.EntityPlacement( + Crystal + ) +) + +function Ahorn.selection(entity::Crystal) + x, y = Ahorn.position(entity) + + return Ahorn.getSpriteRectangle("objects/crystals/fill/idle00.png", x, y, jx=0.5, jy=0.5) +end + +Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::Crystal) = Ahorn.drawSprite(ctx, "objects/crystals/fill/idle00.png", 0, 0, jx=0.5, jy=0.5) + +end \ No newline at end of file diff --git a/Ahorn/entities/flagSequenceController.jl b/Ahorn/entities/flagSequenceController.jl new file mode 100644 index 0000000..5ef04d3 --- /dev/null +++ b/Ahorn/entities/flagSequenceController.jl @@ -0,0 +1,24 @@ +module SetFlagSequenceController + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/flagsequencecontroller" Controller(x::Integer, y::Integer, + prefix::String="", state::Bool=false, startNumber::Integer=1, endNumber::Integer=99) + +const placements = Ahorn.PlacementDict( + "Set Flag Sequence On Spawn Controller (Crystalline)" => Ahorn.EntityPlacement( + Controller + ) +) + +function Ahorn.selection(entity::Controller) + x, y = Ahorn.position(entity) + + return Ahorn.Rectangle(x - 12, y - 12, 24, 24) +end + +Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::Controller, room::Maple.Room) = Ahorn.drawSprite(ctx, "ahorn_flagsequencecontroller.png", 0, 0) + +Ahorn.editingOrder(entity::Controller) = String["x", "y", "startNumber", "endNumber", "prefix", "state"] + +end \ No newline at end of file diff --git a/Ahorn/entities/forceDashCrystal.jl b/Ahorn/entities/forceDashCrystal.jl new file mode 100644 index 0000000..829ee45 --- /dev/null +++ b/Ahorn/entities/forceDashCrystal.jl @@ -0,0 +1,90 @@ +module ForceDashCrystal + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/forcedashcrystal" Crystal(x::Integer, y::Integer, oneUse::Bool=false, + direction::String="Right", respawnTime::Number=2.5, needDash::Bool=false) + +const directions = ["Right", "Downright", "Down", "Downleft", "Left", "Upleft", "Up", "Upright", "None"] + +const directionIsOrtho = Dict{String, Bool}( + "Right" => true, + "Downright" => false, + "Down" => true, + "Downleft" => false, + "Left" => true, + "Upleft" => false, + "Up" => true, + "Upright" => false, + "None" => false +) + +const rotations = Dict{String, Number}( + "Right" => pi * 0.5, + "Downright" => pi * 0.5, + "Down" => pi, + "Downleft" => pi, + "Left" => -pi * 0.5, + "Upleft" => -pi * 0.5, + "Up" => 0, + "Upright" => 0 +) + +const placements = Ahorn.PlacementDict( + "Force Dash Crystal ($(dir)) (Crystalline)" => Ahorn.EntityPlacement( + Crystal, + "point", + Dict{String, Any}( + "direction" => dir + ) + ) for dir in directions +) + +Ahorn.editingOptions(entity::Crystal) = Dict{String, Any}( + "direction" => directions +) + +function Ahorn.selection(entity::Crystal) + x, y = Ahorn.position(entity) + + return Ahorn.Rectangle(x-8, y-8, 16, 16) +end + +function Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::Crystal) + dir = get(entity.data, "direction", "Right") + needdash = get(entity.data, "needDash", false) + crystalType = needdash ? "needdash" : "dashless" + sprite = "objects/crystals/forcedash/" * crystalType * "/" * (directionIsOrtho[dir] ? "ortho" : "diag") * "/idle00.png" + + if dir == "None" + Ahorn.Cairo.save(ctx) + + Ahorn.drawSprite(ctx, sprite, 2, -2, jx=0.5, jy=0.5) + + Ahorn.Cairo.rotate(ctx, pi * 0.5) + Ahorn.drawSprite(ctx, sprite, 2, -2, jx=0.5, jy=0.5) + + Ahorn.Cairo.rotate(ctx, pi * 0.5) + Ahorn.drawSprite(ctx, sprite, 2, -2, jx=0.5, jy=0.5) + + Ahorn.Cairo.rotate(ctx, pi * 0.5) + Ahorn.drawSprite(ctx, sprite, 2, -2, jx=0.5, jy=0.5) + + Ahorn.Cairo.restore(ctx) + else + Ahorn.Cairo.save(ctx) + Ahorn.Cairo.rotate(ctx, rotations[dir]) + if directionIsOrtho[dir] + Ahorn.drawSprite(ctx, sprite, 0, -2, jx=0.5, jy=0.5) + Ahorn.drawSprite(ctx, sprite, 4, 2, jx=0.5, jy=0.5) + Ahorn.drawSprite(ctx, sprite, -4, 2, jx=0.5, jy=0.5) + else + Ahorn.drawSprite(ctx, sprite, 2, -2, jx=0.5, jy=0.5) + Ahorn.drawSprite(ctx, sprite, -3, -1, jx=0.5, jy=0.5) + Ahorn.drawSprite(ctx, sprite, 1, 3, jx=0.5, jy=0.5) + end + Ahorn.Cairo.restore(ctx) + end +end + +end \ No newline at end of file diff --git a/Ahorn/entities/forceJumpCrystal.jl b/Ahorn/entities/forceJumpCrystal.jl new file mode 100644 index 0000000..7eaa96f --- /dev/null +++ b/Ahorn/entities/forceJumpCrystal.jl @@ -0,0 +1,25 @@ +module ForceJumpCrystal + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/forcejumpcrystal" Crystal(x::Integer, y::Integer, oneUse::Bool=false, + respawnTime::Number=2.5, holdJump::Bool=true) + +const placements = Ahorn.PlacementDict( + "Force Jump Crystal (Crystalline)" => Ahorn.EntityPlacement( + Crystal + ) +) + +function Ahorn.selection(entity::Crystal) + x, y = Ahorn.position(entity) + + return Ahorn.Rectangle(x-8, y-8, 16, 16) +end + +function Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::Crystal) + Ahorn.drawSprite(ctx, "objects/crystals/forcejump/idle00.png", -4, 0, jx=0.5, jy=0.5) + Ahorn.drawSprite(ctx, "objects/crystals/forcejump/idle02.png", 4, 0, jx=0.5, jy=0.5, sx=-1) +end + +end \ No newline at end of file diff --git a/Ahorn/entities/keyberry.jl b/Ahorn/entities/keyberry.jl new file mode 100644 index 0000000..33c0c9e --- /dev/null +++ b/Ahorn/entities/keyberry.jl @@ -0,0 +1,157 @@ +module KeyBerry + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/keyberry" Berry(x::Integer, y::Integer, winged::Bool=false) +@mapdef Entity "vitellary/returnkeyberry" ReturnBerry(x::Integer, y::Integer, winged::Bool=false) + +const placements = Ahorn.PlacementDict( + "Keyberry (Crystalline)" => Ahorn.EntityPlacement( + Berry, + "point", + Dict{String, Any}( + "winged" => false + ) + ), + "Keyberry (Winged) (Crystalline)" => Ahorn.EntityPlacement( + Berry, + "point", + Dict{String, Any}( + "winged" => true + ) + ), + "Keyberry With Return (Crystalline)" => Ahorn.EntityPlacement( + ReturnBerry, + "point", + Dict{String, Any}( + "winged" => false + ), + function(entity::ReturnBerry) + entity.data["nodes"] = [ + (Int(entity.data["x"]) + 32, Int(entity.data["y"])), + (Int(entity.data["x"]) + 64, Int(entity.data["y"])) + ] + end + ), + "Keyberry With Return (Winged) (Crystalline)" => Ahorn.EntityPlacement( + ReturnBerry, + "point", + Dict{String, Any}( + "winged" => true + ), + function(entity::ReturnBerry) + entity.data["nodes"] = [ + (Int(entity.data["x"]) + 32, Int(entity.data["y"])), + (Int(entity.data["x"]) + 64, Int(entity.data["y"])) + ] + end + ) +) + +sprite = "collectables/keyberry/normal03" +spriteWinged = "collectables/keyberry/wings00" +spriteSeed = "collectables/keyberry/seed00" + +Ahorn.nodeLimits(entity::Berry) = 0, -1 +Ahorn.nodeLimits(entity::ReturnBerry) = 2, -1 + +function Ahorn.selection(entity::Berry) + x, y = Ahorn.position(entity) + + res = Ahorn.Rectangle[Ahorn.getSpriteRectangle(sprite, x, y)] + + nodes = get(entity.data, "nodes", ()) + for node in nodes + nx, ny = Int.(node) + + push!(res, Ahorn.getSpriteRectangle(spriteSeed, nx, ny)) + end + + return res +end + +function Ahorn.selection(entity::ReturnBerry) + x, y = Ahorn.position(entity) + + res = Ahorn.Rectangle[Ahorn.getSpriteRectangle(sprite, x, y)] + + nodes = get(entity.data, "nodes", ()) + nodelength = length(nodes) + for (i, node) in enumerate(nodes) + nx, ny = Int.(node) + + if i > nodelength - 2 + push!(res, Ahorn.Rectangle(nx - 12, ny - 12, 24, 24)) + else + push!(res, Ahorn.getSpriteRectangle(spriteSeed, nx, ny)) + end + end + + return res +end + +function Ahorn.renderSelectedAbs(ctx::Ahorn.Cairo.CairoContext, entity::Berry) + x, y = Ahorn.position(entity) + + nodes = get(entity.data, "nodes", ()) + for node in nodes + nx, ny = Int.(node) + + theta = atan(y - ny, x - nx) + Ahorn.drawArrow(ctx, x, y, nx + cos(theta) * 8, ny + sin(theta) * 8, Ahorn.colors.selection_selected_fc, headLength=6) + Ahorn.drawSprite(ctx, spriteSeed, nx, ny) + end +end + +function Ahorn.renderSelectedAbs(ctx::Ahorn.Cairo.CairoContext, entity::ReturnBerry) + x, y = Ahorn.position(entity) + + nodes = get(entity.data, "nodes", ()) + nodelength = length(nodes) + for (i, node) in enumerate(nodes) + nx, ny = Int.(node) + + theta = atan(y - ny, x - nx) + if i == nodelength + px, py = Int.(nodes[nodelength - 1]) + bubbleTheta = atan(py - ny, px - nx) + Ahorn.drawArrow(ctx, px, py, nx + cos(bubbleTheta) * 8, ny + sin(bubbleTheta) * 8, Ahorn.colors.selection_selected_fc, headLength=6) + else + Ahorn.drawArrow(ctx, x, y, nx + cos(theta) * 8, ny + sin(theta) * 8, Ahorn.colors.selection_selected_fc, headLength=6) + end + if i > nodelength - 2 + Ahorn.Cairo.save(ctx) + + Ahorn.set_antialias(ctx, 1) + Ahorn.set_line_width(ctx, 1) + + Ahorn.drawCircle(ctx, nx, ny, 12, (1.0, 1.0, 1.0, 1.0)) + + Ahorn.Cairo.restore(ctx) + else + Ahorn.drawSprite(ctx, spriteSeed, nx, ny) + end + end +end + +function Ahorn.renderAbs(ctx::Ahorn.Cairo.CairoContext, entity::Berry, room::Maple.Room) + x, y = Ahorn.position(entity) + + if get(entity.data, "winged", false) + Ahorn.drawSprite(ctx, spriteWinged, x, y+1) + else + Ahorn.drawSprite(ctx, sprite, x, y) + end +end + +function Ahorn.renderAbs(ctx::Ahorn.Cairo.CairoContext, entity::ReturnBerry, room::Maple.Room) + x, y = Ahorn.position(entity) + + if get(entity.data, "winged", false) + Ahorn.drawSprite(ctx, spriteWinged, x, y+1) + else + Ahorn.drawSprite(ctx, sprite, x, y) + end +end + +end \ No newline at end of file diff --git a/Ahorn/entities/linkedMoveBlock.jl b/Ahorn/entities/linkedMoveBlock.jl new file mode 100644 index 0000000..3b372f5 --- /dev/null +++ b/Ahorn/entities/linkedMoveBlock.jl @@ -0,0 +1,121 @@ +module VitMoveBlock + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/vitmoveblock" Block(x::Integer, y::Integer, width::Integer=16, height::Integer=16, + canSteer::Bool=false, direction::String="Right", remote::Integer=0, canActivate::Bool=true, + spritePath::String="objects/vitMoveBlock", moveSpeed::Number=75.0, idleSingleColor::String="465EB5", idleLinkedColor::String="9E45B2", + activeSingleColor::String="4FD6FF", activeLinkedColor::String="FF8CF5", breakingColor::String="CC2541") + +Ahorn.editingOptions(entity::Block) = Dict{String, Any}( + "direction" => Maple.move_block_directions +) +Ahorn.editingOrder(entity::Block) = String["x", "y", "width", "height", "direction", "remote", "moveSpeed", "spritePath", "canSteer", "canActivate"] +Ahorn.editingIgnored(entity::Block, multiple::Bool=false) = multiple ? String["x", "y", "width", "height", "direction"] : String[] +Ahorn.minimumSize(entity::Block) = 16, 16 +Ahorn.resizable(entity::Block) = true, true + +Ahorn.selection(entity::Block) = Ahorn.getEntityRectangle(entity) + +arrows = Dict{String, String}( + "up" => "objects/vitMoveBlock/arrow02", + "left" => "objects/vitMoveBlock/arrow04", + "right" => "objects/vitMoveBlock/arrow00", + "down" => "objects/vitMoveBlock/arrow06", +) + +button = "objects/vitMoveBlock/button_ahorn" + +function Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::Block, room::Maple.Room) + x = Int(get(entity.data, "x", 0)) + y = Int(get(entity.data, "y", 0)) + + width = Int(get(entity.data, "width", 32)) + height = Int(get(entity.data, "height", 32)) + + tilesWidth = div(width, 8) + tilesHeight = div(height, 8) + + canSteer = get(entity.data, "canSteer", false) + direction = lowercase(get(entity.data, "direction", "up")) + remote = get(entity.data, "remote", 0) + arrowSprite = Ahorn.getSprite(arrows[lowercase(direction)], "Gameplay") + + midColor = (17, 17, 22) ./ 255 + buttonColor = (70, 94, 181, 255) ./ 255 + highlightColor = (50, 71, 145) ./ 255 + if remote > 0 + buttonColor = (158, 69, 178, 255) ./ 255 + highlightColor = (113, 52, 142) ./ 255 + end + + frame = "objects/vitMoveBlock/base" + if canSteer + if direction == "up" || direction == "down" + frame = "objects/vitMoveBlock/base_v" + else + frame = "objects/vitMoveBlock/base_h" + end + end + + Ahorn.drawRectangle(ctx, 2, 2, width - 4, height - 4, highlightColor, highlightColor) + Ahorn.drawRectangle(ctx, 8, 8, width - 16, height - 16, midColor) + + for i in 2:tilesWidth - 1 + Ahorn.drawImage(ctx, frame, (i - 1) * 8, 0, 8, 0, 8, 8) + Ahorn.drawImage(ctx, frame, (i - 1) * 8, height - 8, 8, 16, 8, 8) + + if canSteer && (direction != "up" && direction != "down") + Ahorn.drawImage(ctx, button, (i - 1) * 8, -2, 6, 0, 8, 6, tint=buttonColor) + end + end + + for i in 2:tilesHeight - 1 + Ahorn.drawImage(ctx, frame, 0, (i - 1) * 8, 0, 8, 8, 8) + Ahorn.drawImage(ctx, frame, width - 8, (i - 1) * 8, 16, 8, 8, 8) + + if canSteer && (direction == "up" || direction == "down") + Ahorn.Cairo.save(ctx) + + Ahorn.rotate(ctx, -pi / 2) + Ahorn.drawImage(ctx, button, i * 8 - height - 8, -2, 6, 0, 8, 6, tint=buttonColor) + Ahorn.scale(ctx, 1, -1) + Ahorn.drawImage(ctx, button, i * 8 - height - 8, -2 - width, 6, 0, 8, 6, tint=buttonColor) + + Ahorn.Cairo.restore(ctx) + end + end + + Ahorn.drawImage(ctx, frame, 0, 0, 0, 0, 8, 8) + Ahorn.drawImage(ctx, frame, width - 8, 0, 16, 0, 8, 8) + Ahorn.drawImage(ctx, frame, 0, height - 8, 0, 16, 8, 8) + Ahorn.drawImage(ctx, frame, width - 8, height - 8, 16, 16, 8, 8) + + if canSteer && (direction != "up" && direction != "down") + Ahorn.Cairo.save(ctx) + + Ahorn.drawImage(ctx, button, 2, -2, 0, 0, 6, 6, tint=buttonColor) + Ahorn.scale(ctx, -1, 1) + Ahorn.drawImage(ctx, button, 2 - width, -2, 0, 0, 6, 6, tint=buttonColor) + + Ahorn.Cairo.restore(ctx) + end + + if canSteer && (direction == "up" || direction == "down") + Ahorn.Cairo.save(ctx) + + Ahorn.rotate(ctx, -pi / 2) + Ahorn.drawImage(ctx, button, -height + 2, -2, 0, 0, 8, 6, tint=buttonColor) + Ahorn.drawImage(ctx, button, -10, -2, 14, 0, 8, 6, tint=buttonColor) + Ahorn.scale(ctx, 1, -1) + Ahorn.drawImage(ctx, button, -height + 2, -2 -width, 0, 0, 8, 6, tint=buttonColor) + Ahorn.drawImage(ctx, button, -10, -2 -width, 14, 0, 8, 6, tint=buttonColor) + + Ahorn.Cairo.restore(ctx) + end + + Ahorn.drawRectangle(ctx, div(width - arrowSprite.width, 2) + 1, div(height - arrowSprite.height, 2) + 1, 8, 8, highlightColor, highlightColor) + Ahorn.drawImage(ctx, arrowSprite, div(width - arrowSprite.width, 2), div(height - arrowSprite.height, 2)) +end + +end \ No newline at end of file diff --git a/Ahorn/entities/lockedIntroCar.jl b/Ahorn/entities/lockedIntroCar.jl new file mode 100644 index 0000000..e27f081 --- /dev/null +++ b/Ahorn/entities/lockedIntroCar.jl @@ -0,0 +1,34 @@ +module LockedIntroCar + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/lockedintrocar" IntroCar(x::Integer, y::Integer) + +const placements = Ahorn.PlacementDict( + "Locked Intro Car (Crystalline)" => Ahorn.EntityPlacement( + IntroCar + ) +) + +bodySprite = "scenery/car/body" +wheelsSprite = "scenery/car/wheels" + +function Ahorn.selection(entity::IntroCar) + x, y = Ahorn.position(entity) + + rectangles = Ahorn.Rectangle[ + Ahorn.getSpriteRectangle(bodySprite, x, y, jx=0.5, jy=1.0), + Ahorn.getSpriteRectangle(wheelsSprite, x, y, jx=0.5, jy=1.0), + ] + + return Ahorn.coverRectangles(rectangles) +end + +function Ahorn.renderAbs(ctx::Ahorn.Cairo.CairoContext, entity::IntroCar, room::Maple.Room) + x, y = Ahorn.position(entity) + + Ahorn.drawSprite(ctx, wheelsSprite, x, y, jx=0.5, jy=1.0) + Ahorn.drawSprite(ctx, bodySprite, x, y, jx=0.5, jy=1.0) +end + +end \ No newline at end of file diff --git a/Ahorn/entities/starCrystal.jl b/Ahorn/entities/starCrystal.jl new file mode 100644 index 0000000..cd7f0f9 --- /dev/null +++ b/Ahorn/entities/starCrystal.jl @@ -0,0 +1,24 @@ +module StarCrystal + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/starcrystal" Crystal(x::Integer, y::Integer, oneUse::Bool=false, time::Number=2.0, +changeDashes::Bool=true, changeInvuln::Bool=true, changeStamina::Bool=true, respawnTime::Number=2.5) + +const placements = Ahorn.PlacementDict( + "Star Crystal (Crystalline)" => Ahorn.EntityPlacement( + Crystal + ) +) + +Ahorn.editingOrder(entity::Crystal) = String["x", "y", "time", "respawnTime", "changeInvuln", "changeDashes", "changeStamina", "oneUse"] + +function Ahorn.selection(entity::Crystal) + x, y = Ahorn.position(entity) + + return Ahorn.getSpriteRectangle("objects/crystals/star/idle00.png", x, y, jx=0.5, jy=0.5) +end + +Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::Crystal) = Ahorn.drawSprite(ctx, "objects/crystals/star/idle00.png", 0, 0, jx=0.5, jy=0.5) + +end \ No newline at end of file diff --git a/Ahorn/entities/teleCrystal.jl b/Ahorn/entities/teleCrystal.jl new file mode 100644 index 0000000..8b5158d --- /dev/null +++ b/Ahorn/entities/teleCrystal.jl @@ -0,0 +1,101 @@ +module TeleCrystal + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/telecrystal" Crystal(x::Integer, y::Integer, direction::Int=0, oneUse::Bool=false) +@mapdef Entity "vitellary/goodtelecrystal" NewCrystal(x::Integer, y::Integer, direction::String="Right", oneUse::Bool=false, preventCrash::Bool=true, respawnTime::Number=0.2) + +const placements = Ahorn.PlacementDict( + "Tele Crystal (Right) (Crystalline)" => Ahorn.EntityPlacement( + NewCrystal, + "point", + Dict{String, Any}( + "direction" => "Right" + ) + ), + + "Tele Crystal (Down) (Crystalline)" => Ahorn.EntityPlacement( + NewCrystal, + "point", + Dict{String, Any}( + "direction" => "Down" + ) + ), + + "Tele Crystal (Left) (Crystalline)" => Ahorn.EntityPlacement( + NewCrystal, + "point", + Dict{String, Any}( + "direction" => "Left" + ) + ), + + "Tele Crystal (Up) (Crystalline)" => Ahorn.EntityPlacement( + NewCrystal, + "point", + Dict{String, Any}( + "direction" => "Up" + ) + ) +) + +spriteRight = "objects/crystals/tele/right/idle00.png" +spriteDown = "objects/crystals/tele/down/idle00.png" +spriteLeft = "objects/crystals/tele/left/idle00.png" +spriteUp = "objects/crystals/tele/up/idle00.png" + +function getSprite(entity::Crystal) + direction = get(entity.data, "direction", 3) + + if direction == 0 + return spriteRight + elseif direction == 1 + return spriteDown + elseif direction == 2 + return spriteLeft + else + return spriteUp + end +end + +function getSprite(entity::NewCrystal) + direction = get(entity.data, "direction", "Up") + + if direction == "Right" + return spriteRight + elseif direction == "Down" + return spriteDown + elseif direction == "Left" + return spriteLeft + else + return spriteUp + end +end + +Ahorn.editingOptions(entity::NewCrystal) = Dict{String, Any}( + "direction" => ["Right", "Down", "Left", "Up"] +) + +function Ahorn.selection(entity::Crystal) + x, y = Ahorn.position(entity) + + return Ahorn.getSpriteRectangle("objects/crystals/tele/up/idle00.png", x, y, jx=0.5, jy=0.5) +end + +function Ahorn.selection(entity::NewCrystal) + x, y = Ahorn.position(entity) + + return Ahorn.getSpriteRectangle("objects/crystals/tele/up/idle00.png", x, y, jx=0.5, jy=0.5) +end + +function Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::Crystal, room::Maple.Room) + sprite = getSprite(entity) + Ahorn.drawSprite(ctx, sprite, 0, 0) +end + +function Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::NewCrystal, room::Maple.Room) + sprite = getSprite(entity) + Ahorn.drawSprite(ctx, sprite, 0, 0) +end + +end \ No newline at end of file diff --git a/Ahorn/entities/timeCrystal.jl b/Ahorn/entities/timeCrystal.jl new file mode 100644 index 0000000..5e78b21 --- /dev/null +++ b/Ahorn/entities/timeCrystal.jl @@ -0,0 +1,42 @@ +module TimeCrystal + +using ..Ahorn, Maple + +@mapdef Entity "vitellary/timecrystal" Crystal(x::Integer, y::Integer, + oneUse::Bool=false, stopLength::Number=2.0, respawnTime::Number=2.5, + untilDash::Bool=false, immediate::Bool=false, entityTypesToIgnore::String="", + timeScale::Number=0.0) + +const placements = Ahorn.PlacementDict( + "Time Crystal (Crystalline)" => Ahorn.EntityPlacement( + Crystal, + "point" + ), + "Time Crystal (Until Dash) (Crystalline)" => Ahorn.EntityPlacement( + Crystal, + "point", + Dict{String, Any}( + "untilDash" => true + ) + ) +) + +Ahorn.editingOrder(entity::Crystal) = String["x", "y", "stopLength", "respawnTime", "timeScale", + "entityTypesToIgnore", "oneUse", "immediate", "untilDash"] + +function Ahorn.selection(entity::Crystal) + x, y = Ahorn.position(entity) + + return Ahorn.getSpriteRectangle("objects/crystals/time/idle00.png", x, y, jx=0.5, jy=0.5) +end + +function Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::Crystal) + untilDash = get(entity.data, "untilDash", false) + if untilDash + Ahorn.drawSprite(ctx, "objects/crystals/time/untildash/idle00.png", 0, 0, jx=0.5, jy=0.5) + else + Ahorn.drawSprite(ctx, "objects/crystals/time/idle00.png", 0, 0, jx=0.5, jy=0.5) + end +end + +end \ No newline at end of file diff --git a/Ahorn/lang/en_gb.lang b/Ahorn/lang/en_gb.lang new file mode 100644 index 0000000..c27d876 --- /dev/null +++ b/Ahorn/lang/en_gb.lang @@ -0,0 +1,130 @@ +# Fill Crystal +placements.entities.vitellary/fillcrystal.tooltips.oneUse=Whether the refill should respawn after being used. +placements.entities.vitellary/fillcrystal.tooltips.respawnTime=How long (in seconds) after using the crystal for it to respawn. + +# Time Crystal +placements.entities.vitellary/timecrystal.tooltips.oneUse=Whether the refill should respawn after being used. +placements.entities.vitellary/timecrystal.tooltips.stopLength=How long (in seconds) the crystal should stop time. +placements.entities.vitellary/timecrystal.tooltips.respawnTime=How long (in seconds) after using the crystal for it to respawn. +placements.entities.vitellary/timecrystal.tooltips.immediate=Whether the transition to time stopping should be smooth or instantaneous. +placements.entities.vitellary/timecrystal.tooltips.entityTypesToIgnore=List of class names for the time crystal to not affect, separated by commas. +placements.entities.vitellary/timecrystal.tooltips.timeScale=The time scale that the entities should be changed to. + +# Tele Crystal +placements.entities.vitellary/telecrystal.tooltips.direction=The direction of the crystal. +placements.entities.vitellary/telecrystal.tooltips.oneUse=Whether the refill should respawn after being used. +placements.entities.vitellary/goodtelecrystal.tooltips.direction=The direction of the crystal. +placements.entities.vitellary/goodtelecrystal.tooltips.oneUse=Whether the refill should respawn after being used. +placements.entities.vitellary/goodtelecrystal.tooltips.preventCrash=If false, the crystal will attempt to move you as far as possible until you collide with a wall, which will crash the game if it never does collide with a wall. +placements.entities.vitellary/goodtelecrystal.tooltips.respawnTime=How long (in seconds) after using the crystal for it to respawn. + +# Star Crystal +placements.entities.vitellary/starcrystal.tooltips.oneUse=Whether the refill should respawn after being used. +placements.entities.vitellary/starcrystal.tooltips.time=How long the effect should last. +placements.entities.vitellary/starcrystal.tooltips.changeDashes=Whether the crystal should give you infinite dashes. +placements.entities.vitellary/starcrystal.tooltips.changeInvuln=Whether the crystal should make you invincible. +placements.entities.vitellary/starcrystal.tooltips.changeStamina=Whether the crystal should give you infinite stamina. +placements.entities.vitellary/starcrystal.tooltips.respawnTime=How long (in seconds) after using the crystal for it to respawn. + +# Force Dash Crystal +placements.entities.vitellary/forcedashcrystal.tooltips.oneUse=Whether the refill should respawn after being used. +placements.entities.vitellary/forcedashcrystal.tooltips.direction=Direction the player is forced to dash. If "None" is selected, the player dashes in the direction they hold. +placements.entities.vitellary/forcedashcrystal.tooltips.respawnTime=How long (in seconds) after using the crystal for it to respawn. +placements.entities.vitellary/forcedashcrystal.tooltips.needDash=Whether the crystal should require that you have a dash, and consume a dash when used. + +# Force Jump Crystal +placements.entities.vitellary/forcedashcrystal.tooltips.oneUse=Whether the refill should respawn after being used. +placements.entities.vitellary/forcedashcrystal.tooltips.respawnTime=How long (in seconds) after using the crystal for it to respawn. +placements.entities.vitellary/forcedashcrystal.tooltips.holdJump=Whether the jump should be a full height jump or a short hop. + +# Keyberry +placements.entities.vitellary/keyberry.tooltips.winged=The keyberry attempts to vertically rise offscreen when the player dashes. +placements.entities.vitellary/returnkeyberry.tooltips.winged=The keyberry attempts to vertically rise offscreen when the player dashes. + +# Linked Move Block +placements.entities.vitellary/vitmoveblock.tooltips.canSteer=Determines whether the move block can be moved by the player. +placements.entities.vitellary/vitmoveblock.tooltips.direction=Determines the direction the move block moves in upon activation. +placements.entities.vitellary/vitmoveblock.tooltips.remote=The group the move block gets activated with. 0 means it's a normal move block. +placements.entities.vitellary/vitmoveblock.tooltips.canActivate=Determines whether the player is able to activate the block by touching it. +placements.entities.vitellary/vitmoveblock.tooltips.spritePath=Path for the move block's sprite, relative to Graphics/Atlases/Gameplay. +placements.entities.vitellary/vitmoveblock.tooltips.moveSpeed=Speed the block will move at. Default is 75. + +# Remote Trigger +placements.entities.vitellary/remotetrigger.tooltips.value=The Linked Move Block group the trigger activates. + +# Reset Door Trigger +placements.triggers.vitellary/resetdoortrigger.tooltips.oneUse=Whether the trigger can be used more than once in the room. +placements.triggers.vitellary/resetdoortrigger.tooltips.animate=Whether doors and keys should animate upon respawning. +placements.triggers.vitellary/resetdoortrigger.tooltips.onlyInRoom=Whether the trigger should affect keys and doors outside of the current room. + +# Custom Prologue Bridge and Activator +placements.entities.vitellary/customprologuebridge.tooltips.activationID=The ID used in the Activator to begin crumbling the bridge. Do not reuse IDs throughout the level! +placements.entities.vitellary/customprologuebridge.tooltips.activationIndex=Used to determine the order the bridges should fall. 0 is the first bridge that collapses. +placements.entities.vitellary/customprologuebridge.tooltips.left=Whether the bridge should start collapsing from the right side. +placements.entities.vitellary/customprologuebridge.tooltips.delay=How long to wait after the trigger has been activated / the previous bridge has finished collapsing before beginning to collapse. +placements.entities.vitellary/customprologuebridge.tooltips.speed=How fast the bridge should crumble. 0.8 is just slow enough that the player can keep up without dashing. +placements.entities.vitellary/customprologuebridge.tooltips.flag=If the flag is true, the bridge won't appear. +placements.triggers.vitellary/custombridgeactivator.tooltips.activationID=The ID for the group of bridges the trigger should activate. + +# Custom Wind Trigger +placements.triggers.vitellary/customwindtrigger.tooltips.speedX=The horizontal speed of the wind. Can be a list of speeds, separated by commas. For reference, normal wind speed is 4, and strong is 8. +placements.triggers.vitellary/customwindtrigger.tooltips.speedY=The vertical speed of the wind. Can be a list of speeds, separated by commas. For reference, normal wind speed is 4, and strong is 8. +placements.triggers.vitellary/customwindtrigger.tooltips.alternationSpeed=The time, in seconds, that it takes to switch between speeds if there is a list in either horizontal or vertical speed. Can also be a list of speeds, separated by commas, which will be looped through. +placements.triggers.vitellary/customwindtrigger.tooltips.catchupSpeed=How fast the wind changes from the previous value. Default is 1. +placements.triggers.vitellary/customwindtrigger.tooltips.activationType=Special condition for the wind to activate. +placements.triggers.vitellary/customwindtrigger.tooltips.loop=Whether the wind should loop or just stop at the last values when going through a list of speeds. +placements.triggers.vitellary/customwindtrigger.tooltips.persist=If true, the wind created will stay after transitioning to a different room or dying. It will still be replaced by other wind triggers. +placements.triggers.vitellary/customwindtrigger.tooltips.oneUse=Whether the wind trigger should disappear after being used. +placements.triggers.vitellary/customwindtrigger.tooltips.onRoomEnter=Whether the wind trigger should activate immediately when the player enters its room, regardless of the player position. + +# Custom Wind Snow +placements.effects.CrystallineHelper/CustomWindSnow.tooltips.colors=List of possible colors the wind particles can have, separated by commas. +placements.effects.CrystallineHelper/CustomWindSnow.tooltips.alphas=List of alphas associated with each color, separated by commas. If the amount of alphas is not the same as the amount of colors, each particle will just take the value of the first alpha listed. +placements.effects.CrystallineHelper/CustomWindSnow.tooltips.amount=Amount of particles. Default is 240. +placements.effects.CrystallineHelper/CustomWindSnow.tooltips.speedX=Horizontal speed that the effect has by default (does not affect gameplay). Current wind strength will be added to it. +placements.effects.CrystallineHelper/CustomWindSnow.tooltips.speedY=Vertical speed that the effect has by default (does not affect gameplay). Current wind strength will be added to it. +placements.effects.CrystallineHelper/CustomWindSnow.tooltips.ignoreWind=Whether the effect should change based on current wind. + +# Player Timestop Trigger +placements.triggers.vitellary/nomovetrigger.tooltips.stopLength=Determines how long the player will be frozen for. + +# Trigger Trigger +placements.triggers.vitellary/triggertrigger.tooltips.activationType=The condition the trigger checks. If you want to change this, you must update this option, then close and reopen this window, so that the correct options appear.\nFlag: When the flag is true. If the flag is left blank, it will always activate when entered.\nDashing: When the player inside is dashing.\nDash Count: If the player's dash count meets the condition specified.\nDeaths In Room: If the player has died the specified amount of times in the room.\nDeaths In Level: If the player has died the specified amount of times in the entire session.\nHoldable Grabbed: When the player grabs a holdable.\nHorizontal / Vertical Speed: If the player's speed meets the condition specified.\nJumping: When the player jumps.\nCrouching: When the player crouches.\nTime Since Player Moved: If the amount of time the player has stayed perfectly still meets the condition specified.\nHoldable Entered: When a holdable object enters the trigger.\nOn Entity Touch: When the amount of times the player touches the specified type of entity meets the condition specified.\nCore Mode: If the core mode of the level matches the specified mode.\nOn Interaction: When the player interacts (via talk button) with the trigger.\nTouched Solid: If the player is either standing on or grabbing the specified solid, or any solid or platform if none is specified.\nEntity Entered: When the specified type of entity enters the trigger. +placements.triggers.vitellary/triggertrigger.tooltips.oneUse=Whether the trigger disappears after being used. +placements.triggers.vitellary/triggertrigger.tooltips.flag=Flag that must be active for the trigger to be used. If left blank, trigger will not require a flag. +placements.triggers.vitellary/triggertrigger.tooltips.invertFlag=Whether the flag specified should be false instead of true. +placements.triggers.vitellary/triggertrigger.tooltips.delay=How long to wait after activating the trigger for it to activate the chosen triggers. +placements.triggers.vitellary/triggertrigger.tooltips.activateOnTransition=If true, then the trigger will activate upon entering the room. +placements.triggers.vitellary/triggertrigger.tooltips.randomize=If true, the trigger will randomly activate only one of the chosen triggers instead of all of them. +placements.triggers.vitellary/triggertrigger.tooltips.matchPosition=If enabled, the selected triggers will be moved and resized to match this trigger. Allows triggers that change based on position, such as Light Fade, to work. +placements.triggers.vitellary/triggertrigger.tooltips.invertCondition=Whether the condition should not be met in order to activate. +placements.triggers.vitellary/triggertrigger.tooltips.onlyOnEnter=Whether the trigger should only check the condition the first time you enter it, instead of checking every frame you're inside it. +placements.triggers.vitellary/triggertrigger.tooltips.comparisonType=For numerical comparisons, whether the requirement should be less than, equal to or greater than the specified value. +placements.triggers.vitellary/triggertrigger.tooltips.absoluteValue=For numerical comparisons, whether the comparison should only consider the absolute value for the requirement. +placements.triggers.vitellary/triggertrigger.tooltips.deaths=How many times the player needs to have died. Depending on the trigger chosen, will refer to either deaths only within the room (resets upon exiting the room) or total deaths in the level (resets upon restarting chapter / returning to map). +placements.triggers.vitellary/triggertrigger.tooltips.dashCount=How many dashes the player needs to have. +placements.triggers.vitellary/triggertrigger.tooltips.requiredSpeed=How much speed the player should have, in pixels/second. Positive means right / down, negative means left / up. Some values to reference:\nDefault walking speed is 90.\nDefault dashing speed is 240.\nDefault hyper speed is 325. +placements.triggers.vitellary/triggertrigger.tooltips.timeToWait=How long the player needs to wait, in seconds. +placements.triggers.vitellary/triggertrigger.tooltips.coreMode=Core mode the level needs to be. +placements.triggers.vitellary/triggertrigger.tooltips.entityType=Class name of the type of entity to check. +placements.triggers.vitellary/triggertrigger.tooltips.solidType=Class name of the type of solid to check. If left blank, the trigger will allow any solids to be considered. + +# Edit Depth Trigger +placements.triggers.vitellary/editdepthtrigger.tooltips.depth=New depth to set the entity to. Lower / negative values will make the entities render above others. +placements.triggers.vitellary/editdepthtrigger.tooltips.entitiesToAffect=The class name of the entity to alter. Can be a comma separated list of multiple entity types as well. +placements.triggers.vitellary/editdepthtrigger.tooltips.debug=If true, then Celeste will write the names of all entities touching the trigger in the log (can be seen in log.txt immediately), as well as their current depths. Useful to figure out the names of the entities you'd like to affect, though remember to disable the option later. +placements.triggers.vitellary/editdepthtrigger.tooltips.updateOnEntry=If true, the trigger will affect entities that move into it; otherwise, it will only affect entities that are touching it when the room loads. + +# Bloom Strength Trigger +placements.triggers.vitellary/bloomstrengthtrigger.tooltips.bloomStrengthFrom=Determines where the bloom strength starts. +placements.triggers.vitellary/bloomstrengthtrigger.tooltips.bloomStrengthTo=Determines where the bloom strength ends. +placements.triggers.vitellary/bloomstrengthtrigger.tooltips.positionMode=Determines which direction the bloom strength fades towards. + +# Timed Fade Trigger +placements.triggers.vitellary/timedfadetrigger.tooltips.time=How long to fade from the From value to the To value. + +# Flag Sequence On Spawn Controller +placements.entities.vitellary/flagsequencecontroller.tooltips.startNumber=The first number to start the sequence. +placements.entities.vitellary/flagsequencecontroller.tooltips.endNumber=The final number in the sequence. +placements.entities.vitellary/flagsequencecontroller.tooltips.prefix=The text that prefixes each flag set. For example, prefix "flagname" with Start Number 8 and End Number 11 will set "flagname_08", "flagname_09", "flagname_10", and "flagname_11" all to the specified state. +placements.entities.vitellary/flagsequencecontroller.tooltips.state=The state to set all of the flags to. \ No newline at end of file diff --git a/Ahorn/triggers/bloomStrengthTrigger.jl b/Ahorn/triggers/bloomStrengthTrigger.jl new file mode 100644 index 0000000..78c855f --- /dev/null +++ b/Ahorn/triggers/bloomStrengthTrigger.jl @@ -0,0 +1,22 @@ +module VitellaryBloomStrengthTrigger + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/bloomstrengthtrigger" BloomTrigger(x::Integer, y::Integer, + width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight, + bloomStrengthFrom::Number=1.0, bloomStrengthTo::Number=1.0, positionMode::String="NoEffect") + +const placements = Ahorn.PlacementDict( + "Bloom Strength Trigger (Crystalline)" => Ahorn.EntityPlacement( + BloomTrigger, + "rectangle" + ) +) + +function Ahorn.editingOptions(trigger::BloomTrigger) + return Dict{String, Any}( + "positionMode" => Maple.trigger_position_modes + ) +end + +end \ No newline at end of file diff --git a/Ahorn/triggers/cancelTimeCrystal.jl b/Ahorn/triggers/cancelTimeCrystal.jl new file mode 100644 index 0000000..de361e1 --- /dev/null +++ b/Ahorn/triggers/cancelTimeCrystal.jl @@ -0,0 +1,15 @@ +module CancelTimeCrystal + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/canceltimecrystaltrigger" CancelTimestop(x::Integer, y::Integer, +width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight) + +const placements = Ahorn.PlacementDict( + "Cancel Time Crystal Trigger (Crystalline)" => Ahorn.EntityPlacement( + CancelTimestop, + "rectangle" + ) +) + +end \ No newline at end of file diff --git a/Ahorn/triggers/customBridgeActivator.jl b/Ahorn/triggers/customBridgeActivator.jl new file mode 100644 index 0000000..3c33e7a --- /dev/null +++ b/Ahorn/triggers/customBridgeActivator.jl @@ -0,0 +1,14 @@ +module CustomBridgeActivator + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/custombridgeactivator" Activator(x::Integer, y::Integer, width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight, activationID::String="") + +const placements = Ahorn.PlacementDict( + "Custom Bridge Activator (Crystalline)" => Ahorn.EntityPlacement( + Activator, + "rectangle" + ) +) + +end \ No newline at end of file diff --git a/Ahorn/triggers/customWindTrigger.jl b/Ahorn/triggers/customWindTrigger.jl new file mode 100644 index 0000000..4252bb5 --- /dev/null +++ b/Ahorn/triggers/customWindTrigger.jl @@ -0,0 +1,21 @@ +module CustomWindTrigger + +using ..Ahorn, Maple + +const actTypes = ["", "Seed", "Strawberry", "Keyberry", "Locked Door", "Refill", "Jellyfish", "Theo", "Core Mode (Hot)", "Core Mode (Cold)", "Death"] + +@mapdef Trigger "vitellary/customwindtrigger" Wind(x::Integer, y::Integer, width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight, speedX::String="0", speedY::String="0", alternationSpeed::String="0", catchupSpeed::Number=1.0, activationType::String="", loop::Bool=true, persist::Bool=false, oneUse::Bool=false, onRoomEnter::Bool=false) + +const placements = Ahorn.PlacementDict( + "Custom Wind Trigger (Crystalline)" => Ahorn.EntityPlacement( + Wind, + "rectangle" + ) +) + +Ahorn.editingOptions(entity::Wind) = Dict{String, Any}( + "activationType" => actTypes +) +Ahorn.editingOrder(entity::Wind) = String["x", "y", "width", "height", "speedX", "speedY", "alternationSpeed", "catchupSpeed", "activationType", "onRoomEnter", "persist", "loop", "oneUse"] + +end \ No newline at end of file diff --git a/Ahorn/triggers/editDepthTrigger.jl b/Ahorn/triggers/editDepthTrigger.jl new file mode 100644 index 0000000..7757c5b --- /dev/null +++ b/Ahorn/triggers/editDepthTrigger.jl @@ -0,0 +1,17 @@ +module VitellaryEditDepthTrigger + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/editdepthtrigger" NewDepth(x::Integer, y::Integer, + width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight, + depth::Integer=-9000, entitiesToAffect::String="Celeste.MoveBlock", debug::Bool=false, + updateOnEntry::Bool=false) + +const placements = Ahorn.PlacementDict( + "Edit Depth Trigger (Crystalline)" => Ahorn.EntityPlacement( + NewDepth, + "rectangle" + ) +) + +end \ No newline at end of file diff --git a/Ahorn/triggers/linkedMoveBlockTrigger.jl b/Ahorn/triggers/linkedMoveBlockTrigger.jl new file mode 100644 index 0000000..68f98a0 --- /dev/null +++ b/Ahorn/triggers/linkedMoveBlockTrigger.jl @@ -0,0 +1,7 @@ +module RemoteTrigger + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/remotetrigger" Remote(x::Integer, y::Integer, width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight, value::Integer=1) + +end \ No newline at end of file diff --git a/Ahorn/triggers/noDashTrigger.jl b/Ahorn/triggers/noDashTrigger.jl new file mode 100644 index 0000000..d1004d7 --- /dev/null +++ b/Ahorn/triggers/noDashTrigger.jl @@ -0,0 +1,14 @@ +module NoDashTrigger + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/nodashtrigger" NoDash(x::Integer, y::Integer, width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight) + +const placements = Ahorn.PlacementDict( + "No Dash Trigger (Crystalline)" => Ahorn.EntityPlacement( + NoDash, + "rectangle" + ) +) + +end \ No newline at end of file diff --git a/Ahorn/triggers/noGrabTrigger.jl b/Ahorn/triggers/noGrabTrigger.jl new file mode 100644 index 0000000..4e10626 --- /dev/null +++ b/Ahorn/triggers/noGrabTrigger.jl @@ -0,0 +1,14 @@ +module NoGrabTrigger + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/nograbtrigger" NoGrab(x::Integer, y::Integer, width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight) + +const placements = Ahorn.PlacementDict( + "No Grab Trigger (Crystalline)" => Ahorn.EntityPlacement( + NoGrab, + "rectangle" + ) +) + +end \ No newline at end of file diff --git a/Ahorn/triggers/noJumpTrigger.jl b/Ahorn/triggers/noJumpTrigger.jl new file mode 100644 index 0000000..2e7b0c2 --- /dev/null +++ b/Ahorn/triggers/noJumpTrigger.jl @@ -0,0 +1,14 @@ +module NoJumpTrigger + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/nojumptrigger" NoJump(x::Integer, y::Integer, width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight) + +const placements = Ahorn.PlacementDict( + "No Jump Trigger (Crystalline)" => Ahorn.EntityPlacement( + NoJump, + "rectangle" + ) +) + +end \ No newline at end of file diff --git a/Ahorn/triggers/playerTimestopTrigger.jl b/Ahorn/triggers/playerTimestopTrigger.jl new file mode 100644 index 0000000..7a6448a --- /dev/null +++ b/Ahorn/triggers/playerTimestopTrigger.jl @@ -0,0 +1,14 @@ +module NoMoveTrigger + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/nomovetrigger" NoMove(x::Integer, y::Integer, width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight, stopLength::Number=2.0) + +const placements = Ahorn.PlacementDict( + "Player Timestop Trigger (Crystalline)" => Ahorn.EntityPlacement( + NoMove, + "rectangle" + ) +) + +end \ No newline at end of file diff --git a/Ahorn/triggers/resetDoorTrigger.jl b/Ahorn/triggers/resetDoorTrigger.jl new file mode 100644 index 0000000..a274509 --- /dev/null +++ b/Ahorn/triggers/resetDoorTrigger.jl @@ -0,0 +1,14 @@ +module ResetDoorTrigger + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/resetdoortrigger" Remote(x::Integer, y::Integer, width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight, oneUse::Bool=false, animate::Bool=true, onlyInRoom::Bool=false) + +const placements = Ahorn.PlacementDict( + "Reset Door Trigger (Crystalline)" => Ahorn.EntityPlacement( + Remote, + "rectangle" + ) +) + +end \ No newline at end of file diff --git a/Ahorn/triggers/timedFadeTrigger.jl b/Ahorn/triggers/timedFadeTrigger.jl new file mode 100644 index 0000000..b06c260 --- /dev/null +++ b/Ahorn/triggers/timedFadeTrigger.jl @@ -0,0 +1,22 @@ +module VitellaryTimedFadeTrigger + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/timedfadetrigger" TimedTrigger(x::Integer, y::Integer, + width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight, + time::Number=1.0) + +const placements = Ahorn.PlacementDict( + "Timed Fade Trigger (Crystalline)" => Ahorn.EntityPlacement( + TimedTrigger, + "rectangle", + Dict{String, Any}(), + function(trigger) + trigger.data["nodes"] = [(Int(trigger.data["x"]) + Int(trigger.data["width"]) + 8, Int(trigger.data["y"]))] + end + ) +) + +Ahorn.nodeLimits(entity::TimedTrigger) = 1, 1 + +end \ No newline at end of file diff --git a/Ahorn/triggers/triggerTrigger.jl b/Ahorn/triggers/triggerTrigger.jl new file mode 100644 index 0000000..7e43469 --- /dev/null +++ b/Ahorn/triggers/triggerTrigger.jl @@ -0,0 +1,123 @@ +module VitellaryTriggerTrigger + +using ..Ahorn, Maple + +@mapdef Trigger "vitellary/triggertrigger" Ttrigger(x::Integer, y::Integer, + width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight, + oneUse::Bool=false, flag::String="", invertCondition::Bool=false, delay::Number=0.0, + activateOnTransition::Bool=false, randomize::Bool=false, matchPosition::Bool=true, + activationType::String="Flag", comparisonType::String="EqualTo", deaths::Integer=0, + dashCount::Integer=0, requiredSpeed::Number=0.0, absoluteValue::Bool=false, + timeToWait::Number=0.0, coreMode::String="none", entityTypeToCollide::String="Celeste.Strawberry", + talkBubbleX::Integer=0, talkBubbleY::Integer=0, onlyOnEnter::Bool=false, + collideCount::Integer=1, solidType::String="", entityType::String="") + +const activationTypes = Dict{String, String}( + "Flag (Default)" => "Flag", + "Dashing" => "Dashing", + "Dash Count" => "DashCount", + "Deaths In Room" => "DeathsInRoom", + "Deaths In Level" => "DeathsInLevel", + "Holdable Grabbed" => "GrabHoldable", + "Horizontal Speed" => "SpeedX", + "Vertical Speed" => "SpeedY", + "Jumping" => "Jumping", + "Crouching" => "Crouching", + "Time Since Player Moved" => "TimeSinceMovement", + "Holdable Entered" => "OnHoldableEnter", + "On Entity Touch" => "OnEntityCollide", + "Core Mode" => "CoreMode", + "On Interaction" => "OnInteraction", + "Touched Solid" => "OnSolid", + "Entity Entered" => "OnEntityEnter", +) + +const comparisonTypes = ["LessThan", "EqualTo", "GreaterThan"] + +const placements = Ahorn.PlacementDict( + "Trigger Trigger ($name) (Crystalline)" => Ahorn.EntityPlacement( + Ttrigger, + "rectangle", + Dict{String, Any}( + "activationType" => "$acttype", + ), + function(trigger) + trigger.data["nodes"] = [(Int(trigger.data["x"]) + Int(trigger.data["width"]) + 8, Int(trigger.data["y"]))] + if trigger.data["activationType"] == "OnInteraction" + trigger.data["talkBubbleX"] = div(Int(trigger.data["width"]), 2) + end + end + ) for (name, acttype) in activationTypes +) + +Ahorn.nodeLimits(entity::Ttrigger) = 1, -1 + +Ahorn.editingOptions(entity::Ttrigger) = Dict{String, Any}( + "activationType" => activationTypes, + "comparisonType" => comparisonTypes, + "coreMode" => sort(Maple.core_modes) +) + +function Ahorn.editingOrder(entity::Ttrigger) + result = String["x", "y", "width", "height", + "talkBubbleX", "talkBubbleY", "activationType", "delay", + "flag", "comparisonType", "dashCount", "deaths", + "requiredSpeed", "timeToWait", "coreMode", "entityTypeToCollide", "solidType", "entityType", + "collideCount", "absoluteValue", "activateOnTransition", "invertCondition", + "matchPosition", "onlyOnEnter", "oneUse", "randomize"] + + return result +end + +function Ahorn.editingIgnored(entity::Ttrigger, multiple::Bool=false) + atype = get(entity.data, "activationType", "Flag") + result = String["comparisonType", "absoluteValue", "talkBubbleX", "talkBubbleY", "flag", "deaths", + "dashCount", "requiredSpeed", "timeToWait", "coreMode", "entityTypeToCollide", "collideCount", + "solidType", "entityType"] + iscomparison = false + + if atype == "Flag" + deleteat!(result, findall(x->x=="flag",result)) + elseif atype == "DashCount" + deleteat!(result, findall(x->x=="dashCount",result)) + iscomparison = true + elseif atype == "DeathsInRoom" || atype == "DeathsInLevel" + deleteat!(result, findall(x->x=="deaths",result)) + iscomparison = true + elseif atype == "SpeedX" || atype == "SpeedY" + deleteat!(result, findall(x->x=="requiredSpeed",result)) + iscomparison = true + elseif atype == "TimeSinceMovement" + deleteat!(result, findall(x->x=="timeToWait",result)) + iscomparison = true + elseif atype == "CoreMode" + deleteat!(result, findall(x->x=="coreMode",result)) + elseif atype == "OnEntityCollide" + deleteat!(result, findall(x->x=="entityType",result)) + deleteat!(result, findall(x->x=="collideCount",result)) + iscomparison = true + elseif atype == "OnInteraction" + deleteat!(result, findall(x->x=="talkBubbleX",result)) + deleteat!(result, findall(x->x=="talkBubbleY",result)) + elseif atype == "OnSolid" + deleteat!(result, findall(x->x=="solidType",result)) + elseif atype == "OnEntityEnter" + deleteat!(result, findall(x->x=="entityType",result)) + end + + if iscomparison + deleteat!(result, findall(x->x=="comparisonType",result)) + deleteat!(result, findall(x->x=="absoluteValue",result)) + end + + if multiple + insert!(result, "x", 1) + insert!(result, "y", 2) + insert!(result, "width", 3) + insert!(result, "height", 4) + end + + return result +end + +end \ No newline at end of file diff --git a/Code/BloomStrengthTrigger.cs b/Code/BloomStrengthTrigger.cs new file mode 100644 index 0000000..53b74ee --- /dev/null +++ b/Code/BloomStrengthTrigger.cs @@ -0,0 +1,38 @@ +using Celeste; +using Celeste.Mod.Entities; +using MonoMod.Utils; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/bloomstrengthtrigger")] + [Tracked(false)] + public class BloomStrengthTrigger : Trigger + { + public BloomStrengthTrigger(EntityData data, Vector2 offset) : base(data, offset) + { + bloomAddFrom = data.Float("bloomStrengthFrom", 1f); + bloomAddTo = data.Float("bloomStrengthTo", 1f); + positionMode = data.Enum("positionMode", PositionModes.NoEffect); + } + + public override void OnStay(Player player) + { + (Scene as Level).Bloom.Strength = bloomAddFrom + (bloomAddTo - bloomAddFrom) * MathHelper.Clamp(GetPositionLerp(player, positionMode), 0f, 1f); + } + + public float bloomAddFrom; + + public float bloomAddTo; + + // Token: 0x0400199B RID: 6555 + public PositionModes positionMode; + } +} diff --git a/Code/BoostBumper.cs b/Code/BoostBumper.cs new file mode 100644 index 0000000..147ae29 --- /dev/null +++ b/Code/BoostBumper.cs @@ -0,0 +1,170 @@ +using Celeste; +using Celeste.Mod.Entities; +using MonoMod.Utils; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/boostbumper")] + [Tracked] + public class BoostBumper : Entity + { + public BoostBumper(Vector2 position) : base(position) + { + Depth = -8500; + Collider = new Circle(10f, 0f, 2f); + Add(sprite = VitModule.SpriteBank.Create("boostBumper")); + Add(new PlayerCollider(new Action(OnPlayer), null, null)); + Add(light = new VertexLight(Color.Teal, 1f, 16, 32)); + Add(bloom = new BloomPoint(0.5f, 16f)); + Add(wiggler = Wiggler.Create(0.5f, 4f, delegate (float f) + { + sprite.Scale = Vector2.One * (1f + f * 0.25f); + }, false, false)); + Add(new MirrorReflection()); + } + + public BoostBumper(EntityData data, Vector2 offset) : this(data.Position + offset) { } + + public override void Added(Scene scene) + { + base.Added(scene); + Image image = new Image(GFX.Game["objects/booster/outline"]); + image.CenterOrigin(); + image.Color = Color.White * 0.75f; + outline = new Entity(Position); + outline.Depth = 8999; + outline.Visible = false; + outline.Add(image); + outline.Add(new MirrorReflection()); + scene.Add(outline); + } + + public override void Update() + { + base.Update(); + if (cannotUseTimer > 0f) + { + cannotUseTimer -= Engine.DeltaTime; + } + if (respawnTimer > 0f) + { + respawnTimer -= Engine.DeltaTime; + if (respawnTimer <= 0f) + { + Respawn(); + } + } + if (respawnTimer <= 0f) + { + Vector2 target = Vector2.Zero; + Player player = Scene.Tracker.GetEntity(); + if (player != null && CollideCheck(player)) + { + target = player.Center + new Vector2(0f, -2f) - Position; + } + sprite.Position = Calc.Approach(sprite.Position, target, 80f * Engine.DeltaTime); + if (Scene.OnInterval(0.05f)) + { + float dir = Calc.Random.NextAngle(); + SceneAs().Particles.Emit(P_Idle, 1, Center + sprite.Position + Calc.AngleToVector(dir, 8f), Vector2.One * 2f, dir); + } + } + if (sprite.CurrentAnimationID == "inside" && !CollideCheck()) + { + sprite.Play("idle", false, false); + } + } + + public override void Render() + { + Vector2 position = sprite.Position; + sprite.Position = position.Floor(); + if (sprite.CurrentAnimationID != "burst" && sprite.Visible) + { + sprite.DrawOutline(1); + } + base.Render(); + sprite.Position = position; + } + + private void Respawn() + { + Audio.Play("event:/game/04_cliffside/greenbooster_reappear", Position); + sprite.Position = Vector2.Zero; + sprite.Play("idle", true, false); + wiggler.Start(); + sprite.Visible = true; + outline.Visible = false; + AppearParticles(); + } + + private void AppearParticles() + { + ParticleSystem particlesBG = SceneAs().ParticlesBG; + for (int i = 0; i < 360; i += 30) + { + particlesBG.Emit(P_Appear, 1, Center, Vector2.One * 2f, i * 0.0174532924f); + } + } + + private void OnPlayer(Player player) + { + if (respawnTimer <= 0f && cannotUseTimer <= 0f) + { + cannotUseTimer = 0.45f; + player.StateMachine.State = 4; + player.Speed = Vector2.Zero; + DynData playerData = new DynData(player); + playerData.Set("boostTarget", Center); + startedBoosting = true; + Audio.Play("event:/game/04_cliffside/greenbooster_enter", Position); + wiggler.Start(); + sprite.Play("inside", false, false); + sprite.FlipX = player.Facing == Facings.Left; + } + } + + public void PlayerBoosted(Player player, Vector2 direction) + { + startedBoosting = false; + Vector2 launch = player.ExplodeLaunch(player.Center - direction, false, false); + SceneAs().DirectionalShake(launch, 0.15f); + SceneAs().Displacement.AddBurst(Center, 0.3f, 8f, 32f, 0.8f, null, null); + SceneAs().Particles.Emit(Bumper.P_Launch, 12, Center + launch * 12f, Vector2.One * 3f, launch.Angle()); + sprite.Play("burst", false, false); + outline.Visible = true; + sprite.Visible = false; + cannotUseTimer = 0f; + respawnTimer = 1f; + wiggler.Stop(); + } + + public static ParticleType P_Appear; + + public static ParticleType P_Idle; + + public Sprite sprite; + + private VertexLight light; + + private BloomPoint bloom; + + private Wiggler wiggler; + + private Entity outline; + + private float respawnTimer; + + private float cannotUseTimer; + + public bool startedBoosting; + } +} diff --git a/Code/CancelTimeCrystalTrigger.cs b/Code/CancelTimeCrystalTrigger.cs new file mode 100644 index 0000000..efcc01a --- /dev/null +++ b/Code/CancelTimeCrystalTrigger.cs @@ -0,0 +1,29 @@ +using Celeste; +using Celeste.Mod.Entities; +using MonoMod.Utils; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/canceltimecrystaltrigger")] + public class CancelTimeCrystalTrigger : Trigger + { + public CancelTimeCrystalTrigger(EntityData data, Vector2 offset) : base(data, offset) { } + + public override void OnEnter(Player player) + { + base.OnEnter(player); + TimeCrystal.stopTimer = 2f; + TimeCrystal.stopStage = 2; + VitModule.timeStopType = TimeCrystal.freezeTypes.Timer; //hacky thing to get it to resume time normally + VitModule.timeStopScaleTimer = TimeCrystal.timeScaleToSet; + } + } +} diff --git a/Code/CustomBridge.cs b/Code/CustomBridge.cs new file mode 100644 index 0000000..a5a6e9b --- /dev/null +++ b/Code/CustomBridge.cs @@ -0,0 +1,154 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/customprologuebridge")] + public class CustomBridge : Entity + { + public CustomBridge(EntityData data, Vector2 offset) : base(data.Position + offset) + { + width = data.Width; + flag = data.Attr("flag", ""); + actID = data.Attr("activationID", ""); + actIndex = data.Int("activationIndex", 0); + left = data.Bool("left", false); + actDelay = data.Float("delay", 0f); + actSpeed = data.Float("speed", 0.8f) / 10; + id = data.ID; + + Add(sfx = new SoundSource()); + + tileSizes = new List(); + tileSizes.Add(new Rectangle(0, 0, 8, 20)); + tileSizes.Add(new Rectangle(0, 0, 8, 13)); + tileSizes.Add(new Rectangle(0, 0, 8, 13)); + tileSizes.Add(new Rectangle(0, 0, 8, 8)); + tileSizes.Add(new Rectangle(0, 0, 8, 8)); + tileSizes.Add(new Rectangle(0, 0, 8, 8)); + tileSizes.Add(new Rectangle(0, 0, 8, 7)); + tileSizes.Add(new Rectangle(0, 0, 8, 8)); + tileSizes.Add(new Rectangle(0, 0, 8, 8)); + tileSizes.Add(new Rectangle(0, 0, 16, 16)); + tileSizes.Add(new Rectangle(0, 0, 16, 16)); + } + + public override void Added(Scene scene) + { + base.Added(scene); + if (!bridgeList.ContainsKey(actID)) + { + bridgeList.Add(actID, new Dictionary()); + } + if (!bridgeList[actID].ContainsKey(actIndex)) + { + bridgeList[actID].Add(actIndex, this); + } + + Calc.PushRandom(id); + int i = 0; + int tilewidth = (int)Math.Floor((decimal)width / 8); + while (i < tilewidth) + { + int index; + if (i == tilewidth - 1) + { + index = Calc.Random.Next(tileSizes.Count - 2); + } + else + { + index = Calc.Random.Next(tileSizes.Count); + } + CustomBridgeTile tile = new CustomBridgeTile(Position + new Vector2(i * 8, 0), tileSizes[index], index); + tiles.Add(tile); + SceneAs().Add(tile); + if (index >= tileSizes.Count - 2) + { + i += 2; + } + else + { + i++; + } + } + Calc.PopRandom(); + } + + public override void Awake(Scene scene) + { + base.Awake(scene); + if ((scene as Level).Session.GetFlag(flag)) + { + foreach (CustomBridgeTile tile in tiles) + { + tile.DisableStaticMovers(); + tile.RemoveSelf(); + } + RemoveSelf(); + } + } + + public override void Update() + { + base.Update(); + Player player = SceneAs().Tracker.GetEntity(); + if (player == null || player.Dead) + { + sfx.Stop(); + } + } + + public IEnumerator FallRoutine(int bridgeIndex) + { + yield return actDelay; + sfx.Play("event:/game/00_prologue/bridge_rumble_loop"); + for (int i = 0; i < tiles.Count; i++) + { + int tileIndex = left ? (tiles.Count - 1 - i) : i; + CustomBridgeTile tile = tiles[tileIndex]; + tile.Fall(); + yield return actSpeed; + } + int nextBridge = bridgeIndex + 1; + if (bridgeList[actID].ContainsKey(nextBridge)) + { + CustomBridge bridge = bridgeList[actID][nextBridge]; + bridge.Add(new Coroutine(bridge.FallRoutine(nextBridge))); + } + sfx.Stop(); + yield break; + } + + private int width; + + private string flag; + + private string actID; + + private int actIndex; + + private bool left; + + private float actDelay; + + private float actSpeed; + + private SoundSource sfx; + + public static Dictionary> bridgeList = new Dictionary>(); + + private List tileSizes; + + private List tiles = new List(); + + private int id; + } +} diff --git a/Code/CustomBridgeActivator.cs b/Code/CustomBridgeActivator.cs new file mode 100644 index 0000000..c19b314 --- /dev/null +++ b/Code/CustomBridgeActivator.cs @@ -0,0 +1,34 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/custombridgeactivator")] + public class CustomBridgeActivator : Trigger + { + public CustomBridgeActivator(EntityData data, Vector2 offset) : base(data, offset) + { + actID = data.Attr("activationID"); + } + + public override void OnEnter(Player player) + { + base.OnEnter(player); + if (CustomBridge.bridgeList.ContainsKey(actID) && CustomBridge.bridgeList[actID].ContainsKey(0)) + { + CustomBridge bridge = CustomBridge.bridgeList[actID][0]; + bridge.Add(new Coroutine(bridge.FallRoutine(0))); + } + RemoveSelf(); + } + + private string actID; + } +} diff --git a/Code/CustomBridgeTile.cs b/Code/CustomBridgeTile.cs new file mode 100644 index 0000000..378cc50 --- /dev/null +++ b/Code/CustomBridgeTile.cs @@ -0,0 +1,78 @@ +using Celeste; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + public class CustomBridgeTile : Solid + { + public CustomBridgeTile(Vector2 position, Rectangle tileSize, int imageIndex) : base(position, tileSize.Width, tileSize.Height, false) + { + Add(image = new Image(GFX.Game["objects/customBridge/tile" + imageIndex])); + image.Origin = new Vector2(image.Width / 2f, 0f); + image.X = image.Width / 2f; + image.Y = 0f; + } + + public override void Update() + { + base.Update(); + if (fallen) + { + if (shakeTimer > 0f) + { + shakeTimer -= Engine.DeltaTime; + if (Scene.OnInterval(0.02f)) + { + shakeOffset = Calc.Random.ShakeVector(); + } + if (shakeTimer <= 0f) + { + SceneAs().Shake(0.1f); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + } + image.Position = new Vector2(image.Width / 2f, 0f) + shakeOffset; + } + else + { + colorLerp = Calc.Approach(colorLerp, 1f, 10f * Engine.DeltaTime); + image.Color = Color.Lerp(Color.White, Color.Gray, colorLerp); + shakeOffset = Vector2.Zero; + speedY = Calc.Approach(speedY, 200f, 900f * Engine.DeltaTime); + MoveV(speedY * Engine.DeltaTime); + if (Top > SceneAs().Bounds.Bottom) + { + DisableStaticMovers(); + RemoveSelf(); + } + } + } + } + + public void Fall() + { + fallen = true; + Calc.PushRandom(11 / 6); + shakeTimer = Calc.Random.Range(0.1f, 0.5f); + Calc.PopRandom(); + } + + private Image image; + + private bool fallen; + + private float shakeTimer; + + private Vector2 shakeOffset; + + private float colorLerp; + + private float speedY; + } +} diff --git a/Code/CustomWindController.cs b/Code/CustomWindController.cs new file mode 100644 index 0000000..f4b3d83 --- /dev/null +++ b/Code/CustomWindController.cs @@ -0,0 +1,320 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [Tracked] + public class CustomWindController : Entity + { + public static void Load() + { + On.Celeste.WindController.Update += WindController_Update; + On.Celeste.Refill.OnPlayer += Refill_OnPlayer; + On.Celeste.Glider.OnPickup += Glider_OnPickup; + On.Celeste.TheoCrystal.OnPickup += TheoCrystal_OnPickup; + } + + public static void Unload() + { + On.Celeste.WindController.Update -= WindController_Update; + On.Celeste.Refill.OnPlayer -= Refill_OnPlayer; + On.Celeste.Glider.OnPickup -= Glider_OnPickup; + On.Celeste.TheoCrystal.OnPickup -= TheoCrystal_OnPickup; + } + + public CustomWindController(List speedX, List speedY, List alternateSpeed, float catchupSpeed, string activateType, bool loop, bool persist) + { + active = false; + Tag = Tags.TransitionUpdate; + this.speedX = speedX; + this.speedY = speedY; + this.alternateSpeed = alternateSpeed; + this.catchupSpeed = catchupSpeed; + this.activateType = activateType; + this.loop = loop; + if (persist) + { + Tag |= Tags.Global | Tags.Persistent; + } + } + + public override void Update() + { + base.Update(); + CheckActivation(); + Level level = SceneAs(); + level.Wind = Calc.Approach(level.Wind, targetSpeed, catchupSpeed * 1000f * Engine.DeltaTime); + if (level.Wind != Vector2.Zero && !level.Transitioning) + { + foreach (Component component in Scene.Tracker.GetComponents()) + { + WindMover windMover = component as WindMover; + windMover.Move(level.Wind * 0.1f * Engine.DeltaTime); + } + } + } + + private void CheckActivation() + { + switch (activateType) + { + case "Seeds": + bool activate1 = false; + foreach (StrawberrySeed seed in Scene.Tracker.GetEntities()) + { + if (seed.Collected) + { + activate1 = true; + break; + } + } + foreach (KeyBerrySeed seed in Scene.Tracker.GetEntities()) + { + if (seed.collected) + { + activate1 = true; + break; + } + } + if (activate1) + { + ActivateWind(); + } + else + { + DeactivateWind(); + } + break; + case "Strawberry": + Player player = Scene.Tracker.GetEntity(); + bool activate2 = false; + foreach (Follower follower in player.Leader.Followers) + { + if (follower.Entity is Strawberry) + { + Strawberry berry = follower.Entity as Strawberry; + if (!berry.Golden) + { + activate2 = true; + break; + } + } + } + if (activate2) + { + ActivateWind(); + } + else + { + DeactivateWind(); + } + break; + case "Keyberry": + Player player2 = Scene.Tracker.GetEntity(); + bool activate3 = false; + foreach (Follower follower in player2.Leader.Followers) + { + if (follower.Entity is KeyBerry) + { + activate3 = true; + break; + } + } + if (activate3) + { + ActivateWind(); + } + else + { + DeactivateWind(); + } + break; + case "Locked Door": + case "Refill": + case "Jellyfish": + case "Theo": + //handled inside hooks + break; + case "Core Mode (Hot)": + if (SceneAs().CoreMode == Session.CoreModes.Hot) + { + ActivateWind(); + } + else + { + DeactivateWind(); + } + break; + case "Core Mode (Cold)": + if (SceneAs().CoreMode == Session.CoreModes.Cold) + { + ActivateWind(); + } + else + { + DeactivateWind(); + } + break; + case "Death": + Player player3 = Scene.Tracker.GetEntity(); + if (player3 == null || player3.Dead) + { + ActivateWind(); + } + break; + default: + ActivateWind(true); + break; + } + } + + public static void Refill_OnPlayer(On.Celeste.Refill.orig_OnPlayer orig, Refill self, Player player) + { + orig(self, player); + if (!self.Collidable) + { + CustomWindController wind = self.Scene.Tracker.GetEntity(); + if (wind != null && wind.activateType == "Refill") + { + wind.ActivateWind(); + } + } + } + + public static void Glider_OnPickup(On.Celeste.Glider.orig_OnPickup orig, Glider self) + { + orig(self); + CustomWindController wind = self.Scene.Tracker.GetEntity(); + if (wind != null && wind.activateType == "Jellyfish") + { + wind.ActivateWind(); + } + } + + public static void TheoCrystal_OnPickup(On.Celeste.TheoCrystal.orig_OnPickup orig, TheoCrystal self) + { + orig(self); + CustomWindController wind = self.Scene.Tracker.GetEntity(); + if (wind != null && wind.activateType == "Theo") + { + wind.ActivateWind(); + } + } + + public static void WindController_Update(On.Celeste.WindController.orig_Update orig, WindController self) + { + if (self.Scene.Tracker.GetEntities().Count == 0) + { + orig(self); + } + } + + public void ActivateWind(bool debug = false) + { + if (active) return; + active = true; + if (debug && !string.IsNullOrEmpty(activateType)) + { + Console.WriteLine("Custom wind doesn't have a activation case for: " + activateType); + } + if ((speedX.Count > 1 || speedY.Count > 1) && !alternateSpeed.Contains(0)) + { + Add(coroutine = new Coroutine(WindRoutine())); + } + else + { + targetSpeed.X = speedX[0] * 100f; + targetSpeed.Y = speedY[0] * 100f; + SetAmbience(); + } + } + + public void DeactivateWind() + { + if (!active) { return; } + active = false; + if (coroutine != null) + { + coroutine.RemoveSelf(); + } + targetSpeed = Vector2.Zero; + SetAmbience(); + } + + public void SnapWind() + { + if (coroutine != null && coroutine.Active) + { + coroutine.Update(); + } + SceneAs().Wind = targetSpeed; + SetAmbience(); + windIndex = 0; + } + + private void SetAmbience() + { + if (targetSpeed != Vector2.Zero) + { + float angle = (float)Math.Atan2(targetSpeed.Y, targetSpeed.X); + angle += (float)Math.PI / 4; + angle %= (float)Math.PI * 2; + if (angle < Math.PI) + { + Audio.SetParameter(Audio.CurrentAmbienceEventInstance, "wind_direction", 1f); + } + else + { + Audio.SetParameter(Audio.CurrentAmbienceEventInstance, "wind_direction", -1f); + } + } + else + { + Audio.SetParameter(Audio.CurrentAmbienceEventInstance, "wind_direction", 0f); + } + Audio.SetParameter(Audio.CurrentAmbienceEventInstance, "strong_wind", targetSpeed.LengthSquared() > 640000f ? 1f : 0f); + } + + private IEnumerator WindRoutine() + { + while (loop || windIndex < Math.Max(speedX.Count, speedY.Count)) + { + targetSpeed.X = speedX[windIndex % speedX.Count] * 100f; + targetSpeed.Y = speedY[windIndex % speedY.Count] * 100f; + SetAmbience(); + yield return alternateSpeed[windIndex % alternateSpeed.Count]; + windIndex++; + } + RemoveSelf(); + yield break; + } + + private bool active; + + private List speedX; + + private List speedY; + + private List alternateSpeed; + + private float catchupSpeed; + + public string activateType; + + private bool loop; + + private int windIndex = 0; + + private Vector2 targetSpeed; + + private Coroutine coroutine; + } +} diff --git a/Code/CustomWindSnow.cs b/Code/CustomWindSnow.cs new file mode 100644 index 0000000..c622be3 --- /dev/null +++ b/Code/CustomWindSnow.cs @@ -0,0 +1,167 @@ +using Celeste; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + public class CustomWindSnow : Backdrop + { + public CustomWindSnow(string colors, string alphas, int amount, float speedX, float speedY, bool ignoreWind) : base() + { + this.colors = new List(); + string[] colorStrings = colors.Split(','); + foreach(string color in colorStrings) + { + this.colors.Add(Calc.HexToColor(color)); + } + this.alphas = new List(); + string[] alphaStrings = alphas.Split(','); + foreach(string alpha in alphaStrings) + { + this.alphas.Add(float.Parse(alpha)); + } + this.amount = amount; + addSpeed = new Vector2(speedX * 100f, speedY * 100f); + this.ignoreWind = ignoreWind; + + Color = Color.White; + CameraOffset = Vector2.Zero; + scale = Vector2.One; + rotation = 0f; + visibleFade = 1f; + positions = new Vector2[amount]; + particleColors = new int[amount]; + Random rng = new Random(); + for (int i = 0; i < positions.Length; i++) + { + positions[i] = Calc.Random.Range(new Vector2(0f, 0f), new Vector2(640f, 360f)); + particleColors[i] = rng.Next(0, this.colors.Count); + } + sines = new SineWave[amount / 15]; + for (int i = 0; i < sines.Length; i++) + { + sines[i] = new SineWave(Calc.Random.Range(0.8f, 1.2f), 0f); + sines[i].Randomize(); + } + } + + public override void Update(Scene scene) + { + base.Update(scene); + Level level = scene as Level; + visibleFade = Calc.Approach(visibleFade, IsVisible(level) ? 1f : 0f, Engine.DeltaTime * 2f); + foreach(SineWave sine in sines) + { + sine.Update(); + } + windVector = ignoreWind ? Vector2.Zero : level.Wind; + windVector += addSpeed; + scale.X = Math.Max(1f, Math.Abs(windVector.Length()) / 100f); + float vertical = (float)Math.Abs(Math.Sin(Math.Atan2(windVector.Y, windVector.X))); + scale.X /= Math.Max(1f - vertical, 0.4f); + scale.Y = 1f / Math.Max(1f, scale.X * 0.25f); + rotation %= (float)Math.PI * 2; + float target_rot = (float)Math.Atan2(windVector.Y, windVector.X); + if (Math.Abs(rotation - target_rot) == Math.PI) + { + rotation = target_rot; + } + else + { + if (rotation - target_rot > Math.PI) + { + target_rot += (float)Math.PI * 2; + } + else if (target_rot - rotation > Math.PI) + { + target_rot -= (float)Math.PI * 2; + } + } + rotation = Calc.Approach(rotation, target_rot, Engine.DeltaTime * 8f); + for (int i = 0; i < positions.Length; i++) + { + float value = sines[i % sines.Length].Value; + Vector2 zero = new Vector2(windVector.X + value * 10f, windVector.Y * 3f + value * 10f); + if (windVector.Length() == 0f) + { + zero.Y += 20f; + } + positions[i] += zero * Engine.DeltaTime; + } + } + + public override void Render(Scene scene) + { + base.Render(scene); + int index = 0; + float limit = (float)Math.Abs(Math.Sin(Math.Atan2(windVector.Y, windVector.X))); + if (windVector == Vector2.Zero) + { + limit = 0f; + } + limit = 0.6f + (1 - limit) * 0.4f; + foreach(Vector2 init in positions) + { + Color color = colors[particleColors[index]]; + if (alphas.Count == colors.Count) + { + color *= visibleFade * alphas[particleColors[index]]; + } + else + { + color *= visibleFade * alphas[0]; + } + Vector2 position = init; + position.Y -= (scene as Level).Camera.Y + CameraOffset.Y; + position.Y %= 360f; + if (position.Y < 0f) + { + position.Y += 360f; + } + position.X -= (scene as Level).Camera.X + CameraOffset.X; + position.X %= 360f; + if (position.X < 0f) + { + position.X += 360f; + } + if (index < amount * limit) + { + GFX.Game["particles/snow"].DrawCentered(position, color, scale, rotation); + } + index++; + } + } + + private List colors; + + private List alphas; + + private int amount; + + private Vector2 addSpeed; + + private Vector2 windVector; + + private bool ignoreWind; + + public Vector2 CameraOffset; + + private Vector2[] positions; + + private int[] particleColors; + + private SineWave[] sines; + + private Vector2 scale; + + private float rotation; + + private float visibleFade; + } +} diff --git a/Code/CustomWindTrigger.cs b/Code/CustomWindTrigger.cs new file mode 100644 index 0000000..da6a885 --- /dev/null +++ b/Code/CustomWindTrigger.cs @@ -0,0 +1,101 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/customwindtrigger")] + public class CustomWindTrigger : Trigger + { + public CustomWindTrigger(EntityData data, Vector2 offset) : base(data, offset) + { + speedX = new List(); + string[] speedXStrings = data.Attr("speedX", "0").Split(','); + foreach(string sx in speedXStrings) + { + speedX.Add(float.Parse(sx)); + } + speedY = new List(); + string[] speedYStrings = data.Attr("speedY", "0").Split(','); + foreach (string sy in speedYStrings) + { + speedY.Add(float.Parse(sy)); + } + alternateSpeed = new List(); + string[] alternateSpeedStrings = data.Attr("alternationSpeed", "0").Split(','); + foreach(string sa in alternateSpeedStrings) + { + alternateSpeed.Add(float.Parse(sa)); + } + catchupSpeed = data.Float("catchupSpeed", 1f); + activateType = data.Attr("activationType", ""); + loop = data.Bool("loop", true); + persist = data.Bool("persist", false); + oneUse = data.Bool("oneUse", false); + ID = data.ID; + onRoomEnter = data.Bool("onRoomEnter", false); + } + + public override void Awake(Scene scene) + { + base.Awake(scene); + if (onRoomEnter) + { + OnEnter(scene.Tracker.GetEntity()); + } + } + + public override void OnEnter(Player player) + { + base.OnEnter(player); + WindController wind = Scene.Entities.FindFirst(); + if (wind != null) + { + wind.RemoveSelf(); + } + CustomWindController customWind = Scene.Entities.FindFirst(); + if (customWind != null) + { + customWind.RemoveSelf(); + } + customWind = new CustomWindController(speedX, speedY, alternateSpeed, catchupSpeed, activateType, loop, persist); + Scene.Add(customWind); + if (oneUse) + { + RemoveSelf(); + if (persist) + { + Session session = SceneAs().Session; + session.DoNotLoad.Add(new EntityID(session.Level, ID)); + } + } + } + + private List speedX; + + private List speedY; + + private List alternateSpeed; + + private float catchupSpeed; + + private string activateType; + + private bool loop; + + private bool persist; + + private bool oneUse; + + private int ID; + + private bool onRoomEnter; + } +} diff --git a/Code/EditDepthTrigger.cs b/Code/EditDepthTrigger.cs new file mode 100644 index 0000000..5a8481f --- /dev/null +++ b/Code/EditDepthTrigger.cs @@ -0,0 +1,66 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/editdepthtrigger")] + public class EditDepthTrigger : Trigger + { + public EditDepthTrigger(EntityData data, Vector2 offset) : base(data, offset) + { + newDepth = data.Int("depth", 0); + entityNames = data.Attr("entitiesToAffect", "").Split(','); + debug = data.Bool("debug", false); + update = data.Bool("updateOnEntry", false); + } + + public override void Added(Scene scene) + { + base.Added(scene); + foreach (Entity entity in scene.Entities) + { + if (entity.CollideCheck(this)) + { + if (entityNames.Contains(entity.GetType().FullName) || entityNames.Contains(entity.GetType().Name)) + { + entity.Depth = newDepth; + } + if (debug) + { + Console.WriteLine(entity.GetType().FullName + ": " + entity.Depth); + } + } + } + } + + public override void Update() + { + base.Update(); + if (update) + { + foreach (Entity entity in Scene.Entities) + { + if (entity.CollideCheck(this)) + { + if (entityNames.Contains(entity.GetType().FullName) || entityNames.Contains(entity.GetType().Name)) + { + entity.Depth = newDepth; + } + } + } + } + } + + private int newDepth; + private string[] entityNames; + private bool debug; + private bool update; + } +} diff --git a/Code/FillCrystal.cs b/Code/FillCrystal.cs new file mode 100644 index 0000000..7c58f24 --- /dev/null +++ b/Code/FillCrystal.cs @@ -0,0 +1,180 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/fillcrystal")] + public class FillCrystal : Entity + { + public FillCrystal(EntityData data, Vector2 offset) : base(data.Position + offset) + { + oneUse = data.Bool("oneUse", false); + useTime = data.Float("respawnTime", 2.5f); + + Collider = new Hitbox(16f, 16f, -8f, -8f); + Add(new PlayerCollider(new Action(OnPlayer), null, null)); + if (!oneUse) + { + Add(outline = new Image(GFX.Game["objects/crystals/fill/outline"])); + outline.CenterOrigin(); + outline.Visible = false; + } + string spritetype = oneUse ? "idlenr" : "idle"; + Add(sprite = new Sprite(GFX.Game, "objects/crystals/fill/" + spritetype)); + sprite.AddLoop(spritetype, "", 0.1f); + sprite.Play(spritetype, false, false); + sprite.CenterOrigin(); + Add(flash = new Sprite(GFX.Game, "objects/crystals/fill/flash")); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + Add(wiggler = Wiggler.Create(1f, 4f, delegate (float v) + { + sprite.Scale = (flash.Scale = Vector2.One * (1f + v * 0.2f)); + }, false, false)); + Add(new MirrorReflection()); + Add(bloom = new BloomPoint(0.8f, 16f)); + Add(light = new VertexLight(Color.White, 1f, 16, 48)); + Add(sine = new SineWave(0.6f)); + sine.Randomize(); + UpdateY(); + Depth = -100; + } + + public override void Added(Scene scene) + { + base.Added(scene); + level = SceneAs(); + } + + public override void Update() + { + base.Update(); + if (respawnTimer > 0f) + { + respawnTimer -= Engine.DeltaTime; + if (respawnTimer <= 0f) + { + Respawn(); + } + } + else if (Scene.OnInterval(0.1f)) + { + level.ParticlesFG.Emit(P_Glow, 1, Position, Vector2.One * 5f); + } + UpdateY(); + light.Alpha = Calc.Approach(light.Alpha, sprite.Visible ? 1f : 0f, 4f * Engine.DeltaTime); + bloom.Alpha = light.Alpha * 0.8f; + if (Scene.OnInterval(2f) && sprite.Visible) + { + flash.Play("flash", true, false); + flash.Visible = true; + } + } + + private void Respawn() + { + if (!Collidable) + { + Collidable = true; + sprite.Visible = true; + outline.Visible = false; + Depth = -100; + wiggler.Start(); + Audio.Play("event:/game/general/diamond_return", Position); + level.ParticlesFG.Emit(P_Regen, 16, Position, Vector2.One * 2f); + } + } + + private void UpdateY() + { + flash.Y = (sprite.Y = (bloom.Y = sine.Value * 2f)); + } + + public override void Render() + { + if (sprite.Visible) + { + sprite.DrawOutline(1); + } + base.Render(); + } + + private void OnPlayer(Player player) + { + if (SceneAs().Session.Inventory.NoRefills) { + SceneAs().Session.Inventory.NoRefills = false; + Audio.Play("event:/game/general/diamond_touch", Position); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + Collidable = false; + Add(new Coroutine(RefillRoutine(player), true)); + if (oneUse) + { + RemoveSelf(); + } + else + { + respawnTimer = useTime; + } + } + } + + private IEnumerator RefillRoutine(Player player) + { + Celeste.Celeste.Freeze(0.1f); + yield return null; + level.Shake(0.3f); + sprite.Visible = (flash.Visible = false); + if (!oneUse) + { + outline.Visible = true; + } + Depth = 8999; + yield return 0.05f; + float num = player.Speed.Angle(); + level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, num - 1.57079637f); + level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, num + 1.57079637f); + SlashFx.Burst(Position, num); + yield break; + } + + private bool oneUse; + + private float useTime; + + public static ParticleType P_Shatter; + + public static ParticleType P_Regen; + + public static ParticleType P_Glow; + + private Sprite sprite; + + private Sprite flash; + + private Image outline; + + private Wiggler wiggler; + + private BloomPoint bloom; + + private VertexLight light; + + private Level level; + + private SineWave sine; + + private float respawnTimer; + } +} diff --git a/Code/FlagSequenceController.cs b/Code/FlagSequenceController.cs new file mode 100644 index 0000000..301b696 --- /dev/null +++ b/Code/FlagSequenceController.cs @@ -0,0 +1,53 @@ +using Celeste; +using Celeste.Mod.Entities; +using MonoMod.Utils; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/flagsequencecontroller")] + public class FlagSequenceController : Entity + { + public FlagSequenceController(EntityData data, Vector2 offset) : base(data.Position + offset) + { + Level level = Engine.Scene as Level; + if (level == null) + { + LevelLoader levelLoader = Engine.Scene as LevelLoader; + level = (levelLoader != null) ? levelLoader.Level : null; + } + if (level != null) + { + string prefix = data.Attr("prefix", ""); + if (!string.IsNullOrEmpty(prefix)) + { + bool state = data.Bool("state", false); + for (int i = Math.Min(data.Int("startNumber", 1), 0); i <= data.Int("endNumber", 2); i++) + { + if (i < 10) + { + level.Session.SetFlag(prefix + "_0" + i, state); + } + else + { + level.Session.SetFlag(prefix + "_" + i, state); + } + } + } + } + } + + public override void Added(Scene scene) + { + base.Added(scene); + RemoveSelf(); + } + } +} diff --git a/Code/ForceDashCrystal.cs b/Code/ForceDashCrystal.cs new file mode 100644 index 0000000..54b56c2 --- /dev/null +++ b/Code/ForceDashCrystal.cs @@ -0,0 +1,557 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using MonoMod.Utils; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/forcedashcrystal")] + public class ForceDashCrystal : Entity + { + public static void Load() + { + On.Celeste.Input.GetAimVector += Input_GetAimVector; + } + + public static void Unload() + { + On.Celeste.Input.GetAimVector -= Input_GetAimVector; + } + + public ForceDashCrystal(EntityData data, Vector2 offset) : base(data.Position + offset) + { + direction = data.Attr("direction", "Right"); + oneUse = data.Bool("oneUse", false); + useTime = data.Float("respawnTime", 2.5f); + needDash = data.Bool("needDash", false); + + string crystalType = needDash ? "needdash" : "dashless"; + string useType = oneUse ? "idlenr" : "idle"; + + sprites = new List(); + spritePositions = new List(); + flashes = new List(); + sines = new List(); + + switch (direction) + { + case "Downright": + dirVector = Vector2.One; + for (int i = 0; i < 3; i++) + { + Sprite sprite = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/diag/" + useType); + sprite.AddLoop("idle", "", 0.1f); + sprite.Play("idle", false, false); + sprite.CenterOrigin(); + sprite.Rotation = (float)Math.PI * 0.5f; + Add(sprite); + sprites.Add(sprite); + + Sprite flash = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/diag/flash"); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + flash.Rotation = (float)Math.PI * 0.5f; + Add(flash); + flashes.Add(flash); + } + flashes[0].Position = sprites[0].Position = new Vector2(2f, 2f); + flashes[1].Position = sprites[1].Position = new Vector2(1f, -3f); + flashes[2].Position = sprites[2].Position = new Vector2(-3f, 1f); + + outline = new Image(GFX.Game["objects/crystals/forcedash/" + crystalType + "/diag/outline"]); + outline.CenterOrigin(); + outline.Rotation = (float)Math.PI * 0.5f; + outline.Visible = false; + break; + case "Down": + dirVector = Vector2.UnitY; + for (int i = 0; i < 3; i++) + { + Sprite sprite = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/ortho/" + useType); + sprite.AddLoop("idle", "", 0.1f); + sprite.Play("idle", false, false); + sprite.CenterOrigin(); + sprite.Rotation = (float)Math.PI; + Add(sprite); + sprites.Add(sprite); + + Sprite flash = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/ortho/flash"); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + flash.Rotation = (float)Math.PI; + Add(flash); + flashes.Add(flash); + } + flashes[0].Position = sprites[0].Position = new Vector2(0, 2f); + flashes[1].Position = sprites[1].Position = new Vector2(4f, -2f); + flashes[2].Position = sprites[2].Position = new Vector2(-4f, -2f); + + outline = new Image(GFX.Game["objects/crystals/forcedash/" + crystalType + "/ortho/outline"]); + outline.CenterOrigin(); + outline.Rotation = (float)Math.PI; + outline.Visible = false; + break; + case "Downleft": + dirVector = new Vector2(-1f, 1f); + for (int i = 0; i < 3; i++) + { + Sprite sprite = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/diag/" + useType); + sprite.AddLoop("idle", "", 0.1f); + sprite.Play("idle", false, false); + sprite.CenterOrigin(); + sprite.Rotation = (float)Math.PI; + Add(sprite); + sprites.Add(sprite); + + Sprite flash = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/diag/flash"); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + flash.Rotation = (float)Math.PI; + Add(flash); + flashes.Add(flash); + } + flashes[0].Position = sprites[0].Position = new Vector2(-2f, 2f); + flashes[1].Position = sprites[1].Position = new Vector2(-1f, -3f); + flashes[2].Position = sprites[2].Position = new Vector2(3f, 1f); + + outline = new Image(GFX.Game["objects/crystals/forcedash/" + crystalType + "/diag/outline"]); + outline.CenterOrigin(); + outline.Rotation = (float)Math.PI; + outline.Visible = false; + break; + case "Left": + dirVector = -Vector2.UnitX; + for (int i = 0; i < 3; i++) + { + Sprite sprite = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/ortho/" + useType); + sprite.AddLoop("idle", "", 0.1f); + sprite.Play("idle", false, false); + sprite.CenterOrigin(); + sprite.Rotation = (float)-Math.PI * 0.5f; + Add(sprite); + sprites.Add(sprite); + + Sprite flash = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/ortho/flash"); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + flash.Rotation = (float)-Math.PI * 0.5f; + Add(flash); + flashes.Add(flash); + } + flashes[0].Position = sprites[0].Position = new Vector2(-2f, 0); + flashes[1].Position = sprites[1].Position = new Vector2(2f, -4f); + flashes[2].Position = sprites[2].Position = new Vector2(2f, 4f); + + outline = new Image(GFX.Game["objects/crystals/forcedash/" + crystalType + "/ortho/outline"]); + outline.CenterOrigin(); + outline.Rotation = (float)-Math.PI * 0.5f; + outline.Visible = false; + break; + case "Upleft": + dirVector = -Vector2.One; + for (int i = 0; i < 3; i++) + { + Sprite sprite = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/diag/" + useType); + sprite.AddLoop("idle", "", 0.1f); + sprite.Play("idle", false, false); + sprite.CenterOrigin(); + sprite.Rotation = (float)-Math.PI * 0.5f; + Add(sprite); + sprites.Add(sprite); + + Sprite flash = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/diag/flash"); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + flash.Rotation = (float)-Math.PI * 0.5f; + Add(flash); + flashes.Add(flash); + } + flashes[0].Position = sprites[0].Position = new Vector2(-2f, -2f); + flashes[1].Position = sprites[1].Position = new Vector2(-1f, 3f); + flashes[2].Position = sprites[2].Position = new Vector2(3f, -1f); + + outline = new Image(GFX.Game["objects/crystals/forcedash/" + crystalType + "/diag/outline"]); + outline.CenterOrigin(); + outline.Rotation = (float)-Math.PI * 0.5f; + outline.Visible = false; + break; + case "Up": + dirVector = -Vector2.UnitY; + for (int i = 0; i < 3; i++) + { + Sprite sprite = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/ortho/" + useType); + sprite.AddLoop("idle", "", 0.1f); + sprite.Play("idle", false, false); + sprite.CenterOrigin(); + Add(sprite); + sprites.Add(sprite); + + Sprite flash = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/ortho/flash"); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + Add(flash); + flashes.Add(flash); + } + flashes[0].Position = sprites[0].Position = new Vector2(0, -2f); + flashes[1].Position = sprites[1].Position = new Vector2(4f, 2f); + flashes[2].Position = sprites[2].Position = new Vector2(-4f, 2f); + + outline = new Image(GFX.Game["objects/crystals/forcedash/" + crystalType + "/ortho/outline"]); + outline.CenterOrigin(); + outline.Visible = false; + break; + case "Upright": + dirVector = new Vector2(1f, -1f); + for (int i = 0; i < 3; i++) + { + Sprite sprite = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/diag/" + useType); + sprite.AddLoop("idle", "", 0.1f); + sprite.Play("idle", false, false); + sprite.CenterOrigin(); + Add(sprite); + sprites.Add(sprite); + + Sprite flash = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/diag/flash"); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + Add(flash); + flashes.Add(flash); + } + flashes[0].Position = sprites[0].Position = new Vector2(2f, -2f); + flashes[1].Position = sprites[1].Position = new Vector2(1f, 3f); + flashes[2].Position = sprites[2].Position = new Vector2(-3f, -1f); + + outline = new Image(GFX.Game["objects/crystals/forcedash/" + crystalType + "/diag/outline"]); + outline.CenterOrigin(); + outline.Visible = false; + break; + case "Right": + dirVector = Vector2.UnitX; + for (int i = 0; i < 3; i++) + { + Sprite sprite = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/ortho/" + useType); + sprite.AddLoop("idle", "", 0.1f); + sprite.Play("idle", false, false); + sprite.CenterOrigin(); + sprite.Rotation = (float)-Math.PI * 0.5f; + Add(sprite); + sprites.Add(sprite); + + Sprite flash = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/ortho/flash"); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + flash.Rotation = (float)-Math.PI * 0.5f; + Add(flash); + flashes.Add(flash); + } + flashes[0].Position = sprites[0].Position = new Vector2(2f, 0); + flashes[1].Position = sprites[1].Position = new Vector2(-2f, -4f); + flashes[2].Position = sprites[2].Position = new Vector2(-2f, 4f); + + outline = new Image(GFX.Game["objects/crystals/forcedash/" + crystalType + "/ortho/outline"]); + outline.CenterOrigin(); + outline.Rotation = (float)Math.PI * 0.5f; + outline.Visible = false; + break; + default: // None + for (int i = 0; i < 4; i++) + { + Sprite sprite = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/diag/" + useType); + sprite.AddLoop("idle", "", 0.1f); + sprite.Play("idle", false, false); + sprite.CenterOrigin(); + sprite.Rotation = i * (float)Math.PI / 2f; + Add(sprite); + sprites.Add(sprite); + + Sprite flash = new Sprite(GFX.Game, "objects/crystals/forcedash/" + crystalType + "/diag/flash"); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + flash.Rotation = i * (float)Math.PI / 2f; + Add(flash); + flashes.Add(flash); + } + flashes[0].Position = sprites[0].Position = new Vector2(2f, -2f); + flashes[1].Position = sprites[1].Position = new Vector2(2f, 2f); + flashes[2].Position = sprites[2].Position = new Vector2(-2f, 2f); + flashes[3].Position = sprites[3].Position = new Vector2(-2f, -2f); + + outline = new Image(GFX.Game["objects/crystals/forcedash/" + crystalType + "/diag/outline_none"]); + outline.CenterOrigin(); + outline.Visible = false; + break; + } + Add(outline); + + for (int i = 0; i < (direction == "None" ? 4 : 3); i++) + { + spritePositions.Add(sprites[i].Position); + sprites[i].SetAnimationFrame(Calc.Random.Next()); + + SineWave sine = new SineWave(0.6f, Calc.Random.Range(0f, 1f)); + Add(sine); + sines.Add(sine); + } + + Collider = new Hitbox(16f, 16f, -8f, -8f); + Add(new PlayerCollider(new Action(OnPlayer), null, null)); + + Add(wiggler = Wiggler.Create(1f, 4f, (float v) => + { + for(int i = 0; i < (direction == "None" ? 4 : 3); i++) + { + flashes[i].Scale = sprites[i].Scale = Vector2.One * (1f + v * 0.2f); + } + }, false, false)); + Add(new MirrorReflection()); + Add(bloom = new BloomPoint(0.8f, 16f)); + Add(light = new VertexLight(Color.White, 1f, 16, 48)); + + Depth = -100; + UpdateSprite(); + } + + public override void Update() + { + base.Update(); + if (respawnTimer > 0f) + { + respawnTimer -= Engine.DeltaTime; + if (respawnTimer <= 0f) + { + Respawn(); + } + } + else if (Scene.OnInterval(0.1f)) + { + SceneAs().ParticlesFG.Emit(P_Glow, 1, Position, Vector2.One * 5f); + } + UpdateSprite(); + light.Alpha = Calc.Approach(light.Alpha, sprites[1].Visible ? 1f : 0f, 4f * Engine.DeltaTime); + bloom.Alpha = light.Alpha * 0.8f; + if (Scene.OnInterval(2f) && sprites[1].Visible) + { + foreach (Sprite flash in flashes) + { + flash.Play("flash", true, false); + flash.Visible = true; + } + } + } + + public override void Removed(Scene scene) + { + base.Removed(scene); + dirToUse = null; + } + + private void Respawn() + { + if (!Collidable) + { + Collidable = true; + foreach (Sprite sprite in sprites) + { + sprite.Visible = true; + } + outline.Visible = false; + Depth = -100; + wiggler.Start(); + Audio.Play("event:/game/general/diamond_return", Position); + SceneAs().ParticlesFG.Emit(P_Regen, 16, Position, Vector2.One * 2f); + } + } + + private void UpdateSprite() + { + if (direction == "None") + { + for (int i = 0; i < 4; i++) + { + flashes[i].Position = sprites[i].Position = + spritePositions[i] + (new Vector2(1f, -1f).Rotate(i * (float)Math.PI / 2f) * sines[i].Value); + } + } + else + { + if (dirVector.X == 0 || dirVector.Y == 0) + { + for (int i = 0; i < 3; i++) + { + flashes[i].Position = sprites[i].Position = spritePositions[i] + (dirVector * sines[i].Value * 2f); + } + bloom.Position = dirVector * sines[0].Value * 2f; + } + else + { + for (int i = 0; i < 3; i++) + { + flashes[i].Position = sprites[i].Position = spritePositions[i] + (dirVector * sines[i].Value); + } + bloom.Position = dirVector * sines[0].Value; + } + } + } + + public override void Render() + { + foreach (Sprite sprite in sprites) + { + if (sprite.Visible) + { + sprite.DrawOutline(1); + } + } + base.Render(); + } + + private void OnPlayer(Player player) + { + if (!needDash || player.Dashes > 0) + { + player.StateMachine.State = 0; + if (direction != "None") + { + dirToUse = Vector2.Normalize(dirVector); + } + player.StateMachine.State = 2; + if (needDash) + { + player.Dashes--; + } + Audio.Play("event:/game/general/diamond_touch", Position); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + Collidable = false; + Add(new Coroutine(RefillRoutine(player), true)); + if (!oneUse) + { + respawnTimer = useTime; + } + } + } + + private IEnumerator RefillRoutine(Player player) + { + Celeste.Celeste.Freeze(0.05f); + yield return null; + Level level = SceneAs(); + level.Shake(0.3f); + for (int i = 0; i < (direction == "None" ? 4 : 3); i++) + { + flashes[i].Visible = sprites[i].Visible = false; + } + if (!oneUse) + { + outline.Visible = true; + } + Depth = 8999; + yield return 0.05f; + if (dirToUse == Vector2.Normalize(dirVector)) + { + dirToUse = null; + } + float num = player.Speed.Angle(); + level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, num - 1.57079637f); + level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, num + 1.57079637f); + SlashFx.Burst(Position, num); + if (oneUse) + { + RemoveSelf(); + } + yield break; + } + + public static Vector2 Input_GetAimVector(On.Celeste.Input.orig_GetAimVector orig, Facings defaultFacing) + { + return dirToUse ?? orig(defaultFacing); + } + + private bool oneUse; + + private string direction; + + private float useTime; + + private bool needDash; + + private Vector2 dirVector; + + public static Vector2? dirToUse; + + private float respawnTimer; + + private List sprites; + + private List flashes; + + private List spritePositions; + + private Image outline; + + private List sines; + + public static ParticleType P_Shatter; + + public static ParticleType P_Regen; + + public static ParticleType P_Glow; + + public static ParticleType P_NeedDash_Shatter; + + public static ParticleType P_NeedDash_Regen; + + public static ParticleType P_NeedDash_Glow; + + private Wiggler wiggler; + + private BloomPoint bloom; + + private VertexLight light; + + private static MethodInfo playerDashBegin = typeof(Player).GetMethod("DashBegin", BindingFlags.Instance | BindingFlags.NonPublic); + } +} diff --git a/Code/ForceJumpCrystal.cs b/Code/ForceJumpCrystal.cs new file mode 100644 index 0000000..5d64be0 --- /dev/null +++ b/Code/ForceJumpCrystal.cs @@ -0,0 +1,296 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using MonoMod.Utils; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/forcejumpcrystal")] + public class ForceJumpCrystal : Entity + { + public ForceJumpCrystal(EntityData data, Vector2 offset) : base(data.Position + offset) + { + oneUse = data.Bool("oneUse", false); + useTime = data.Float("respawnTime", 2.5f); + holdJump = data.Bool("holdJump", true); + onlyIfPossible = data.Bool("onlyJumpIfPossible", false); + + string useType = oneUse ? "idlenr" : "idle"; + + sprites = new List(); + flashSprites = new List(); + sines = new List(); + + Sprite leftSprite = new Sprite(GFX.Game, "objects/crystals/forcejump/" + useType); + leftSprite.AddLoop("idle", "", 0.1f); + leftSprite.Play("idle", false, true); + leftSprite.CenterOrigin(); + leftSprite.X -= 4; + Add(leftSprite); + sprites.Add(leftSprite); + + Sprite leftFlash = new Sprite(GFX.Game, "objects/crystals/forcejump/flash"); + leftFlash.Add("flash", "", 0.05f); + leftFlash.OnFinish = delegate (string anim) + { + leftFlash.Visible = false; + }; + leftFlash.CenterOrigin(); + leftFlash.X -= 4; + Add(leftFlash); + flashSprites.Add(leftFlash); + + Sprite rightSprite = new Sprite(GFX.Game, "objects/crystals/forcejump/" + useType); + rightSprite.AddLoop("idle", "", 0.1f); + rightSprite.Play("idle", false, true); + rightSprite.CenterOrigin(); + rightSprite.X += 4; + rightSprite.FlipX = true; + Add(rightSprite); + sprites.Add(rightSprite); + + Sprite rightFlash = new Sprite(GFX.Game, "objects/crystals/forcejump/flash"); + rightFlash.Add("flash", "", 0.05f); + rightFlash.OnFinish = delegate (string anim) + { + rightFlash.Visible = false; + }; + rightFlash.CenterOrigin(); + rightFlash.X += 4; + rightFlash.FlipX = true; + Add(rightFlash); + flashSprites.Add(rightFlash); + + outline = new Image(GFX.Game["objects/crystals/forcejump/outline"]); + outline.CenterOrigin(); + outline.Visible = false; + Add(outline); + + for (int i = 0; i < 2; i++) + { + SineWave sine = new SineWave(0.6f, Calc.Random.Range(0f, 1f)); + Add(sine); + sines.Add(sine); + } + + Collider = new Hitbox(16f, 16f, -8f, -8f); + Add(new PlayerCollider(new Action(OnPlayer), null, null)); + + Add(wiggler = Wiggler.Create(1f, 4f, (float v) => + { + for (int i = 0; i < 2; i++) + { + flashSprites[i].Scale = sprites[i].Scale = Vector2.One * (1f + v * 0.2f); + } + }, false, false)); + Add(new MirrorReflection()); + Add(bloom = new BloomPoint(0.8f, 16f)); + Add(light = new VertexLight(Color.White, 1f, 16, 48)); + + Depth = -100; + UpdateSprite(); + } + + public override void Update() + { + base.Update(); + if (respawnTimer > 0f) + { + respawnTimer -= Engine.DeltaTime; + if (respawnTimer <= 0f) + { + Respawn(); + } + } + else if (Scene.OnInterval(0.1f)) + { + SceneAs().ParticlesFG.Emit(P_Glow, 1, Position, Vector2.One * 5f); + } + UpdateSprite(); + light.Alpha = Calc.Approach(light.Alpha, sprites[0].Visible ? 1f : 0f, 4f * Engine.DeltaTime); + bloom.Alpha = light.Alpha * 0.8f; + if (Scene.OnInterval(2f) && sprites[0].Visible) + { + foreach (Sprite flash in flashSprites) + { + flash.Play("flash", true, false); + flash.Visible = true; + } + } + } + + private void Respawn() + { + if (!Collidable) + { + Collidable = true; + foreach (Sprite sprite in sprites) + { + sprite.Visible = true; + } + outline.Visible = false; + Depth = -100; + wiggler.Start(); + Audio.Play("event:/game/general/diamond_return", Position); + SceneAs().ParticlesFG.Emit(P_Regen, 16, Position, Vector2.One * 2f); + } + } + + private void UpdateSprite() + { + for (int i = 0; i < 2; i++) + { + flashSprites[i].Y = sprites[i].Y = sines[i].Value; + } + } + + public override void Render() + { + foreach (Sprite sprite in sprites) + { + if (sprite.Visible) + { + sprite.DrawOutline(1); + } + } + base.Render(); + } + + private void OnPlayer(Player player) + { + DynData playerData = new DynData(player); + player.StateMachine.State = 0; + if (player.DashAttacking) + { + if (playerData.Get("SuperWallJumpAngleCheck")) + { + if ((bool)m_WallJumpCheck.Invoke(player, new object[] { -1 })) + { + m_SuperWallJump.Invoke(player, new object[] { 1 }); + } + else if ((bool)m_WallJumpCheck.Invoke(player, new object[] { 1 })) + { + m_SuperWallJump.Invoke(player, new object[] { -1 }); + } + else + { + m_SuperWallJump.Invoke(player, new object[] { 0 }); + } + } + else + { + m_SuperJump.Invoke(player, new object[] { }); + } + } + else + { + if ((bool)m_WallJumpCheck.Invoke(player, new object[] { (int)player.Facing })) + { + if (Input.GrabCheck && player.Stamina > 0f && player.Holding == null && + !ClimbBlocker.Check(Scene, player, player.Position + Vector2.UnitX * 3f)) + { + m_ClimbJump.Invoke(player, new object[] { }); + } + else + { + m_WallJump.Invoke(player, new object[] { -(int)player.Facing }); + } + } + else if ((bool)m_WallJumpCheck.Invoke(player, new object[] { -(int)player.Facing })) + { + m_WallJump.Invoke(player, new object[] { (int)player.Facing }); + } + else + { + player.Jump(); + } + } + player.AutoJump = holdJump; + Audio.Play("event:/game/general/diamond_touch", Position); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + Collidable = false; + Add(new Coroutine(RefillRoutine(player), true)); + if (!oneUse) + { + respawnTimer = useTime; + } + } + + private IEnumerator RefillRoutine(Player player) + { + Celeste.Celeste.Freeze(0.05f); + yield return null; + Level level = SceneAs(); + level.Shake(0.3f); + for (int i = 0; i < 2; i++) + { + flashSprites[i].Visible = sprites[i].Visible = false; + } + if (!oneUse) + { + outline.Visible = true; + } + Depth = 8999; + yield return 0.05f; + float num = player.Speed.Angle(); + level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, num - 1.57079637f); + level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, num + 1.57079637f); + SlashFx.Burst(Position, num); + if (oneUse) + { + RemoveSelf(); + } + yield break; + } + + private bool oneUse; + + private float useTime; + + private bool holdJump; + + private bool onlyIfPossible; + + private List sprites; + + private List flashSprites; + + private List sines; + + private Image outline; + + private Wiggler wiggler; + + private BloomPoint bloom; + + private VertexLight light; + + private float respawnTimer; + + public static ParticleType P_Glow; + + public static ParticleType P_Regen; + + public static ParticleType P_Shatter; + + //functions for making player jump + private static MethodInfo m_SuperJump = typeof(Player).GetMethod( + "SuperJump", BindingFlags.Instance | BindingFlags.NonPublic); + private static MethodInfo m_ClimbJump = typeof(Player).GetMethod( + "ClimbJump", BindingFlags.Instance | BindingFlags.NonPublic); + private static MethodInfo m_WallJumpCheck = typeof(Player).GetMethod( + "WallJumpCheck", BindingFlags.Instance | BindingFlags.NonPublic); + private static MethodInfo m_SuperWallJump = typeof(Player).GetMethod( + "SuperWallJump", BindingFlags.Instance | BindingFlags.NonPublic); + private static MethodInfo m_WallJump = typeof(Player).GetMethod( + "WallJump", BindingFlags.Instance | BindingFlags.NonPublic); + } +} diff --git a/Code/IntroLockedCar.cs b/Code/IntroLockedCar.cs new file mode 100644 index 0000000..fce796b --- /dev/null +++ b/Code/IntroLockedCar.cs @@ -0,0 +1,176 @@ +using Celeste; +using Celeste.Mod.Entities; +using MonoMod.Utils; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/lockedintrocar")] + [Tracked] + public class IntroLockedCar : Solid + { + public IntroLockedCar(EntityData data, Vector2 offset, EntityID id) : base(data.Position + offset, 25f, 4f, true) + { + ID = id; + if (!VitModule.Session.introCarEntityDatas.ContainsKey(ID)) + { + VitModule.Session.introCarEntityDatas.Add(ID, data); + VitModule.Session.introCarOffsets.Add(ID, offset); + } + opening = false; + didHaveRider = false; + startY = Y; + Depth = 1; + bodySprite = VitModule.SpriteBank.Create("locked_intro_car_body"); + bodySprite.Y -= 9f; + Add(bodySprite); + Hitbox hitbox = new Hitbox(27f, 15f, -17f, -17f); + Hitbox hitbox2 = new Hitbox(15f, 9f, 10f, -11f); + Collider = new ColliderList(new Collider[] + { + hitbox, + hitbox2 + }); + Add(new PlayerCollider(new Action(OnPlayer), new Circle(60f), null)); + } + + public override void Added(Scene scene) + { + base.Added(scene); + wheels = new Entity(Position); + wheelSprite = VitModule.SpriteBank.Create("locked_intro_car_wheels"); + wheelSprite.Y -= 9f; + wheels.Add(wheelSprite); + wheels.Depth = 3; + Scene.Add(wheels); + } + + public override void Update() + { + bool hasRider = HasRider(); + if (Y > startY && !hasRider) + { + MoveV(-1f); + } + if (Y <= startY && !didHaveRider && hasRider) + { + MoveV(1f); + } + if (didHaveRider && !hasRider) + { + Audio.Play("event:/game/00_prologue/car_up", Position); + } + didHaveRider = hasRider; + base.Update(); + } + + public override int GetLandSoundIndex(Entity entity) + { + Audio.Play("event:/game/00_prologue/car_down", Position); + return -1; + } + + private void OnPlayer(Player player) + { + if (!opening) + { + foreach (Follower follower in player.Leader.Followers) + { + if (follower.Entity is Key && !(follower.Entity as Key).StartedUsing) + { + TryOpen(player, follower); + break; + } + } + } + } + + private void TryOpen(Player player, Follower follower) + { + Collidable = false; + if (!Scene.CollideCheck(player.Center, Center)) + { + opening = true; + (follower.Entity as Key).StartedUsing = true; + Add(new Coroutine(UnlockRoutine(follower), true)); + } + Collidable = true; + } + + private IEnumerator UnlockRoutine(Follower follower) + { + SoundEmitter emitter = SoundEmitter.Play("event:/game/05_mirror_temple/key_unlock_light", this, null); + emitter.Source.DisposeOnTransition = true; + Level level = SceneAs(); + Key key = follower.Entity as Key; + Add(new Coroutine(key.UseRoutine(Position + new Vector2(-5f, -7f)), true)); + yield return 1.2f; + level.Session.DoNotLoad.Add(ID); + VitModule.Session.introCarsToReset.Add(ID); + key.RegisterUsed(); + yield return 0.3f; + yield return bodySprite.PlayRoutine("open", false); + bodySprite.Play("openIdle"); + while (key.Turning) + { + yield return null; + } + Tag |= Tags.TransitionUpdate; + Collidable = false; + emitter.Source.DisposeOnTransition = false; + level.Shake(0.3f); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + wheelSprite.Play("burst"); + CustomWindController wind = Scene.Tracker.GetEntity(); + if (wind != null && wind.activateType == "Locked Door") + { + wind.ActivateWind(); + } + yield return bodySprite.PlayRoutine("burst", false); + RemoveSelf(); + wheels.RemoveSelf(); + yield break; + } + + public IEnumerator KeyberryUnlock() + { + SoundEmitter emitter = SoundEmitter.Play("event:/game/05_mirror_temple/key_unlock_light", this, null); + emitter.Source.DisposeOnTransition = true; + Level level = SceneAs(); + yield return 0.15f; + level.Session.DoNotLoad.Add(ID); + VitModule.Session.introCarsToReset.Add(ID); + Tag |= Tags.TransitionUpdate; + Collidable = false; + emitter.Source.DisposeOnTransition = false; + level.Shake(0.3f); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + wheelSprite.Play("burst"); + yield return bodySprite.PlayRoutine("burst", false); + RemoveSelf(); + wheels.RemoveSelf(); + yield break; + } + + private EntityID ID; + + private bool opening; + + private bool didHaveRider; + + private float startY; + + public Sprite bodySprite; + + public Entity wheels; + + public Sprite wheelSprite; + } +} diff --git a/Code/KaizoBlock.cs b/Code/KaizoBlock.cs new file mode 100644 index 0000000..9b89588 --- /dev/null +++ b/Code/KaizoBlock.cs @@ -0,0 +1,146 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using MonoMod.Utils; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace vitmod +{ + [CustomEntity("vitellary/kaizoblock")] + [Tracked] + public class KaizoBlock : Solid + { + public static void Load() + { + On.Celeste.Player.Update += Player_Update; + } + + public static void Unload() + { + On.Celeste.Player.Update -= Player_Update; + } + + public KaizoBlock(EntityData data, Vector2 offset, EntityID ID) : base(data.Position + offset - new Vector2(8, 8), 16, 16, true) + { + persistent = data.Bool("persistent", false); + dashDisable = data.Float("noDashTimer", 0.2f); + + Depth = -9999; + id = ID.ToString(); + Collidable = false; + + Add(sprite = VitModule.SpriteBank.Create("kaizoblock")); + sprite.Play("idle"); + sprite.Visible = false; + sprite.Position = new Vector2(8, 8); + Add(spriteWiggler = Wiggler.Create(0.5f, 4f, delegate (float f) + { + sprite.Scale = Vector2.One * (1f + f * 0.25f); + })); + moveWiggler = Wiggler.Create(0.8f, 2f); + moveWiggler.StartZero = true; + Add(moveWiggler); + } + + public override void Added(Scene scene) + { + base.Added(scene); + Level level = scene as Level; + if (persistent && level.Session.GetFlag("kaizoblock_flag_" + id)) + { + activated = true; + Collidable = true; + sprite.Visible = true; + } + scene.Add(new OutlineRenderer(this)); + } + + public override void Update() + { + base.Update(); + if (!activated) + { + Player player = SceneAs().Tracker.GetEntity(); + if (player == null) return; + if (CollideCheck(Position + Vector2.UnitY) && player.Speed.Y < 0f) + { + Hit(player); + } + } + } + + private void Hit(Player player) + { + player.Speed.Y = 160f; + player.StateMachine.State = 0; + player.NaiveMove(new Vector2(0, Bottom - player.Top)); + DynData playerData = new DynData(player); + playerData.Set("dashCooldownTimer", dashDisable); + + Audio.Play("event:/game/general/thing_booped", Position); + sprite.Play("flash"); + sprite.Visible = true; + Add(Alarm.Create(Alarm.AlarmMode.Oneshot, delegate + { + Audio.Play("event:/game/07_summit/checkpoint_confetti", Position); + }, 0.25f, start: true)); + spriteWiggler.Start(); + moveWiggler.Start(); + activated = true; + Collidable = true; + + if (persistent) + { + SceneAs().Session.SetFlag("kaizoblock_flag_" + id); + } + } + + private static void Player_Update(On.Celeste.Player.orig_Update orig, Player self) + { + List kaizoBlocks = self.SceneAs().Tracker.GetEntities(); + kaizoBlocks = kaizoBlocks.Where(kaizo => !(kaizo as KaizoBlock).activated).ToList(); + foreach (KaizoBlock kaizo in kaizoBlocks) + { + kaizo.Collidable = kaizo.Bottom < self.Top; + } + orig(self); + foreach (KaizoBlock kaizo in kaizoBlocks) + { + kaizo.Collidable = false; + } + } + + private class OutlineRenderer : Entity + { + public KaizoBlock kaizo; + + public OutlineRenderer(KaizoBlock kaizoBlock) + { + Depth = 5000; + kaizo = kaizoBlock; + } + + public override void Render() + { + if (kaizo.activated) + { + Draw.Rect(new Rectangle((int)(kaizo.X + kaizo.Shake.X), (int)(kaizo.Y + kaizo.Shake.Y - 1f), (int)kaizo.Width, (int)kaizo.Height + 2), Color.Black); + Draw.Rect(new Rectangle((int)(kaizo.X + kaizo.Shake.X - 1f), (int)(kaizo.Y + kaizo.Shake.Y), (int)kaizo.Width + 2, (int)kaizo.Height), Color.Black); + } + } + } + + private bool persistent; + private float dashDisable; + private string id; + + public bool activated; + private Sprite sprite; + private Wiggler spriteWiggler; + private Wiggler moveWiggler; + } +} diff --git a/Code/KeyBerry.cs b/Code/KeyBerry.cs new file mode 100644 index 0000000..1c3deae --- /dev/null +++ b/Code/KeyBerry.cs @@ -0,0 +1,488 @@ +using Celeste; +using Celeste.Mod.Entities; +using MonoMod.Utils; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/keyberry", "vitellary/returnkeyberry")] + [TrackedAs(typeof(Strawberry))] + public class KeyBerry : Entity + { + public KeyBerry(EntityData data, Vector2 offset, EntityID gid) : base(data.Position + offset) + { + wobble = 0f; + collectTimer = 0f; + collected = false; + returnHomeWhenLost = true; + ID = gid; + winged = data.Bool("winged", false); + hasReturnBubble = data.Name == "vitellary/returnkeyberry"; + start = Position; + Depth = -100; + Collider = new Hitbox(14f, 14f, -7f, -7f); + Add(new PlayerCollider(new Action(OnPlayer), null, null)); + Add(new MirrorReflection()); + Add(Follower = new Follower(ID, null, new Action(OnLoseLeader))); + Follower.FollowDelay = 0.3f; + if (winged) + { + Add(new DashListener + { + OnDash = new Action(OnDash) + }); + } + if (data.Nodes != null && data.Nodes.Length != 0) + { + int node_max = data.Nodes.Length; + if (hasReturnBubble) + { + node_max = data.Nodes.Length - 2; + bubbleControl = data.Nodes[node_max] + offset; + bubbleEnd = data.Nodes[node_max + 1] + offset; + } + Seeds = new List(); + for (int i = 0; i < node_max; i++) + { + Seeds.Add(new KeyBerrySeed(this, offset + data.Nodes[i], i)); + } + } + if (!VitModule.Session.keyberryEntityDatas.ContainsKey(gid)) + { + VitModule.Session.keyberryEntityDatas.Add(gid, data); + VitModule.Session.keyberryPositions.Add(gid, data.Position); + VitModule.Session.keyberryOffsets.Add(gid, offset); + VitModule.Session.keyberryBubbles.Add(gid, hasReturnBubble); + } + } + + public override void Added(Scene scene) + { + base.Added(scene); + sprite = VitModule.SpriteBank.Create("keyberry"); + Add(sprite); + if (winged) + { + sprite.Play("flap", false, false); + } + sprite.OnFrameChange = new Action(OnAnimate); + Add(wiggler = Wiggler.Create(0.4f, 4f, delegate (float v) + { + sprite.Scale = Vector2.One * (1f + v * 0.35f); + }, false, false)); + Add(rotateWiggler = Wiggler.Create(0.5f, 4f, delegate (float v) + { + sprite.Rotation = v * 30f * 0.0174532924f; + }, false, false)); + Add(bloom = new BloomPoint(1f, 12f)); + Add(light = new VertexLight(Color.White, 1f, 16, 24)); + Add(lightTween = light.CreatePulseTween()); + if (Seeds != null && Seeds.Count > 0) + { + foreach (KeyBerrySeed entity in Seeds) + { + scene.Add(entity); + } + Visible = false; + Collidable = false; + waitingOnSeeds = true; + bloom.Visible = (light.Visible = false); + } + if (SceneAs().Session.BloomBaseAdd > 0.1f) + { + bloom.Alpha *= 0.5f; + } + } + + public override void Update() + { + if (!waitingOnSeeds) + { + if (!collected) + { + if (!winged) + { + wobble += Engine.DeltaTime * 4f; + sprite.Y = (bloom.Y = (light.Y = (float)Math.Sin(wobble) * 2f)); + } + int followIndex = Follower.FollowIndex; + bool islastberry = false; + for (int i = followIndex - 1; i >= 0; i--) + { + Entity entity = Follower.Leader.Followers[i].Entity; + if (entity is KeyBerry) + { + islastberry = true; + break; + } + if (Celeste.Mod.StrawberryRegistry.IsFirstStrawberry(entity)) + { + break; + } + } + if (Follower.Leader != null && Follower.DelayTimer <= 0f && !islastberry) + { + Player player = Follower.Leader.Entity as Player; + if (player != null && player.Scene != null && !player.StrawberriesBlocked) + { + if (player.OnSafeGround) + { + collectTimer += Engine.DeltaTime; + if (collectTimer > 0.15f) + { + OnCollect(); + } + } + else + { + collectTimer = Math.Min(collectTimer, 0f); + } + } + } + else + { + if (followIndex > 0) + { + collectTimer = -0.15f; + } + if (winged) + { + Y += flapSpeed * Engine.DeltaTime; + if (flyingAway) + { + if (Y < SceneAs().Bounds.Top - 16) + { + RemoveSelf(); + } + } + else + { + flapSpeed = Calc.Approach(flapSpeed, 20f, 170f * Engine.DeltaTime); + if (Y < start.Y - 5f) + { + Y = start.Y - 5f; + } + else if (Y > start.Y + 5f) + { + Y = start.Y + 5f; + } + } + } + } + } + base.Update(); + if (Follower.Leader != null && Scene.OnInterval(0.08f)) + { + SceneAs().ParticlesFG.Emit(Strawberry.P_GoldGlow, Position + Calc.Random.Range(-Vector2.One * 6f, Vector2.One * 6f)); + } + } + } + + private void OnPlayer(Player player) + { + if (Follower.Leader == null && !collected && !waitingOnSeeds) + { + returnHomeWhenLost = true; + if (winged) + { + Level level = SceneAs(); + winged = false; + sprite.Rate = 0f; + Alarm.Set(this, Follower.FollowDelay, delegate + { + sprite.Rate = 1f; + sprite.Play("idle", false, false); + level.Particles.Emit(Strawberry.P_WingsBurst, 8, Position + new Vector2(8f, 0f), new Vector2(4f, 2f)); + level.Particles.Emit(Strawberry.P_WingsBurst, 8, Position - new Vector2(8f, 0f), new Vector2(4f, 2f)); + }, Alarm.AlarmMode.Oneshot); + } + Audio.Play("event:/game/general/key_get", Position); + // player.Leader.GainFollower(Follower); + player.Leader.Followers.Insert(0, Follower); + Follower.OnGainLeaderUtil(player.Leader); + wiggler.Start(); + Depth = -1000000; + if (hasReturnBubble) + { + Add(new Coroutine(ReturnRoutine(player))); + } + } + } + + private IEnumerator ReturnRoutine(Player player) + { + yield return 0.3f; + bool flag = !player.Dead; + if (flag) + { + Audio.Play("event:/game/general/cassette_bubblereturn", SceneAs().Camera.Position + new Vector2(160f, 90f)); + player.StartCassetteFly(bubbleEnd, bubbleControl); + } + yield break; + } + + private void OnLoseLeader() + { + if (!collected && returnHomeWhenLost) + { + Alarm.Set(this, 0.15f, delegate + { + Vector2 vector = (start - Position).SafeNormalize(); + float num = Vector2.Distance(Position, start); + float scaleFactor = Calc.ClampedMap(num, 16f, 120f, 16f, 96f); + Vector2 control = start + vector * 16f + vector.Perpendicular() * scaleFactor * Calc.Random.Choose(1, -1); + SimpleCurve curve = new SimpleCurve(Position, start, control); + Tween tween = Tween.Create(Tween.TweenMode.Oneshot, Ease.SineOut, MathHelper.Max(num / 100f, 0.4f), true); + tween.OnUpdate = delegate (Tween f) + { + Position = curve.GetPoint(f.Eased); + }; + tween.OnComplete = delegate (Tween f) + { + Depth = 0; + }; + Add(tween); + }, Alarm.AlarmMode.Oneshot); + } + } + + private void OnDash(Vector2 dir) + { + if (!flyingAway && winged && !waitingOnSeeds) + { + Depth = -1000000; + Add(new Coroutine(FlyAwayRoutine(), true)); + flyingAway = true; + } + } + + private IEnumerator FlyAwayRoutine() + { + rotateWiggler.Start(); + flapSpeed = -200f; + Tween tween = Tween.Create(Tween.TweenMode.Oneshot, Ease.CubeOut, 0.25f, true); + tween.OnUpdate = delegate (Tween t) + { + flapSpeed = MathHelper.Lerp(-200f, 0f, t.Eased); + }; + Add(tween); + yield return 0.1f; + Audio.Play("event:/game/general/strawberry_laugh", Position); + yield return 0.2f; + if (!Follower.HasLeader) + { + Audio.Play("event:/game/general/strawberry_flyaway", Position); + } + tween = Tween.Create(Tween.TweenMode.Oneshot, null, 0.5f, true); + tween.OnUpdate = delegate (Tween t) + { + flapSpeed = MathHelper.Lerp(0f, -200f, t.Eased); + }; + Add(tween); + yield break; + } + + private void OnAnimate(string id) + { + if (!flyingAway && id == "flap" && sprite.CurrentAnimationFrame % 9 == 4) + { + Audio.Play("event:/game/general/strawberry_wingflap", Position); + flapSpeed = -50f; + } + int num; + if (id == "flap") + { + num = 25; + } + else + { + num = 30; + } + if (sprite.CurrentAnimationFrame == num) + { + lightTween.Start(); + Audio.Play("event:/game/general/strawberry_pulse", Position); + SceneAs().Displacement.AddBurst(Position, 0.6f, 4f, 28f, (!collected && (CollideCheck() || CollideCheck())) ? 0.1f : 0.2f, null, null); + } + } + + private void OnCollect() + { + if (!collected) + { + int collectIndex = 0; + collected = true; + if (Follower.Leader != null) + { + Player player = Follower.Leader.Entity as Player; + collectIndex = player.StrawberryCollectIndex; + player.StrawberryCollectIndex++; + player.StrawberryCollectResetTimer = 2.5f; + Follower.Leader.LoseFollower(Follower); + bool used = false; + foreach (Solid solid in Scene.Tracker.GetEntities()) + { + if (solid is LockBlock && Vector2.Distance(solid.Center, player.Center) <= 64f) + { + LockBlock door = solid as LockBlock; + used = true; + door.Add(new Coroutine(KeyBerryOpenDoor(door))); + } + } + foreach (IntroLockedCar car in Scene.Tracker.GetEntities()) + { + if (Vector2.Distance(car.Center, player.Center) <= 64f) + { + used = true; + car.Add(new Coroutine(car.KeyberryUnlock())); + } + } + if (used) + { + SceneAs().Session.DoNotLoad.Add(ID); + VitModule.Session.keyberriesToReset.Add(ID); + } + } + Add(new Coroutine(CollectRoutine(collectIndex), true)); + } + } + + private static IEnumerator KeyBerryOpenDoor(LockBlock door) + { + DynData doorData = new DynData(door); + SoundEmitter emitter = SoundEmitter.Play(doorData.Get("unlockSfxName"), door); + emitter.Source.DisposeOnTransition = true; + Level level = door.SceneAs(); + yield return 0.15f; + door.UnlockingRegistered = true; + if (doorData.Get("stepMusicProgress")) + { + AudioTrackState music = level.Session.Audio.Music; + int progress = music.Progress; + music.Progress = progress + 1; + level.Session.Audio.Apply(false); + } + level.Session.DoNotLoad.Add(door.ID); + VitModule.Session.doorsToReset.Add(door.ID); + door.Tag |= Tags.TransitionUpdate; + door.Collidable = false; + emitter.Source.DisposeOnTransition = false; + yield return doorData.Get("sprite").PlayRoutine("open", false); + level.Shake(0.3f); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + yield return doorData.Get("sprite").PlayRoutine("burst", false); + door.RemoveSelf(); + yield break; + } + + private IEnumerator CollectRoutine(int collectIndex) + { + Level level = SceneAs(); + Tag = Tags.TransitionUpdate; + Depth = -2000010; + Audio.Play("event:/game/general/strawberry_get", Position, "colour", 0f, "count", (collectIndex == 5 ? 5 : 0)); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + sprite.Play("collect", false, false); + while (sprite.Animating) + { + yield return null; + } + Scene.Add(new KeyBerryPoints(Position, collectIndex)); + if (collectIndex <= lastChain) + { + oneUpIDs.Clear(); + } + if (collectIndex < 5) + { + oneUpIDs.Add(ID); + } + else if (collectIndex == 5) + { + foreach (EntityID entityID in oneUpIDs) + { + level.Session.DoNotLoad.Add(entityID); + VitModule.Session.keyberriesToReset.Add(entityID); + } + bool used = false; + foreach (Solid solid in Scene.Tracker.GetEntities()) + { + if (solid is LockBlock) + { + used = true; + LockBlock door = solid as LockBlock; + door.Add(new Coroutine(KeyBerryOpenDoor(door))); + } + } + if (used) + { + level.Session.DoNotLoad.Add(ID); + VitModule.Session.keyberriesToReset.Add(ID); + } + } + lastChain = collectIndex; + RemoveSelf(); + yield break; + } + + public void CollectedSeeds() + { + waitingOnSeeds = false; + Visible = true; + Collidable = true; + bloom.Visible = (light.Visible = true); + } + + public bool winged; + + private BloomPoint bloom; + + private static int lastChain; + + private static List oneUpIDs = new List(); + + private bool collected; + + private float collectTimer; + + private float flapSpeed; + + private bool flyingAway; + + public Follower Follower; + + public EntityID ID; + + private VertexLight light; + + private Tween lightTween; + + public bool returnHomeWhenLost; + + private Wiggler rotateWiggler; + + private bool hasReturnBubble; + + private Vector2 bubbleEnd; + + private Vector2 bubbleControl; + + public List Seeds; + + private Sprite sprite; + + private Vector2 start; + + public bool waitingOnSeeds; + + private Wiggler wiggler; + + private float wobble; + } +} diff --git a/Code/KeyBerryPoints.cs b/Code/KeyBerryPoints.cs new file mode 100644 index 0000000..5d8c750 --- /dev/null +++ b/Code/KeyBerryPoints.cs @@ -0,0 +1,98 @@ +using Celeste; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [TrackedAs(typeof(StrawberryPoints))] + public class KeyBerryPoints : Entity + { + public KeyBerryPoints(Vector2 position, int index) : base(position) + { + Add(sprite = VitModule.SpriteBank.Create("keyberry")); + Add(light = new VertexLight(Color.White, 1f, 16, 24)); + Add(bloom = new BloomPoint(1f, 12f)); + Depth = -2000100; + Tag = (Tags.Persistent | Tags.TransitionUpdate | Tags.FrozenUpdate); + this.index = index; + } + + public override void Added(Scene scene) + { + if (index == 5) + { + sprite.Play("fade1up", false, false); + } + else + { + sprite.Play("fade", false, false); + } + sprite.OnFinish = delegate (string a) + { + RemoveSelf(); + }; + base.Added(scene); + foreach (Entity entity in Scene.Tracker.GetEntities()) + { + if (entity != this && Vector2.DistanceSquared(entity.Position, Position) <= 256f) + { + entity.RemoveSelf(); + } + } + } + + public override void Update() + { + Level level = SceneAs(); + if (level.Frozen) + { + if (burst != null) + { + burst.AlphaFrom = (burst.AlphaTo = 0f); + burst.Percent = burst.Duration; + } + } + else + { + base.Update(); + Camera camera = level.Camera; + Y -= 8f * Engine.DeltaTime; + X = Calc.Clamp(X, camera.Left + 8f, camera.Right - 8f); + Y = Calc.Clamp(Y, camera.Top + 8f, camera.Bottom - 8f); + light.Alpha = Calc.Approach(light.Alpha, 0f, Engine.DeltaTime * 4f); + bloom.Alpha = light.Alpha; + if (Scene.OnInterval(0.05f)) + { + if (sprite.Color == Strawberry.P_Glow.Color) + { + sprite.Color = Strawberry.P_Glow.Color2; + } + else + { + sprite.Color = Strawberry.P_Glow.Color; + } + } + if (Scene.OnInterval(0.06f) && sprite.CurrentAnimationFrame > 11) + { + level.ParticlesFG.Emit(Strawberry.P_Glow, 1, Position + Vector2.UnitY * -2f, new Vector2(8f, 4f)); + } + } + } + + private Sprite sprite; + + private BloomPoint bloom; + + private DisplacementRenderer.Burst burst; + + private int index; + + private VertexLight light; + } +} diff --git a/Code/KeyBerrySeed.cs b/Code/KeyBerrySeed.cs new file mode 100644 index 0000000..d2f1cad --- /dev/null +++ b/Code/KeyBerrySeed.cs @@ -0,0 +1,325 @@ +using Celeste; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [Tracked] + public class KeyBerrySeed : Entity + { + public KeyBerrySeed(KeyBerry keyberry, Vector2 position, int index) : base(position) + { + this.keyberry = keyberry; + Depth = -100; + start = Position; + Collider = new Hitbox(12f, 12f, -6f, -6f); + this.index = index; + Add(follower = new Follower(new Action(OnGainLeader), new Action(OnLoseLeader))); + follower.FollowDelay = 0.2f; + follower.PersistentFollow = false; + Add(new StaticMover + { + SolidChecker = ((Solid s) => s.CollideCheck(this)), + OnAttach = delegate (Platform p) + { + Depth = -1000000; + Collider = new Hitbox(24f, 24f, -12f, -12f); + attached = p; + start = Position - p.Position; + } + }); + Add(new PlayerCollider(new Action(OnPlayer), null, null)); + Add(wiggler = Wiggler.Create(0.5f, 4f, delegate (float v) + { + sprite.Scale = Vector2.One * (1f + 0.2f * v); + }, false, false)); + Add(sine = new SineWave(0.5f, 0f).Randomize()); + Add(shaker = new Shaker(false, null)); + Add(bloom = new BloomPoint(1f, 12f)); + Add(light = new VertexLight(Color.White, 1f, 16, 24)); + Add(lightTween = light.CreatePulseTween()); + } + + public override void Awake(Scene scene) + { + level = SceneAs(); + base.Awake(scene); + sprite = VitModule.SpriteBank.Create("keyberrySeed"); + sprite.Position = new Vector2(sine.Value * 2f, sine.ValueOverTwo * 1f); + Add(sprite); + float spriteoffset = 1f - index / (Scene.Tracker.CountEntities() + 1f); + spriteoffset = 0.25f + spriteoffset * 0.75f; + sprite.PlayOffset("idle", spriteoffset, false); + sprite.OnFrameChange = delegate (string s) + { + if (Visible && sprite.CurrentAnimationID == "idle" && sprite.CurrentAnimationFrame == 19) + { + Audio.Play("event:/game/general/seed_pulse", Position, "count", index); + lightTween.Start(); + level.Displacement.AddBurst(Position, 0.6f, 8f, 20f, 0.2f, null, null); + } + }; + } + + public override void Update() + { + base.Update(); + if (!finished) + { + if (canLoseTimer > 0f) + { + canLoseTimer -= Engine.DeltaTime; + } + else + { + if (follower.HasLeader && player.LoseShards) + { + losing = true; + } + } + if (losing) + { + if (loseTimer <= 0f || player.Speed.Y < 0f) + { + player.Leader.LoseFollower(follower); + losing = false; + } + else + { + if (player.LoseShards) + { + loseTimer -= Engine.DeltaTime; + } + else + { + loseTimer = 0.15f; + losing = false; + } + } + } + sprite.Position = new Vector2(sine.Value * 2f, sine.ValueOverTwo * 1f) + shaker.Value; + } + else + { + light.Alpha = Calc.Approach(light.Alpha, 0f, Engine.DeltaTime * 4f); + } + } + + private void OnPlayer(Player player) + { + Audio.Play("event:/game/general/seed_touch", Position, "count", index); + this.player = player; + player.Leader.GainFollower(follower); + Collidable = false; + Depth = -1000000; + bool complete = true; + foreach (KeyBerrySeed keyberrySeed in keyberry.Seeds) + { + if (!keyberrySeed.follower.HasLeader) + { + complete = false; + } + } + if (complete) + { + Add(new Coroutine(CutsceneRoutine(), true)); + } + } + + private void OnGainLeader() + { + collected = true; + wiggler.Start(); + canLoseTimer = 0.25f; + loseTimer = 0.15f; + } + + private void OnLoseLeader() + { + collected = false; + if (!finished) + { + Add(new Coroutine(ReturnRoutine(), true)); + } + } + + private IEnumerator CutsceneRoutine() + { + Level level = SceneAs(); + foreach (KeyBerrySeed seed in keyberry.Seeds) + { + seed.OnAllCollected(); + } + keyberry.Depth = -2000002; + keyberry.AddTag(Tags.FrozenUpdate); + yield return 0.35f; + ParticleSystem system = new ParticleSystem(-2000002, 50); + system.Tag = Tags.FrozenUpdate; + level.Add(system); + float angleSep = 6.28318548f / keyberry.Seeds.Count; + float angle = 1.57079637f; + Vector2 avg = Vector2.Zero; + foreach (KeyBerrySeed seed in keyberry.Seeds) + { + avg += seed.Position; + } + avg /= keyberry.Seeds.Count; + foreach (KeyBerrySeed seed in keyberry.Seeds) + { + seed.StartSpinAnimation(avg, keyberry.Position, angle, 1f); + angle -= angleSep; + } + avg = default; + yield return 0.9f; + Input.Rumble(RumbleStrength.Light, RumbleLength.Long); + Audio.Play("event:/game/general/seed_complete_berry", keyberry.Position); + foreach (KeyBerrySeed seed in keyberry.Seeds) + { + seed.StartCombineAnimation(keyberry.Position, 0.3f, system); + } + yield return 0.3f; + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + foreach (KeyBerrySeed seed in keyberry.Seeds) + { + seed.RemoveSelf(); + } + keyberry.CollectedSeeds(); + yield return 0.5f; + keyberry.Depth = -100; + keyberry.RemoveTag(Tags.FrozenUpdate); + yield break; + } + + private IEnumerator ReturnRoutine() + { + Audio.Play("event:/game/general/seed_poof", Position); + Collidable = false; + sprite.Scale = Vector2.One * 2f; + yield return 0.05f; + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + int num; + for (int i = 0; i < 6; i = num + 1) + { + float dir = Calc.Random.NextFloat(6.28318548f); + level.ParticlesFG.Emit(StrawberrySeed.P_Burst, 1, Position + Calc.AngleToVector(dir, 4f), Vector2.Zero, dir); + num = i; + } + Visible = false; + yield return 0.3f + index * 0.1f; + Audio.Play("event:/game/general/seed_reappear", Position, "count", index); + Position = start; + if (attached != null) + { + Position += attached.Position; + } + shaker.ShakeFor(0.4f, false); + sprite.Scale = Vector2.One; + Visible = true; + Collidable = true; + level.Displacement.AddBurst(Position, 0.2f, 8f, 28f, 0.2f, null, null); + yield break; + } + + public void OnAllCollected() + { + finished = true; + follower.Leader.LoseFollower(follower); + Depth = -2000002; + Tag = Tags.FrozenUpdate; + wiggler.Start(); + } + + public void StartSpinAnimation(Vector2 averagePos, Vector2 centerPos, float angleOffset, float time) + { + float spinLerp = 0f; + Vector2 start = Position; + sprite.Play("noFlash", false, false); + Tween tween = Tween.Create(Tween.TweenMode.Oneshot, Ease.CubeIn, time / 2f, true); + tween.OnUpdate = delegate (Tween t) + { + spinLerp = t.Eased; + }; + Add(tween); + tween = Tween.Create(Tween.TweenMode.Oneshot, Ease.CubeInOut, time, true); + tween.OnUpdate = delegate (Tween t) + { + float angleRadians = 1.57079637f + angleOffset - MathHelper.Lerp(0f, 15.7079633f, t.Eased); + Vector2 value = Vector2.Lerp(averagePos, centerPos, spinLerp); + Vector2 value2 = value + Calc.AngleToVector(angleRadians, 25f); + Position = Vector2.Lerp(start, value2, spinLerp); + }; + Add(tween); + } + + public void StartCombineAnimation(Vector2 centerPos, float time, ParticleSystem particleSystem) + { + Vector2 position = Position; + float startAngle = Calc.Angle(centerPos, position); + Tween tween = Tween.Create(Tween.TweenMode.Oneshot, Ease.BigBackIn, time, true); + tween.OnUpdate = delegate (Tween t) + { + float angleRadians = MathHelper.Lerp(startAngle, startAngle - 6.28318548f, Ease.CubeIn(t.Percent)); + float length = MathHelper.Lerp(25f, 0f, t.Eased); + Position = centerPos + Calc.AngleToVector(angleRadians, length); + }; + tween.OnComplete = delegate (Tween t) + { + Visible = false; + for (int i = 0; i < 6; i++) + { + float num = Calc.Random.NextFloat(6.28318548f); + particleSystem.Emit(StrawberrySeed.P_Burst, 1, Position + Calc.AngleToVector(num, 4f), Vector2.Zero, num); + } + }; + Add(tween); + } + + private Platform attached; + + private BloomPoint bloom; + + private float canLoseTimer; + + private bool finished; + + private Follower follower; + + private int index; + + private Level level; + + private VertexLight light; + + private Tween lightTween; + + private const float LoseDelay = 0.25f; + + private const float LoseGraceTime = 0.15f; + + private float loseTimer; + + private bool losing; + + public bool collected; + + private Player player; + + private Shaker shaker; + + private SineWave sine; + + private Sprite sprite; + + private Vector2 start; + + public KeyBerry keyberry; + + private Wiggler wiggler; + } +} diff --git a/Code/NoDashTrigger.cs b/Code/NoDashTrigger.cs new file mode 100644 index 0000000..545f04a --- /dev/null +++ b/Code/NoDashTrigger.cs @@ -0,0 +1,39 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/nodashtrigger")] + [Tracked(false)] + public class NoDashTrigger : Trigger + { + public static void Load() + { + On.Celeste.Player.StartDash += Player_StartDash; + } + + public static void Unload() + { + On.Celeste.Player.StartDash -= Player_StartDash; + } + + public NoDashTrigger(EntityData data, Vector2 offset) : base(data, offset) { } + + public static int Player_StartDash(On.Celeste.Player.orig_StartDash orig, Player self) + { + if (!self.Dead && self.CollideCheck()) + { + self.Speed -= (Vector2) self.GetType().GetProperty("LiftBoost", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(self); + return self.StateMachine.State; + } + return orig(self); + } + } +} diff --git a/Code/NoGrabTrigger.cs b/Code/NoGrabTrigger.cs new file mode 100644 index 0000000..f751f4b --- /dev/null +++ b/Code/NoGrabTrigger.cs @@ -0,0 +1,41 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/nograbtrigger")] + [Tracked(false)] + public class NoGrabTrigger : Trigger + { + public static void Load() + { + On.Celeste.Player.ClimbUpdate += Player_ClimbUpdate; + } + + public static void Unload() + { + On.Celeste.Player.ClimbUpdate -= Player_ClimbUpdate; + } + + public NoGrabTrigger(EntityData data, Vector2 offset) : base(data, offset) + { + Add(new ClimbBlocker(true)); + } + + public static int Player_ClimbUpdate(On.Celeste.Player.orig_ClimbUpdate orig, Player self) + { + if (!self.Dead && self.CollideCheck()) { + self.Speed += (Vector2)self.GetType().GetProperty("LiftBoost", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(self); + return 0; + } + return orig(self); + } + } +} diff --git a/Code/NoJumpTrigger.cs b/Code/NoJumpTrigger.cs new file mode 100644 index 0000000..9257e08 --- /dev/null +++ b/Code/NoJumpTrigger.cs @@ -0,0 +1,50 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/nojumptrigger")] + [Tracked(false)] + public class NoJumpTrigger : Trigger + { + public static void Load() + { + On.Celeste.Player.Jump += Player_Jump; + On.Celeste.Player.SuperJump += Player_SuperJump; + } + + public static void Unload() + { + On.Celeste.Player.Jump -= Player_Jump; + On.Celeste.Player.SuperJump -= Player_SuperJump; + } + + public NoJumpTrigger(EntityData data, Vector2 offset) : base(data, offset) { } + + public static void Player_Jump(On.Celeste.Player.orig_Jump orig, Player self, bool particles, bool playSfx) + { + grabbing = self.CollideCheck(self.Position + Vector2.UnitX * (float) self.Facing) && Input.Grab.Check; + if (!self.Dead && (!self.CollideCheck() || grabbing)) + { + orig(self, particles, playSfx); + } + } + + public static void Player_SuperJump(On.Celeste.Player.orig_SuperJump orig, Player self) + { + if (!self.Dead && !self.CollideCheck()) + { + orig(self); + } + } + + private static bool grabbing; + } +} diff --git a/Code/NoMoveTrigger.cs b/Code/NoMoveTrigger.cs new file mode 100644 index 0000000..c534724 --- /dev/null +++ b/Code/NoMoveTrigger.cs @@ -0,0 +1,114 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/nomovetrigger")] + [Tracked(false)] + public class NoMoveTrigger : Trigger + { + public static void Load() + { + On.Monocle.VirtualIntegerAxis.Update += VirtualIntegerAxis_Update; + On.Monocle.VirtualButton.Update += VirtualButton_Update; + } + + public static void Unload() + { + On.Monocle.VirtualIntegerAxis.Update -= VirtualIntegerAxis_Update; + On.Monocle.VirtualButton.Update -= VirtualButton_Update; + } + + public NoMoveTrigger(EntityData data, Vector2 offset) : base(data, offset) + { + stopLength = data.Float("stopLength", 2f); + } + + public override void OnEnter(Player player) + { + if (!alreadyIn) + { + VitModule.noMoveScaleTimer = 0f; + stopTimer = stopLength; + stopStage = 1; + } + alreadyIn = true; + } + + public override void OnLeave(Player player) + { + if (player.Scene != null && !player.CollideCheck()) + { + alreadyIn = false; + } + } + + static Dictionary> buttonNodes = new Dictionary>(); + public static void VirtualButton_Update(On.Monocle.VirtualButton.orig_Update orig, VirtualButton self) + { + if (self == Input.Jump || self == Input.Grab) + { + if (stopStage > 0 && GetDeltaMult() == 0) + { + if (!buttonNodes.ContainsKey(self)) + { + buttonNodes.Add(self, self.Nodes); + self.Nodes = new List(); + } + } + else + { + if (buttonNodes.ContainsKey(self)) + { + self.Nodes = buttonNodes[self]; + buttonNodes.Remove(self); + } + } + } + + orig(self); + } + + public static void VirtualIntegerAxis_Update(On.Monocle.VirtualIntegerAxis.orig_Update orig, VirtualIntegerAxis self) + { + orig(self); + + if (self == Input.MoveX || self == Input.MoveY) + { + if (stopStage > 0 && GetDeltaMult() == 0) + { + self.Value = 0; + } + } + } + + private float stopLength; + public static float stopTimer; + public static float stopStage; + + public static bool alreadyIn; + + public static float GetDeltaMult() + { + float delta_mult = 1; + + if (stopStage == 1) + { + delta_mult = Math.Max(0, 1 - (VitModule.noMoveScaleTimer / 0.3f)); + } + else if (stopStage == 2) + { + delta_mult = Math.Min(1, VitModule.noMoveScaleTimer / 0.3f); + } + + return delta_mult; + } + } +} \ No newline at end of file diff --git a/Code/RemoteTrigger.cs b/Code/RemoteTrigger.cs new file mode 100644 index 0000000..cce47fa --- /dev/null +++ b/Code/RemoteTrigger.cs @@ -0,0 +1,44 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + +namespace vitmod +{ + [CustomEntity("vitellary/remotetrigger")] + [Tracked(false)] + public class RemoteTrigger : Trigger + { + public RemoteTrigger(EntityData data, Vector2 offset) : base(data, offset) + { + remote = data.Int("value", 1); + } + + public override void OnEnter(Player player) + { + if (remote > 0) + { + foreach (var entity in player.SceneAs()) + { + if (entity is VitMoveBlock) + { + var moveBlock = entity as VitMoveBlock; + + if (moveBlock.remote == remote) + { + moveBlock.triggered = true; + } + } + } + } + } + + private int remote; + } +} \ No newline at end of file diff --git a/Code/ResetDoorTrigger.cs b/Code/ResetDoorTrigger.cs new file mode 100644 index 0000000..3cd3985 --- /dev/null +++ b/Code/ResetDoorTrigger.cs @@ -0,0 +1,295 @@ +using Celeste; +using Celeste.Mod.Entities; +using MonoMod.Utils; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/resetdoortrigger")] + [Tracked(false)] + public class ResetDoorTrigger : Trigger + { + public static void Load() + { + On.Celeste.LockBlock.ctor_EntityData_Vector2_EntityID += LockBlock_ctor_EntityData_Vector2_EntityID; + On.Celeste.LockBlock.UnlockRoutine += LockBlock_UnlockRoutine; + On.Celeste.Key.ctor_EntityData_Vector2_EntityID += Key_ctor_EntityData_Vector2_EntityID; + On.Celeste.Key.OnPlayer += Key_OnPlayer; + } + + public static void Unload() + { + On.Celeste.LockBlock.ctor_EntityData_Vector2_EntityID -= LockBlock_ctor_EntityData_Vector2_EntityID; + On.Celeste.LockBlock.UnlockRoutine -= LockBlock_UnlockRoutine; + On.Celeste.Key.ctor_EntityData_Vector2_EntityID -= Key_ctor_EntityData_Vector2_EntityID; + On.Celeste.Key.OnPlayer -= Key_OnPlayer; + } + + public ResetDoorTrigger(EntityData data, Vector2 offset) : base(data, offset) { + oneUse = data.Bool("oneUse", false); + animate = data.Bool("animate", true); + onlyInRoom = data.Bool("onlyInRoom", false); + } + + public override void OnEnter(Player player) + { + Level level = SceneAs(); + Session session = level.Session; + foreach (EntityID entityID in VitModule.Session.doorsToReset) + { + if (entityID.Level == session.Level || !onlyInRoom) + { + session.DoNotLoad.Remove(entityID); + } + if (entityID.Level == session.Level) //currently loaded room + { + LockBlock door = new LockBlock(VitModule.Session.doorEntityDatas[entityID], VitModule.Session.doorOffsets[entityID], entityID); + level.Add(door); + if (animate) + { + door.Add(new Coroutine(DoorAnimation(door))); + } + } + } + VitModule.Session.doorsToReset.Clear(); + foreach (EntityID entityID in VitModule.Session.introCarsToReset) + { + if (entityID.Level == session.Level || !onlyInRoom) + { + session.DoNotLoad.Remove(entityID); + } + if (entityID.Level == session.Level) //currently loaded room + { + IntroLockedCar car = new IntroLockedCar(VitModule.Session.introCarEntityDatas[entityID], VitModule.Session.introCarOffsets[entityID], entityID); + level.Add(car); + if (animate) + { + car.Add(new Coroutine(CarAnimation(car))); + } + } + } + VitModule.Session.introCarsToReset.Clear(); + foreach (EntityID entityID in VitModule.Session.keysToReset) + { + if (!session.Keys.Contains(entityID)) + { + if (entityID.Level == session.Level || !onlyInRoom) + { + session.DoNotLoad.Remove(entityID); + } + if (entityID.Level == session.Level && VitModule.Session.keyEntityDatas.ContainsKey(entityID)) + { + Key key = new Key(VitModule.Session.keyEntityDatas[entityID], VitModule.Session.keyOffsets[entityID], entityID); + level.Add(key); + if (animate) + { + level.ParticlesFG.Emit(P_Respawn, 10, key.Position, Vector2.One * 4f); + } + } + } + } + VitModule.Session.keysToReset.Clear(); + foreach (EntityID entityID in VitModule.Session.keyberriesToReset) + { + if (!session.Keys.Contains(entityID)) + { + if (entityID.Level == session.Level || !onlyInRoom) + { + session.DoNotLoad.Remove(entityID); + } + if (entityID.Level == session.Level) + { + KeyBerry keyberry = new KeyBerry(VitModule.Session.keyberryEntityDatas[entityID], VitModule.Session.keyberryOffsets[entityID], entityID); + level.Add(keyberry); + if (animate) + { + level.ParticlesFG.Emit(P_Respawn, 10, keyberry.Position, Vector2.One * 4f); + } + } + } + } + VitModule.Session.keyberriesToReset.Clear(); + if (VitModule.frostHelperLoaded) + { + KeyIceReset(level, session); + } + if (oneUse) + { + RemoveSelf(); + } + } + + private void KeyIceReset(Level level, Session session) + { + foreach (EntityID entityID in VitModule.Session.keyIcesToReset) + { + if (!session.Keys.Contains(entityID)) + { + if (entityID.Level == session.Level || !onlyInRoom) + { + session.DoNotLoad.Remove(entityID); + } + if (entityID.Level == session.Level) + { + FrostHelper.KeyIce key = new FrostHelper.KeyIce(VitModule.Session.keyIceEntityDatas[entityID], VitModule.Session.keyIceOffsets[entityID], entityID, VitModule.Session.keyIceNodes[entityID]); + level.Add(key); + if (animate) + { + level.ParticlesFG.Emit(P_IceRespawn, 10, key.Position, Vector2.One * 4f); + } + } + } + } + VitModule.Session.keyIcesToReset.Clear(); + } + + private IEnumerator DoorAnimation(LockBlock door) + { + DynData doorData = new DynData(door); + Sprite sprite = doorData.Get("sprite"); + //reverse is broken, so we have to do it manually + sprite.Play("burst", true); + for (int i = sprite.CurrentAnimationTotalFrames-1; i >= 0; i--) + { + sprite.SetAnimationFrame(i); + yield return null; + } + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + yield return 0.06f; + sprite.Play("open", true); + for (int i = sprite.CurrentAnimationTotalFrames-1; i >= 0; i--) + { + sprite.SetAnimationFrame(i); + yield return null; + } + sprite.Play("idle", true); + yield break; + } + + private IEnumerator CarAnimation(IntroLockedCar car) + { + car.bodySprite.Play("burst", true); + car.wheelSprite.Play("burst", true); + for (int i = car.bodySprite.CurrentAnimationTotalFrames - 1; i >= 0; i--) + { + car.bodySprite.SetAnimationFrame(i); + car.wheelSprite.SetAnimationFrame(i); + yield return null; + } + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + yield return 0.06f; + car.bodySprite.Play("open", true); + car.wheelSprite.Play("idle", true); + for (int i = car.bodySprite.CurrentAnimationTotalFrames - 1; i >= 0; i--) + { + car.bodySprite.SetAnimationFrame(i); + yield return null; + } + car.bodySprite.Play("idle", true); + yield break; + } + + public static void LockBlock_ctor_EntityData_Vector2_EntityID(On.Celeste.LockBlock.orig_ctor_EntityData_Vector2_EntityID orig, LockBlock self, EntityData data, Vector2 offset, EntityID id) + { + orig(self, data, offset, id); + if (!VitModule.Session.doorEntityDatas.ContainsKey(id)) + { + VitModule.Session.doorEntityDatas.Add(id, data); + VitModule.Session.doorOffsets.Add(id, offset); + } + } + + public static IEnumerator LockBlock_UnlockRoutine(On.Celeste.LockBlock.orig_UnlockRoutine orig, LockBlock self, Follower fol) + { + IEnumerator orig_enum = orig(self, fol); + DynData doorData = new DynData(self); + CustomWindController wind = self.Scene.Tracker.GetEntity(); + while (orig_enum.MoveNext()) + { + if (wind != null && wind.activateType == "Locked Door" && doorData.Get("sprite").CurrentAnimationID == "burst") + { + wind.ActivateWind(); + } + yield return orig_enum.Current; + } + VitModule.Session.doorsToReset.Add(self.ID); + yield break; + } + + public static void Key_ctor_EntityData_Vector2_EntityID(On.Celeste.Key.orig_ctor_EntityData_Vector2_EntityID orig, Key self, EntityData data, Vector2 offset, EntityID id) + { + orig(self, data, offset, id); + if (!VitModule.Session.keyEntityDatas.ContainsKey(id)) + { + VitModule.Session.keyEntityDatas.Add(id, data); + VitModule.Session.keyOffsets.Add(id, offset); + } + } + + public static void Key_OnPlayer(On.Celeste.Key.orig_OnPlayer orig, Key self, Player player) + { + orig(self, player); + VitModule.Session.keysToReset.Add(self.ID); + } + + private delegate void KeyIce_orig_ctor(Entity self, EntityData data, Vector2 offset, EntityID id, Vector2[] nodes); + private static void KeyIce_ctor(KeyIce_orig_ctor orig, Entity self, EntityData data, Vector2 offset, EntityID id, Vector2[] nodes) + { + orig(self, data, offset, id, nodes); + if (!VitModule.Session.keyIceEntityDatas.ContainsKey(id)) + { + VitModule.Session.keyIceEntityDatas.Add(id, data); + VitModule.Session.keyIceOffsets.Add(id, offset); + VitModule.Session.keyIceNodes.Add(id, nodes); + } + } + + private delegate void KeyIce_orig_Update(Entity self); + private static void KeyIce_Update(KeyIce_orig_Update orig, Entity self) + { + orig(self); + FrostHelper.KeyIce key = self as FrostHelper.KeyIce; + if (self.SceneAs().Session.DoNotLoad.Contains(key.ID) && !VitModule.Session.keyIcesToReset.Contains(key.ID)) + { + VitModule.Session.keyIcesToReset.Add(key.ID); + } + else if (!self.SceneAs().Session.DoNotLoad.Contains(key.ID) && VitModule.Session.keyIcesToReset.Contains(key.ID) && !key.IsUsed) + { + VitModule.Session.keyIcesToReset.Remove(key.ID); + } + } + + private delegate IEnumerator KeyIce_orig_DissolveRoutine(Entity self); + private static IEnumerator KeyIce_DissolveRoutine(KeyIce_orig_DissolveRoutine orig, Entity self) + { + IEnumerator orig_enum = orig(self); + while (orig_enum.MoveNext()) + { + yield return orig_enum.Current; + } + Key key = self as Key; + if (VitModule.Session.keyIcesToReset.Contains(key.ID)) + { + VitModule.Session.keyIcesToReset.Remove(key.ID); + } + yield break; + } + + private bool oneUse; + + private bool animate; + + private bool onlyInRoom; + + public static ParticleType P_IceRespawn; + + public static ParticleType P_Respawn; + } +} diff --git a/Code/StarCrystal.cs b/Code/StarCrystal.cs new file mode 100644 index 0000000..e29caf3 --- /dev/null +++ b/Code/StarCrystal.cs @@ -0,0 +1,244 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/starcrystal")] + public class StarCrystal : Entity + { + public static void Load() + { + On.Celeste.Player.DashBegin += Player_DashBegin; + On.Celeste.Solid.Update += Solid_Update; + } + + public static void Unload() + { + On.Celeste.Player.DashBegin -= Player_DashBegin; + } + + public StarCrystal(EntityData data, Vector2 offset) : base(data.Position + offset) + { + oneUse = data.Bool("oneUse", false); + time = data.Float("time", 2f); + useTime = data.Float("respawnTime", 2.5f); + changeDashes = data.Bool("changeDashes", true); + changeInvuln = data.Bool("changeInvuln", true); + changeStamina = data.Bool("changeStamina", true); + + Collider = new Hitbox(16f, 16f, -8f, -8f); + Add(new PlayerCollider(new Action(OnPlayer), null, null)); + if (!oneUse) + { + Add(outline = new Image(GFX.Game["objects/crystals/star/outline"])); + outline.CenterOrigin(); + outline.Visible = false; + } + string spritetype = oneUse ? "idlenr" : "idle"; + Add(sprite = new Sprite(GFX.Game, "objects/crystals/star/" + spritetype)); + sprite.AddLoop(spritetype, "", 0.1f); + sprite.Play(spritetype, false, false); + sprite.CenterOrigin(); + Add(flash = new Sprite(GFX.Game, "objects/crystals/star/flash")); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + Add(wiggler = Wiggler.Create(1f, 4f, delegate (float v) + { + sprite.Scale = (flash.Scale = Vector2.One * (1f + v * 0.2f)); + }, false, false)); + Add(new MirrorReflection()); + Add(bloom = new BloomPoint(0.8f, 16f)); + Add(light = new VertexLight(Color.White, 1f, 16, 48)); + Add(sine = new SineWave(0.6f)); + sine.Randomize(); + UpdateY(); + Depth = -100; + } + + public override void Added(Scene scene) + { + base.Added(scene); + level = SceneAs(); + } + + public override void Update() + { + base.Update(); + if (respawnTimer > 0f) + { + respawnTimer -= Engine.DeltaTime; + if (respawnTimer <= 0f) + { + Respawn(); + } + } + else if (Scene.OnInterval(0.1f)) + { + level.ParticlesFG.Emit(P_Glow, 1, Position, Vector2.One * 5f); + } + UpdateY(); + light.Alpha = Calc.Approach(light.Alpha, sprite.Visible ? 1f : 0f, 4f * Engine.DeltaTime); + bloom.Alpha = light.Alpha * 0.8f; + if (Scene.OnInterval(2f) && sprite.Visible) + { + flash.Play("flash", true, false); + flash.Visible = true; + } + } + + private void Respawn() + { + if (!Collidable) + { + Collidable = true; + sprite.Visible = true; + outline.Visible = false; + Depth = -100; + wiggler.Start(); + Audio.Play("event:/game/general/diamond_return", Position); + level.ParticlesFG.Emit(P_Regen, 16, Position, Vector2.One * 2f); + } + } + + private void UpdateY() + { + flash.Y = (sprite.Y = (bloom.Y = sine.Value * 2f)); + } + + public override void Render() + { + if (sprite.Visible) + { + sprite.DrawOutline(1); + } + base.Render(); + } + + private void OnPlayer(Player player) + { + if (changeDashes) + { + player.Dashes = player.MaxDashes; + } + Audio.Play("event:/game/general/diamond_touch", Position); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + Collidable = false; + Add(new Coroutine(RefillRoutine(player), true)); + if (changeDashes) + { + starDashTimer = time; + } + if (changeInvuln) + { + starInvulnTimer = time; + } + if (changeStamina) + { + starStaminaTimer = time; + } + if (oneUse) + { + RemoveSelf(); + } + else + { + respawnTimer = useTime; + } + } + + private IEnumerator RefillRoutine(Player player) + { + Celeste.Celeste.Freeze(0.1f); + yield return null; + level.Shake(0.3f); + sprite.Visible = (flash.Visible = false); + if (!oneUse) + { + outline.Visible = true; + } + Depth = 8999; + yield return 0.05f; + float num = player.Speed.Angle(); + level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, num - 1.57079637f); + level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, num + 1.57079637f); + SlashFx.Burst(Position, num); + yield break; + } + + public static void Player_DashBegin(On.Celeste.Player.orig_DashBegin orig, Player self) + { + orig(self); + if (starDashTimer > 0f) + { + self.Dashes = self.MaxDashes; + } + } + + private static void Solid_Update(On.Celeste.Solid.orig_Update orig, Solid self) + { + orig(self); + if (starInvulnTimer > 0f && self.Components.Get() == null && self.Collidable) + { + Player player = self.CollideFirst(); + if (player != null && player.StateMachine.State != 9 && player.StateMachine.State != 21) + { + self.Add(new SolidOnInvinciblePlayer()); + } + } + } + + private bool oneUse; + + private float time; + + private float useTime; + + private bool changeDashes; + + private bool changeInvuln; + + private bool changeStamina; + + public static ParticleType P_Shatter; + + public static ParticleType P_Regen; + + public static ParticleType P_Glow; + + public static float starDashTimer; + + public static float starInvulnTimer; + + public static float starStaminaTimer; + + private Sprite sprite; + + private Sprite flash; + + private Image outline; + + private Wiggler wiggler; + + private BloomPoint bloom; + + private VertexLight light; + + private Level level; + + private SineWave sine; + + private float respawnTimer; + } +} diff --git a/Code/TeleCrystal.cs b/Code/TeleCrystal.cs new file mode 100644 index 0000000..4f746ca --- /dev/null +++ b/Code/TeleCrystal.cs @@ -0,0 +1,227 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/telecrystal", "vitellary/goodtelecrystal")] + public class TeleCrystal : Entity + { + public TeleCrystal(EntityData data, Vector2 offset) : base(data.Position + offset) + { + string dirstr = ""; + if (data.Name == "vitellary/telecrystal") + { + switch (data.Int("direction")) + { + case 0: + dirstr = "right"; break; + case 1: + dirstr = "down"; break; + case 2: + dirstr = "left"; break; + case 3: + dirstr = "up"; break; + } + } + else + { + dirstr = data.Attr("direction").ToLower(); + } + switch (dirstr) + { + case "right": + dirVector = Vector2.UnitX; break; + case "down": + dirVector = Vector2.UnitY; break; + case "left": + dirVector = -Vector2.UnitX; break; + case "up": + dirVector = -Vector2.UnitY; break; + } + oneUse = data.Bool("oneUse", false); + preventCrash = data.Bool("preventCrash", true); + useTime = data.Float("respawnTime", 0.2f); + + Collider = new Hitbox(16f, 16f, -8f, -8f); + Add(new PlayerCollider(new Action(OnPlayer), null, null)); + if (!oneUse) + { + Add(outline = new Image(GFX.Game["objects/crystals/tele/" + dirstr + "/outline"])); + outline.CenterOrigin(); + outline.Visible = false; + } + string spritetype = oneUse ? "idlenr" : "idle"; + Add(sprite = new Sprite(GFX.Game, "objects/crystals/tele/" + dirstr + "/" + spritetype)); + sprite.AddLoop(spritetype, "", 0.1f); + sprite.Play(spritetype, false, false); + sprite.CenterOrigin(); + Add(flash = new Sprite(GFX.Game, "objects/crystals/tele/" + dirstr + "/flash")); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + Add(wiggler = Wiggler.Create(1f, 4f, delegate (float v) + { + sprite.Scale = (flash.Scale = Vector2.One * (1f + v * 0.2f)); + }, false, false)); + Add(new MirrorReflection()); + Add(bloom = new BloomPoint(0.8f, 16f)); + Add(light = new VertexLight(Color.White, 1f, 16, 48)); + Add(sine = new SineWave(0.6f)); + sine.Randomize(); + UpdateY(); + Depth = -100; + } + + public override void Added(Scene scene) + { + base.Added(scene); + level = SceneAs(); + } + + public override void Update() + { + base.Update(); + if (respawnTimer > 0f) + { + respawnTimer -= Engine.DeltaTime; + if (respawnTimer <= 0f) + { + Respawn(); + } + } + else if (Scene.OnInterval(0.1f)) + { + level.ParticlesFG.Emit(P_Glow, 1, Position, Vector2.One * 5f); + } + UpdateY(); + light.Alpha = Calc.Approach(light.Alpha, sprite.Visible ? 1f : 0f, 4f * Engine.DeltaTime); + bloom.Alpha = light.Alpha * 0.8f; + if (Scene.OnInterval(2f) && sprite.Visible) + { + flash.Play("flash", true, false); + flash.Visible = true; + } + } + + private void Respawn() + { + if (!Collidable) + { + Collidable = true; + sprite.Visible = true; + outline.Visible = false; + Depth = -100; + wiggler.Start(); + Audio.Play("event:/game/general/diamond_return", Position); + level.ParticlesFG.Emit(P_Regen, 16, Position, Vector2.One * 2f); + } + } + + private void UpdateY() + { + flash.Y = (sprite.Y = (bloom.Y = sine.Value * 2f)); + } + + public override void Render() + { + if (sprite.Visible) + { + sprite.DrawOutline(1); + } + base.Render(); + } + + private void OnPlayer(Player player) + { + player.MoveHExact((int)dirVector.X * (preventCrash ? SceneAs().Bounds.Width : int.MaxValue)); + player.MoveVExact((int)dirVector.Y * (preventCrash ? SceneAs().Bounds.Height : int.MaxValue)); + if (dirVector == Vector2.UnitY) + { + player.MoveVExact(-2); + } + if (dirVector.X != 0) + { + player.Speed.X = 0; + } + else + { + player.Speed.Y = 0; + } + player.StateMachine.State = 0; + Audio.Play("event:/game/general/diamond_touch", Position); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + Collidable = false; + Add(new Coroutine(RefillRoutine(player), true)); + if (oneUse) + { + RemoveSelf(); + } + else + { + respawnTimer = useTime; + } + } + + private IEnumerator RefillRoutine(Player player) + { + Celeste.Celeste.Freeze(0.05f); + yield return null; + level.Shake(0.3f); + sprite.Visible = (flash.Visible = false); + if (!oneUse) + { + outline.Visible = true; + } + Depth = 8999; + yield return 0.05f; + float num = player.Speed.Angle(); + level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, num - 1.57079637f); + level.ParticlesFG.Emit(P_Shatter, 5, Position, Vector2.One * 4f, num + 1.57079637f); + SlashFx.Burst(Position, num); + yield break; + } + + private bool oneUse; + + private bool preventCrash; + + private float useTime; + + private Vector2 dirVector; + + private float respawnTimer; + + public static ParticleType P_Shatter; + + public static ParticleType P_Regen; + + public static ParticleType P_Glow; + + private Sprite sprite; + + private Sprite flash; + + private Image outline; + + private Wiggler wiggler; + + private BloomPoint bloom; + + private VertexLight light; + + private Level level; + + private SineWave sine; + } +} diff --git a/Code/TimeCrystal.cs b/Code/TimeCrystal.cs new file mode 100644 index 0000000..9a770af --- /dev/null +++ b/Code/TimeCrystal.cs @@ -0,0 +1,274 @@ +using Celeste; +using Celeste.Mod.Entities; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/timecrystal")] + public class TimeCrystal : Entity + { + public static void Load() + { + On.Celeste.CoreModeToggle.OnPlayer += CoreModeToggle_OnPlayer; + On.Celeste.Player.WallBoosterCheck += Player_WallBoosterCheck; + } + + public static void Unload() + { + On.Celeste.CoreModeToggle.OnPlayer -= CoreModeToggle_OnPlayer; + On.Celeste.Player.WallBoosterCheck -= Player_WallBoosterCheck; + } + + public TimeCrystal(EntityData data, Vector2 offset) : base(data.Position + offset) + { + oneUse = data.Bool("oneUse", false); + stopLength = data.Float("stopLength", 2f); + useTime = data.Float("respawnTime", 2.5f); + immediate = data.Bool("immediate", false); + untilDash = data.Bool("untilDash", false); + entityTypesIgnore = data.Attr("entityTypesToIgnore", "").Split(','); + privateTimeScale = data.Float("timeScale", 0f); + + Collider = new Hitbox(16f, 16f, -8f, -8f); + Add(new PlayerCollider(new Action(OnPlayer), null, null)); + if (!oneUse) + { + Add(outline = new Image(GFX.Game["objects/crystals/time/outline"])); + outline.CenterOrigin(); + outline.Visible = false; + } + string spritetype = oneUse ? "idlenr" : "idle"; + Add(sprite = new Sprite(GFX.Game, "objects/crystals/time/" + (untilDash ? "untildash/" : "") + spritetype)); + sprite.AddLoop(spritetype, "", 0.1f); + sprite.Play(spritetype, false, false); + sprite.CenterOrigin(); + Add(flash = new Sprite(GFX.Game, "objects/crystals/time/flash")); + flash.Add("flash", "", 0.05f); + flash.OnFinish = delegate (string anim) + { + flash.Visible = false; + }; + flash.CenterOrigin(); + Add(wiggler = Wiggler.Create(1f, 4f, delegate (float v) + { + sprite.Scale = (flash.Scale = Vector2.One * (1f + v * 0.2f)); + }, false, false)); + Add(new MirrorReflection()); + Add(bloom = new BloomPoint(0.8f, 16f)); + Add(light = new VertexLight(Color.White, 1f, 16, 48)); + Add(sine = new SineWave(0.6f)); + sine.Randomize(); + UpdateY(); + Depth = -100; + } + + public override void Added(Scene scene) + { + base.Added(scene); + level = SceneAs(); + } + + public override void Update() + { + base.Update(); + if (respawnTimer > 0f) + { + respawnTimer -= Engine.DeltaTime; + if (respawnTimer <= 0f) + { + Respawn(); + } + } + else if (Scene.OnInterval(0.1f) && stopStage != 1) + { + level.ParticlesFG.Emit(untilDash ? P_Glow_UntilDash : P_Glow, 1, Position, Vector2.One * 5f); + } + UpdateY(); + light.Alpha = Calc.Approach(light.Alpha, sprite.Visible ? 1f : 0f, 4f * Engine.DeltaTime); + bloom.Alpha = light.Alpha * 0.8f; + if (Scene.OnInterval(2f) && sprite.Visible) + { + flash.Play("flash", true, false); + flash.Visible = true; + } + } + + private void Respawn() + { + if (!Collidable) + { + Collidable = true; + sprite.Visible = true; + outline.Visible = false; + Depth = -100; + wiggler.Start(); + Audio.Play("event:/game/general/diamond_return", Position); + level.ParticlesFG.Emit(untilDash ? P_Regen_UntilDash : P_Regen, 16, Position, Vector2.One * 2f); + } + } + + private void UpdateY() + { + flash.Y = (sprite.Y = (bloom.Y = sine.Value * 2f)); + } + + public override void Render() + { + if (sprite.Visible) + { + sprite.DrawOutline(1); + } + base.Render(); + } + + private void OnPlayer(Player player) + { + Audio.Play("event:/game/general/diamond_touch", Position); + Input.Rumble(RumbleStrength.Medium, RumbleLength.Medium); + Collidable = false; + Add(new Coroutine(RefillRoutine(player), true)); + if (oneUse) + { + RemoveSelf(); + } + else + { + respawnTimer = useTime; + } + entitiesToIgnore = entityTypesIgnore; + if (stopStage != 1) + { + if (untilDash) + { + if (player.Dashes < player.MaxDashes) + { + player.Dashes = player.MaxDashes; + } + VitModule.timeStopType = freezeTypes.UntilDash; + } + else + { + stopTimer = stopLength; + } + timeScaleToSet = privateTimeScale; + VitModule.timeStopScaleTimer = immediate ? 1f : 0f; + stopStage = 1; + } + else + { + stopTimer += stopLength; + } + } + + private IEnumerator RefillRoutine(Player player) + { + Celeste.Celeste.Freeze(0.05f); + yield return null; + level.Shake(0.3f); + sprite.Visible = (flash.Visible = false); + if (!oneUse) + { + outline.Visible = true; + } + Depth = 8999; + yield return 0.05f; + float num = player.Speed.Angle(); + level.ParticlesFG.Emit(untilDash ? P_Shatter_UntilDash : P_Shatter, 5, Position, Vector2.One * 4f, num - 1.57079637f); + level.ParticlesFG.Emit(untilDash ? P_Shatter_UntilDash : P_Shatter, 5, Position, Vector2.One * 4f, num + 1.57079637f); + SlashFx.Burst(Position, num); + yield break; + } + + private static void CoreModeToggle_OnPlayer(On.Celeste.CoreModeToggle.orig_OnPlayer orig, CoreModeToggle self, Player player) + { + if (stopStage == 1) // if time is frozen, delay the activation by 1 frame so that it won't trigger until after time is normal + { + self.Add(Alarm.Create(Alarm.AlarmMode.Oneshot, () => + { + orig(self, player); + }, 0.01f, true)); + } + else + { + orig(self, player); + } + } + + private static WallBooster Player_WallBoosterCheck(On.Celeste.Player.orig_WallBoosterCheck orig, Player self) + { + if (stopStage != 1) + { + return orig(self); + } + else + { + return null; + } + } + + private bool oneUse; + + private float stopLength; + + private float useTime; + + private bool immediate; + + private bool untilDash; + + private string[] entityTypesIgnore; + + private float privateTimeScale; + + public static string[] entitiesToIgnore; + + public static float timeScaleToSet = 0f; + + public static ParticleType P_Shatter; + + public static ParticleType P_Shatter_UntilDash; + + public static ParticleType P_Regen; + + public static ParticleType P_Regen_UntilDash; + + public static ParticleType P_Glow; + + public static ParticleType P_Glow_UntilDash; + + public static float stopTimer; + + public static int stopStage; + + private Sprite sprite; + + private Sprite flash; + + private Image outline; + + private Wiggler wiggler; + + private BloomPoint bloom; + + private VertexLight light; + + private Level level; + + private SineWave sine; + + private float respawnTimer; + + public enum freezeTypes + { + Timer, + UntilDash + } + } +} \ No newline at end of file diff --git a/Code/TimeFadeTrigger.cs b/Code/TimeFadeTrigger.cs new file mode 100644 index 0000000..86a6f54 --- /dev/null +++ b/Code/TimeFadeTrigger.cs @@ -0,0 +1,106 @@ +using Celeste; +using Celeste.Mod.Entities; +using MonoMod.Utils; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/timedfadetrigger")] + [Tracked(false)] + public class TimeFadeTrigger : Trigger + { + public static void Load() + { + On.Celeste.Trigger.GetPositionLerp += Trigger_GetPositionLerp; + } + + public static void Unload() + { + On.Celeste.Trigger.GetPositionLerp -= Trigger_GetPositionLerp; + } + + public TimeFadeTrigger(EntityData data, Vector2 offset) : base(data, offset) + { + nodes = data.NodesOffset(offset); + totalTime = data.Float("time", 1f); + } + + public override void Awake(Scene scene) + { + base.Awake(scene); + Trigger trigger = scene.CollideFirst(nodes[0]); + if (trigger == null) + { + trigger = scene.Tracker.GetNearestEntity(nodes[0]); + } + if (trigger != null) + { + trigger.Collidable = false; + triggerToFade = trigger; + } + } + + public override void Update() + { + base.Update(); + if (playerInside != null && activatedTimer < totalTime) + { + activatedTimer += Engine.DeltaTime; + if (activatedTimer >= totalTime) + { + activatedTimer = totalTime; + if (triggerToFade != null) + { + triggerToFade.OnLeave(playerInside); + } + } + else + { + if (triggerToFade != null) + { + triggerToFade.OnStay(playerInside); + } + } + } + } + + public override void OnEnter(Player player) + { + base.OnEnter(player); + if (triggerToFade != null) + { + triggerToFade.OnEnter(player); + } + playerInside = player; + } + + private static float Trigger_GetPositionLerp(On.Celeste.Trigger.orig_GetPositionLerp orig, Trigger self, Player player, PositionModes mode) + { + foreach (TimeFadeTrigger trigger in self.SceneAs().Tracker.GetEntities()) + { + if (trigger.triggerToFade == self) + { + return trigger.activatedTimer / trigger.totalTime; + } + } + return orig(self, player, mode); + } + + private Vector2[] nodes; + + public float totalTime; + + public Trigger triggerToFade; + + private Player playerInside; + + public float activatedTimer; + } +} diff --git a/Code/TriggerTrigger.cs b/Code/TriggerTrigger.cs new file mode 100644 index 0000000..b64df2d --- /dev/null +++ b/Code/TriggerTrigger.cs @@ -0,0 +1,593 @@ +using Celeste; +using Celeste.Mod.Entities; +using MonoMod.Utils; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/triggertrigger")] + [Tracked(false)] + public class TriggerTrigger : Trigger + { + public static void Load() + { + On.Celeste.Player.Jump += Player_Jump; + On.Celeste.PlayerCollider.Check += PlayerCollider_Check; + } + + public static void Unload() + { + On.Celeste.Player.Jump -= Player_Jump; + On.Celeste.PlayerCollider.Check -= PlayerCollider_Check; + } + + public TriggerTrigger(EntityData data, Vector2 offset) : base(data, offset) + { + nodes = data.NodesOffset(offset); + oneUse = data.Bool("oneUse", false); + activationType = data.Enum("activationType", ActivationTypes.Flag); + if (data.Has("invertFlag")) + { + invertCondition = data.Bool("invertFlag", false); + } + else + { + invertCondition = data.Bool("invertCondition", false); + } + comparisonType = data.Enum("comparisonType", ComparisonTypes.EqualTo); + absoluteValue = data.Bool("absoluteValue", false); + + flag = data.Attr("flag", ""); + deaths = data.Int("deaths", -1); + dashCount = data.Int("dashCount", 0); + requiredSpeed = data.Float("requiredSpeed", 0f); + waitTime = data.Float("timeToWait", 0f); + coreMode = data.Enum("coreMode", Session.CoreModes.None); + if (string.IsNullOrEmpty(data.Attr("entityType", ""))) + { + collideEnity = data.Attr("entityTypeToCollide", "Celeste.Strawberry"); + } + else + { + collideEnity = data.Attr("entityType", ""); + } + collideCount = data.Int("collideCount", 1); + entitiesTouched = new List(); + collideSolid = data.Attr("solidType", ""); + entitiesInside = new List(); + Add(new HoldableCollider((Holdable holdable) => { + if (activationType == ActivationTypes.OnHoldableEnter) + { + entitiesInside.Add(holdable.Entity); + } + })); + if (activationType == ActivationTypes.OnInteraction) + { + Add(new TalkComponent( + new Rectangle(0, 0, (int)Width, (int)Height), + new Vector2(data.Int("talkBubbleX", (int)Width / 2), data.Int("talkBubbleY", 0)), + (player) => + { + externalActivation = true; + } + ) + { + PlayerMustBeFacing = false + }); + } + + delay = data.Float("delay", 0f); + randomize = data.Bool("randomize", false); + Global = data.Bool("activateOnTransition", false); + if (data.Has("requirePlayerInside")) + { + Global = !data.Bool("requirePlayerInside", true); + } + if (bypassGlobal.Contains(activationType)) + { + Global = true; + } + matchPosition = data.Bool("matchPosition", true); + onlyOnEnter = data.Bool("onlyOnEnter", false); + + Add(new TransitionListener + { + OnOut = (f) => DeactivateTriggers(Scene?.Tracker.GetEntity()) + }); + } + + public override void Awake(Scene scene) + { + base.Awake(scene); + triggers = new List(); + foreach (Vector2 node in nodes) + { + var lastCollideable = new Dictionary(); + foreach (Trigger trig in scene.Tracker.GetEntities()) + { + lastCollideable.Add(trig, trig.Collidable); + trig.Collidable = true; + } + + var trigger = scene.CollideFirst(node); + + foreach (Trigger trig in scene.Tracker.GetEntities()) + { + trig.Collidable = lastCollideable[trig]; + } + + if (trigger == null) + { + trigger = scene.Tracker.GetNearestEntity(node); + } + if (trigger != this && trigger != null) + { + triggers.Add(trigger); + trigger.Collidable = false; + } + } + } + + public override void OnEnter(Player player) + { + base.OnEnter(player); + if (!Global) + { + TryActivate(player); + if (Activated && oneUse) + { + RemoveSelf(); + } + } + } + + public override void OnLeave(Player player) + { + base.OnLeave(player); + if (!Global) + { + TryDeactivate(player, false); + } + } + + public override void Update() + { + base.Update(); + + var player = Scene.Tracker.GetEntity(); + + if (player == null) { return; } + + UpdateConditions(player); + + if (!onlyOnEnter) + { + if (Global || PlayerIsInside) + { + TryActivate(player); + TryDeactivate(player, true); + } + else + { + TryDeactivate(player, false); + } + } + + if (Activated) + { + if (oneUse) + { + RemoveSelf(); + } + else + { + UpdateTriggers(player); + } + } + } + + public void UpdateConditions(Player player) + { + if (player.Speed == Vector2.Zero) + { + hasWaited += Engine.DeltaTime; + } + else + { + hasWaited = 0f; + } + + List entitiesToRemove = new List(); + foreach (Entity entity in entitiesInside) + { + if (!entity.CollideCheck(this)) + { + entitiesToRemove.Add(entity); + } + } + foreach (Entity entity in entitiesToRemove) + { + entitiesInside.Remove(entity); + } + } + + public void TryActivate(Player player) + { + if (activating || (Activated && !deactivating)) return; + + if (GetActivateCondition(player)) + { + if (delay > 0f) + { + activating = true; + Add(Alarm.Create(Alarm.AlarmMode.Oneshot, () => + { + activating = false; + ActivateTriggers(player); + }, delay, true)); + } + else + { + ActivateTriggers(player); + } + } + } + + public void TryDeactivate(Player player, bool inside) + { + if (deactivating || (!Activated && !activating)) return; + + if (!inside || !GetActivateCondition(player)) + { + if (delay > 0f) + { + deactivating = true; + Add(Alarm.Create(Alarm.AlarmMode.Oneshot, () => + { + deactivating = false; + DeactivateTriggers(player); + }, delay, true)); + } + else + { + DeactivateTriggers(player); + } + } + } + + public bool GetActivateCondition(Player player) + { + bool result = false; + switch (activationType) + { + case ActivationTypes.Flag: + result = string.IsNullOrEmpty(flag) || SceneAs().Session.GetFlag(flag); + break; + case ActivationTypes.Dashing: + result = player.DashAttacking; + break; + case ActivationTypes.DashCount: + result = Compare(player.Dashes, dashCount); + break; + case ActivationTypes.DeathsInRoom: + result = Compare(SceneAs().Session.DeathsInCurrentLevel, deaths); + break; + case ActivationTypes.DeathsInLevel: + result = Compare(SceneAs().Session.Deaths, deaths); + break; + case ActivationTypes.OnHoldableEnter: + result = entitiesInside.Count > 0; + break; + case ActivationTypes.GrabHoldable: + result = player.Holding != null && player.Holding.IsHeld; + break; + case ActivationTypes.SpeedX: + result = Compare(player.Speed.X, requiredSpeed); + break; + case ActivationTypes.SpeedY: + result = Compare(player.Speed.Y, requiredSpeed); + break; + case ActivationTypes.Jumping: + result = player.AutoJumpTimer > 0f; + break; + case ActivationTypes.Crouching: + result = player.Ducking; + break; + case ActivationTypes.TimeSinceMovement: + result = Compare(hasWaited, waitTime); + break; + case ActivationTypes.CoreMode: + result = player.SceneAs().CoreMode == coreMode; + break; + case ActivationTypes.OnEntityCollide: + result = Compare(collideEntityCount, collideCount); + break; + case ActivationTypes.OnSolid: + Rectangle playerCollision = player.Collider.Bounds; + playerCollision.Inflate(1, 3); + foreach (Solid solid in Scene.CollideAll(playerCollision)) + { + if (string.IsNullOrEmpty(collideSolid) || VitModule.GetClassName(collideSolid, solid)) + { + if (player.IsRiding(solid)) + { + result = true; + break; + } + } + } + if (string.IsNullOrEmpty(collideSolid) && player.OnGround()) + { + result = true; + } + break; + case ActivationTypes.OnEntityEnter: + foreach (Entity entity in Scene.Entities) + { + if (entity.CollideCheck(this) && VitModule.GetClassName(collideEnity, entity)) + { + result = true; + break; + } + } + break; + default: + result = false; + break; + } + if (externalActivation) + { + result = true; + } + if (invertCondition) + { + result = !result; + } + return result; + } + + private bool Compare(float a, float b) + { + if (absoluteValue) + { + a = Math.Abs(a); + b = Math.Abs(b); + } + switch (comparisonType) + { + case ComparisonTypes.LessThan: + return a < b; + case ComparisonTypes.GreaterThan: + return a > b; + default: + return a == b; + } + } + + private void CleanTriggers() + { + triggers.RemoveAll((trigger) => trigger.Scene == null); + + if (chosenTrigger?.Scene == null) + { + chosenTrigger = null; + } + } + + private void ActivateTriggers(Player player) + { + DeactivateTriggers(player); + CleanTriggers(); + + Activated = true; + + if (!randomize) + { + foreach (Trigger trigger in triggers) + { + if (trigger.PlayerIsInside) + { + trigger.OnLeave(player); + } + trigger.OnEnter(player); + } + } + else if (triggers.Count > 0) + { + if (VitModule.Settings.TriggerTriggerRandomizationType == RandomizationTypes.FileTimer) + { + Calc.PushRandom((int)(SaveData.Instance.Time % int.MaxValue)); + } + else + { + Calc.PushRandom((int)(SceneAs().Session.Time % int.MaxValue)); + } + chosenTrigger = Calc.Choose(Calc.Random, triggers); + Calc.PopRandom(); + + if (chosenTrigger.PlayerIsInside) + { + chosenTrigger.OnLeave(player); + } + chosenTrigger.OnEnter(player); + } + } + + private void DeactivateTriggers(Player player) + { + CleanTriggers(); + + Activated = false; + + foreach (Trigger trigger in triggers) + { + if (trigger.PlayerIsInside) + { + trigger.OnLeave(player); + } + } + + chosenTrigger = null; + } + + private void UpdateTriggers(Player player) + { + CleanTriggers(); + + foreach (Trigger trigger in triggers) + { + if (matchPosition) + { + if (!Global) + { + trigger.Position = Position; + trigger.Collider.Width = Width; + trigger.Collider.Height = Height; + } + else + { + var level = SceneAs(); + trigger.Position = new Vector2(level.Bounds.X, level.Bounds.Y); + trigger.Collider.Width = level.Bounds.Width; + trigger.Collider.Height = level.Bounds.Height; + } + } + + if (!randomize) + { + trigger.OnStay(player); + } + } + + chosenTrigger?.OnStay(player); + } + + private static void Player_Jump(On.Celeste.Player.orig_Jump orig, Player self, bool particles, bool playSfx) + { + orig(self, particles, playSfx); + if (self == null) { return; } + foreach (TriggerTrigger trigger in self.SceneAs().Tracker.GetEntities()) + { + if (trigger.activationType == ActivationTypes.Jumping) + { + trigger.externalActivation = true; + self.Add(new Coroutine(trigger.JumpRoutine(self, trigger), true)); + } + } + } + + public IEnumerator JumpRoutine(Player player, TriggerTrigger trigger) + { + while (!player.OnGround()) + { + yield return null; + } + trigger.externalActivation = false; + yield break; + } + + private static bool PlayerCollider_Check(On.Celeste.PlayerCollider.orig_Check orig, PlayerCollider self, Player player) + { + bool result = orig(self, player); + + Entity entity = self.Entity; + foreach (TriggerTrigger trigger in self.SceneAs().Tracker.GetEntities()) + { + if (result) + { + if (trigger.activationType == ActivationTypes.OnEntityCollide && VitModule.GetClassName(trigger.collideEnity, entity)) + { + if (!trigger.entitiesTouched.Contains(entity)) + { + trigger.entitiesTouched.Add(entity); + trigger.collideEntityCount++; + } + } + } + else if (trigger.entitiesTouched.Contains(entity)) + { + trigger.entitiesTouched.Remove(entity); + } + } + + return result; + } + + public bool Global; + public bool Activated; + + private Vector2[] nodes; + private bool oneUse; + public ActivationTypes activationType; + private string flag; + private int deaths; + private int dashCount; + private float requiredSpeed; + private float waitTime; + private float hasWaited; + public string collideEnity; + public int collideEntityCount; + private int collideCount; + public List entitiesTouched; + private Session.CoreModes coreMode; + private List entitiesInside; + private string collideSolid; + public bool externalActivation; + private bool invertCondition; + private ComparisonTypes comparisonType; + private bool absoluteValue; + private float delay; + private bool randomize; + private bool matchPosition; + private bool onlyOnEnter; + + private List triggers; + private bool activating; + private bool deactivating; + private Trigger chosenTrigger; + + public enum ActivationTypes + { + Flag, + Dashing, + DashCount, + DeathsInRoom, + DeathsInLevel, + GrabHoldable, + SpeedX, + SpeedY, + Jumping, + Crouching, + TimeSinceMovement, + OnHoldableEnter, + CoreMode, + OnEntityCollide, + OnInteraction, + OnSolid, + OnEntityEnter, + }; + public enum RandomizationTypes + { + FileTimer, + ChapterTimer + }; + private static List bypassGlobal = new List() { + ActivationTypes.OnHoldableEnter, + ActivationTypes.OnInteraction, + ActivationTypes.OnEntityEnter, + }; + private enum ComparisonTypes + { + LessThan, + EqualTo, + GreaterThan, + }; + } +} diff --git a/Code/VitModule.cs b/Code/VitModule.cs new file mode 100644 index 0000000..824fb16 --- /dev/null +++ b/Code/VitModule.cs @@ -0,0 +1,820 @@ +using Celeste; +using Celeste.Mod; +using MonoMod.Utils; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using MonoMod.RuntimeDetour; +using MonoMod.Cil; +using Mono.Cecil.Cil; +using System.Linq; + +namespace vitmod +{ + public class VitModule : EverestModule + { + public static VitModule Instance; + public VitModule() + { + Instance = this; + } + public class VitModuleSession : EverestModuleSession + { + public List doorsToReset = new List(); + public Dictionary doorEntityDatas = new Dictionary(); + public Dictionary doorOffsets = new Dictionary(); + + public List keysToReset = new List(); + public Dictionary keyEntityDatas = new Dictionary(); + public Dictionary keyOffsets = new Dictionary(); + + public List keyberriesToReset = new List(); + public Dictionary keyberryEntityDatas = new Dictionary(); + public Dictionary keyberryPositions = new Dictionary(); + public Dictionary keyberryOffsets = new Dictionary(); + public Dictionary keyberryBubbles = new Dictionary(); + + public List keyIcesToReset = new List(); + public Dictionary keyIceEntityDatas = new Dictionary(); + public Dictionary keyIceOffsets = new Dictionary(); + public Dictionary keyIceNodes = new Dictionary(); + + public List introCarsToReset = new List(); + public Dictionary introCarEntityDatas = new Dictionary(); + public Dictionary introCarOffsets = new Dictionary(); + } + + public class VitModuleSettings : EverestModuleSettings + { + public TriggerTrigger.RandomizationTypes TriggerTriggerRandomizationType + { + get; + set; + } = TriggerTrigger.RandomizationTypes.FileTimer; + } + + public override Type SessionType => typeof(VitModuleSession); + public static VitModuleSession Session => (VitModuleSession)Instance._Session; + + public override Type SettingsType => typeof(VitModuleSettings); + public static VitModuleSettings Settings => (VitModuleSettings)Instance._Settings; + + public override void LoadContent(bool firstLoad) + { + SpriteBank = new SpriteBank(GFX.Game, "Graphics/CrystallineHelper/CustomSprites.xml"); + //fill crystal + FillCrystal.P_Shatter = new ParticleType(Refill.P_Shatter) + { + Color = Calc.HexToColor("ffddc2"), + Color2 = Calc.HexToColor("fcad85") + }; + FillCrystal.P_Glow = new ParticleType(Refill.P_Glow) + { + Color = Calc.HexToColor("ffb6a3"), + Color2 = Calc.HexToColor("ffb36b") + }; + FillCrystal.P_Regen = new ParticleType(FillCrystal.P_Glow) + { + SpeedMin = 30f, + SpeedMax = 40f, + SpeedMultiplier = 0.2f, + DirectionRange = 6.28318548f + }; + + //star crystal + StarCrystal.P_Shatter = new ParticleType(Refill.P_Shatter) + { + Source = GFX.Game["particles/stars/02"], + Color = Calc.HexToColor("fff7a3"), + Color2 = Calc.HexToColor("ffdb7d") + }; + StarCrystal.P_Glow = new ParticleType(Refill.P_Glow) + { + Color = Calc.HexToColor("ffec8c"), + Color2 = Calc.HexToColor("fffba6") + }; + StarCrystal.P_Regen = new ParticleType(StarCrystal.P_Glow) + { + SpeedMin = 30f, + SpeedMax = 40f, + SpeedMultiplier = 0.2f, + DirectionRange = 6.28318548f + }; + + //tele crystal + TeleCrystal.P_Shatter = new ParticleType(Refill.P_Shatter) + { + Color = Calc.HexToColor("a6b5ff"), + Color2 = Calc.HexToColor("cfd8ff") + }; + TeleCrystal.P_Glow = new ParticleType(Refill.P_Glow) + { + Color = Calc.HexToColor("cfecff"), + Color2 = Calc.HexToColor("dbdeff") + }; + TeleCrystal.P_Regen = new ParticleType(TeleCrystal.P_Glow) + { + SpeedMin = 30f, + SpeedMax = 40f, + SpeedMultiplier = 0.2f, + DirectionRange = 6.28318548f + }; + + //time crystal + TimeCrystal.P_Shatter = new ParticleType(Refill.P_Shatter) + { + Color = Calc.HexToColor("bababa"), + Color2 = Calc.HexToColor("dedede") + }; + TimeCrystal.P_Glow = new ParticleType(Refill.P_Glow) + { + Color = Calc.HexToColor("bababa"), + Color2 = Calc.HexToColor("dedede") + }; + TimeCrystal.P_Regen = new ParticleType(TimeCrystal.P_Glow) + { + SpeedMin = 30f, + SpeedMax = 40f, + SpeedMultiplier = 0.2f, + DirectionRange = 6.28318548f + }; + TimeCrystal.P_Shatter_UntilDash = new ParticleType(Refill.P_Shatter) + { + Color = Calc.HexToColor("aaddff"), + Color2 = Calc.HexToColor("99aaff") + }; + TimeCrystal.P_Glow_UntilDash = new ParticleType(Refill.P_Glow) + { + Color = Calc.HexToColor("aaddff"), + Color2 = Calc.HexToColor("99aaff") + }; + TimeCrystal.P_Regen_UntilDash = new ParticleType(TimeCrystal.P_Glow_UntilDash) + { + SpeedMin = 30f, + SpeedMax = 40f, + SpeedMultiplier = 0.2f, + DirectionRange = 6.28318548f + }; + + //force dash crystal + ForceDashCrystal.P_Shatter = new ParticleType(Refill.P_Shatter) + { + Color = Calc.HexToColor("ffccdd"), + Color2 = Calc.HexToColor("eebbee") + }; + ForceDashCrystal.P_Glow = new ParticleType(Refill.P_Glow) + { + Color = Calc.HexToColor("ffccdd"), + Color2 = Calc.HexToColor("eebbee") + }; + ForceDashCrystal.P_Regen = new ParticleType(ForceDashCrystal.P_Glow) + { + SpeedMin = 30f, + SpeedMax = 40f, + SpeedMultiplier = 0.2f, + DirectionRange = 6.28318548f + }; + ForceDashCrystal.P_NeedDash_Shatter = new ParticleType(Refill.P_Shatter) + { + Color = Calc.HexToColor("cceeff"), + Color2 = Calc.HexToColor("bbeeee") + }; + ForceDashCrystal.P_NeedDash_Glow = new ParticleType(Refill.P_Glow) + { + Color = Calc.HexToColor("cceeff"), + Color2 = Calc.HexToColor("bbeeee") + }; + ForceDashCrystal.P_NeedDash_Regen = new ParticleType(ForceDashCrystal.P_NeedDash_Glow) + { + SpeedMin = 30f, + SpeedMax = 40f, + SpeedMultiplier = 0.2f, + DirectionRange = 6.28318548f + }; + + //force jump crystal (i'm just stealing from tele crystal it's basically the same colors) + ForceJumpCrystal.P_Shatter = new ParticleType(TeleCrystal.P_Shatter); + ForceJumpCrystal.P_Glow = new ParticleType(TeleCrystal.P_Glow); + ForceJumpCrystal.P_Regen = new ParticleType(TeleCrystal.P_Regen); + + //linked move block + VitMoveBlock.P_Activate = new ParticleType + { + Size = 1f, + Color = Color.Black, + FadeMode = ParticleType.FadeModes.Late, + DirectionRange = 0.34906584f, + LifeMin = 0.4f, + LifeMax = 0.6f, + SpeedMin = 20f, + SpeedMax = 40f, + SpeedMultiplier = 0.25f + }; + VitMoveBlock.P_Break = new ParticleType(VitMoveBlock.P_Activate); + VitMoveBlock.P_Move = new ParticleType(VitMoveBlock.P_Activate); + + //reset door trigger (respawning key) + ResetDoorTrigger.P_Respawn = new ParticleType(Refill.P_Shatter) + { + Source = GFX.Game["particles/rect"], + Color = Calc.HexToColor("e2d926"), + Color2 = Calc.HexToColor("fffeef"), + DirectionRange = 6.28318531f + }; + ResetDoorTrigger.P_IceRespawn = new ParticleType(ResetDoorTrigger.P_Respawn) + { + Color = Calc.HexToColor("6385ff"), + Color2 = Calc.HexToColor("72f0ff") + }; + + //boost bumper + BoostBumper.P_Appear = new ParticleType(Booster.P_Appear) + { + Color = Calc.HexToColor("C0796A") + }; + BoostBumper.P_Idle = new ParticleType(Bumper.P_Ambience); + } + public override void Load() + { + //cacheing + deltaTimeInfo = typeof(Engine).GetProperty("DeltaTime"); + rawDeltaTimeInfo = typeof(Engine).GetProperty("RawDeltaTime"); + rendererListSceneInfo = typeof(RendererList).GetField("scene", BindingFlags.NonPublic | BindingFlags.Instance); + frostHelperLoaded = Everest.Loader.DependencyLoaded(new EverestModuleMetadata + { + Name = "FrostHelper", + Version = new Version(1, 3, 0) + }); + vivHelperLoaded = Everest.Loader.DependencyLoaded(new EverestModuleMetadata + { + Name = "VivHelper", + Version = new Version(1, 5, 4) + }); + + NoJumpTrigger.Load(); + NoDashTrigger.Load(); + NoGrabTrigger.Load(); + StarCrystal.Load(); + ForceDashCrystal.Load(); + NoMoveTrigger.Load(); + ResetDoorTrigger.Load(); + if (frostHelperLoaded) + { + HookedKeyIceInit(); + } + CustomWindController.Load(); + TriggerTrigger.Load(); + TimeCrystal.Load(); + TimeFadeTrigger.Load(); + KaizoBlock.Load(); + + + //timestuff + On.Celeste.Level.Update += Level_Update; + IL.Monocle.EntityList.Update += EntityList_Update; + IL.Monocle.RendererList.Update += RendererList_Update; + On.Celeste.CrystalStaticSpinner.UpdateHue += CrystalStaticSpinner_UpdateHue; + + //player hooks + On.Celeste.Player.Update += Player_Update; + hookedPlayerUpdate = new ILHook(typeof(Player).GetMethod("orig_Update"), Player_IL_Update); + On.Celeste.Player.Die += Player_Die; + On.Celeste.Player.CallDashEvents += Player_CallDashEvents; + On.Celeste.PlayerHair.GetHairColor += PlayerHair_GetHairColor; + + //effects + Everest.Events.Level.OnLoadBackdrop += Level_OnLoadBackdrop; + + //misc + On.Celeste.Level.LoadLevel += Level_LoadLevel; + On.Celeste.Level.Reload += Level_Reload; + On.Celeste.Level.End += Level_End; + } + + private static void HookedKeyIceInit() + { + hookedKeyIceCtor = new Hook(typeof(FrostHelper.KeyIce).GetConstructor(new Type[]{typeof(EntityData), typeof(Vector2), typeof(EntityID), typeof(Vector2[])}), typeof(ResetDoorTrigger).GetMethod("KeyIce_ctor", BindingFlags.NonPublic | BindingFlags.Static)); + hookedKeyIceUpdate = new Hook(typeof(FrostHelper.KeyIce).GetMethod("Update"), typeof(ResetDoorTrigger).GetMethod("KeyIce_Update", BindingFlags.NonPublic | BindingFlags.Static)); + hookedKeyIceDissolveRoutine = new Hook(typeof(FrostHelper.KeyIce).GetMethod("DissolveRoutine", BindingFlags.NonPublic | BindingFlags.Instance), typeof(ResetDoorTrigger).GetMethod("KeyIce_DissolveRoutine", BindingFlags.NonPublic | BindingFlags.Static)); + } + + private void Level_Update(On.Celeste.Level.orig_Update orig, Level self) + { + //timestop crystal + if (!self.Paused) + { + if (TimeCrystal.stopTimer > 0f) + { + TimeCrystal.stopTimer -= Engine.DeltaTime; + if (timeStopType == TimeCrystal.freezeTypes.Timer) + { + if (TimeCrystal.stopTimer <= 0f) + { + if (TimeCrystal.stopStage == 1) + { + TimeCrystal.stopTimer = 2f; + TimeCrystal.stopStage = 2; + timeStopScaleTimer = TimeCrystal.timeScaleToSet; + } + else if (TimeCrystal.stopStage == 2) + { + TimeCrystal.stopTimer = 0f; + TimeCrystal.stopStage = 0; + timeStopScaleTimer = 0f; + } + } + } + } + if (timeStopType == TimeCrystal.freezeTypes.UntilDash) + { + if (TimeCrystal.stopTimer > 0f) + { + TimeCrystal.stopTimer -= Engine.DeltaTime; + } + if (TimeCrystal.stopTimer <= 0f) + { + Player player = self.Tracker.GetEntity(); + if (player != null && player.Dashes < 1) + { + TimeCrystal.stopTimer = 2f; + TimeCrystal.stopStage = 2; + timeStopType = TimeCrystal.freezeTypes.Timer; //hacky thing to get it to resume time normally + timeStopScaleTimer = TimeCrystal.timeScaleToSet; + } + } + } + } + + if (TimeCrystal.stopStage > 0) + { + if (!self.Paused) + { + if (TimeCrystal.timeScaleToSet < 1) + { + timeStopScaleTimer += Engine.DeltaTime; + } + else + { + timeStopScaleTimer -= Engine.DeltaTime; + } + } + + float timestop_delta_mult = 1; + if (TimeCrystal.stopStage == 1) + { + timestop_delta_mult = Math.Max(TimeCrystal.timeScaleToSet, 1 - (timeStopScaleTimer / 0.5f)); + } + else if (TimeCrystal.stopStage == 2) + { + timestop_delta_mult = Math.Min(1, timeStopScaleTimer / 0.5f); + } + + if (timestop_delta_mult != 1) + { + useTimeStopDelta = true; + timeStopDelta = Engine.DeltaTime * timestop_delta_mult; + timeStopRawDelta = Engine.RawDeltaTime * timestop_delta_mult; + } + else + { + useTimeStopDelta = false; + } + } + else + { + useTimeStopDelta = false; + } + + //no move trigger + if (NoMoveTrigger.stopTimer > 0f && !self.Paused) + { + NoMoveTrigger.stopTimer -= Engine.DeltaTime; + if (NoMoveTrigger.stopTimer <= 0f) + { + if (NoMoveTrigger.stopStage == 1) + { + NoMoveTrigger.stopTimer = 2f; + NoMoveTrigger.stopStage = 2; + } + else if (NoMoveTrigger.stopStage == 2) + { + NoMoveTrigger.stopTimer = 0f; + NoMoveTrigger.stopStage = 0; + } + noMoveScaleTimer = 0f; + } + } + + if (NoMoveTrigger.stopStage > 0) + { + if (!self.Paused) + { + noMoveScaleTimer += Engine.DeltaTime; + } + + float nomove_delta_mult = NoMoveTrigger.GetDeltaMult(); + + if (nomove_delta_mult != 1) + { + useNoMoveDelta = true; + noMoveDelta = Engine.DeltaTime * nomove_delta_mult; + } + else + { + useNoMoveDelta = false; + } + } + else + { + useNoMoveDelta = false; + } + + orig(self); + } + + private void EntityList_Update(ILContext il) { + var cursor = new ILCursor(il); + + int locEntity = 0; + ILLabel labelEnd = null; + if (cursor.TryGotoNext(MoveType.After, + instr => instr.MatchLdloc(out locEntity), + instr => instr.MatchLdfld("Active"))) + { + if (cursor.TryGotoNext(MoveType.After, instr => instr.MatchBrfalse(out labelEnd))) + { + Logger.Log("CrystallineHelper", "Adding EntityList.Update hook"); + + cursor.Emit(OpCodes.Ldarg_0); + cursor.Emit(OpCodes.Ldloc, locEntity); + cursor.EmitDelegate>((self, entity) => { + lastDeltaTime = Engine.DeltaTime; + lastRawDeltaTime = Engine.RawDeltaTime; + + var timeStopCheck = useTimeStopDelta && !(entity is Player || entity is PlayerDeadBody + || entity is TimeCrystal || entity is CrystalStaticSpinner || entity is DustStaticSpinner + || entity is Lookout || entity is FakeWall); + if (frostHelperLoaded) { + timeStopCheck = timeStopCheck && !IsFrostHelperSpinner(entity); + } + if (vivHelperLoaded) + { + timeStopCheck = timeStopCheck && !IsVivHelperSpinner(entity); + } + var noMoveCheck = useNoMoveDelta && entity is Player; + + if (entity.Scene is Level) { + if (noMoveCheck) { + deltaTimeInfo.SetValue(null, noMoveDelta); + } else if (timeStopCheck) { + if (!TimeCrystal.entitiesToIgnore.Contains(entity.GetType().FullName) && + !TimeCrystal.entitiesToIgnore.Contains(entity.GetType().Name) && + !(timeStopDelta < 0f && entity is ParticleSystem)) + { + deltaTimeInfo.SetValue(null, timeStopDelta); + foreach (Component component in entity.Components) + { + if (component is SoundSource sound) + { + if (timeStopDelta == 0 && sound.Playing) + { + sound.Pause(); + } + else if (timeStopDelta != 0 && !sound.Playing) + { + sound.Resume(); + } + } + } + if (entity is ParticleSystem) + { + rawDeltaTimeInfo.SetValue(null, timeStopRawDelta); + } + } + } + } + }); + + cursor.GotoLabel(labelEnd, MoveType.Before); + + cursor.EmitDelegate(() => { + if (Engine.DeltaTime != lastDeltaTime) { + deltaTimeInfo.SetValue(null, lastDeltaTime); + } + if (Engine.RawDeltaTime != lastRawDeltaTime) { + rawDeltaTimeInfo.SetValue(null, lastRawDeltaTime); + } + }); + } + } + } + + private void RendererList_Update(ILContext il) { + var cursor = new ILCursor(il); + + if (cursor.TryGotoNext(MoveType.Before, + instr => instr.MatchLdarg(0), + instr => instr.MatchLdfld("scene"), + instr => instr.MatchCallvirt("Update"))) + { + Logger.Log("CrystallineHelper", "Adding RendererList.Update hook"); + + cursor.EmitDelegate>((renderer) => { + lastDeltaTime = Engine.DeltaTime; + if (useTimeStopDelta && !(renderer is DisplacementRenderer)) { + deltaTimeInfo.SetValue(null, timeStopDelta); + } + return renderer; + }); + + cursor.Index += 3; + + cursor.EmitDelegate(() => { + if (Engine.DeltaTime != lastDeltaTime) { + deltaTimeInfo.SetValue(null, lastDeltaTime); + } + }); + } + } + + private bool IsFrostHelperSpinner(Entity entity) + { + return entity is FrostHelper.CustomSpinner; + } + + private bool IsVivHelperSpinner(Entity entity) + { + return entity is VivHelper.Entities.CustomSpinner || entity is VivHelper.Entities.AnimatedSpinner; + } + + private void CrystalStaticSpinner_UpdateHue(On.Celeste.CrystalStaticSpinner.orig_UpdateHue orig, CrystalStaticSpinner self) + { + if (TimeCrystal.stopStage != 2) + { + orig(self); + } + } + + private void Level_LoadLevel(On.Celeste.Level.orig_LoadLevel orig, Level self, Player.IntroTypes playerIntro, bool isFromLoader) + { + CustomBridge.bridgeList.Clear(); + orig(self, playerIntro, isFromLoader); + } + + private void Level_Reload(On.Celeste.Level.orig_Reload orig, Level self) + { + orig(self); + CustomWindController customWind = self.Entities.FindFirst(); + if (customWind != null) + { + customWind.SnapWind(); + } + else + { + self.Wind = Vector2.Zero; + } + } + + private void Level_End(On.Celeste.Level.orig_End orig, Level self) + { + NoMoveTrigger.stopTimer = 0f; + NoMoveTrigger.stopStage = 0; + noMoveScaleTimer = 0f; + NoMoveTrigger.alreadyIn = false; + TimeCrystal.stopTimer = 0f; + TimeCrystal.stopStage = 0; + timeStopScaleTimer = 0f; + orig(self); + } + + private void Player_Update(On.Celeste.Player.orig_Update orig, Player self) + { + orig(self); + rainbowTimer += Engine.DeltaTime; + if (StarCrystal.starDashTimer > 0f) + { + StarCrystal.starDashTimer -= Engine.DeltaTime; + } + if (StarCrystal.starInvulnTimer > 0f) + { + StarCrystal.starInvulnTimer -= Engine.DeltaTime; + if (self.OnGround()) + { + self.RefillDash(); + } + } + if (StarCrystal.starStaminaTimer > 0f) + { + self.Stamina = 110f; + StarCrystal.starStaminaTimer -= Engine.DeltaTime; + } + } + + private void Player_IL_Update(ILContext il) + { + ILCursor cursor = new ILCursor(il); + + if (!cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdfld("ForceCameraUpdate"))) + { + return; + } + if (cursor.TryGotoNext(MoveType.After, instr => instr.MatchCall("get_DeltaTime"))) + { + Logger.Log("CrystallineHelper", "Adding Player.Update IL hook"); + + cursor.EmitDelegate>(dt => + { + if (useNoMoveDelta) + { + return lastDeltaTime; + } + else + { + return dt; + } + }); + } + } + + private void Player_CallDashEvents(On.Celeste.Player.orig_CallDashEvents orig, Player self) + { + foreach (BoostBumper booster in self.Scene.Tracker.GetEntities()) + { + if (booster.startedBoosting) + { + booster.PlayerBoosted(self, self.DashDir); + return; + } + } + orig(self); + } + + public static PlayerDeadBody Player_Die(On.Celeste.Player.orig_Die orig, Player self, Vector2 direction, bool evenIfInvincible, bool registerDeathInStats) + { + if (StarCrystal.starInvulnTimer > 0f && !evenIfInvincible) + { + return null; + } + PlayerDeadBody orig_result = orig(self, direction, evenIfInvincible, registerDeathInStats); + if (orig_result != null) + { + //basically just reset all the variables for things + NoMoveTrigger.stopTimer = 0f; + NoMoveTrigger.stopStage = 0; + noMoveScaleTimer = 0f; + NoMoveTrigger.alreadyIn = false; + TimeCrystal.stopTimer = 0f; + TimeCrystal.stopStage = 0; + timeStopScaleTimer = 0f; + timeStopType = TimeCrystal.freezeTypes.Timer; + StarCrystal.starDashTimer = 0f; + StarCrystal.starInvulnTimer = 0f; + StarCrystal.starStaminaTimer = 0f; + } + + return orig_result; + } + + private Color PlayerHair_GetHairColor(On.Celeste.PlayerHair.orig_GetHairColor orig, PlayerHair self, int index) + { + Scene scene = self.Scene; + if (scene == null) + { + return orig(self, index); + } + float startimer = Math.Max(Math.Max(StarCrystal.starDashTimer, StarCrystal.starInvulnTimer), StarCrystal.starStaminaTimer); + Player player = scene.Tracker.GetEntity(); + if (player == null) + { + return orig(self, index); + } + if (debug) + { + return Calc.HexToColor("00ff00"); + } + if (startimer > 0f) + { + float sat; + if (player.Dashes == player.MaxDashes) + { + sat = 1f; + } + else + { + sat = 0.3f; + } + if (startimer < 0.2f) + { + return Calc.HsvToColor((rainbowTimer + index * 0.1f) % 1f, 4.5f * startimer, sat); + } + else + { + return Calc.HsvToColor((rainbowTimer + index * 0.1f) % 1f, 0.9f, sat); + } + } + return orig(self, index); + } + + private Backdrop Level_OnLoadBackdrop(MapData map, BinaryPacker.Element child, BinaryPacker.Element above) + { + Backdrop result; + switch (child.Name) + { + case "CrystallineHelper/CustomWindSnow": + result = new CustomWindSnow( + child.Attr("colors", "ffffff"), + child.Attr("alphas", "1"), + child.AttrInt("amount", 240), + child.AttrFloat("speedX", 0f), + child.AttrFloat("speedY", 0f), + child.AttrBool("ignoreWind", false) + ); + return result; + } + return null; + } + + public static bool GetClassName(string name, Entity entity) + { + return entity.GetType().FullName == name || entity.GetType().Name == name; + } + + public override void Unload() + { + NoJumpTrigger.Unload(); + NoDashTrigger.Unload(); + NoGrabTrigger.Unload(); + StarCrystal.Unload(); + ForceDashCrystal.Unload(); + NoMoveTrigger.Unload(); + ResetDoorTrigger.Unload(); + if (frostHelperLoaded) + { + HookedKeyIceInit(); + } + CustomWindController.Unload(); + TriggerTrigger.Unload(); + TimeCrystal.Unload(); + TimeFadeTrigger.Unload(); + KaizoBlock.Unload(); + On.Celeste.Level.Update -= Level_Update; + IL.Monocle.EntityList.Update -= EntityList_Update; + IL.Monocle.RendererList.Update -= RendererList_Update; + On.Celeste.CrystalStaticSpinner.UpdateHue -= CrystalStaticSpinner_UpdateHue; + On.Celeste.Player.Update -= Player_Update; + hookedPlayerUpdate.Dispose(); + On.Celeste.Player.Die -= Player_Die; + On.Celeste.Player.CallDashEvents -= Player_CallDashEvents; + On.Celeste.PlayerHair.GetHairColor -= PlayerHair_GetHairColor; + Everest.Events.Level.OnLoadBackdrop -= Level_OnLoadBackdrop; + On.Celeste.Level.LoadLevel -= Level_LoadLevel; + On.Celeste.Level.Reload -= Level_Reload; + } + + public static SpriteBank SpriteBank; + + private float rainbowTimer; + + public static float timeStopScaleTimer; + + private bool useTimeStopDelta; + + private float timeStopDelta; + + private float timeStopRawDelta; + + public static TimeCrystal.freezeTypes timeStopType; + + public static float noMoveScaleTimer; + + private bool useNoMoveDelta; + + private float noMoveDelta; + + private float lastDeltaTime; + + private float lastRawDeltaTime; + + public static bool debug; + + private PropertyInfo deltaTimeInfo; + + private PropertyInfo rawDeltaTimeInfo; + + private FieldInfo rendererListSceneInfo; + + public static bool frostHelperLoaded; + + public static bool vivHelperLoaded; + + public static Hook hookedCustomSpinner; + + public static Hook hookedKeyIceCtor; + public static Hook hookedKeyIceUpdate; + public static Hook hookedKeyIceDissolveRoutine; + public static ILHook hookedPlayerUpdate; + } +} \ No newline at end of file diff --git a/Code/VitMoveBlock.cs b/Code/VitMoveBlock.cs new file mode 100644 index 0000000..c46def0 --- /dev/null +++ b/Code/VitMoveBlock.cs @@ -0,0 +1,978 @@ +using Celeste; +using Celeste.Mod.Entities; +using FMOD.Studio; +using Microsoft.Xna.Framework; +using Monocle; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace vitmod +{ + [CustomEntity("vitellary/vitmoveblock")] + public class VitMoveBlock : Solid + { + public VitMoveBlock(EntityData data, Vector2 offset) : base(data.Position + offset, data.Width, data.Height, false) + { + body = new List(); + topButton = new List(); + leftButton = new List(); + rightButton = new List(); + arrows = new List(); + fillColor = (remote == 0 ? idleBgFill : idleRemoteBgFill); + Depth = -9000; + startPosition = data.Position + offset; + direction = data.Enum("direction"); + remote = data.Int("remote", 0); + canSteer = data.Bool("canSteer", false); + canActivate = data.Bool("canActivate", true); + spritePath = data.Attr("spritePath", "objects/vitMoveBlock"); + moveSpeed = data.Float("moveSpeed", 75f); + idleBgFill = Calc.HexToColor(data.Attr("idleSingleColor", "465eb5")); + activeBgFill = Calc.HexToColor(data.Attr("activeSingleColor", "4fd6ff")); + idleRemoteBgFill = Calc.HexToColor(data.Attr("idleLinkedColor", "9e45b2")); + activeRemoteBgFill = Calc.HexToColor(data.Attr("activeLinkedColor", "ff8cf5")); + breakingBgFill = Calc.HexToColor(data.Attr("breakingColor", "cc2541")); + + switch (direction) + { + case VitMoveBlock.Directions.Left: + homeAngle = (targetAngle = (angle = 3.14159274f)); + angleSteerSign = -1; + break; + default: + homeAngle = (targetAngle = (angle = 0f)); + angleSteerSign = 1; + break; + case VitMoveBlock.Directions.Up: + homeAngle = (targetAngle = (angle = -1.57079637f)); + angleSteerSign = 1; + break; + case VitMoveBlock.Directions.Down: + homeAngle = (targetAngle = (angle = 1.57079637f)); + angleSteerSign = -1; + break; + } + int tileWidth = data.Width / 8; + int tileHeight = data.Height / 8; + MTexture mtexture = GFX.Game[spritePath + "/base"]; + MTexture mtexture2 = GFX.Game[spritePath + "/button"]; + if (canSteer && (direction == VitMoveBlock.Directions.Left || direction == VitMoveBlock.Directions.Right)) + { + for (int i = 0; i < tileWidth; i++) + { + int num3 = (i == 0) ? 0 : ((i < tileWidth - 1) ? 1 : 2); + AddImage(mtexture2.GetSubtexture(num3 * 8, 0, 8, 8, null), new Vector2((i * 8), -4f), 0f, new Vector2(1f, 1f), topButton); + } + mtexture = GFX.Game[spritePath + "/base_h"]; + } + else if (canSteer && (direction == VitMoveBlock.Directions.Up || direction == VitMoveBlock.Directions.Down)) + { + for (int j = 0; j < tileHeight; j++) + { + int num4 = (j == 0) ? 0 : ((j < tileHeight - 1) ? 1 : 2); + AddImage(mtexture2.GetSubtexture(num4 * 8, 0, 8, 8, null), new Vector2(-4f, (j * 8)), 1.57079637f, new Vector2(1f, -1f), leftButton); + AddImage(mtexture2.GetSubtexture(num4 * 8, 0, 8, 8, null), new Vector2(((tileWidth - 1) * 8 + 4), (j * 8)), 1.57079637f, new Vector2(1f, 1f), rightButton); + } + mtexture = GFX.Game[spritePath + "/base_v"]; + } + for (int k = 0; k < tileWidth; k++) + { + for (int l = 0; l < tileHeight; l++) + { + int num5 = (k == 0) ? 0 : ((k < tileWidth - 1) ? 1 : 2); + int num6 = (l == 0) ? 0 : ((l < tileHeight - 1) ? 1 : 2); + AddImage(mtexture.GetSubtexture(num5 * 8, num6 * 8, 8, 8, null), new Vector2(k, l) * 8f, 0f, new Vector2(1f, 1f), body); + } + } + arrows = GFX.Game.GetAtlasSubtextures(spritePath + "/arrow"); + Add(moveSfx = new SoundSource()); + Add(new Coroutine(Controller(), true)); + UpdateColors(); + Add(new LightOcclude(0.5f)); + } + + public override void Awake(Scene scene) + { + base.Awake(scene); + scene.Add(border = new Border(this)); + } + private IEnumerator Controller() + { + while (true) + { + triggered = false; + state = VitMoveBlock.MovementState.Idling; + while (!triggered && ((remote > 0 && !canActivate) || !HasPlayerRider())) + { + yield return null; + } + if (remote > 0) + { + foreach (var entity in SceneAs()) + { + if (entity is VitMoveBlock) + { + var moveBlock = entity as VitMoveBlock; + + if (moveBlock.remote == remote) + { + moveBlock.triggered = true; + } + } + } + } + Audio.Play("event:/game/04_cliffside/arrowblock_activate", Position); + state = VitMoveBlock.MovementState.Moving; + StartShaking(0.2f); + ActivateParticles(); + yield return 0.2f; + targetSpeed = moveSpeed; + moveSfx.Play("event:/game/04_cliffside/arrowblock_move", null, 0f); + moveSfx.Param("arrow_stop", 0f); + StopPlayerRunIntoAnimation = false; + float crashTimer = 0.15f; + float crashResetTimer = 0.1f; + float noSteerTimer = 0.2f; + while (true) + { + heldTopButton = false; + heldSideButton = false; + if (canSteer) + { + targetAngle = homeAngle; + bool flag; + if (direction == VitMoveBlock.Directions.Right || direction == VitMoveBlock.Directions.Left) + { + flag = HasPlayerOnTop(); + heldTopButton = HasPlayerOnTop(); + } + else + { + flag = HasPlayerClimbing(); + heldSideButton = HasPlayerClimbing(); + } + if (!flag) + { + foreach (var entity in SceneAs()) + { + if (entity is VitMoveBlock) + { + var moveBlock = entity as VitMoveBlock; + + if (moveBlock.remote == remote + && moveBlock.state == VitMoveBlock.MovementState.Moving + && ( + (moveBlock.heldTopButton && (direction == VitMoveBlock.Directions.Left || direction == VitMoveBlock.Directions.Right)) + || (moveBlock.heldSideButton && (direction == VitMoveBlock.Directions.Up || direction == VitMoveBlock.Directions.Down)))) + { + flag = true; + break; + } + } + } + } + if (flag && noSteerTimer > 0f) + { + noSteerTimer -= Engine.DeltaTime; + } + if (flag) + { + if (noSteerTimer <= 0f) + { + if (direction == VitMoveBlock.Directions.Right || direction == VitMoveBlock.Directions.Left) + { + targetAngle = homeAngle + 0.7853982f * angleSteerSign * Input.MoveY.Value; + } + else + { + targetAngle = homeAngle + 0.7853982f * angleSteerSign * Input.MoveX.Value; + } + } + } + else + { + noSteerTimer = 0.2f; + } + } + if (Scene.OnInterval(0.02f)) + { + MoveParticles(); + } + speed = Calc.Approach(speed, targetSpeed, 300f * Engine.DeltaTime); + angle = Calc.Approach(angle, targetAngle, 50.2654839f * Engine.DeltaTime); + Vector2 vector = Calc.AngleToVector(angle, speed) * Engine.DeltaTime; + bool flag2; + if (direction == VitMoveBlock.Directions.Right || direction == VitMoveBlock.Directions.Left) + { + flag2 = MoveCheck(vector.XComp()); + if (heldTopButton) + { + noSquish = Scene.Tracker.GetEntity(); + } + MoveVCollideSolids(vector.Y, false, null); + noSquish = null; + if (Scene.OnInterval(0.03f)) + { + if (vector.Y > 0f) + { + ScrapeParticles(Vector2.UnitY); + } + else if (vector.Y < 0f) + { + ScrapeParticles(-Vector2.UnitY); + } + } + } + else + { + flag2 = MoveCheck(vector.YComp()); + if (heldSideButton) + { + noSquish = Scene.Tracker.GetEntity(); + } + MoveHCollideSolids(vector.X, false, null); + noSquish = null; + if (Scene.OnInterval(0.03f)) + { + if (vector.X > 0f) + { + ScrapeParticles(Vector2.UnitX); + } + else if (vector.X < 0f) + { + ScrapeParticles(-Vector2.UnitX); + } + } + if (direction == VitMoveBlock.Directions.Down && Top > (SceneAs().Bounds.Bottom + 32)) + { + flag2 = true; + } + } + if (flag2) + { + moveSfx.Param("arrow_stop", 1f); + crashResetTimer = 0.1f; + if (crashTimer <= 0f) + { + break; + } + crashTimer -= Engine.DeltaTime; + } + else + { + moveSfx.Param("arrow_stop", 0f); + if (crashResetTimer > 0f) + { + crashResetTimer -= Engine.DeltaTime; + } + else + { + crashTimer = 0.15f; + } + } + Level level = Scene as Level; + if (Left < level.Bounds.Left || Top < level.Bounds.Top || Right > level.Bounds.Right) + { + break; + } + yield return null; + } + Audio.Play("event:/game/04_cliffside/arrowblock_break", Position); + moveSfx.Stop(true); + state = VitMoveBlock.MovementState.Breaking; + speed = targetSpeed = 0f; + angle = (targetAngle = homeAngle); + StartShaking(0.2f); + StopPlayerRunIntoAnimation = true; + yield return 0.2f; + BreakParticles(); + List debris = new List(); + int num = 0; + while (num < Width) + { + int num2 = 0; + while (num2 < Height) + { + Vector2 value = new Vector2(num + 4f, num2 + 4f); + Debris debris2 = Engine.Pooler.Create().Init(Position + value, Center, startPosition + value); + debris.Add(debris2); + Scene.Add(debris2); + num2 += 8; + } + num += 8; + } + MoveStaticMovers(startPosition - Position); + DisableStaticMovers(); + Position = startPosition; + Visible = (Collidable = false); + yield return 2.2f; + using (List.Enumerator enumerator = debris.GetEnumerator()) + { + while (enumerator.MoveNext()) + { + Debris debris3 = enumerator.Current; + debris3.StopMoving(); + } + goto IL_6A5; + } + IL_6A5: + if (!CollideCheck() && !CollideCheck()) + { + Collidable = true; + EventInstance instance = Audio.Play("event:/game/04_cliffside/arrowblock_reform_begin", debris[0].Position); + Coroutine routine; + Add(routine = new Coroutine(SoundFollowsDebrisCenter(instance, debris), true)); + foreach (Debris debris4 in debris) + { + debris4.StartShaking(); + } + yield return 0.2f; + foreach (Debris debris5 in debris) + { + debris5.ReturnHome(0.65f); + } + yield return 0.6f; + routine.RemoveSelf(); + foreach (Debris debris6 in debris) + { + debris6.RemoveSelf(); + } + routine = null; + Audio.Play("event:/game/04_cliffside/arrowblock_reappear", Position); + Visible = true; + EnableStaticMovers(); + speed = (targetSpeed = 0f); + angle = (targetAngle = homeAngle); + noSquish = null; + fillColor = (remote == 0 ? idleBgFill : idleRemoteBgFill); + UpdateColors(); + flash = 1f; + continue; + } + } + } + private IEnumerator SoundFollowsDebrisCenter(EventInstance instance, List debris) + { + while (true) + { + PLAYBACK_STATE playback_STATE; + instance.getPlaybackState(out playback_STATE); + if (playback_STATE == PLAYBACK_STATE.STOPPED) + { + break; + } + Vector2 vector = Vector2.Zero; + foreach (Debris debris2 in debris) + { + vector += debris2.Position; + } + vector /= debris.Count; + Audio.Position(instance, vector); + yield return null; + } + yield break; + } + public override void Update() + { + base.Update(); + if (canSteer) + { + bool flag = (direction == VitMoveBlock.Directions.Up || direction == VitMoveBlock.Directions.Down) && CollideCheck(Position + new Vector2(-1f, 0f)); + bool flag2 = (direction == VitMoveBlock.Directions.Up || direction == VitMoveBlock.Directions.Down) && CollideCheck(Position + new Vector2(1f, 0f)); + bool flag3 = (direction == VitMoveBlock.Directions.Left || direction == VitMoveBlock.Directions.Right) && CollideCheck(Position + new Vector2(0f, -1f)); + foreach (Image image in topButton) + { + image.Y = (flag3 ? 2 : 0); + } + foreach (Image image2 in leftButton) + { + image2.X = (flag ? 2 : 0); + } + foreach (Image image3 in rightButton) + { + image3.X = Width + (flag2 ? -2 : 0); + } + if ((flag && !leftPressed) || (flag3 && !topPressed) || (flag2 && !rightPressed)) + { + Audio.Play("event:/game/04_cliffside/arrowblock_side_depress", Position); + } + if ((!flag && leftPressed) || (!flag3 && topPressed) || (!flag2 && rightPressed)) + { + Audio.Play("event:/game/04_cliffside/arrowblock_side_release", Position); + } + leftPressed = flag; + rightPressed = flag2; + topPressed = flag3; + } + if (moveSfx != null && moveSfx.Playing) + { + int num = (int)Math.Floor(((-(double)(Calc.AngleToVector(angle, 1f) * new Vector2(-1f, 1f)).Angle() + 6.28318548f) % 6.28318548f / 6.28318548f * 8f + 0.5f)); + moveSfx.Param("arrow_influence", (num + 1)); + } + border.Visible = Visible; + flash = Calc.Approach(flash, 0f, Engine.DeltaTime * 5f); + UpdateColors(); + } + public override void MoveHExact(int move) + { + if (noSquish != null) + { + if (move >= 0 || noSquish.X >= X) + { + if (move <= 0 || noSquish.X <= X) + { + goto IL_6E; + } + } + while (move != 0 && noSquish.CollideCheck(noSquish.Position + Vector2.UnitX * move)) + { + move -= Math.Sign(move); + } + } + IL_6E: + base.MoveHExact(move); + } + public override void MoveVExact(int move) + { + if (noSquish != null && move < 0 && noSquish.Y <= Y) + { + while (move != 0 && noSquish.CollideCheck(noSquish.Position + Vector2.UnitY * move)) + { + move -= Math.Sign(move); + } + } + base.MoveVExact(move); + } + private bool MoveCheck(Vector2 speed) + { + if (speed.X != 0f) + { + if (MoveHCollideSolids(speed.X, false, null)) + { + for (int i = 1; i <= 3; i++) + { + for (int j = 1; j >= -1; j -= 2) + { + Vector2 value = new Vector2(Math.Sign(speed.X), (i * j)); + if (!CollideCheck(Position + value)) + { + MoveVExact(i * j); + MoveHExact(Math.Sign(speed.X)); + return false; + } + } + } + return true; + } + return false; + } + else + { + if (speed.Y == 0f) + { + return false; + } + if (MoveVCollideSolids(speed.Y, false, null)) + { + for (int k = 1; k <= 3; k++) + { + for (int l = 1; l >= -1; l -= 2) + { + Vector2 value2 = new Vector2((k * l), Math.Sign(speed.Y)); + if (!CollideCheck(Position + value2)) + { + MoveHExact(k * l); + MoveVExact(Math.Sign(speed.Y)); + return false; + } + } + } + return true; + } + return false; + } + } + private void UpdateColors() + { + Color value = (remote == 0 ? idleBgFill : idleRemoteBgFill); + if (state == VitMoveBlock.MovementState.Moving) + { + value = (remote == 0 ? activeBgFill : activeRemoteBgFill); + } + else if (state == VitMoveBlock.MovementState.Breaking) + { + value = breakingBgFill; + } + fillColor = Color.Lerp(fillColor, value, 10f * Engine.DeltaTime); + foreach (Image image in topButton) + { + image.Color = fillColor; + } + foreach (Image image2 in leftButton) + { + image2.Color = fillColor; + } + foreach (Image image3 in rightButton) + { + image3.Color = fillColor; + } + } + private void AddImage(MTexture tex, Vector2 position, float rotation, Vector2 scale, List addTo) + { + Image image = new Image(tex); + image.Position = position + new Vector2(4f, 4f); + image.CenterOrigin(); + image.Rotation = rotation; + image.Scale = scale; + Add(image); + if (addTo != null) + { + addTo.Add(image); + } + } + private void SetVisible(List images, bool visible) + { + foreach (Image image in images) + { + image.Visible = visible; + } + } + public override void Render() + { + Vector2 position = Position; + Position += Shake; + foreach (Image image in leftButton) + { + image.Render(); + } + foreach (Image image2 in rightButton) + { + image2.Render(); + } + foreach (Image image3 in topButton) + { + image3.Render(); + } + Draw.Rect(X + 3f, Y + 3f, Width - 6f, Height - 6f, fillColor); + foreach (Image image4 in body) + { + image4.Render(); + } + Draw.Rect(Center.X - 4f, Center.Y - 4f, 8f, 8f, fillColor); + if (state != VitMoveBlock.MovementState.Breaking) + { + int value = (int)Math.Floor((-(double)angle + 6.28318548f) % 6.28318548f / 6.28318548f * 8f + 0.5f); + arrows[Calc.Clamp(value, 0, 7)].DrawCentered(Center); + } + else + { + GFX.Game[spritePath + "/x"].DrawCentered(Center); + } + float num = flash * 4f; + Draw.Rect(X - num, Y - num, Width + num * 2f, Height + num * 2f, Color.White * flash); + Position = position; + } + private void ActivateParticles() + { + bool flag = direction == VitMoveBlock.Directions.Down || direction == VitMoveBlock.Directions.Up; + if ((!canSteer || !flag) && !CollideCheck(Position - Vector2.UnitX)) + { + SceneAs().ParticlesBG.Emit(P_Activate, (int)(Height / 2f), CenterLeft, Vector2.UnitY * (Height - 4f) * 0.5f, 3.14159274f); + } + if ((!canSteer || !flag) && !CollideCheck(Position + Vector2.UnitX)) + { + SceneAs().ParticlesBG.Emit(P_Activate, (int)(Height / 2f), CenterRight, Vector2.UnitY * (Height - 4f) * 0.5f, 0f); + } + if ((!canSteer || flag) && !CollideCheck(Position - Vector2.UnitY)) + { + SceneAs().ParticlesBG.Emit(P_Activate, (int)(Width / 2f), TopCenter, Vector2.UnitX * (Width - 4f) * 0.5f, -1.57079637f); + } + SceneAs().ParticlesBG.Emit(P_Activate, (int)(Width / 2f), BottomCenter, Vector2.UnitX * (Width - 4f) * 0.5f, 1.57079637f); + } + private void BreakParticles() + { + Vector2 center = Center; + int num = 0; + while (num < Width) + { + int num2 = 0; + while (num2 < Height) + { + Vector2 vector = Position + new Vector2((2 + num), (2 + num2)); + SceneAs().Particles.Emit(P_Break, 1, vector, Vector2.One * 2f, (vector - center).Angle()); + num2 += 4; + } + num += 4; + } + } + private void MoveParticles() + { + Vector2 position; + Vector2 vector; + float num; + float num2; + if (direction == VitMoveBlock.Directions.Right) + { + position = CenterLeft + Vector2.UnitX; + vector = Vector2.UnitY * (Height - 4f); + num = 3.14159274f; + num2 = Height / 32f; + } + else if (direction == VitMoveBlock.Directions.Left) + { + position = CenterRight; + vector = Vector2.UnitY * (Height - 4f); + num = 0f; + num2 = Height / 32f; + } + else if (direction == VitMoveBlock.Directions.Down) + { + position = TopCenter + Vector2.UnitY; + vector = Vector2.UnitX * (Width - 4f); + num = -1.57079637f; + num2 = Width / 32f; + } + else + { + position = BottomCenter; + vector = Vector2.UnitX * (Width - 4f); + num = 1.57079637f; + num2 = Width / 32f; + } + particleRemainder += num2; + int num3 = (int)particleRemainder; + particleRemainder -= num3; + vector *= 0.5f; + if (num3 > 0) + { + SceneAs().ParticlesBG.Emit(P_Move, num3, position, vector, num); + } + } + private void ScrapeParticles(Vector2 dir) + { + bool collidable = Collidable; + Collidable = false; + if (dir.X != 0f) + { + float x; + if (dir.X > 0f) + { + x = Right; + } + else + { + x = Left - 1f; + } + int num = 0; + while (num < Height) + { + Vector2 vector = new Vector2(x, Top + 4f + num); + if (Scene.CollideCheck(vector)) + { + SceneAs().ParticlesFG.Emit(ZipMover.P_Scrape, vector); + } + num += 8; + } + } + else + { + float y; + if (dir.Y > 0f) + { + y = Bottom; + } + else + { + y = Top - 1f; + } + int num2 = 0; + while (num2 < Width) + { + Vector2 vector2 = new Vector2(Left + 4f + num2, y); + if (Scene.CollideCheck(vector2)) + { + SceneAs().ParticlesFG.Emit(ZipMover.P_Scrape, vector2); + } + num2 += 8; + } + } + Collidable = true; + } + + public static ParticleType P_Activate; + + public static ParticleType P_Break; + + public static ParticleType P_Move; + + public int remote; + + public bool triggered; + + public bool heldTopButton; + + public bool heldSideButton; + + private bool canSteer; + + private bool canActivate; + + private Directions direction; + + private string spritePath; + + private float moveSpeed; + + private float homeAngle; + + private int angleSteerSign; + + private Vector2 startPosition; + + public MovementState state; + + private bool leftPressed; + + private bool rightPressed; + + private bool topPressed; + + private float speed; + + private float targetSpeed; + + private float angle; + + private float targetAngle; + + private Player noSquish; + + private List body; + + private List topButton; + + private List leftButton; + + private List rightButton; + + private List arrows; + + private Border border; + + private Color fillColor; + + private Color idleBgFill; + + private Color activeBgFill = Calc.HexToColor("4fd6ff"); + + private Color idleRemoteBgFill = Calc.HexToColor("9e45b2"); + + private Color activeRemoteBgFill = Calc.HexToColor("ff8cf5"); + + private Color breakingBgFill = Calc.HexToColor("cc2541"); + + private float flash; + + private SoundSource moveSfx; + + private float particleRemainder; + + public enum Directions + { + Left, + Right, + Up, + Down + } + + public enum MovementState + { + Idling, + Moving, + Breaking + } + + private class Border : Entity + { + public Border(VitMoveBlock parent) + { + Parent = parent; + Depth = 1; + } + + public override void Update() + { + if (Parent.Scene != Scene) + { + RemoveSelf(); + } + base.Update(); + } + + public override void Render() + { + Draw.Rect(Parent.X + Parent.Shake.X - 1f, Parent.Y + Parent.Shake.Y - 1f, Parent.Width + 2f, Parent.Height + 2f, Color.Black); + } + + public VitMoveBlock Parent; + } + + private class Debris : Actor + { + public Debris() : base(Vector2.Zero) + { + Tag = Tags.TransitionUpdate; + Collider = new Hitbox(4f, 4f, -2f, -2f); + Add(sprite = new Image(Calc.Random.Choose(GFX.Game.GetAtlasSubtextures("objects/vitMoveBlock/debris")))); + sprite.CenterOrigin(); + sprite.FlipX = Calc.Random.Chance(0.5f); + onCollideH = delegate (CollisionData c) + { + speed.X = -speed.X * 0.5f; + }; + onCollideV = delegate (CollisionData c) + { + if (firstHit || speed.Y > 50f) + { + Audio.Play("event:/game/general/debris_stone", Position, "debris_velocity", Calc.ClampedMap(speed.Y, 0f, 600f, 0f, 1f)); + } + if (speed.Y > 0f && speed.Y < 40f) + { + speed.Y = 0f; + } + else + { + speed.Y = -speed.Y * 0.25f; + } + firstHit = false; + }; + } + protected override void OnSquish(CollisionData data) + { + } + public VitMoveBlock.Debris Init(Vector2 position, Vector2 center, Vector2 returnTo) + { + Collidable = true; + Position = position; + speed = (position - center).SafeNormalize(60f + Calc.Random.NextFloat(60f)); + home = returnTo; + sprite.Position = Vector2.Zero; + sprite.Rotation = Calc.Random.NextAngle(); + returning = false; + shaking = false; + sprite.Scale.X = 1f; + sprite.Scale.Y = 1f; + sprite.Color = Color.White; + alpha = 1f; + firstHit = false; + spin = Calc.Random.Range(3.49065852f, 10.4719753f) * Calc.Random.Choose(1, -1); + return this; + } + + public override void Update() + { + base.Update(); + if (!returning) + { + if (Collidable) + { + speed.X = Calc.Approach(speed.X, 0f, Engine.DeltaTime * 100f); + if (!OnGround(1)) + { + speed.Y = speed.Y + 400f * Engine.DeltaTime; + } + MoveH(speed.X * Engine.DeltaTime, onCollideH, null); + MoveV(speed.Y * Engine.DeltaTime, onCollideV, null); + } + if (shaking && Scene.OnInterval(0.05f)) + { + sprite.X = (-1 + Calc.Random.Next(3)); + sprite.Y = (-1 + Calc.Random.Next(3)); + } + } + else + { + Position = returnCurve.GetPoint(Ease.CubeOut(returnEase)); + returnEase = Calc.Approach(returnEase, 1f, Engine.DeltaTime / returnDuration); + sprite.Scale = Vector2.One * (1f + returnEase * 0.5f); + } + if ((Scene as Level).Transitioning) + { + alpha = Calc.Approach(alpha, 0f, Engine.DeltaTime * 4f); + sprite.Color = Color.White * alpha; + } + sprite.Rotation += spin * Calc.ClampedMap(Math.Abs(speed.Y), 50f, 150f, 0f, 1f) * Engine.DeltaTime; + } + + public void StopMoving() + { + Collidable = false; + } + + public void StartShaking() + { + shaking = true; + } + + public void ReturnHome(float duration) + { + if (Scene != null) + { + Camera camera = (Scene as Level).Camera; + if (X < camera.X) + { + X = camera.X - 8f; + } + if (Y < camera.Y) + { + Y = camera.Y - 8f; + } + if (X > camera.X + 320f) + { + X = camera.X + 320f + 8f; + } + if (Y > camera.Y + 180f) + { + Y = camera.Y + 180f + 8f; + } + } + returning = true; + returnEase = 0f; + returnDuration = duration; + Vector2 vector = (home - Position).SafeNormalize(); + Vector2 control = (Position + home) / 2f + new Vector2(vector.Y, -vector.X) * (Calc.Random.NextFloat(16f) + 16f) * Calc.Random.Facing(); + returnCurve = new SimpleCurve(Position, home, control); + } + + private Image sprite; + + private Vector2 home; + + private Vector2 speed; + + private bool shaking; + + private bool returning; + + private float returnEase; + + private float returnDuration; + + private SimpleCurve returnCurve; + + private bool firstHit; + + private float alpha; + + private Collision onCollideH; + + private Collision onCollideV; + + private float spin; + } + } +} \ No newline at end of file diff --git a/Code/lib-stripped/FrostTempleHelper.dll b/Code/lib-stripped/FrostTempleHelper.dll new file mode 100644 index 0000000..4f48c59 Binary files /dev/null and b/Code/lib-stripped/FrostTempleHelper.dll differ diff --git a/Code/lib-stripped/VivHelper.dll b/Code/lib-stripped/VivHelper.dll new file mode 100644 index 0000000..52a8128 Binary files /dev/null and b/Code/lib-stripped/VivHelper.dll differ diff --git a/Code/vitmod.csproj b/Code/vitmod.csproj new file mode 100644 index 0000000..f0d50b8 --- /dev/null +++ b/Code/vitmod.csproj @@ -0,0 +1,62 @@ + + + + net452 + vitmod + vitmod + latest + ..\.. + ..\..\.. + lib-stripped + XNA + FNA + $(WINDIR)\Microsoft.NET\assembly\GAC_32\{0}\v4.0_4.0.0.0__842cf8be1de50553\{0}.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(MSBuildProjectDirectory)=CrystallineHelper/ + + + + None + + + \ No newline at end of file diff --git a/CrystallineHelper.sln b/CrystallineHelper.sln new file mode 100644 index 0000000..ffea89b --- /dev/null +++ b/CrystallineHelper.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32901.215 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "vitmod", "Code\vitmod.csproj", "{DCD16B99-521A-46E1-9630-AD2258F6145F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DCD16B99-521A-46E1-9630-AD2258F6145F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCD16B99-521A-46E1-9630-AD2258F6145F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCD16B99-521A-46E1-9630-AD2258F6145F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCD16B99-521A-46E1-9630-AD2258F6145F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FFB1C4C1-BE00-4AF3-816A-DB50BD628EC6} + EndGlobalSection +EndGlobal diff --git a/Graphics/Atlases/Gameplay/ahorn_flagsequencecontroller.png b/Graphics/Atlases/Gameplay/ahorn_flagsequencecontroller.png new file mode 100644 index 0000000..52cb39e Binary files /dev/null and b/Graphics/Atlases/Gameplay/ahorn_flagsequencecontroller.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal00.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal00.png new file mode 100644 index 0000000..15f62b5 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal00.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal01.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal01.png new file mode 100644 index 0000000..85f2e45 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal01.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal02.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal02.png new file mode 100644 index 0000000..5cc7b49 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal02.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal03.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal03.png new file mode 100644 index 0000000..038728e Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal03.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal04.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal04.png new file mode 100644 index 0000000..ca58df6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal04.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal05.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal05.png new file mode 100644 index 0000000..4cb549c Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal05.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal06.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal06.png new file mode 100644 index 0000000..18bf137 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal06.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal07.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal07.png new file mode 100644 index 0000000..ab2baad Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal07.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal08.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal08.png new file mode 100644 index 0000000..63acd90 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal08.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal09.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal09.png new file mode 100644 index 0000000..bba12fc Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal09.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal10.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal10.png new file mode 100644 index 0000000..6a0659d Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal10.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal11.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal11.png new file mode 100644 index 0000000..4213ffa Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal11.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal12.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal12.png new file mode 100644 index 0000000..a215ca9 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal12.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal13.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal13.png new file mode 100644 index 0000000..bf6d50f Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal13.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal14.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal14.png new file mode 100644 index 0000000..37df7b3 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal14.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal15.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal15.png new file mode 100644 index 0000000..55dec99 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal15.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal16.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal16.png new file mode 100644 index 0000000..8bcdfce Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal16.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal17.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal17.png new file mode 100644 index 0000000..c832eb2 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal17.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal18.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal18.png new file mode 100644 index 0000000..6f710d8 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal18.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal19.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal19.png new file mode 100644 index 0000000..5166641 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal19.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal20.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal20.png new file mode 100644 index 0000000..2debf17 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal20.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal21.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal21.png new file mode 100644 index 0000000..57c8436 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal21.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal22.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal22.png new file mode 100644 index 0000000..fb8c413 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal22.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal23.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal23.png new file mode 100644 index 0000000..57c8436 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal23.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal24.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal24.png new file mode 100644 index 0000000..fb8c413 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal24.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal25.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal25.png new file mode 100644 index 0000000..69b4f66 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal25.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal26.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal26.png new file mode 100644 index 0000000..86db6bd Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal26.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal27.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal27.png new file mode 100644 index 0000000..8d660f6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal27.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal28.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal28.png new file mode 100644 index 0000000..048c8ff Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal28.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/normal29.png b/Graphics/Atlases/Gameplay/collectables/keyberry/normal29.png new file mode 100644 index 0000000..60a46f9 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/normal29.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/seed00.png b/Graphics/Atlases/Gameplay/collectables/keyberry/seed00.png new file mode 100644 index 0000000..4f9b55c Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/seed00.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/seed01.png b/Graphics/Atlases/Gameplay/collectables/keyberry/seed01.png new file mode 100644 index 0000000..26d48b1 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/seed01.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/wings00.png b/Graphics/Atlases/Gameplay/collectables/keyberry/wings00.png new file mode 100644 index 0000000..80bda26 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/wings00.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/wings01.png b/Graphics/Atlases/Gameplay/collectables/keyberry/wings01.png new file mode 100644 index 0000000..c1b8c1f Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/wings01.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/wings02.png b/Graphics/Atlases/Gameplay/collectables/keyberry/wings02.png new file mode 100644 index 0000000..a972640 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/wings02.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/wings03.png b/Graphics/Atlases/Gameplay/collectables/keyberry/wings03.png new file mode 100644 index 0000000..c9f06da Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/wings03.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/wings04.png b/Graphics/Atlases/Gameplay/collectables/keyberry/wings04.png new file mode 100644 index 0000000..44114b8 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/wings04.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/wings05.png b/Graphics/Atlases/Gameplay/collectables/keyberry/wings05.png new file mode 100644 index 0000000..006f84f Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/wings05.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/wings06.png b/Graphics/Atlases/Gameplay/collectables/keyberry/wings06.png new file mode 100644 index 0000000..d75b334 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/wings06.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/wings07.png b/Graphics/Atlases/Gameplay/collectables/keyberry/wings07.png new file mode 100644 index 0000000..381e130 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/wings07.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/wings08.png b/Graphics/Atlases/Gameplay/collectables/keyberry/wings08.png new file mode 100644 index 0000000..57e5ce5 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/wings08.png differ diff --git a/Graphics/Atlases/Gameplay/collectables/keyberry/wings09.png b/Graphics/Atlases/Gameplay/collectables/keyberry/wings09.png new file mode 100644 index 0000000..c80ac28 Binary files /dev/null and b/Graphics/Atlases/Gameplay/collectables/keyberry/wings09.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster00.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster00.png new file mode 100644 index 0000000..94dac4b Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster01.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster01.png new file mode 100644 index 0000000..2c8ac93 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster02.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster02.png new file mode 100644 index 0000000..d7922a9 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster03.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster03.png new file mode 100644 index 0000000..3e01b5b Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster04.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster04.png new file mode 100644 index 0000000..2ee0ca1 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster05.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster05.png new file mode 100644 index 0000000..2fa9465 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster06.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster06.png new file mode 100644 index 0000000..2c8ac93 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster06.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster07.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster07.png new file mode 100644 index 0000000..32e4606 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster07.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster08.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster08.png new file mode 100644 index 0000000..bf1da27 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster08.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster09.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster09.png new file mode 100644 index 0000000..fb73fc9 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster09.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster10.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster10.png new file mode 100644 index 0000000..c9601fc Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster10.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster11.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster11.png new file mode 100644 index 0000000..5be8045 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster11.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster12.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster12.png new file mode 100644 index 0000000..e5ac328 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster12.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster13.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster13.png new file mode 100644 index 0000000..c33ab48 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster13.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster14.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster14.png new file mode 100644 index 0000000..1e37135 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster14.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster15.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster15.png new file mode 100644 index 0000000..b2cb7f3 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster15.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster16.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster16.png new file mode 100644 index 0000000..a2d0bf7 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster16.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster17.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster17.png new file mode 100644 index 0000000..8e095e6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster17.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster18.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster18.png new file mode 100644 index 0000000..33041db Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster18.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster19.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster19.png new file mode 100644 index 0000000..a4ad014 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster19.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster20.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster20.png new file mode 100644 index 0000000..2422390 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster20.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster21.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster21.png new file mode 100644 index 0000000..5076762 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster21.png differ diff --git a/Graphics/Atlases/Gameplay/objects/boostBumper/booster22.png b/Graphics/Atlases/Gameplay/objects/boostBumper/booster22.png new file mode 100644 index 0000000..90d37ba Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/boostBumper/booster22.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash00.png new file mode 100644 index 0000000..9934644 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash01.png new file mode 100644 index 0000000..2de17a9 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash02.png new file mode 100644 index 0000000..f6bef24 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash03.png new file mode 100644 index 0000000..3bcbbc3 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash04.png new file mode 100644 index 0000000..341f115 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash05.png new file mode 100644 index 0000000..d74fc71 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/idle00.png new file mode 100644 index 0000000..b747e9c Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/idle01.png new file mode 100644 index 0000000..f6103e7 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/idle02.png new file mode 100644 index 0000000..f6211e0 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/idle03.png new file mode 100644 index 0000000..6ed3690 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/idle04.png new file mode 100644 index 0000000..c1b3a98 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr00.png new file mode 100644 index 0000000..e5f8646 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr01.png new file mode 100644 index 0000000..0825521 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr02.png new file mode 100644 index 0000000..ad99fa7 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr03.png new file mode 100644 index 0000000..fe13563 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr04.png new file mode 100644 index 0000000..cdc65cc Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/fill/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/fill/outline.png new file mode 100644 index 0000000..ae8ec21 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/fill/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash00.png new file mode 100644 index 0000000..2b04224 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash01.png new file mode 100644 index 0000000..39a9259 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash02.png new file mode 100644 index 0000000..9446a9c Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash03.png new file mode 100644 index 0000000..47ba12b Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash04.png new file mode 100644 index 0000000..14bd209 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash05.png new file mode 100644 index 0000000..91d22e4 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle00.png new file mode 100644 index 0000000..8957a3f Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle01.png new file mode 100644 index 0000000..8ee4271 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle02.png new file mode 100644 index 0000000..6a2a6ab Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle03.png new file mode 100644 index 0000000..8cd66c0 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle04.png new file mode 100644 index 0000000..78984ba Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr00.png new file mode 100644 index 0000000..41ca1d1 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr01.png new file mode 100644 index 0000000..b6ca582 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr02.png new file mode 100644 index 0000000..4462895 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr03.png new file mode 100644 index 0000000..eef737f Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr04.png new file mode 100644 index 0000000..8925a69 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/outline.png new file mode 100644 index 0000000..219b726 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/outline_none.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/outline_none.png new file mode 100644 index 0000000..20522cd Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/diag/outline_none.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash00.png new file mode 100644 index 0000000..2b04224 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash01.png new file mode 100644 index 0000000..c9c4395 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash02.png new file mode 100644 index 0000000..5687a36 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash03.png new file mode 100644 index 0000000..3fa2ef6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash04.png new file mode 100644 index 0000000..2317f22 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash05.png new file mode 100644 index 0000000..0da2adb Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle00.png new file mode 100644 index 0000000..2cc158d Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle01.png new file mode 100644 index 0000000..5d8b2b5 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle02.png new file mode 100644 index 0000000..28b87cd Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle03.png new file mode 100644 index 0000000..fa93edc Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle04.png new file mode 100644 index 0000000..cf31b7f Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr00.png new file mode 100644 index 0000000..16a75f6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr01.png new file mode 100644 index 0000000..b622849 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr02.png new file mode 100644 index 0000000..6123967 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr03.png new file mode 100644 index 0000000..579c25a Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr04.png new file mode 100644 index 0000000..b3326f8 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/outline.png new file mode 100644 index 0000000..bbaee2e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/dashless/ortho/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash00.png new file mode 100644 index 0000000..2b04224 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash01.png new file mode 100644 index 0000000..39a9259 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash02.png new file mode 100644 index 0000000..9446a9c Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash03.png new file mode 100644 index 0000000..47ba12b Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash04.png new file mode 100644 index 0000000..14bd209 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash05.png new file mode 100644 index 0000000..91d22e4 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle00.png new file mode 100644 index 0000000..bec70db Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle01.png new file mode 100644 index 0000000..ffbe52f Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle02.png new file mode 100644 index 0000000..f415c5e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle03.png new file mode 100644 index 0000000..944932f Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle04.png new file mode 100644 index 0000000..753893f Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr00.png new file mode 100644 index 0000000..07dab94 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr01.png new file mode 100644 index 0000000..8e72412 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr02.png new file mode 100644 index 0000000..eeacf5e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr03.png new file mode 100644 index 0000000..640039e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr04.png new file mode 100644 index 0000000..941c2cb Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/outline.png new file mode 100644 index 0000000..219b726 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/outline_none.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/outline_none.png new file mode 100644 index 0000000..20522cd Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/diag/outline_none.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash00.png new file mode 100644 index 0000000..2b04224 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash01.png new file mode 100644 index 0000000..c9c4395 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash02.png new file mode 100644 index 0000000..5687a36 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash03.png new file mode 100644 index 0000000..3fa2ef6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash04.png new file mode 100644 index 0000000..2317f22 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash05.png new file mode 100644 index 0000000..0da2adb Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle00.png new file mode 100644 index 0000000..1e3e5be Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle01.png new file mode 100644 index 0000000..c59ca67 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle02.png new file mode 100644 index 0000000..5ebff79 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle03.png new file mode 100644 index 0000000..8cd970b Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle04.png new file mode 100644 index 0000000..4ce8b71 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr00.png new file mode 100644 index 0000000..6732235 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr01.png new file mode 100644 index 0000000..71edae8 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr02.png new file mode 100644 index 0000000..589f151 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr03.png new file mode 100644 index 0000000..810a0b8 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr04.png new file mode 100644 index 0000000..a1901a7 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/outline.png new file mode 100644 index 0000000..bbaee2e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcedash/needdash/ortho/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash00.png new file mode 100644 index 0000000..7e2bd5e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash01.png new file mode 100644 index 0000000..34eacee Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash02.png new file mode 100644 index 0000000..897be49 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash03.png new file mode 100644 index 0000000..d0c2071 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash04.png new file mode 100644 index 0000000..96651d5 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash05.png new file mode 100644 index 0000000..4b4cd03 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash06.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash06.png new file mode 100644 index 0000000..9ab96fd Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash06.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash07.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash07.png new file mode 100644 index 0000000..022e19c Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/flash07.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle00.png new file mode 100644 index 0000000..8ed41cd Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle01.png new file mode 100644 index 0000000..41973fb Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle02.png new file mode 100644 index 0000000..9a6fb49 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle03.png new file mode 100644 index 0000000..32a399d Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr00.png new file mode 100644 index 0000000..fdbeadc Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr01.png new file mode 100644 index 0000000..07a1cf3 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr02.png new file mode 100644 index 0000000..19770d0 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr03.png new file mode 100644 index 0000000..7264298 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/forcejump/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/outline.png new file mode 100644 index 0000000..acb29c3 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/forcejump/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/star/flash00.png new file mode 100644 index 0000000..f021542 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/flash01.meta.yaml b/Graphics/Atlases/Gameplay/objects/crystals/star/flash01.meta.yaml new file mode 100644 index 0000000..ef677be --- /dev/null +++ b/Graphics/Atlases/Gameplay/objects/crystals/star/flash01.meta.yaml @@ -0,0 +1,5 @@ +X: 9 +Y: 9 +Width: 16 +Height: 16 +Premultiplied: false \ No newline at end of file diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/star/flash01.png new file mode 100644 index 0000000..9ce0fa7 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/flash02.meta.yaml b/Graphics/Atlases/Gameplay/objects/crystals/star/flash02.meta.yaml new file mode 100644 index 0000000..8dec2a7 --- /dev/null +++ b/Graphics/Atlases/Gameplay/objects/crystals/star/flash02.meta.yaml @@ -0,0 +1,5 @@ +X: 8 +Y: 7 +Width: 16 +Height: 16 +Premultiplied: false \ No newline at end of file diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/star/flash02.png new file mode 100644 index 0000000..2567022 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/flash03.meta.yaml b/Graphics/Atlases/Gameplay/objects/crystals/star/flash03.meta.yaml new file mode 100644 index 0000000..508e4aa --- /dev/null +++ b/Graphics/Atlases/Gameplay/objects/crystals/star/flash03.meta.yaml @@ -0,0 +1,5 @@ +X: 4 +Y: 4 +Width: 16 +Height: 16 +Premultiplied: false \ No newline at end of file diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/star/flash03.png new file mode 100644 index 0000000..7df05c7 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/flash04.meta.yaml b/Graphics/Atlases/Gameplay/objects/crystals/star/flash04.meta.yaml new file mode 100644 index 0000000..508e4aa --- /dev/null +++ b/Graphics/Atlases/Gameplay/objects/crystals/star/flash04.meta.yaml @@ -0,0 +1,5 @@ +X: 4 +Y: 4 +Width: 16 +Height: 16 +Premultiplied: false \ No newline at end of file diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/star/flash04.png new file mode 100644 index 0000000..093c09d Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/flash05.meta.yaml b/Graphics/Atlases/Gameplay/objects/crystals/star/flash05.meta.yaml new file mode 100644 index 0000000..508e4aa --- /dev/null +++ b/Graphics/Atlases/Gameplay/objects/crystals/star/flash05.meta.yaml @@ -0,0 +1,5 @@ +X: 4 +Y: 4 +Width: 16 +Height: 16 +Premultiplied: false \ No newline at end of file diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/star/flash05.png new file mode 100644 index 0000000..837e513 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idle00.meta.yaml b/Graphics/Atlases/Gameplay/objects/crystals/star/idle00.meta.yaml new file mode 100644 index 0000000..9f9b2df --- /dev/null +++ b/Graphics/Atlases/Gameplay/objects/crystals/star/idle00.meta.yaml @@ -0,0 +1,5 @@ +X: 3 +Y: 3 +Width: 16 +Height: 16 +Premultiplied: false diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/star/idle00.png new file mode 100644 index 0000000..42ce941 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idle01.meta.yaml b/Graphics/Atlases/Gameplay/objects/crystals/star/idle01.meta.yaml new file mode 100644 index 0000000..9f9b2df --- /dev/null +++ b/Graphics/Atlases/Gameplay/objects/crystals/star/idle01.meta.yaml @@ -0,0 +1,5 @@ +X: 3 +Y: 3 +Width: 16 +Height: 16 +Premultiplied: false diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/star/idle01.png new file mode 100644 index 0000000..3ace1de Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idle02.meta.yaml b/Graphics/Atlases/Gameplay/objects/crystals/star/idle02.meta.yaml new file mode 100644 index 0000000..9f9b2df --- /dev/null +++ b/Graphics/Atlases/Gameplay/objects/crystals/star/idle02.meta.yaml @@ -0,0 +1,5 @@ +X: 3 +Y: 3 +Width: 16 +Height: 16 +Premultiplied: false diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/star/idle02.png new file mode 100644 index 0000000..548d7dc Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idle03.meta.yaml b/Graphics/Atlases/Gameplay/objects/crystals/star/idle03.meta.yaml new file mode 100644 index 0000000..9f9b2df --- /dev/null +++ b/Graphics/Atlases/Gameplay/objects/crystals/star/idle03.meta.yaml @@ -0,0 +1,5 @@ +X: 3 +Y: 3 +Width: 16 +Height: 16 +Premultiplied: false diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/star/idle03.png new file mode 100644 index 0000000..5b2fcd4 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idle04.meta.yaml b/Graphics/Atlases/Gameplay/objects/crystals/star/idle04.meta.yaml new file mode 100644 index 0000000..9f9b2df --- /dev/null +++ b/Graphics/Atlases/Gameplay/objects/crystals/star/idle04.meta.yaml @@ -0,0 +1,5 @@ +X: 3 +Y: 3 +Width: 16 +Height: 16 +Premultiplied: false diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/star/idle04.png new file mode 100644 index 0000000..d0b15aa Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr00.png new file mode 100644 index 0000000..7aea7cc Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr01.png new file mode 100644 index 0000000..7ed03d2 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr02.png new file mode 100644 index 0000000..3cd25fd Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr03.png new file mode 100644 index 0000000..821ed86 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr04.png new file mode 100644 index 0000000..ce2c4b5 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/outline.meta.yaml b/Graphics/Atlases/Gameplay/objects/crystals/star/outline.meta.yaml new file mode 100644 index 0000000..9f9b2df --- /dev/null +++ b/Graphics/Atlases/Gameplay/objects/crystals/star/outline.meta.yaml @@ -0,0 +1,5 @@ +X: 3 +Y: 3 +Width: 16 +Height: 16 +Premultiplied: false diff --git a/Graphics/Atlases/Gameplay/objects/crystals/star/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/star/outline.png new file mode 100644 index 0000000..fce7939 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/star/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash00.png new file mode 100644 index 0000000..9934644 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash01.png new file mode 100644 index 0000000..5384615 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash02.png new file mode 100644 index 0000000..d31f140 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash03.png new file mode 100644 index 0000000..c5cd62d Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash04.png new file mode 100644 index 0000000..421b4d4 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash05.png new file mode 100644 index 0000000..55ed890 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle00.png new file mode 100644 index 0000000..c6d2368 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle01.png new file mode 100644 index 0000000..35a3df2 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle02.png new file mode 100644 index 0000000..dc21464 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle03.png new file mode 100644 index 0000000..492e7b7 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle04.png new file mode 100644 index 0000000..6247f3a Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr00.png new file mode 100644 index 0000000..5f83011 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr01.png new file mode 100644 index 0000000..d96965c Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr02.png new file mode 100644 index 0000000..7a592c3 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr03.png new file mode 100644 index 0000000..a683237 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr04.png new file mode 100644 index 0000000..fe469b0 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/down/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/outline.png new file mode 100644 index 0000000..af49550 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/down/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash00.png new file mode 100644 index 0000000..9934644 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash01.png new file mode 100644 index 0000000..353d9bb Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash02.png new file mode 100644 index 0000000..5b8616d Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash03.png new file mode 100644 index 0000000..bfd797e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash04.png new file mode 100644 index 0000000..06a21a9 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash05.png new file mode 100644 index 0000000..3c2da8c Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle00.png new file mode 100644 index 0000000..9295fee Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle01.png new file mode 100644 index 0000000..9ec1aab Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle02.png new file mode 100644 index 0000000..70e8111 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle03.png new file mode 100644 index 0000000..f4dacab Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle04.png new file mode 100644 index 0000000..0e06d3c Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr00.png new file mode 100644 index 0000000..081e5e6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr01.png new file mode 100644 index 0000000..24a9a96 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr02.png new file mode 100644 index 0000000..f4e6aaa Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr03.png new file mode 100644 index 0000000..dfb0576 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr04.png new file mode 100644 index 0000000..dffd10e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/left/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/outline.png new file mode 100644 index 0000000..668ec0a Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/left/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash00.png new file mode 100644 index 0000000..9934644 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash01.png new file mode 100644 index 0000000..82c5518 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash02.png new file mode 100644 index 0000000..daa7ede Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash03.png new file mode 100644 index 0000000..124039c Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash04.png new file mode 100644 index 0000000..28fe508 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash05.png new file mode 100644 index 0000000..26438e6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle00.png new file mode 100644 index 0000000..14a3ba0 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle01.png new file mode 100644 index 0000000..88149a1 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle02.png new file mode 100644 index 0000000..ab3a926 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle03.png new file mode 100644 index 0000000..4f417b4 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle04.png new file mode 100644 index 0000000..a9cf198 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr00.png new file mode 100644 index 0000000..01e4961 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr01.png new file mode 100644 index 0000000..64bfc16 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr02.png new file mode 100644 index 0000000..f866a36 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr03.png new file mode 100644 index 0000000..2848098 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr04.png new file mode 100644 index 0000000..c4f4cb9 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/right/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/outline.png new file mode 100644 index 0000000..025e87a Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/right/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash00.png new file mode 100644 index 0000000..9934644 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash01.png new file mode 100644 index 0000000..f62087b Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash02.png new file mode 100644 index 0000000..1b65c25 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash03.png new file mode 100644 index 0000000..c97f033 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash04.png new file mode 100644 index 0000000..bc6c095 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash05.png new file mode 100644 index 0000000..be30749 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle00.png new file mode 100644 index 0000000..985c104 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle01.png new file mode 100644 index 0000000..130a08c Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle02.png new file mode 100644 index 0000000..d8def9f Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle03.png new file mode 100644 index 0000000..2c5a4dd Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle04.png new file mode 100644 index 0000000..b02139e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr00.png new file mode 100644 index 0000000..6d92f34 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr01.png new file mode 100644 index 0000000..a22aea5 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr02.png new file mode 100644 index 0000000..5458ec9 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr03.png new file mode 100644 index 0000000..03fd658 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr04.png new file mode 100644 index 0000000..c7527e9 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/tele/up/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/outline.png new file mode 100644 index 0000000..86792e1 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/tele/up/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/flash00.png b/Graphics/Atlases/Gameplay/objects/crystals/time/flash00.png new file mode 100644 index 0000000..9934644 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/flash00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/flash01.png b/Graphics/Atlases/Gameplay/objects/crystals/time/flash01.png new file mode 100644 index 0000000..2f76d55 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/flash01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/flash02.png b/Graphics/Atlases/Gameplay/objects/crystals/time/flash02.png new file mode 100644 index 0000000..ff2d83f Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/flash02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/flash03.png b/Graphics/Atlases/Gameplay/objects/crystals/time/flash03.png new file mode 100644 index 0000000..3bcbbc3 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/flash03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/flash04.png b/Graphics/Atlases/Gameplay/objects/crystals/time/flash04.png new file mode 100644 index 0000000..c389fdd Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/flash04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/flash05.png b/Graphics/Atlases/Gameplay/objects/crystals/time/flash05.png new file mode 100644 index 0000000..9850461 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/flash05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idle00.png new file mode 100644 index 0000000..324bd55 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idle01.png new file mode 100644 index 0000000..e7d2e46 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idle02.png new file mode 100644 index 0000000..50866cc Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idle03.png new file mode 100644 index 0000000..a45eac1 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idle04.png new file mode 100644 index 0000000..8956f4a Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idle05.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idle05.png new file mode 100644 index 0000000..022a00f Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idle05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idle06.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idle06.png new file mode 100644 index 0000000..19dce9d Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idle06.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idle07.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idle07.png new file mode 100644 index 0000000..610958d Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idle07.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr00.png new file mode 100644 index 0000000..8b87c92 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr01.png new file mode 100644 index 0000000..cc6c561 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr02.png new file mode 100644 index 0000000..dbb7d66 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr03.png new file mode 100644 index 0000000..6b70d64 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr04.png new file mode 100644 index 0000000..74d8c58 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr05.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr05.png new file mode 100644 index 0000000..80f0158 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr06.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr06.png new file mode 100644 index 0000000..e6ef8aa Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr06.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr07.png b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr07.png new file mode 100644 index 0000000..2a19111 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/idlenr07.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/outline.png b/Graphics/Atlases/Gameplay/objects/crystals/time/outline.png new file mode 100644 index 0000000..29bb352 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/outline.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle00.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle00.png new file mode 100644 index 0000000..0658154 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle01.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle01.png new file mode 100644 index 0000000..2a051b0 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle02.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle02.png new file mode 100644 index 0000000..c9b9069 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle03.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle03.png new file mode 100644 index 0000000..c7e3d94 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle04.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle04.png new file mode 100644 index 0000000..6838f92 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle05.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle05.png new file mode 100644 index 0000000..a9a9096 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle06.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle06.png new file mode 100644 index 0000000..5480ecd Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle06.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle07.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle07.png new file mode 100644 index 0000000..1c46dd7 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idle07.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr00.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr00.png new file mode 100644 index 0000000..b9a4da6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr01.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr01.png new file mode 100644 index 0000000..d3c8aea Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr02.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr02.png new file mode 100644 index 0000000..0a29361 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr03.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr03.png new file mode 100644 index 0000000..c36a222 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr04.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr04.png new file mode 100644 index 0000000..6252091 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr05.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr05.png new file mode 100644 index 0000000..7918b23 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr06.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr06.png new file mode 100644 index 0000000..5362a30 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr06.png differ diff --git a/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr07.png b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr07.png new file mode 100644 index 0000000..01ee003 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/crystals/time/untildash/idlenr07.png differ diff --git a/Graphics/Atlases/Gameplay/objects/customBridge/tile0.png b/Graphics/Atlases/Gameplay/objects/customBridge/tile0.png new file mode 100644 index 0000000..f5efc81 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/customBridge/tile0.png differ diff --git a/Graphics/Atlases/Gameplay/objects/customBridge/tile1.png b/Graphics/Atlases/Gameplay/objects/customBridge/tile1.png new file mode 100644 index 0000000..51a1fe7 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/customBridge/tile1.png differ diff --git a/Graphics/Atlases/Gameplay/objects/customBridge/tile10.png b/Graphics/Atlases/Gameplay/objects/customBridge/tile10.png new file mode 100644 index 0000000..edb1966 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/customBridge/tile10.png differ diff --git a/Graphics/Atlases/Gameplay/objects/customBridge/tile2.png b/Graphics/Atlases/Gameplay/objects/customBridge/tile2.png new file mode 100644 index 0000000..51a1fe7 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/customBridge/tile2.png differ diff --git a/Graphics/Atlases/Gameplay/objects/customBridge/tile3.png b/Graphics/Atlases/Gameplay/objects/customBridge/tile3.png new file mode 100644 index 0000000..2b3084e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/customBridge/tile3.png differ diff --git a/Graphics/Atlases/Gameplay/objects/customBridge/tile4.png b/Graphics/Atlases/Gameplay/objects/customBridge/tile4.png new file mode 100644 index 0000000..dda1050 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/customBridge/tile4.png differ diff --git a/Graphics/Atlases/Gameplay/objects/customBridge/tile5.png b/Graphics/Atlases/Gameplay/objects/customBridge/tile5.png new file mode 100644 index 0000000..b65e89d Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/customBridge/tile5.png differ diff --git a/Graphics/Atlases/Gameplay/objects/customBridge/tile6.png b/Graphics/Atlases/Gameplay/objects/customBridge/tile6.png new file mode 100644 index 0000000..952c018 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/customBridge/tile6.png differ diff --git a/Graphics/Atlases/Gameplay/objects/customBridge/tile7.png b/Graphics/Atlases/Gameplay/objects/customBridge/tile7.png new file mode 100644 index 0000000..6d6bdc3 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/customBridge/tile7.png differ diff --git a/Graphics/Atlases/Gameplay/objects/customBridge/tile8.png b/Graphics/Atlases/Gameplay/objects/customBridge/tile8.png new file mode 100644 index 0000000..c36ff7d Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/customBridge/tile8.png differ diff --git a/Graphics/Atlases/Gameplay/objects/customBridge/tile9.png b/Graphics/Atlases/Gameplay/objects/customBridge/tile9.png new file mode 100644 index 0000000..b1ba288 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/customBridge/tile9.png differ diff --git a/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock00.png b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock00.png new file mode 100644 index 0000000..750743d Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock01.png b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock01.png new file mode 100644 index 0000000..421fd0e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock02.png b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock02.png new file mode 100644 index 0000000..691de23 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock03.png b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock03.png new file mode 100644 index 0000000..3705396 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock04.png b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock04.png new file mode 100644 index 0000000..12f81eb Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock05.png b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock05.png new file mode 100644 index 0000000..d754e1b Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock06.png b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock06.png new file mode 100644 index 0000000..f1866f7 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock06.png differ diff --git a/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock07.png b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock07.png new file mode 100644 index 0000000..7bf9691 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock07.png differ diff --git a/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock08.png b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock08.png new file mode 100644 index 0000000..6f3236b Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock08.png differ diff --git a/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock09.png b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock09.png new file mode 100644 index 0000000..a29f11e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblock09.png differ diff --git a/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblockflash.png b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblockflash.png new file mode 100644 index 0000000..262d96b Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/kaizoBlock/kaizoblockflash.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst00.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst00.png new file mode 100644 index 0000000..bfdb1e6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst01.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst01.png new file mode 100644 index 0000000..1227a90 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst02.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst02.png new file mode 100644 index 0000000..9947ec1 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst03.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst03.png new file mode 100644 index 0000000..0d2ae41 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst04.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst04.png new file mode 100644 index 0000000..73aa630 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst05.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst05.png new file mode 100644 index 0000000..95cefe4 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst06.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst06.png new file mode 100644 index 0000000..55ea1ea Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst06.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst07.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst07.png new file mode 100644 index 0000000..2a16661 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst07.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst08.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst08.png new file mode 100644 index 0000000..7c3fa71 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst08.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst09.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst09.png new file mode 100644 index 0000000..4b86f46 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst09.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst10.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst10.png new file mode 100644 index 0000000..a1816de Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst10.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst11.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst11.png new file mode 100644 index 0000000..04f8de2 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/burst11.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/idle00.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/idle00.png new file mode 100644 index 0000000..7f42a22 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open00.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open00.png new file mode 100644 index 0000000..ea80757 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open01.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open01.png new file mode 100644 index 0000000..658cdeb Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open02.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open02.png new file mode 100644 index 0000000..bb794ff Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open03.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open03.png new file mode 100644 index 0000000..d6aa847 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open04.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open04.png new file mode 100644 index 0000000..1165983 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open05.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open05.png new file mode 100644 index 0000000..af2460c Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open06.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open06.png new file mode 100644 index 0000000..ba2773a Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open06.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open07.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open07.png new file mode 100644 index 0000000..8a7a033 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open07.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open08.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open08.png new file mode 100644 index 0000000..9f313b6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open08.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open09.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open09.png new file mode 100644 index 0000000..b891d87 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open09.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open10.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open10.png new file mode 100644 index 0000000..9f313b6 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/open10.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst00.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst00.png new file mode 100644 index 0000000..301f6bf Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst01.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst01.png new file mode 100644 index 0000000..633b543 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst02.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst02.png new file mode 100644 index 0000000..4efd49c Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst03.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst03.png new file mode 100644 index 0000000..5484932 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst04.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst04.png new file mode 100644 index 0000000..a96be3b Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_burst04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_idle00.png b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_idle00.png new file mode 100644 index 0000000..555eb72 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/lockedIntroCar/wheels_idle00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow00.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow00.png new file mode 100644 index 0000000..8a925d8 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow01.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow01.png new file mode 100644 index 0000000..ef86988 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow02.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow02.png new file mode 100644 index 0000000..a54d2ac Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow03.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow03.png new file mode 100644 index 0000000..78258b5 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow03.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow04.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow04.png new file mode 100644 index 0000000..28120cc Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow04.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow05.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow05.png new file mode 100644 index 0000000..7160760 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow05.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow06.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow06.png new file mode 100644 index 0000000..86566cd Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow06.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow07.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow07.png new file mode 100644 index 0000000..b543929 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/arrow07.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/base.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/base.png new file mode 100644 index 0000000..2d8cebd Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/base.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/base_h.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/base_h.png new file mode 100644 index 0000000..aafb59e Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/base_h.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/base_v.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/base_v.png new file mode 100644 index 0000000..2fa5f66 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/base_v.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/button.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/button.png new file mode 100644 index 0000000..3993609 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/button.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/button_ahorn.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/button_ahorn.png new file mode 100644 index 0000000..26f1025 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/button_ahorn.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/debris00.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/debris00.png new file mode 100644 index 0000000..ccf042b Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/debris00.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/debris01.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/debris01.png new file mode 100644 index 0000000..2dd6ab5 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/debris01.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/debris02.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/debris02.png new file mode 100644 index 0000000..04368d1 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/debris02.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/glow.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/glow.png new file mode 100644 index 0000000..c3d0123 Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/glow.png differ diff --git a/Graphics/Atlases/Gameplay/objects/vitMoveBlock/x.png b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/x.png new file mode 100644 index 0000000..70b129a Binary files /dev/null and b/Graphics/Atlases/Gameplay/objects/vitMoveBlock/x.png differ diff --git a/Graphics/CrystallineHelper/CustomSprites.xml b/Graphics/CrystallineHelper/CustomSprites.xml new file mode 100644 index 0000000..92a694f --- /dev/null +++ b/Graphics/CrystallineHelper/CustomSprites.xml @@ -0,0 +1,45 @@ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + + + +
+ + + + + +
+ + + + + + +
+ + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fecb4f2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2022 vitellary (original project) +Copyright (c) 2022 Communal Helper Team (all other changes) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Loenn/effects/custom_wind_snow.lua b/Loenn/effects/custom_wind_snow.lua new file mode 100644 index 0000000..0745db4 --- /dev/null +++ b/Loenn/effects/custom_wind_snow.lua @@ -0,0 +1,14 @@ +local customWindSnow = {} + +customWindSnow.name = "CrystallineHelper/CustomWindSnow" + +customWindSnow.defaultData = { + colors = "FFFFFF", + alphas = "1", + amount = 240, + speedX = 0.0, + speedY = 0.0, + ignoreWind = false +} + +return customWindSnow diff --git a/Loenn/entities/boost_bumper.lua b/Loenn/entities/boost_bumper.lua new file mode 100644 index 0000000..afe4703 --- /dev/null +++ b/Loenn/entities/boost_bumper.lua @@ -0,0 +1,22 @@ +local utils = require "utils" + +local boostBumper = {} + +boostBumper.name = "vitellary/boostbumper" +boostBumper.depth = 0 + +boostBumper.nodeLimits = {0, 1} +boostBumper.nodeLineRenderType = "line" + +boostBumper.placements = { + name = "boost_bumper" +} + +boostBumper.texture = "objects/boostBumper/booster00" + +function boostBumper.selection(room, entity) + local x, y = entity.x or 0, entity.y or 0 + return utils.rectangle(x - 9, y - 9, 18, 18) +end + +return boostBumper \ No newline at end of file diff --git a/Loenn/entities/custom_prologue_bridge.lua b/Loenn/entities/custom_prologue_bridge.lua new file mode 100644 index 0000000..1d44f7b --- /dev/null +++ b/Loenn/entities/custom_prologue_bridge.lua @@ -0,0 +1,60 @@ +local drawableSprite = require "structs.drawable_sprite" + +local customPrologueBridge = {} + +customPrologueBridge.name = "vitellary/customprologuebridge" +customPrologueBridge.minimumSize = {8, 8} +customPrologueBridge.canResize = {true, false} + +customPrologueBridge.fieldInformation = { + delay = { + minimumValue = 0.0 + }, + speed = { + minimumValue = 0.0 + } +} + +customPrologueBridge.placements = { + { + name = "custom_prologue_bridge", + type = "rectangle", + data = { + width = 8, + height = 8, + flag = "", + activationID = "", + activationIndex = 0, + left = false, + delay = 0.2, + speed = 0.8 + } + } +} + +local tiles = { + "objects/customBridge/tile3", + "objects/customBridge/tile4", + "objects/customBridge/tile5", + "objects/customBridge/tile6", + "objects/customBridge/tile7", + "objects/customBridge/tile8" +} + +function customPrologueBridge.sprite(room, entity) + local w = math.floor((entity.width or 8) / 8) + + local sprites = {} + + for i = 0, w - 1 do + local tileSprite = drawableSprite.fromTexture(tiles[i % 6 + 1], entity) + tileSprite:setJustification(0, 0) + tileSprite:addPosition(i * 8, 0) + + table.insert(sprites, tileSprite) + end + + return sprites +end + +return customPrologueBridge diff --git a/Loenn/entities/fill_crystal.lua b/Loenn/entities/fill_crystal.lua new file mode 100644 index 0000000..0e5291f --- /dev/null +++ b/Loenn/entities/fill_crystal.lua @@ -0,0 +1,24 @@ +local fillCrystal = {} + +fillCrystal.name = "vitellary/fillcrystal" +fillCrystal.depth = -100 + +fillCrystal.fieldInformation = { + respawnTime = { + minimumValue = 0.0 + } +} + +fillCrystal.placements = { + { + name = "fill_crystal", + data = { + oneUse = false, + respawnTime = 2.5 + } + } +} + +fillCrystal.texture = "objects/crystals/fill/idle00" + +return fillCrystal diff --git a/Loenn/entities/flag_sequence_controller.lua b/Loenn/entities/flag_sequence_controller.lua new file mode 100644 index 0000000..59b3968 --- /dev/null +++ b/Loenn/entities/flag_sequence_controller.lua @@ -0,0 +1,20 @@ +local flagSequenceController = {} + +flagSequenceController.name = "vitellary/flagsequencecontroller" +flagSequenceController.depth = -100 + +flagSequenceController.placements = { + { + name = "flag_sequence_controller", + data = { + prefix = "", + state = false, + startNumber = 1, + endNumber = 99 + } + } +} + +flagSequenceController.texture = "ahorn_flagsequencecontroller" + +return flagSequenceController diff --git a/Loenn/entities/force_dash_crystal.lua b/Loenn/entities/force_dash_crystal.lua new file mode 100644 index 0000000..91366f6 --- /dev/null +++ b/Loenn/entities/force_dash_crystal.lua @@ -0,0 +1,139 @@ +local utils = require "utils" +local drawableSprite = require "structs.drawable_sprite" + +local directions = { + ["Right"] = "Right", + ["Down Right"] = "Downright", + ["Down"] = "Down", + ["Down Left"] = "Downleft", + ["Left"] = "Left", + ["Up Left"] = "Upleft", + ["Up"] = "Up", + ["Up Right"] = "Upright", + ["None"] = "None" +} + +local forceDashCrystal = {} + +forceDashCrystal.name = "vitellary/forcedashcrystal" +forceDashCrystal.depth = -100 + +forceDashCrystal.fieldInformation = { + respawnTime = { + minimumValue = 0.0 + }, + direction = { + editable = false, + options = directions + } +} + +forceDashCrystal.placements = {} +for _, dir in pairs(directions) do + local placement = { + name = string.lower(dir), + data = { + oneUse = false, + direction = dir, + respawnTime = 2.5, + needDash = false + } + } + + table.insert(forceDashCrystal.placements, placement) +end + +local crystalSpriteData = { + Right = { + ortho = true, + rotation = 0.5 * math.pi + }, + Downright = { + ortho = false, + rotation = 0.5 * math.pi + }, + Down = { + ortho = true, + rotation = math.pi + }, + Downleft = { + ortho = false, + rotation = math.pi + }, + Left = { + ortho = true, + rotation = -0.5 * math.pi + }, + Upleft = { + ortho = false, + rotation = -0.5 * math.pi + }, + Up = { + ortho = true, + rotation = 0 + }, + Upright = { + ortho = false, + rotation = 0 + }, + None = { + ortho = false, + rotation = 0 + } +} + +local crystalOffsets = { + ortho = { + {x = 0, y = -2}, + {x = -4, y = 2}, + {x = 4, y = 2} + }, + diag = { + {x = 2, y = -2}, + {x = -3, y = -1}, + {x = 1, y = 3} + }, + none = { + {x = 2, y = -2, r = 0}, + {x = 2, y = -2, r = 0.5 * math.pi}, + {x = 2, y = -2, r = math.pi}, + {x = 2, y = -2, r = -0.5 * math.pi} + } +} + +function forceDashCrystal.sprite(room, entity) + local direction = entity.direction or "Right" + local noDirection = direction == "None" + + local data = crystalSpriteData[direction] + + local appearance = entity.needDash and "needdash" or "dashless" + local orientation = data.ortho and "ortho" or "diag" + local texture = string.format("objects/crystals/forcedash/%s/%s/idle00", appearance, orientation) + + local rotation = data.rotation or 0 + + local sprites = {} + + local offsets = noDirection and crystalOffsets.none or data.ortho and crystalOffsets.ortho or crystalOffsets.diag + for _, o in ipairs(offsets) do + local sprite = drawableSprite.fromTexture(texture, entity) + sprite.rotation = o.r or rotation + local cos, sin = math.cos(sprite.rotation), math.sin(sprite.rotation) + + local ox = o.x * cos - o.y * sin + local oy = o.y * cos + o.x * sin + sprite:addPosition(ox, oy) + + table.insert(sprites, sprite) + end + + return sprites +end + +function forceDashCrystal.selection(room, entity) + local x, y = entity.x or 0, entity.y or 0 + return utils.rectangle(x - 8, y - 8, 16, 16) +end + +return forceDashCrystal diff --git a/Loenn/entities/force_jump_crystal.lua b/Loenn/entities/force_jump_crystal.lua new file mode 100644 index 0000000..80ae864 --- /dev/null +++ b/Loenn/entities/force_jump_crystal.lua @@ -0,0 +1,42 @@ +local utils = require "utils" +local drawableSprite = require "structs.drawable_sprite" + +local forceJumpCrystal = {} + +forceJumpCrystal.name = "vitellary/forcejumpcrystal" +forceJumpCrystal.depth = -100 + +forceJumpCrystal.fieldInformation = { + respawnTime = { + minimumValue = 0.0 + } +} + +forceJumpCrystal.placements = { + { + name = "force_jump_crystal", + data = { + oneUse = false, + respawnTime = 2.5, + holdJump = true + } + } +} + +function forceJumpCrystal.sprite(room, entity) + local left = drawableSprite.fromTexture("objects/crystals/forcejump/idle00", entity) + left:addPosition(-4, 0) + + local right = drawableSprite.fromTexture("objects/crystals/forcejump/idle00", entity) + right:addPosition(4, 0) + right:setScale(-1, 1) + + return {left, right} +end + +function forceJumpCrystal.selection(room, entity) + local x, y = entity.x or 0, entity.y or 0 + return utils.rectangle(x - 8, y - 8, 16, 16) +end + +return forceJumpCrystal diff --git a/Loenn/entities/keyberry.lua b/Loenn/entities/keyberry.lua new file mode 100644 index 0000000..78e3f90 --- /dev/null +++ b/Loenn/entities/keyberry.lua @@ -0,0 +1,53 @@ +local utils = require "utils" +local drawableSprite = require "structs.drawable_sprite" + +local keyberry = {} + +keyberry.name = "vitellary/keyberry" +keyberry.depth = -100 + +keyberry.nodeLineRenderType = "fan" +keyberry.nodeLimits = {0, -1} + +keyberry.placements = { + { + name = "normal", + data = { + winged = false + } + }, + { + name = "winged", + data = { + winged = true + } + } +} + +function keyberry.sprite(room, entity) + local winged = entity.winged + + local texture = winged and "collectables/keyberry/wings00" or "collectables/keyberry/normal03" + local sprite = drawableSprite.fromTexture(texture, entity) + if winged then + sprite:addPosition(0, 1) + end + + return sprite +end + +keyberry.nodeTexture = "collectables/keyberry/seed00" + +function keyberry.selection(room, entity) + local x, y = entity.x or 0, entity.y or 0 + local nodes = entity.nodes or {} + + local rects = {} + for _, node in ipairs(nodes) do + table.insert(rects, utils.rectangle(node.x - 5, node.y - 4, 9, 10)) + end + + return utils.rectangle(x - 8, y - 8, 16, 16), rects +end + +return keyberry diff --git a/Loenn/entities/keyberry_with_return.lua b/Loenn/entities/keyberry_with_return.lua new file mode 100644 index 0000000..09527e8 --- /dev/null +++ b/Loenn/entities/keyberry_with_return.lua @@ -0,0 +1,70 @@ +local utils = require "utils" +local drawableSprite = require "structs.drawable_sprite" +local drawableLine = require "structs.drawable_line" + +local returnKeyberry = {} + +returnKeyberry.name = "vitellary/returnkeyberry" +returnKeyberry.depth = -100 + +returnKeyberry.nodeLimits = {2, -1} + +returnKeyberry.placements = { + { + name = "normal", + data = { + winged = false + } + }, + { + name = "winged", + data = { + winged = true + } + } +} + +function returnKeyberry.sprite(room, entity) + local winged = entity.winged + + local texture = winged and "collectables/keyberry/wings00" or "collectables/keyberry/normal03" + local sprite = drawableSprite.fromTexture(texture, entity) + if winged then + sprite:addPosition(0, 1) + end + + return sprite +end + +function returnKeyberry.nodeSprite(room, entity, node, nodeIndex, viewport) + local x, y = entity.x or 0, entity.y or 0 + local nodes = entity.nodes or {{x = 0, y = 0}, {x = 0, y = 0}} + + local bubble = nodeIndex <= 2 + local sprite = drawableSprite.fromTexture(bubble and "characters/player/bubble" or "collectables/keyberry/seed00", node) + + if nodeIndex == 2 then + x, y = nodes[1].x, nodes[1].y + end + local line = drawableLine.fromPoints({x, y, node.x, node.y}, {255 / 255, 0 / 255, 255 / 255, 102 / 255}) + + return {sprite, line} +end + +function returnKeyberry.selection(room, entity) + local x, y = entity.x or 0, entity.y or 0 + local nodes = entity.nodes or {{x = 0, y = 0}, {x = 0, y = 0}} + + local rects = {} + for i, node in ipairs(nodes) do + if i <= 2 then + table.insert(rects, utils.rectangle(node.x - 11, node.y - 11, 23, 23)) + else + table.insert(rects, utils.rectangle(node.x - 5, node.y - 4, 9, 10)) + end + end + + return utils.rectangle(x - 8, y - 8, 16, 16), rects +end + +return returnKeyberry diff --git a/Loenn/entities/locked_intro_car.lua b/Loenn/entities/locked_intro_car.lua new file mode 100644 index 0000000..4b84acf --- /dev/null +++ b/Loenn/entities/locked_intro_car.lua @@ -0,0 +1,45 @@ +local drawableSprite = require "structs.drawable_sprite" +local utils = require "utils" + +local lockedIntroCar = {} + +local bodyTexture = "scenery/car/body" +local wheelsTexture = "scenery/car/wheels" + +lockedIntroCar.name = "vitellary/lockedintrocar" + +lockedIntroCar.placements = { + { + name = "locked_intro_car", + data = {} + } +} + +function lockedIntroCar.sprite(room, entity) + local sprites = {} + + local bodySprite = drawableSprite.fromTexture(bodyTexture, entity) + bodySprite:setJustification(0.5, 1.0) + bodySprite.depth = 1 + + local wheelSprite = drawableSprite.fromTexture(wheelsTexture, entity) + wheelSprite:setJustification(0.5, 1.0) + wheelSprite.depth = 3 + + table.insert(sprites, bodySprite) + table.insert(sprites, wheelSprite) + + return sprites +end + +function lockedIntroCar.selection(room, entity) + local bodySprite = drawableSprite.fromTexture(bodyTexture, entity) + local wheelSprite = drawableSprite.fromTexture(wheelsTexture, entity) + + bodySprite:setJustification(0.5, 1.0) + wheelSprite:setJustification(0.5, 1.0) + + return utils.rectangle(utils.coverRectangles({bodySprite:getRectangle(), wheelSprite:getRectangle()})) +end + +return lockedIntroCar diff --git a/Loenn/entities/star_crystal.lua b/Loenn/entities/star_crystal.lua new file mode 100644 index 0000000..3ecc4cd --- /dev/null +++ b/Loenn/entities/star_crystal.lua @@ -0,0 +1,31 @@ +local starCrystal = {} + +starCrystal.name = "vitellary/starcrystal" +starCrystal.depth = -100 + +starCrystal.fieldInformation = { + time = { + minimumValue = 0.0 + }, + respawnTime = { + minimumValue = 0.0 + } +} + +starCrystal.placements = { + { + name = "star_crystal", + data = { + oneUse = false, + time = 2.0, + changeDashes = true, + changeInvuln = true, + changeStamina = true, + respawnTime = 2.5 + } + } +} + +starCrystal.texture = "objects/crystals/star/idle00" + +return starCrystal diff --git a/Loenn/entities/tele_crystal.lua b/Loenn/entities/tele_crystal.lua new file mode 100644 index 0000000..23aca30 --- /dev/null +++ b/Loenn/entities/tele_crystal.lua @@ -0,0 +1,47 @@ +local directions = { + "Up", + "Down", + "Left", + "Right" +} + +local teleCrystal = {} + +teleCrystal.name = "vitellary/goodtelecrystal" +teleCrystal.depth = -100 + +teleCrystal.fieldInformation = { + respawnTime = { + minimumValue = 0.0 + }, + direction = { + editable = false, + options = directions + } +} + +teleCrystal.placements = {} +for i, dir in ipairs(directions) do + teleCrystal.placements[i] = { + name = string.lower(dir), + data = { + direction = dir, + oneUse = false, + preventCrash = true, + respawnTime = 0.2 + } + } +end + +local crystalTextures = { + ["Right"] = "objects/crystals/tele/right/idle00", + ["Down"] = "objects/crystals/tele/down/idle00", + ["Left"] = "objects/crystals/tele/left/idle00", + ["Up"] = "objects/crystals/tele/up/idle00" +} + +function teleCrystal.texture(room, entity) + return crystalTextures[entity.direction] or crystalTextures["Right"] +end + +return teleCrystal diff --git a/Loenn/entities/time_crystal.lua b/Loenn/entities/time_crystal.lua new file mode 100644 index 0000000..24687d1 --- /dev/null +++ b/Loenn/entities/time_crystal.lua @@ -0,0 +1,49 @@ +local timeCrystal = {} + +timeCrystal.name = "vitellary/timecrystal" +timeCrystal.depth = -100 + +timeCrystal.fieldInformation = { + stopLength = { + minimumValue = 0.0 + }, + respawnTime = { + minimumValue = 0.0 + }, + timeScale = { + minimumValue = 0.0 + } +} + +timeCrystal.placements = { + { + name = "normal", + data = { + oneUse = false, + stopLength = 2.0, + respawnTime = 2.5, + untilDash = false, + immediate = false, + entityTypesToIgnore = "", + timeScale = 0.0 + } + }, + { + name = "until_dash", + data = { + oneUse = false, + stopLength = 2.0, + respawnTime = 2.5, + untilDash = true, + immediate = false, + entityTypesToIgnore = "", + timeScale = 0.0 + } + } +} + +function timeCrystal.texture(room, entity) + return entity.untilDash and "objects/crystals/time/untildash/idle00" or "objects/crystals/time/idle00" +end + +return timeCrystal diff --git a/Loenn/lang/en_gb.lang b/Loenn/lang/en_gb.lang new file mode 100644 index 0000000..678d44f --- /dev/null +++ b/Loenn/lang/en_gb.lang @@ -0,0 +1,204 @@ +mods.vitellary.name=Crystalline +mods.CrystallineHelper.name=Crystalline + + + + +# - Placement names - + +entities.vitellary/boostbumper.placements.name.boost_bumper=Boost Bumper +entities.vitellary/fillcrystal.placements.name.fill_crystal=Fill Crystal +entities.vitellary/customprologuebridge.placements.name.custom_prologue_bridge=Custom Prologue Bridge +entities.vitellary/fillcrystal.placements.name.fill_crystal=Fill Crystal +entities.vitellary/flagsequencecontroller.placements.name.flag_sequence_controller=Flag Sequence Controller +entities.vitellary/forcedashcrystal.placements.name.up=Force Dash Crystal (Up) +entities.vitellary/forcedashcrystal.placements.name.upright=Force Dash Crystal (Up Right) +entities.vitellary/forcedashcrystal.placements.name.right=Force Dash Crystal (Right) +entities.vitellary/forcedashcrystal.placements.name.downright=Force Dash Crystal (Down Right) +entities.vitellary/forcedashcrystal.placements.name.down=Force Dash Crystal (Down) +entities.vitellary/forcedashcrystal.placements.name.downleft=Force Dash Crystal (Down Left) +entities.vitellary/forcedashcrystal.placements.name.left=Force Dash Crystal (Left) +entities.vitellary/forcedashcrystal.placements.name.upleft=Force Dash Crystal (Up Left) +entities.vitellary/forcedashcrystal.placements.name.none=Force Dash Crystal (None) +entities.vitellary/forcejumpcrystal.placements.name.force_jump_crystal=Force Jump Crystal +entities.vitellary/keyberry.placements.name.normal=Keyberry +entities.vitellary/keyberry.placements.name.winged=Keyberry (Winged) +entities.vitellary/returnkeyberry.placements.name.normal=Keyberry With Return +entities.vitellary/returnkeyberry.placements.name.winged=Keyberry With Return (Winged) +entities.vitellary/lockedintrocar.placements.name.locked_intro_car=Locked Intro Car +entities.vitellary/starcrystal.placements.name.star_crystal=Star Crystal +entities.vitellary/goodtelecrystal.placements.name.up=Tele Crystal (Up) +entities.vitellary/goodtelecrystal.placements.name.down=Tele Crystal (Down) +entities.vitellary/goodtelecrystal.placements.name.left=Tele Crystal (Left) +entities.vitellary/goodtelecrystal.placements.name.right=Tele Crystal (Right) +entities.vitellary/timecrystal.placements.name.normal=Time Crystal +entities.vitellary/timecrystal.placements.name.until_dash=Time Crystal (Until Dash) + +triggers.vitellary/bloomstrengthtrigger.placements.name.bloom_strength_trigger=Bloom Strength Trigger +triggers.vitellary/canceltimecrystaltrigger.placements.name.cancel_time_crystal_trigger=Cancel Time Crystal Trigger +triggers.vitellary/custombridgeactivator.placements.name.custom_bridge_activator=Custom Bridge Activator +triggers.vitellary/customwindtrigger.placements.name.custom_wind_trigger=Custom Wind Trigger +triggers.vitellary/editdepthtrigger.placements.name.edit_depth_trigger=Edit Depth Trigger +triggers.vitellary/nodashtrigger.placements.name.no_dash_trigger=No Dash Trigger +triggers.vitellary/nograbtrigger.placements.name.no_grab_trigger=No Grab Trigger +triggers.vitellary/nojumptrigger.placements.name.no_jump_trigger=No Jump Trigger +triggers.vitellary/nomovetrigger.placements.name.no_move_trigger=Player Timestop Trigger +triggers.vitellary/resetdoortrigger.placements.name.reset_door_trigger=Reset Door Trigger +triggers.vitellary/timedfadetrigger.placements.name.timed_fade_trigger=Timed Fade Trigger +triggers.vitellary/triggertrigger.placements.name.coremode=Trigger Trigger (Core Mode) +triggers.vitellary/triggertrigger.placements.name.flag=Trigger Trigger (Flag) +triggers.vitellary/triggertrigger.placements.name.dashing=Trigger Trigger (Dashing) +triggers.vitellary/triggertrigger.placements.name.dashcount=Trigger Trigger (Dash Count) +triggers.vitellary/triggertrigger.placements.name.deathsinroom=Trigger Trigger (Deaths In Room) +triggers.vitellary/triggertrigger.placements.name.deathsinlevel=Trigger Trigger (Deaths In Level) +triggers.vitellary/triggertrigger.placements.name.grabholdable=Trigger Trigger (Holdable Grabbed) +triggers.vitellary/triggertrigger.placements.name.speedx=Trigger Trigger (Horizontal Speed) +triggers.vitellary/triggertrigger.placements.name.speedy=Trigger Trigger (Vertical Speed) +triggers.vitellary/triggertrigger.placements.name.jumping=Trigger Trigger (Jumping) +triggers.vitellary/triggertrigger.placements.name.crouching=Trigger Trigger (Crouching) +triggers.vitellary/triggertrigger.placements.name.timesincemovement=Trigger Trigger (Time Since Player Moved) +triggers.vitellary/triggertrigger.placements.name.onholdableenter=Trigger Trigger (Holdable Entered) +triggers.vitellary/triggertrigger.placements.name.onentitycollide=Trigger Trigger (On Entity Touch) +triggers.vitellary/triggertrigger.placements.name.oninteraction=Trigger Trigger (On Interaction) +triggers.vitellary/triggertrigger.placements.name.onsolid=Trigger Trigger (Touched Solid) +triggers.vitellary/triggertrigger.placements.name.onentityenter=Trigger Trigger (Entity Entered) + +style.effects.CrystallineHelper/CustomWindSnow.name=Custom Wind Snow + + + + +# - Tooltips - + +# Fill Crystal +entities.vitellary/fillcrystal.attributes.description.oneUse=Whether the refill should respawn after being used. +entities.vitellary/fillcrystal.attributes.description.respawnTime=How long (in seconds) after using the crystal for it to respawn. + +# Time Crystal +entities.vitellary/timecrystal.attributes.description.oneUse=Whether the refill should respawn after being used. +entities.vitellary/timecrystal.attributes.description.stopLength=How long (in seconds) the crystal should stop time. +entities.vitellary/timecrystal.attributes.description.respawnTime=How long (in seconds) after using the crystal for it to respawn. +entities.vitellary/timecrystal.attributes.description.immediate=Whether the transition to time stopping should be smooth or instantaneous. +entities.vitellary/timecrystal.attributes.description.entityTypesToIgnore=List of class names for the time crystal to not affect, separated by commas. +entities.vitellary/timecrystal.attributes.description.timeScale=The time scale that the entities should be changed to. + +# Tele Crystal +entities.vitellary/telecrystal.attributes.description.direction=The direction of the crystal. +entities.vitellary/telecrystal.attributes.description.oneUse=Whether the refill should respawn after being used. +entities.vitellary/goodtelecrystal.attributes.description.direction=The direction of the crystal. +entities.vitellary/goodtelecrystal.attributes.description.oneUse=Whether the refill should respawn after being used. +entities.vitellary/goodtelecrystal.attributes.description.preventCrash=If false, the crystal will attempt to move you as far as possible until you collide with a wall, which will crash the game if it never does collide with a wall. +entities.vitellary/goodtelecrystal.attributes.description.respawnTime=How long (in seconds) after using the crystal for it to respawn. + +# Star Crystal +entities.vitellary/starcrystal.attributes.description.oneUse=Whether the refill should respawn after being used. +entities.vitellary/starcrystal.attributes.description.time=How long the effect should last. +entities.vitellary/starcrystal.attributes.description.changeDashes=Whether the crystal should give you infinite dashes. +entities.vitellary/starcrystal.attributes.description.changeInvuln=Whether the crystal should make you invincible. +entities.vitellary/starcrystal.attributes.description.changeStamina=Whether the crystal should give you infinite stamina. +entities.vitellary/starcrystal.attributes.description.respawnTime=How long (in seconds) after using the crystal for it to respawn. + +# Force Dash Crystal +entities.vitellary/forcedashcrystal.attributes.description.oneUse=Whether the refill should respawn after being used. +entities.vitellary/forcedashcrystal.attributes.description.direction=Direction the player is forced to dash. If "None" is selected, the player dashes in the direction they hold. +entities.vitellary/forcedashcrystal.attributes.description.respawnTime=How long (in seconds) after using the crystal for it to respawn. +entities.vitellary/forcedashcrystal.attributes.description.needDash=Whether the crystal should require that you have a dash, and consume a dash when used. + +# Force Jump Crystal +entities.vitellary/forcejumpcrystal.attributes.description.oneUse=Whether the refill should respawn after being used. +entities.vitellary/forcejumpcrystal.attributes.description.respawnTime=How long (in seconds) after using the crystal for it to respawn. +entities.vitellary/forcejumpcrystal.attributes.description.holdJump=Whether the jump should be a full height jump or a short hop. + +# Keyberry +entities.vitellary/keyberry.attributes.description.winged=The keyberry attempts to vertically rise offscreen when the player dashes. + +# Keyberry With Return +entities.vitellary/returnkeyberry.attributes.description.winged=The keyberry attempts to vertically rise offscreen when the player dashes. + +# Linked Move Block +entities.vitellary/vitmoveblock.attributes.description.canSteer=Determines whether the move block can be moved by the player. +entities.vitellary/vitmoveblock.attributes.description.direction=Determines the direction the move block moves in upon activation. +entities.vitellary/vitmoveblock.attributes.description.remote=The group the move block gets activated with. 0 means it's a normal move block. +entities.vitellary/vitmoveblock.attributes.description.canActivate=Determines whether the player is able to activate the block by touching it. +entities.vitellary/vitmoveblock.attributes.description.spritePath=Path for the move block's sprite, relative to Graphics/Atlases/Gameplay. +entities.vitellary/vitmoveblock.attributes.description.moveSpeed=Speed the block will move at. Default is 75. + +# Remote Trigger +entities.vitellary/remotetrigger.attributes.description.value=The Linked Move Block group the trigger activates. + +# Reset Door Trigger +triggers.vitellary/resetdoortrigger.attributes.description.oneUse=Whether the trigger can be used more than once in the room. +triggers.vitellary/resetdoortrigger.attributes.description.animate=Whether doors and keys should animate upon respawning. +triggers.vitellary/resetdoortrigger.attributes.description.onlyInRoom=Whether the trigger should affect keys and doors outside of the current room. + +# Custom Prologue Bridge and Activator +entities.vitellary/customprologuebridge.attributes.description.activationID=The ID used in the Activator to begin crumbling the bridge. Do not reuse IDs throughout the level! +entities.vitellary/customprologuebridge.attributes.description.activationIndex=Used to determine the order the bridges should fall. 0 is the first bridge that collapses. +entities.vitellary/customprologuebridge.attributes.description.left=Whether the bridge should start collapsing from the right side. +entities.vitellary/customprologuebridge.attributes.description.delay=How long to wait after the trigger has been activated / the previous bridge has finished collapsing before beginning to collapse. +entities.vitellary/customprologuebridge.attributes.description.speed=How fast the bridge should crumble. 0.8 is just slow enough that the player can keep up without dashing. +entities.vitellary/customprologuebridge.attributes.description.flag=If the flag is true, the bridge won't appear. +triggers.vitellary/custombridgeactivator.attributes.description.activationID=The ID for the group of bridges the trigger should activate. + +# Custom Wind Trigger +triggers.vitellary/customwindtrigger.attributes.description.speedX=The horizontal speed of the wind. Can be a list of speeds, separated by commas. For reference, normal wind speed is 4, and strong is 8. +triggers.vitellary/customwindtrigger.attributes.description.speedY=The vertical speed of the wind. Can be a list of speeds, separated by commas. For reference, normal wind speed is 4, and strong is 8. +triggers.vitellary/customwindtrigger.attributes.description.alternationSpeed=The time, in seconds, that it takes to switch between speeds if there is a list in either horizontal or vertical speed. Can also be a list of speeds, separated by commas, which will be looped through. +triggers.vitellary/customwindtrigger.attributes.description.catchupSpeed=How fast the wind changes from the previous value. Default is 1. +triggers.vitellary/customwindtrigger.attributes.description.activationType=Special condition for the wind to activate. +triggers.vitellary/customwindtrigger.attributes.description.loop=Whether the wind should loop or just stop at the last values when going through a list of speeds. +triggers.vitellary/customwindtrigger.attributes.description.persist=If true, the wind created will stay after transitioning to a different room or dying. It will still be replaced by other wind triggers. +triggers.vitellary/customwindtrigger.attributes.description.oneUse=Whether the wind trigger should disappear after being used. +triggers.vitellary/customwindtrigger.attributes.description.onRoomEnter=Whether the wind trigger should activate immediately when the player enters its room, regardless of the player position. + +# Custom Wind Snow +effects.CrystallineHelper/CustomWindSnow.attributes.description.colors=List of possible colors the wind particles can have, separated by commas. +effects.CrystallineHelper/CustomWindSnow.attributes.description.alphas=List of alphas associated with each color, separated by commas. If the amount of alphas is not the same as the amount of colors, each particle will just take the value of the first alpha listed. +effects.CrystallineHelper/CustomWindSnow.attributes.description.amount=Amount of particles. Default is 240. +effects.CrystallineHelper/CustomWindSnow.attributes.description.speedX=Horizontal speed that the effect has by default (does not affect gameplay). Current wind strength will be added to it. +effects.CrystallineHelper/CustomWindSnow.attributes.description.speedY=Vertical speed that the effect has by default (does not affect gameplay). Current wind strength will be added to it. +effects.CrystallineHelper/CustomWindSnow.attributes.description.ignoreWind=Whether the effect should change based on current wind. + +# Player Timestop Trigger +triggers.vitellary/nomovetrigger.attributes.description.stopLength=Determines how long the player will be frozen for. + +# Trigger Trigger +triggers.vitellary/triggertrigger.attributes.description.activationType=The condition the trigger checks. If you want to change this, you must update this option, then close and reopen this window, so that the correct options appear.\nFlag: When the flag is true. If the flag is left blank, it will always activate when entered.\nDashing: When the player inside is dashing.\nDash Count: If the player's dash count meets the condition specified.\nDeaths In Room: If the player has died the specified amount of times in the room.\nDeaths In Level: If the player has died the specified amount of times in the entire session.\nHoldable Grabbed: When the player grabs a holdable.\nHorizontal / Vertical Speed: If the player's speed meets the condition specified.\nJumping: When the player jumps.\nCrouching: When the player crouches.\nTime Since Player Moved: If the amount of time the player has stayed perfectly still meets the condition specified.\nHoldable Entered: When a holdable object enters the trigger.\nOn Entity Touch: When the amount of times the player touches the specified type of entity meets the condition specified.\nCore Mode: If the core mode of the level matches the specified mode.\nOn Interaction: When the player interacts (via talk button) with the trigger.\nTouched Solid: If the player is either standing on or grabbing the specified solid, or any solid or platform if none is specified.\nEntity Entered: When the specified type of entity enters the trigger. +triggers.vitellary/triggertrigger.attributes.description.oneUse=Whether the trigger disappears after being used. +triggers.vitellary/triggertrigger.attributes.description.flag=Flag that must be active for the trigger to be used. If left blank, trigger will not require a flag. +triggers.vitellary/triggertrigger.attributes.description.invertFlag=Whether the flag specified should be false instead of true. +triggers.vitellary/triggertrigger.attributes.description.delay=How long to wait after activating the trigger for it to activate the chosen triggers. +triggers.vitellary/triggertrigger.attributes.description.activateOnTransition=If true, then the trigger will activate upon entering the room. +triggers.vitellary/triggertrigger.attributes.description.randomize=If true, the trigger will randomly activate only one of the chosen triggers instead of all of them. +triggers.vitellary/triggertrigger.attributes.description.matchPosition=If enabled, the selected triggers will be moved and resized to match this trigger. Allows triggers that change based on position, such as Light Fade, to work. +triggers.vitellary/triggertrigger.attributes.description.invertCondition=Whether the condition should not be met in order to activate. +triggers.vitellary/triggertrigger.attributes.description.onlyOnEnter=Whether the trigger should only check the condition the first time you enter it, instead of checking every frame you're inside it. +triggers.vitellary/triggertrigger.attributes.description.comparisonType=For numerical comparisons, whether the requirement should be less than, equal to or greater than the specified value. +triggers.vitellary/triggertrigger.attributes.description.absoluteValue=For numerical comparisons, whether the comparison should only consider the absolute value for the requirement. +triggers.vitellary/triggertrigger.attributes.description.deaths=How many times the player needs to have died. Depending on the trigger chosen, will refer to either deaths only within the room (resets upon exiting the room) or total deaths in the level (resets upon restarting chapter / returning to map). +triggers.vitellary/triggertrigger.attributes.description.dashCount=How many dashes the player needs to have. +triggers.vitellary/triggertrigger.attributes.description.requiredSpeed=How much speed the player should have, in pixels/second. Positive means right / down, negative means left / up. Some values to reference:\nDefault walking speed is 90.\nDefault dashing speed is 240.\nDefault hyper speed is 325. +triggers.vitellary/triggertrigger.attributes.description.timeToWait=How long the player needs to wait, in seconds. +triggers.vitellary/triggertrigger.attributes.description.coreMode=Core mode the level needs to be. +triggers.vitellary/triggertrigger.attributes.description.entityType=Class name of the type of entity to check. +triggers.vitellary/triggertrigger.attributes.description.solidType=Class name of the type of solid to check. If left blank, the trigger will allow any solids to be considered. + +# Edit Depth Trigger +triggers.vitellary/editdepthtrigger.attributes.description.depth=New depth to set the entity to. Lower / negative values will make the entities render above others. +triggers.vitellary/editdepthtrigger.attributes.description.entitiesToAffect=The class name of the entity to alter. Can be a comma separated list of multiple entity types as well. +triggers.vitellary/editdepthtrigger.attributes.description.debug=If true, then Celeste will write the names of all entities touching the trigger in the log (can be seen in log.txt immediately), as well as their current depths. Useful to figure out the names of the entities you'd like to affect, though remember to disable the option later. +triggers.vitellary/editdepthtrigger.attributes.description.updateOnEntry=If true, the trigger will affect entities that move into it; otherwise, it will only affect entities that are touching it when the room loads. + +# Bloom Strength Trigger +triggers.vitellary/bloomstrengthtrigger.attributes.description.bloomStrengthFrom=Determines where the bloom strength starts. +triggers.vitellary/bloomstrengthtrigger.attributes.description.bloomStrengthTo=Determines where the bloom strength ends. +triggers.vitellary/bloomstrengthtrigger.attributes.description.positionMode=Determines which direction the bloom strength fades towards. + +# Timed Fade Trigger +triggers.vitellary/timedfadetrigger.attributes.description.time=How long to fade from the From value to the To value. + +# Flag Sequence On Spawn Controller +entities.vitellary/flagsequencecontroller.attributes.description.startNumber=The first number to start the sequence. +entities.vitellary/flagsequencecontroller.attributes.description.endNumber=The final number in the sequence. +entities.vitellary/flagsequencecontroller.attributes.description.prefix=The text that prefixes each flag set. For example, prefix "flagname" with Start Number 8 and End Number 11 will set "flagname_08", "flagname_09", "flagname_10", and "flagname_11" all to the specified state. +entities.vitellary/flagsequencecontroller.attributes.description.state=The state to set all of the flags to. diff --git a/Loenn/triggers/bloom_strength_trigger.lua b/Loenn/triggers/bloom_strength_trigger.lua new file mode 100644 index 0000000..e3c03ee --- /dev/null +++ b/Loenn/triggers/bloom_strength_trigger.lua @@ -0,0 +1,25 @@ +local enums = require "consts.celeste_enums" + +local bloomStrengthTrigger = {} + +bloomStrengthTrigger.name = "vitellary/bloomstrengthtrigger" + +bloomStrengthTrigger.fieldInformation = { + positionMode = { + editable = false, + options = enums.trigger_position_modes + } +} + +bloomStrengthTrigger.placements = { + { + name = "bloom_strength_trigger", + data = { + bloomStrengthFrom = 1.0, + bloomStrengthTo = 1.0, + positionMode = "NoEffect" + } + } +} + +return bloomStrengthTrigger diff --git a/Loenn/triggers/cancel_time_crystal_trigger.lua b/Loenn/triggers/cancel_time_crystal_trigger.lua new file mode 100644 index 0000000..1d29865 --- /dev/null +++ b/Loenn/triggers/cancel_time_crystal_trigger.lua @@ -0,0 +1,12 @@ +local cancelTimeCrystalTrigger = {} + +cancelTimeCrystalTrigger.name = "vitellary/canceltimecrystaltrigger" + +cancelTimeCrystalTrigger.placements = { + { + name = "cancel_time_crystal_trigger", + data = {} + } +} + +return cancelTimeCrystalTrigger diff --git a/Loenn/triggers/custom_bridge_activator.lua b/Loenn/triggers/custom_bridge_activator.lua new file mode 100644 index 0000000..f818ac3 --- /dev/null +++ b/Loenn/triggers/custom_bridge_activator.lua @@ -0,0 +1,14 @@ +local customBridgeActivator = {} + +customBridgeActivator.name = "vitellary/custombridgeactivator" + +customBridgeActivator.placements = { + { + name = "custom_bridge_activator", + data = { + activationID = "" + } + } +} + +return customBridgeActivator diff --git a/Loenn/triggers/custom_wind_trigger.lua b/Loenn/triggers/custom_wind_trigger.lua new file mode 100644 index 0000000..50b849a --- /dev/null +++ b/Loenn/triggers/custom_wind_trigger.lua @@ -0,0 +1,43 @@ +local activationTypes = { + "", + "Seed", + "Strawberry", + "Keyberry", + "Locked Door", + "Refill", + "Jellyfish", + "Theo", + "Core Mode (Hot)", + "Core Mode (Cold)", + "Death" +} + +local customWindTrigger = {} + +customWindTrigger.name = "vitellary/customwindtrigger" + +customWindTrigger.fieldInformation = { + activationType = { + editable = false, + options = activationTypes + } +} + +customWindTrigger.placements = { + { + name = "custom_wind_trigger", + data = { + speedX = "0", + speedY = "0", + alternationSpeed = "0", + catchupSpeed = 1.0, + activationType = "", + loop = true, + persist = false, + oneUse = false, + onRoomEnter = false + } + } +} + +return customWindTrigger diff --git a/Loenn/triggers/edit_depth_trigger.lua b/Loenn/triggers/edit_depth_trigger.lua new file mode 100644 index 0000000..adaa40a --- /dev/null +++ b/Loenn/triggers/edit_depth_trigger.lua @@ -0,0 +1,53 @@ +-- stolen from consts.object_depths.lua, edited to look better in Lönn. +-- see: https://github.com/CelestialCartographers/Loenn/blob/master/src/consts/object_depths.lua +local depths = { + ["BG Terrain (10000)"] = 10000, + ["BG Mirrors (9500)"] = 9500, + ["BG Decals (9000)"] = 9000, + ["BG Particles (8000)"] = 8000, + ["Solids Below (5000)"] = 5000, + ["Below (2000)"] = 2000, + ["NPCs (1000)"] = 1000, + ["Theo Crystal (100)"] = 100, + ["Player (0)"] = 0, + ["Dust (-50)"] = -50, + ["Pickups (-100)"] = -100, + ["Seeker (-200)"] = -200, + ["Particles (-8000)"] = -8000, + ["Above (-8500)"] = -8500, + ["Solids (-9000)"] = -9000, + ["FG Terrain (-10000)"] = -10000, + ["FG Decals (-10500)"] = -10500, + ["Dream Blocks (-11000)"] = -11000, + ["Crystal Spinners (-11500)"] = -11500, + ["Player Dreamdashing (-12000)"] = -12000, + ["Enemy (-12500)"] = -12500, + ["Fake Walls (-13000)"] = -13000, + ["FG Particles (-50000)"] = -50000, + ["Top (-1000000)"] = -1000000, + ["Formation Sequences (-2000000)"] = -2000000, +} + +local editDepthTrigger = {} + +editDepthTrigger.name = "vitellary/editdepthtrigger" + +editDepthTrigger.fieldInformation = { + depth = { + options = depths + } +} + +editDepthTrigger.placements = { + { + name = "edit_depth_trigger", + data = { + depth = -9000, + entitiesToAffect = "Celeste.MoveBlock", + debug = false, + updateOnEntry = false + } + } +} + +return editDepthTrigger diff --git a/Loenn/triggers/no_dash_trigger.lua b/Loenn/triggers/no_dash_trigger.lua new file mode 100644 index 0000000..27f86bf --- /dev/null +++ b/Loenn/triggers/no_dash_trigger.lua @@ -0,0 +1,12 @@ +local noDashTrigger = {} + +noDashTrigger.name = "vitellary/nodashtrigger" + +noDashTrigger.placements = { + { + name = "no_dash_trigger", + data = {} + } +} + +return noDashTrigger diff --git a/Loenn/triggers/no_grab_trigger.lua b/Loenn/triggers/no_grab_trigger.lua new file mode 100644 index 0000000..7207a28 --- /dev/null +++ b/Loenn/triggers/no_grab_trigger.lua @@ -0,0 +1,12 @@ +local noGrabTrigger = {} + +noGrabTrigger.name = "vitellary/nograbtrigger" + +noGrabTrigger.placements = { + { + name = "no_grab_trigger", + data = {} + } +} + +return noGrabTrigger diff --git a/Loenn/triggers/no_jump_trigger.lua b/Loenn/triggers/no_jump_trigger.lua new file mode 100644 index 0000000..8f9dfd8 --- /dev/null +++ b/Loenn/triggers/no_jump_trigger.lua @@ -0,0 +1,12 @@ +local noJumpTrigger = {} + +noJumpTrigger.name = "vitellary/nojumptrigger" + +noJumpTrigger.placements = { + { + name = "no_jump_trigger", + data = {} + } +} + +return noJumpTrigger diff --git a/Loenn/triggers/player_timestop_trigger.lua b/Loenn/triggers/player_timestop_trigger.lua new file mode 100644 index 0000000..62bb237 --- /dev/null +++ b/Loenn/triggers/player_timestop_trigger.lua @@ -0,0 +1,20 @@ +local noMoveTrigger = {} + +noMoveTrigger.name = "vitellary/nomovetrigger" + +noMoveTrigger.fieldInformation = { + stopLength = { + minimumValue = 0.0 + } +} + +noMoveTrigger.placements = { + { + name = "no_move_trigger", + data = { + stopLength = 2.0 + } + } +} + +return noMoveTrigger diff --git a/Loenn/triggers/reset_door_trigger.lua b/Loenn/triggers/reset_door_trigger.lua new file mode 100644 index 0000000..b4490eb --- /dev/null +++ b/Loenn/triggers/reset_door_trigger.lua @@ -0,0 +1,16 @@ +local resetDoorTrigger = {} + +resetDoorTrigger.name = "vitellary/resetdoortrigger" + +resetDoorTrigger.placements = { + { + name = "reset_door_trigger", + data = { + oneUse = false, + animate = true, + onlyInRoom = false + } + } +} + +return resetDoorTrigger diff --git a/Loenn/triggers/timed_fade_trigger.lua b/Loenn/triggers/timed_fade_trigger.lua new file mode 100644 index 0000000..c827617 --- /dev/null +++ b/Loenn/triggers/timed_fade_trigger.lua @@ -0,0 +1,21 @@ +local timedFadeTrigger = {} + +timedFadeTrigger.name = "vitellary/timedfadetrigger" +timedFadeTrigger.nodeLimits = {1, 1} + +timedFadeTrigger.fieldInformation = { + time = { + minimumValue = 0.0 + } +} + +timedFadeTrigger.placements = { + { + name = "timed_fade_trigger", + data = { + time = 1.0 + } + } +} + +return timedFadeTrigger diff --git a/Loenn/triggers/trigger_trigger.lua b/Loenn/triggers/trigger_trigger.lua new file mode 100644 index 0000000..b25c11d --- /dev/null +++ b/Loenn/triggers/trigger_trigger.lua @@ -0,0 +1,152 @@ +local enums = require "consts.celeste_enums" + +local activationTypes = { + ["Flag (Default)"] = "Flag", + ["Dashing"] = "Dashing", + ["Dash Count"] = "DashCount", + ["Deaths In Room"] = "DeathsInRoom", + ["Deaths In Level"] = "DeathsInLevel", + ["Holdable Grabbed"] = "GrabHoldable", + ["Horizontal Speed"] = "SpeedX", + ["Vertical Speed"] = "SpeedY", + ["Jumping"] = "Jumping", + ["Crouching"] = "Crouching", + ["Time Since Player Moved"] = "TimeSinceMovement", + ["Holdable Entered"] = "OnHoldableEnter", + ["On Entity Touch"] = "OnEntityCollide", + ["Core Mode"] = "CoreMode", + ["On Interaction"] = "OnInteraction", + ["Touched Solid"] = "OnSolid", + ["Entity Entered"] = "OnEntityEnter" +} + +local comparisonTypes = { + "LessThan", + "EqualTo", + "GreaterThan" +} + +local triggerTrigger = {} + +triggerTrigger.name = "vitellary/triggertrigger" + +triggerTrigger.nodeLimits = {1, -1} +triggerTrigger.nodeLineRenderType = "fan" + +triggerTrigger.fieldInformation = { + activationType = { + editable = false, + options = activationTypes + }, + comparisonType = { + editable = false, + options = comparisonTypes + }, + coreMode = { + editable = false, + options = enums.core_modes + } +} + +function triggerTrigger.ignoredFields(entity) + local ignored = { + "_id", + "_name", + "comparisonType", + "absoluteValue", + "talkBubbleX", + "talkBubbleY", + "flag", + "deaths", + "dashCount", + "requiredSpeed", + "timeToWait", + "coreMode", + "entityTypeToCollide", + "collideCount", + "solidType", + "entityType" + } + + local function doNotIgnore(value) + for i = #ignored, 1, -1 do + if ignored[i] == value then + table.remove(ignored, i) + return + end + end + end + + local atype = entity.activationType or "Flag" + local iscomparison = false + + if atype == "Flag" then + doNotIgnore("flag") + elseif atype == "DashCount" then + doNotIgnore("dashCount") + iscomparison = true + elseif atype == "DeathsInRoom" or atype == "DeathsInLevel" then + doNotIgnore("deaths") + iscomparison = true + elseif atype == "SpeedX" or atype == "SpeedY" then + doNotIgnore("requiredSpeed") + iscomparison = true + elseif atype == "TimeSinceMovement" then + doNotIgnore("timeToWait") + iscomparison = true + elseif atype == "CoreMode" then + doNotIgnore("coreMode") + elseif atype == "OnEntityCollide" then + doNotIgnore("entityType") + doNotIgnore("collideCount") + iscomparison = true + elseif atype == "OnInteraction" then + doNotIgnore("talkBubbleX") + doNotIgnore("talkBubbleY") + elseif atype == "OnSolid" then + doNotIgnore("solidType") + elseif atype == "OnEntityEnter" then + doNotIgnore("entityType") + end + + if iscomparison then + doNotIgnore("comparisonType") + doNotIgnore("absoluteValue") + end + + return ignored +end + +triggerTrigger.placements = {} +for _, mode in pairs(activationTypes) do + local placement = { + name = string.lower(mode), + data = { + oneUse = false, + flag = "", + invertCondition = false, + delay = 0.0, + activateOnTransition = false, + randomize = false, + matchPosition = true, + activationType = mode, + comparisonType = "EqualTo", + deaths = 0, + dashCount = 0, + requiredSpeed = 0.0, + absoluteValue = false, + timeToWait = 0.0, + coreMode = "None", + entityTypeToCollide = "Celeste.Strawberry", + talkBubbleX = 0, + talkBubbleY = 0, + onlyOnEnter = false, + collideCount = 1, + solidType = "", + entityType = "" + } + } + table.insert(triggerTrigger.placements, placement) +end + +return triggerTrigger diff --git a/README.md b/README.md new file mode 100644 index 0000000..3cdbfca --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Crystalline Helper + +A helper for Celeste. Originally created by vitellary and now maintained by the Communal Helper organization. + +The release build can be downloaded [here](https://gamebanana.com/mods/53760). + +Head to our [issues page](https://github.com/CommunalHelper/CrystallineHelper/issues) to leave a bug report or feature request. \ No newline at end of file diff --git a/everest.yaml b/everest.yaml new file mode 100644 index 0000000..8b47efc --- /dev/null +++ b/everest.yaml @@ -0,0 +1,11 @@ +- Name: CrystallineHelper + Version: 1.12.3 + DLL: Code/bin/vitmod.dll + Dependencies: + - Name: Everest + Version: 1.2002.0 + OptionalDependencies: + - Name: FrostHelper + Version: 1.21.2 + - Name: VivHelper + Version: 1.5.4 \ No newline at end of file