Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Background-based Filter Progression #5762

Merged

Conversation

ThePotatoGuy
Copy link
Member

@ThePotatoGuy ThePotatoGuy commented May 12, 2020

NOTE: there are a lot of changes in sprite-chart, but the only real change is moving MASHighlightMap up to init -10.

Key Changes

  • Sunset filter - set to be duration of 30 minutes, and starts 30 minute before sunset time. This filter is also used as a sunrise for 30 minutes starting at the sunrise time.
  • background-based filters
  • filter-weather mechanics
  • island images are no longer tied to weather

filtering changes and additions

  • Added fallback filter mechanics. This basically means that each filter may have a filter that can be considered its "fallback". The day and night filter are the core filters that can be fallen back to. Each subsequent filter MUST have a fallback to handle cases of sprite objects that do explicit filter-image mapping and do not have an image for a given filter. If a new filter doesn't want to list a fallback, it will be considered a core filter so EVERY sprite must have a version for that filter, no exceptions. All fallbacks are checked on start for circular references.
  • Added sunset filter for all non-UI sprites, except for rain/overcast weather. Its fallback is the day filter. This filter is also used as sunrise.
  • Added various new filter-based displayables and switches:
    • MASDayNightFilterSwitch - filter switch that only switches images based on the day/night aspect of a filter, as determined by the background.
    • MASFallbackFilterDisplayable - dynamic displayable that applies fallback filter mechanics when determinig an image to pass back. This should be used for explicit image-filter mapping.
    • MASFilterWeatherDisplayable - dynamic displayable that maps filter + weather (precip_type) to an image. This can use fallback mechanics if desired. This should be used for explicit image-filter+weather mapping.
    • MASFilterWeatherDisplayableCustom - like MASFilterWeatherDisplayable, but supports a custom select function instead of the standard one.
  • mas_fwm_select - MASFilterWeatherDisplayable select function
  • mas_fbf_select - MASFallbackFilterDisplayable select function
  • mas_sprites.add_filter - added option to setup base (fallback) filter
  • MASFilterMap - made caching and verification params
  • MASFilterMap.verify - verifies filters and raises exceptions upon invalid ones
  • MASFilterMapSimple - wrapper class around MASFilterMap, should be used/extended by all code that wants to leverage simple filter mapping.
  • MASFilterMapFallback - extended class of MASFilterMapSimple, should be used/extended by all code that wants to leverage fallback-based filter mapping

background mechanics

  • New timeslice-based way of dividing a day into filters. Background objects now contain filters in a slice format, which allows for a filter to be given a minimum amount (and optionally maximum) amount of time to be shown for. This is also generated dynamically depending on a user's suntime settings, and is smart enough to remove filters based on available time and priority.
  • Backgrounds are now the main source of truth when determining the current filter. The filter itself remains a private variable in mas_sprites, but is set according to the background's rules.
  • Backgrounds also determine if a filter is considered "day" or "night". This is very background-specific.

class changes and additions

  • MASBackground has been replaced with MASFilterableBackground. MASBackground is now a function that can build an old-style background using the filter-based background mechanics.
  • MASBackgroundFilterSlice - filter representation for backgrounds. this uses caching to avoid too many extra slice objects.
  • MASBackgroundFilterSliceData - wrapper around MASBackgroundFilterSlice that contains timeslice-related data, including position, starting offset, and length.
  • MASBackgroundFilterChunk - grouping of filter slices. Chunks are effectively the suntime slices (midnight to sunrise, sunrise to sunset, sunset to midnight).
  • MASBackgroundFilterManager - manages chunks of filters for a day.
  • default_MBGFM - creates a MASBackgroundFilterManager using default (pre-0.11.3) mechanics.

Structure

The new background structure is as follows:

  • MASFilterableBackground - main background object
    • MASBackgroundFilterManager - manages the filters for this background
      • MASBackgroundFilterChunk - each filter manager contains 3 of these, 1 for each suntime slice.
        • MASBackgroundFilterSliceData - each chunk can contain any number of these. These contain time data for a filter
          • MASBackgroundFilterSlice - the actual filter being organized.

The background filter management system relies on seconds since midnight to determine the appropriate filter to use at a given time. Filter progression occurs when mas_progressFilter is called. The filter time slices should be made when creating the MASFilterableBackground object.

Background images are now stored in a MASFilterWeatherMap inside the MASFilterableBackground. See below for more info.

A day is split into 3 chunks based on suntimes. The chunks are separated with offsets (in seconds) from midnight. Each chunk can contain several slices, which are separated with offsets (in seconds) from the chunk's starting time.

filter slice algorithm

Since suntimes are dynamic, the amount of time each filter slice will actually take is determined dynamically. This is handled via the MASBackgroundFilterChunk.build function:

  1. First, all filter slices are assembled in order with their minimum lengths until the total length exceeds the chunk's length or there are no more slices to assemble with.
  2. If the total length of all slices fits within the chunk's length, skip to step 4.
  3. The remaining slices are added based on priority comparisons. This is done in MASBackgroundFilterChunk._priority_fill. This basically swaps slices from the assembled list to the remaining slice list when something in the remaining slices has a higher priority than one in the assembled list. This is done until all the the slices in the assembled list are the of the highest priority and fit within the chunk's length.
  4. The remaining chunk time is distributed equally among the slices. If a slice reaches its max length, it's extra time is distributed among other slices that have not reached their max length. This process repeats until all the remaining chunk time has been distributed. There will always be at least one slice with no priority (aka priority 11) that can grow infinitely if all the other slices have reached their max length.

filter progression

Filter progression is determined by checking the current time and seeing if it matches the current chunk/slice. If the current time does not belong to the current chunk/slice, progression occurs.

When progression happens, the next chunk/slice is determined by first checking if the chunk should change, then checking for the correct slice to be in. If the chunk does not change, then only the slice progression occurs.

Filters are considered "day" or "night" depending on the MASBackgroundFilterChunk they are in.

There are two main functions for progressing the filter:

  1. MASFilterableBackground.progress - used for actual filter progression
  2. MASFilterableBackground.update - used when we are in init or have reset the suntimes build. This just determines the correct chunk/slice that we should be in and adjusts the MASBackgroundFilterManager accordingly. The progress function should be called after this (via mas_progressFilter) to actually change the global filter.

filter progpoints

The following hooks are available:

  • upon slice change for a specific MASBackgroundFilterChunk
  • upon chunk change for a specific MASBackgroundFilterManager
  • global filter change - mas_background._gbl_flt_change
  • global chunk change - mas_background._gbl_chunk_change

Progpoints do not always run in every circumstances. The rules are as follows:

  • if progression remains in the same chunk:
    1. progpoint in that chunk is ran for every slice change
    2. global progpoint is ran for every slice change
  • if progression moves to the next chunk:
    1. progpoint in the manager is ran for the chunk change
    2. global progpoint is ran for the chunk change
    3. progpoints in the new chunk is ran for every slice change
    4. global progpoint is ran for every slice change in the new chunk.
  • if progression moves through multiple chunks:
    1. progpoint in the manager is ran for every chunk change
    2. global progpoint is ran for every chunk change.
    3. progpoints in the chunk we end up in is ran for every slice change.
    4. global progpoint is ran for for every slice change in the chunk we end up in.
  • if progression changes via updated:
    1. global progpoint is ran for one slice change if the filter changes. This is unique in that it may be called in lieu of a chunk change even if it is a chunk change.

deprecations

  • MASBackground.getDayRoom - replaced with MASFilterableBackground.getDayRooms since there is no longer 1 "day" image.
  • MASBackground.getNightRoom - replaced with MASFilterableBackground.getNightRooms since there is no longer 1 "night" image.

weather changes and additions

  • MASWeather replaced with MASFilterableWeather. MASWeather is now a function that builds old-style weather objects.
  • Weather images now use the MASFallbackFilterDisplayable instead of being defined separately for day and night.
  • Island images have been removed from weather objects. See below for more info.
  • MASFilterableWeather.get_mask returns the appropraite displayable to use, keeping animations into account.
  • mas_weather store changed to init -99.
  • MASWeatherMap - wrapper class around MASHighlightMap that uses precip_types as the keys. Meant for mapping precip_type to values.
  • MASFilterWeatherMap - extension of MASFilterMapSimple that combines filters with MASWeatherMap objects. This should be used for all instances where both filters and precip_type determine a value.

deprecations

  • MASWeather.sp_window - now just passes to MASFilterableWeather.get_mask
  • MASWeather.isbg_window - returns nothing as island images are separate.

island changes

  • new displayable MASIslandBackground - island-specific displayable for dealing with island images with filters + weather. This has handling for if the images could not be decoded and should be used for all island bg images from now on. (This is just a wrapper around DynamicDisplayable).
  • This also means that island images are no longer tied to weather objects.
  • mas_islands_wf - Islands images with frame
  • mas_islands_wof - Islands images without frame
  • mas_islands_snow_wf_mfwm - MASFilterWeatherMap for snow weather, with frame
  • mas_islands_snow_wof_mfwm - MASFilterWeatherMap for snow weather, without frame
  • _mas_islands_select - select function for the MASIslandBackground DynamicDisplayable.
  • mas_island_event.getBackground - changed to work with the new island images

bitmask flag usage

  • added bitmask flags:
    • EV_FLAG_HFM - temporarily hides event from menus
    • EV_FLAG_HFRS - temporarily hides event from random topic selection, starting greeting, random farewell
    • EV_FLAG_HFNAS - combines HFM and HFRS
  • bitmask flags are temporary until restart or flag unset. This allows for doing things like hiding a topic without actually locking it and having to unlock it on next start.
    • NOTE: we should NOT go back and try to make all event that use this if applicable. That kind of change is too risky. We should only try to use this with new events or when substantially fixing old ones.
  • new bitmask functions
    • Event.flag - event object function to add flags
    • Event.unflag - event object function to remove flags
    • Event.anyflags - event object function to check if any given flags are in this event's flags
    • Event.allflags - event object function to check if all given flags are in this event's flags
    • mas_flagEVL - flags an event given EVL and code
    • mas_unflagEVL - unflags an event given EVL and code
  • bitmask checking adding to Event.filterEvents - as param flag_req and flag_ban for required and excluded flags, respectively
  • added EV_FLAG_HFM checks to all calls to Event.filterEvents where appropriate
  • added EV_FLAG_HFRS checks to farewells and greeting filters, as well as random topic selection

other changes

  • Simplified Event.filterEvents to use kw args
  • changed priority of the dev fast farewell to -1 so it always shows in dev mode if its enabled as it should. (caused by the farewell simplification changes)
  • moved ch30_reset code that should have been last to the end of the label
  • fixed mas_changeBackground so it doesn't run exit code if the BG isn't changing.
  • added _mas_game_menu_start and _mas_game_menu_end to run code before and after opening the game menu.

new util functions

  • mas_utils.all_none - new function to check if a dict or list is all full of none values
  • mas_utils.writestack - new function that writes the current stack to mas_log.txt
  • mas_utils.secInDay - returns number of seconds in a day
  • mas_utils.time2sec - converts a datetime.time object into seconds
  • mas_utils.fli_indk - Find List Item IN Dictionary Keys - finds index of an item in a list if it is a key in a dictionary.
  • mas_utils.insert_sort - generalized round of insertion sort that uses a key function to get the sortkey
  • mas_utils.insert_sort_compare - generalized round of insertion sort that uses a compare function
  • mas_utils.insert_sort_keyless - generalized round of insertion sort that assumes the items have natural comparisons
  • mas_utils.nz_count - counts all non-zero values in a list
  • mas_utils.ev_distribute - EVen Distribute - evenly distributes a number value to each space in a list
  • mas_utils.fz_distribute - Flipped Zero Distribute - redistributes values in a unique way. see the docstring for more info
  • mas_utils.ip_distribute - In Place Distribute - Adds values from one list to the other list, matching indexes if available.
  • mas_utils.lo_distribute - LeftOver Distribute - like ev_distribute, except distributes leftovers (value < size of list) as well

Testing

General

  • Verify overall stability:
    • background images should look fine for all filters (day/night/sunset)
    • all weather, animated and static, should look fine for all filters (day/night/sunset) - rain/overcast/thunder do not have sunset variants.
    • Monika sprites should look fine with sunset filter
    • if the suntimes are changed so that the current time will force a filter change, the actual change may occur either right away, after the talk menu has been opened, or after a minute or so of waiting (depends on random chatter freq).
    • the correct filter should be used when starting (aka, no starting in daytime then suddenly it goes dark).
    • there should be no weirdness if the suntimes are set to not have any day time.

Sunset mechanics

  • sunset should start roughly 30 minutes before the sunset time, and end roughly when the sunset time has been reached.
  • sunrise should start at the sunrise time and end roughly 30 minutes after the sunrise time.
  • if suntimes are set to have only 5 minutes of day (the minimum non-zero value possible), the amount of seconds will be split between the day/sunset filters. This means a third of the 5 minutes is sunrise, then day, then sunset.

Islands

  • verify the correct island images are shown in the appropraite weathers
  • verify correct island images with/without frames
  • verify correct island images with different filters. Islands do not have a sunset filter, so the topic should not be available when the filter is sunset

Event changes

  • islands event should be not visible when the sunset filter is active, and become visible again after sunset. This also includes the island greeting if starting in sunset filter. NOTE: This does NOT lock the topic, instead this uses the flags to mark a topic as temporarily hidden.

@ThePotatoGuy ThePotatoGuy added this to the 0.11.3 milestone May 12, 2020
@ThePotatoGuy ThePotatoGuy changed the title Filter-based Backgrounds Background-based Filter Progression May 12, 2020
@ThePotatoGuy ThePotatoGuy added awaiting code review someone needs to check for syntax/logic/indentation errors awaiting testing code needs to be tested labels Jun 23, 2020
@ThePotatoGuy ThePotatoGuy marked this pull request as ready for review June 23, 2020 03:30
@ThePotatoGuy ThePotatoGuy removed awaiting code review someone needs to check for syntax/logic/indentation errors awaiting testing code needs to be tested labels Jun 29, 2020
@ThePotatoGuy ThePotatoGuy merged commit 5911dd3 into Monika-After-Story:content Jun 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants