diff --git a/assets/content/cookbook/Advanced/2.ScriptedClasses.md b/assets/content/cookbook/Advanced/2.ScriptedClasses.md index 2fdee046..a08052c4 100644 --- a/assets/content/cookbook/Advanced/2.ScriptedClasses.md +++ b/assets/content/cookbook/Advanced/2.ScriptedClasses.md @@ -24,25 +24,27 @@ class BallisticSong extends Song { There is a predefined list of classes which the game has set up to be scriptable, and will automatically load and execute when relevant. More of these will be added in the future. -- `funkin.play.song.Song` for providing unique behavior to custom songs, including playing cutscenes and other stuff. See [Scripted Songs](21-scripted-classes/21-01-scripted-songs.md). - - See also [Video Cutscenes](21-scripted-classes/21-03-video-cutscenes.md), [Ingame Cutscenes](21-scripted-classes/21-04-ingame-cutscenes.md), and [Dialogue Cutscenes](21-scripted-classes/21-05-dialogue-cutscenes.md) -- `funkin.play.character.BaseCharacter` for providing unique behavior to custom characters (such as playing custom animations in certain circumstances). See [Scripted Characters](21-scripted-classes/21-05-scripted-characters.md). +- `funkin.play.song.Song` for providing unique behavior to custom songs, including playing cutscenes and other stuff. See [Scripted Songs](3.ScriptedSongs.md). + - See also [Video Cutscenes](6.VideoCutscenes.md), [Ingame Cutscenes](21-scripted-classes/21-04-ingame-cutscenes.md), and [Dialogue Cutscenes](7.DialogueCutscenes.md) +- `funkin.play.character.BaseCharacter` for providing unique behavior to custom characters (such as playing custom animations in certain circumstances). See [Scripted Characters](4.ScriptedCharacters.md). + - Note that you need to choose the correct subclass of this class for the animation type of your character! - - `funkin.play.character.SparrowCharacter` is used for characters that have Sparrow spritesheet animations. - - `funkin.play.character.MultiSparrowCharacter` is used for characters that have several Sparrow spritesheet animations to combine into one character. - - `funkin.play.character.PackerCharacter` is used for characters that have Packer spritesheet animations. - - `funkin.play.character.AnimateAtlasCharacter` is used for characters that have Adobe Animate texture atlases. - - `funkin.play.character.BaseCharacter` has empty stubs for all the rendering and animation handlers, and is only useful for people who want to reimplement their character's animation system by hand. + + - `funkin.play.character.SparrowCharacter` is used for characters that have Sparrow spritesheet animations. + - `funkin.play.character.MultiSparrowCharacter` is used for characters that have several Sparrow spritesheet animations to combine into one character. + - `funkin.play.character.PackerCharacter` is used for characters that have Packer spritesheet animations. + - `funkin.play.character.AnimateAtlasCharacter` is used for characters that have Adobe Animate texture atlases. + - `funkin.play.character.BaseCharacter` has empty stubs for all the rendering and animation handlers, and is only useful for people who want to reimplement their character's animation system by hand. - `funkin.play.stage.Stage` for providing unique behavior to custom stages, such as creating custom moving props and defining when props animate or when sound effects play in sync with the stage. See [Scripted Stages](21-scripted-classes/24-06-scripted-stages.md). - `funkin.ui.story.Level` for providing unique behavior to levels in Story Mode. See [Scripted Story Levels](21-scripted-classes/25-07-scripted-story-levels.md). - `funkin.play.notes.notekind.NoteKind` for providing unique visuals and behavior to certain kinds of notes, which can then be placed in the Chart Editor. See [Custom Note Kinds](21-scripted-classes/26-00-custom-note-kinds.md). - `funkin.play.event.SongEvent` for creating custom Song Events, which you can place in the Chart Editor and which perform game actions when they are reached. See [Custom Song Events](21-scripted-classes/28-00-custom-note-kinds.md) -- `funkin.ui.freeplay.charselect.PlayableCharacter` for providing unique behavior to custom playable characters. See [Scripted Playable Characters](21-scripted-classes/25-10-scripted-playable-characters.md) +- `funkin.ui.freeplay.charselect.PlayableCharacter` for providing unique behavior to custom playable characters. See [Scripted Playable Characters](5.ScriptedPlayableCharacters.md) - `funkin.ui.freeplay.FreeplayStyle` for defining the sprites and colors used by the Freeplay menu when a given character is selected. See [WIP] - `funkin.play.notes.notestyle.NoteStyle` for modifying the behavior of custom note styles. See [WIP] -- `funkin.play.cutscene.dialogue.Conversation` for providing unique behavior to custom dialogue conversations. See [Dialogue Cutscenes](21-scripted-classes/21-05-dialogue-cutscenes.md) -- `funkin.play.cutscene.dialogue.DialogueBox` for providing unique behavior to custom dialogue boxes used in conversations. See [Dialogue Cutscenes](21-scripted-classes/21-05-dialogue-cutscenes.md) -- `funkin.play.cutscene.dialogue.Speaker` for providing unique behavior to custom speakers used in conversations. See [Dialogue Cutscenes](21-scripted-classes/21-05-dialogue-cutscenes.md) +- `funkin.play.cutscene.dialogue.Conversation` for providing unique behavior to custom dialogue conversations. See [Dialogue Cutscenes](7.DialogueCutscenes.md) +- `funkin.play.cutscene.dialogue.DialogueBox` for providing unique behavior to custom dialogue boxes used in conversations. See [Dialogue Cutscenes](7.DialogueCutscenes.md) +- `funkin.play.cutscene.dialogue.Speaker` for providing unique behavior to custom speakers used in conversations. See [Dialogue Cutscenes](7.DialogueCutscenes.md) - `funkin.ui.freeplay.Album` for defining custom behavior for Freeplay Albums. See [WIP] There is also `funkin.modding.module.Module` for custom scripted Modules, which are scripts which receive events everywhere, rather than only in a specific context. See [Scripted Modules](30-scripted-modules/30-00-scripted-modules.md) for more information on how these work. diff --git a/assets/content/cookbook/Intermediate/1.CustomPlayableCharacters.md b/assets/content/cookbook/Intermediate/1.CustomPlayableCharacters.md index b897b6ea..e1db2469 100644 --- a/assets/content/cookbook/Intermediate/1.CustomPlayableCharacters.md +++ b/assets/content/cookbook/Intermediate/1.CustomPlayableCharacters.md @@ -10,27 +10,36 @@ This chapter goes over adding new playable characters to the game, ensuring that In order to make a fleshed out custom character that can be used from Character Select in Friday Night Funkin', you need a large number of textures, animations, and audio tracks: -- A [custom character](../03-custom-characters/03-00-custom-characters.md) +- A [custom character](../Introduction/3.CustomCharacters.md). + - This requires a set of singing animations for the character. -- At least one custom song that uses that character; this can be either [a new song](../02-custom-songs-and-custom-levels/02-02-adding-the-custom-song.md) or a [variation added to an existing song](../02-custom-songs-and-custom-levels/02-05-adding-variations-to-existing-songs.md). +- At least one custom song that uses that character; this can be either [a new song](../Introduction/2.CustomSongs.md#adding-the-custom-song) or a [variation added to an existing song](../Introduction/2.CustomSongs.md#adding-variations-to-existing-songs). + - This requires an instrumental and split vocal tracks. - A pixel icon asset to use for that character's icon in the Character Select grid. + - This supports either a static image or a Sparrow spritesheet (which includes the animation to play when the character is selected). - A namecard asset to use for that character's name above them in the Character Select menu. + - The pixellation effect is done in code so this just needs to be a single static image. - Animations for the character to use in the Character Select menu. + - This is currently hard-coded to use an Adobe Animate texture atlas and cannot use a Sparrow spritesheet. - The character needs animations for unlock, idle, slide in, slide out, select, and deselect. - Assets to use for the character's Girlfriend character to the left of them in the Character Select menu. + - This is currently hard-coded to use an Adobe Animate texture atlas and cannot use a Sparrow spritesheet. - The character needs animations for unlock, idle, slide in, slide out, select, and deselect. - Assets for the character to use on the Freeplay menu. + - This is currently hardcoded to use an Adobe Animate texture atlas. - The character needs animations for leaping in, idle, confirm, and moving to character select. It also optionally has an idle and cartoon animation. - Assets for the character's Freeplay skin and the backing card. + - This requires a variety of assets but can use Boyfriend's as a fallback. - NOTE: This is currently hardcoded to BF or Pico. - Assets for the character's animations in the Results screen. + - Each rank has its own animation and music, but animations can be reused between ranks and results themes can fall back to the default. - Rank animations are Loss, Good, Great, Excellent, Perfect, and Perfect Gold (the base game uses the same animation for Perfect and Perfect Gold) - Each also can take its own music, but you can reuse Boyfriend's as a good placeholder. @@ -196,31 +205,41 @@ A custom playable character requires creating a new JSON file in the `data/chara ``` The available fields are: + - `version`: The version number for the Playable Character data file format. Leave this at `1.0.0`. - `name`: The readable name for the character, used internally. -- `ownedCharacters`: The list of [Characters](../03-custom-characters/03-00-custom-characters.md) this character owns. +- `ownedCharacters`: The list of [Characters](../Introduction/3.CustomCharacters.md) this character owns. + - When determining which songs to display in Freeplay, the game checks for any songs where the player character is in this list and displays those. Songs where the player character is in another array are not displayed. - `showUnownedChars`: If this value is `true`, then songs whose player character is not in any `ownedCharacters` list will be displayed for this character. - `unlocked`: Whether the character is unlocked. - - Create a scripted class for this playable character and override `isUnlocked():Bool` to make this conditional. See [Scripted Playable Characters](21-scripted-classes\21-10-scripted-playable-characters.md) + + - Create a scripted class for this playable character and override `isUnlocked():Bool` to make this conditional. See [Scripted Playable Characters](../Advanced/5.ScriptedPlayableCharacters.md) - `freeplayStyle`: The ID for a Freeplay style to display. + - You can use `"bf"` here to use Boyfriend's Freeplay style as a default, or create a new JSON file in the `data/ui/freeplay/styles` folder (copy the Pico one and edit that). - `freeplayDJ`: Data for how the character displays as the DJ in the Freeplay menu. - `charSelect`: Data for how the character displays in the Character Select menu. - `results`: Data for how the character displays in the Results screen. Freeplay DJ data is structured like so: + - `assetPath`: The folder where the Animate Atlas for this character is located, relative to the `images/` folder. + - Note that Sparrow atlases are not supported for Freeplay animations. - `animations`: A list of animation data for the character. + - Valid animation names include `intro` `idle` `idleEasterEgg` `confirm` `fistPump` `loss` `charSelect` and ` - `charSelect`: A structured data object containing: + - `transitionDelay`: A duration (in seconds) between when the character's transition to Character Select starts and the camera starts to fade. - `fistPump`: A structured data object containing: + - `introStartFrame` The frame number in the `fistPump` animation where the intro animation (which loops until the rank slams down) starts. - `introEndFrame` The frame number in the `fistPump` animation where the intro animation ends. - `loopStartFrame` The frame number in the `fistPump` animation where the follow-up animation starts. - `loopEndFrame` The frame number in the `fistPump` animation where the follow-up animation ends. + - Use `-1` to use the last frame of the specified frame label. - `introBadStartFrame` The frame number in the `loss` animation where the intro animation starts. - `introBadEndFrame` The frame number in the `loss` animation where the intro animation ends. @@ -228,19 +247,26 @@ Freeplay DJ data is structured like so: - `loopBadEndFrame` The frame number in the `loss` animation where the follow-up animation ends. Character Select data is structured like so: + - `position`: The preferred grid square for the character in the Character Select grid. + - `0` represents the top left, `3` represents the middle left, and `8` represents the bottom right. - Characters are evaluated alphabetically, and if the slot is already occupied, they will be shifted over until they fit. - At time of writing (v0.5.1) only 9 total characters can fit in the grid. - `gf`: (NEW with v0.5.1) A structured data object containing: + - `assetPath`: The folder where the Animate Atlas for this character is located, relative to the `images/` folder. + - Note that Sparrow atlases are not supported. - `animInfoPath`: A path to a Flash JSFL file describing character sliding movement. - `visualizer`: Whether the character is hooked up to display a visualizer (like Nene's ABot). + - Check the Nene Character Select FLA to see how to implement this. Results data is structured like so: + - `music`: A structured data object containing: + - `PERFECT_GOLD`: The path to a music track in the `music/` folder. Played during the Perfect rank animation with all SICKs. - `PERFECT`: The path to a music track in the `music/` folder. Played during the Perfect rank animation. - `EXCELLENT`: The path to a music track in the `music/` folder. Played during the Excellent rank animation. @@ -250,6 +276,7 @@ Results data is structured like so: - Make sure to include a metadata file in the folder to tell the game what BPM the song is, and how to loop it. - Include a variation of the track with the suffix `-intro.ogg` to play that track once before playing the main music track. - `perfect`: An array of animation data structures, describing the animation played when the player gets a Perfect rank. + - Data is in the form of an array of animation objects. - You can use Sparrow animations or `animateatlas` sprites. Use `renderType` to tell the game which one to use. - Use `loopFrame` to tell the game which frame to start looping at, or set `looped` to `"false"` to just play the animation once. @@ -258,6 +285,7 @@ Results data is structured like so: - `good`: Data for the animation played when the player gets a Good rank. - `loss`: Data for the animation played when the player gets a Loss rank. - `perfectGold`: Data for the animation played when the player gets a Perfect rank with all SICKs. + - In the base game, this is just the same data as `perfect`, but you can make it different if you like. [^picosource]: diff --git a/assets/content/cookbook/Intermediate/2.CustomNotestyles.md b/assets/content/cookbook/Intermediate/2.CustomNotestyles.md index 3a12978c..331026c7 100644 --- a/assets/content/cookbook/Intermediate/2.CustomNotestyles.md +++ b/assets/content/cookbook/Intermediate/2.CustomNotestyles.md @@ -195,6 +195,7 @@ Below is the "funkin" (aka the default) note style json file `assets/data/notest ``` There is quite a lot to unravel, let's break it all down. + - `version`: The version number for the Note Style data file format. Leave this at `1.0.0`. - `name`: The readable name for the note style, used in places like the Chart Editor. - `author`: The author of the note style, aka the artist who created the assets. @@ -203,6 +204,7 @@ There is quite a lot to unravel, let's break it all down. - See [list of assets](#note-style-assets) that you can provide the data for. Asset data is structured like so: + - `assetPath`: The main asset path to use for this asset. - `scale`: Specify the size of the asset relative to the original size. For example, `2.0` makes the sprite twice as big. Defaults to `1.0` if unspecified. - `offsets`: Some animations may need their positions to be corrected relative to the idle animation. @@ -211,6 +213,7 @@ Asset data is structured like so: - `data`: The structure of note style asset data objects that depends on the asset you are going to edit. Note Style Asset data is structured like so: + - For `note`: List of animation data for the `left`, `down`, `up` and `right` arrows. - For `noteStrumline`: List of animation data for each direction and it's variations, such as `Static`, `Press`, `Confirm`, `ConfirmHold` replacing `` with it's each and every corresponding direction. - As you may see from the [example](#note-style-data)[^notestylesource] that was given, animation data for the `confirm` and `confirmHold` match up, however you can make it have unique animations. @@ -221,6 +224,7 @@ Note Style Asset data is structured like so: - `enabled`: Specify whether to display the asset. Optional, defaults to `true`. Animation data is structured like so: + - `prefix`: The animation name as specified by your spritesheet. - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. diff --git a/assets/content/cookbook/Intermediate/3.CustomStickerPacks.md b/assets/content/cookbook/Intermediate/3.CustomStickerPacks.md index b13b5813..1b0db62b 100644 --- a/assets/content/cookbook/Intermediate/3.CustomStickerPacks.md +++ b/assets/content/cookbook/Intermediate/3.CustomStickerPacks.md @@ -33,15 +33,17 @@ Below is the "default" sticker pack JSON file `assets/data/stickerpacks/default. Let's break it all down. - `version`: The version number for the Sticker Pack data file format. Leave this at `1.0.0`. - - This will increase if the data file format changes, and tell the game whether additional processing needs to be done for backwards compatibility. + + - This will increase if the data file format changes, and tell the game whether additional processing needs to be done for backwards compatibility. - `name`: The readable name for the sticker pack, used in places like the Chart Editor. - `author`: The author of the sticker pack, aka the artist who created the assets. - `stickers`: A list of all the paths for all the stickers to use, as strings. - - You cannot currently specify any additional arguments, such as scale, offsets, texture smoothing, or animations. + + - You cannot currently specify any additional arguments, such as scale, offsets, texture smoothing, or animations. # Modifying an Existing Sticker Pack -You can use the [JSONPatch](../10-appending-and-merging-files/10-02-merging-files.md) feature to add or remove stickers from an existing sticker pack. +You can use the [JSONPatch](../Introduction/5.AppendingAndMerge.md#merging) feature to add or remove stickers from an existing sticker pack. For example, to add to Boyfriend's standard sticker pack, you can use the following JSON Patch file (placed in `mods/mymod/_merge/data/stickerpacks/standard-bf.json`, use a different file path to patch a different sticker pack): @@ -56,7 +58,7 @@ For example, to add to Boyfriend's standard sticker pack, you can use the follow There are two ways the game defines a given sticker pack to be used: -- Each [Playable Character](../05-custom-playable-characters/05-00-custom-playable-characters.md) defines the `stickerPack` variable, which specifies the sticker pack to be used by songs containing that character. For example, `bf` uses the `standard-bf` sticker pack. You can define a sticker pack to be used for your custom playable character by setting the `stickerPack` value, or modify which sticker pack is used by other playable characters by using [JSONPatch](../10-appending-and-merging-files/10-02-merging-files.md) to modify the `stickerPack` value of that character. +- Each [Playable Character](1.CustomPlayableCharacters.md) defines the `stickerPack` variable, which specifies the sticker pack to be used by songs containing that character. For example, `bf` uses the `standard-bf` sticker pack. You can define a sticker pack to be used for your custom playable character by setting the `stickerPack` value, or modify which sticker pack is used by other playable characters by using [JSONPatch](../Introduction/5.AppendingAndMerge.md#merging) to modify the `stickerPack` value of that character. - Each song has a value in its metadata to define which sticker pack is used. Set the `playData.stickerPack` on a song (or use JSONPatch to modify metadata of an existing song) to override which sticker pack it uses. The game checks and uses sticker packs in this order: diff --git a/assets/content/cookbook/Intermediate/4.Migration.md b/assets/content/cookbook/Intermediate/4.Migration.md index 011be69a..988d9976 100644 --- a/assets/content/cookbook/Intermediate/4.Migration.md +++ b/assets/content/cookbook/Intermediate/4.Migration.md @@ -44,7 +44,7 @@ In your mod's `_merge` folder, look for any `json` files and rewrite their conte ] ``` -More information about this new system can be found at [Merging Files](../10-appending-and-merging-files/10-02-merging-files.md). +More information about this new system can be found at [Merging Files](../Introduction/5.AppendingAndMerge.md#merging). ## Removal of Flixel UI @@ -69,7 +69,7 @@ Once all the migration steps above have been performed, the last step is to modi } ``` -NOTE: For versions of Friday Night Funkin' between v0.3.0 and v0.4.1, the modding system always looked for `"0.1.0"` for the `api_version` and refused to load the mod in all other cases. With the v0.5.0 update, this version will now change to match the game version with every update, but only breaking changes will forcibly disable mods. Those breaking changes will be documented on this page. +> NOTE: For versions of Friday Night Funkin' between v0.3.0 and v0.4.1, the modding system always looked for `"0.1.0"` for the `api_version` and refused to load the mod in all other cases. With the v0.5.0 update, this version will now change to match the game version with every update, but only breaking changes will forcibly disable mods. Those breaking changes will be documented on this page. # Migrating from v0.5.0 to v0.6.3 @@ -137,6 +137,6 @@ if (Std.isOfType(currentState, OptionsState)) { v0.6.0 rewrote how stickers get used by the game (and v0.6.3 rewrote it again but better this time). Any existing mods that provided stickers will probably break. -New or updating mods looking to add, remove, or replace stickers should consult the [custom Sticker Packs documentation](../07-custom-sticker-packs/07-00-custom-sticker-packs.md) +New or updating mods looking to add, remove, or replace stickers should consult the [custom Sticker Packs documentation](3.CustomStickerPacks.md) > Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file diff --git a/assets/content/cookbook/Introduction/2.CustomSongs.md b/assets/content/cookbook/Introduction/2.CustomSongs.md index 9c1a9b85..b7e6889e 100644 --- a/assets/content/cookbook/Introduction/2.CustomSongs.md +++ b/assets/content/cookbook/Introduction/2.CustomSongs.md @@ -36,7 +36,7 @@ To add the song to our mod, we need to get that info out. This is fairly easy, b # Adding The Custom Song -At the end of [Creating A Chart](02-01-creating-a-chart.md) we learned that `.fnfc` files were just `.zip` archives, so we can simply rename it and unzip it. Once we have thse files, we just need to put them in the correct spots in our mod folder! +At the end of [Creating A Chart](#creating-a-chart) we learned that `.fnfc` files were just `.zip` archives, so we can simply rename it and unzip it. Once we have thse files, we just need to put them in the correct spots in our mod folder! - The `manifest.json` file can be discarded, our mod won't need it. diff --git a/assets/content/cookbook/Introduction/3.CustomCharacters.md b/assets/content/cookbook/Introduction/3.CustomCharacters.md index 6b01f1bd..6114acd5 100644 --- a/assets/content/cookbook/Introduction/3.CustomCharacters.md +++ b/assets/content/cookbook/Introduction/3.CustomCharacters.md @@ -115,62 +115,73 @@ The available fields are: - `version`: The version number for the Character data file format. Leave this at `1.0.0`. - `name`: The readable name for the character, used in places like the Chart Editor. - `renderType`: The render type. One of `sparrow`, `packer`, `animateatlas`, `multisparrow`. + - `assetPath`: The main asset path to use for this character, relative to the `images` directory in your mod folder. - - For the `sparrow` asset type, this must point to the path where the `xml` and `png` are located, without the file extension. - - For the `packer` asset type, this must point to the path where the `txt` and `png` are located, without the file extension. - - For the `animateatlas` asset type, this must point to the folder where the `Animation.json` and any spritemaps are located. - - For the `multisparrow` asset type, point to the path where your main Sparrow spritesheet is located. On each animations which uses a different Sparrow spritesheet from the main one, add the `assetPath` key to that specific animation. + + - For the `sparrow` asset type, this must point to the path where the `xml` and `png` are located, without the file extension. + - For the `packer` asset type, this must point to the path where the `txt` and `png` are located, without the file extension. + - For the `animateatlas` asset type, this must point to the folder where the `Animation.json` and any spritemaps are located. + - For the `multisparrow` asset type, point to the path where your main Sparrow spritesheet is located. On each animations which uses a different Sparrow spritesheet from the main one, add the `assetPath` key to that specific animation. - `scale` *(currently buggy)*: Specify the size of the character relative to the original size. For example, `2.0` makes the sprite twice as big. Optional, defaults to `1.0`. - `healthIcon`: Data for the health icon to display in-game. For example, Boyfriend will obviously use Boyfriend's health icon. Optional, defaults its ID to character's ID. - `death`: Data for the death screen to use, when the character reaches `0` health. Optional, doesn't default to a specific object. - `offsets`: The global offset to the character's position, in pixels. Optional, defaults to `[0, 0]`. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. + + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `cameraOffsets`: The amount to offset the camera by while focusing on the character. Optional, default value focuses on the character directly. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. + + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `isPixel`: Specify whether to disable texture smoothing for the character. Optional, defaults to `false`. - `danceEvery`: The frequency at which the character will play its idle animation, in beats. Optional, defaults to `1`. - - Increasing this number will make the character dance less often. + + - Increasing this number will make the character dance less often. - `flipX`: Whether to flip the whole sprite horizontally in-game. Useful for characters that could also be played (Pico). Optional, defaults to `false`. - `startingAnimation`: The animation for the character to play when they are first loaded in. Optional, defaults to `idle`. - `singTime`: The amount of time, in steps, for a character to keep singing after they let go of a note. Optional, defaults to `8`. - - Decrease this if the character seems to hold their poses for too long after their section is done. - - Increase this if the character resets to the idle animation in the middle of their singing animations. + + - Decrease this if the character seems to hold their poses for too long after their section is done. + - Increase this if the character resets to the idle animation in the middle of their singing animations. - `animations`: A list of animation data objects for the character. Health Icon data is structured like so: - - `id`: The ID to use for the health icon, defaults to character's ID. - - `scale`: Specify the size of the health icon relative to the original size. For example, `2.0` makes the sprite twice as big. Optional, defaults to `1.0`. - - `flipX`: Whether to flip the whole sprite horizontally in-game. Optional, defaults to `false`. - - `isPixel`: Specify whether to disable texture smoothing for this characters health icon. Optional, defaults to `false`. - - `offsets`: The offset of the health icon, in pixels. Optional, defaults to `[0, 0]`. +- `id`: The ID to use for the health icon, defaults to character's ID. +- `scale`: Specify the size of the health icon relative to the original size. For example, `2.0` makes the sprite twice as big. Optional, defaults to `1.0`. +- `flipX`: Whether to flip the whole sprite horizontally in-game. Optional, defaults to `false`. +- `isPixel`: Specify whether to disable texture smoothing for this characters health icon. Optional, defaults to `false`. +- `offsets`: The offset of the health icon, in pixels. Optional, defaults to `[0, 0]`. + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. Death data is structured like so: - - `cameraOffsets`: The amount to offset the camera by while focusing on this character as they die. Optional, defaults to `[0, 0]`. +- `cameraOffsets`: The amount to offset the camera by while focusing on this character as they die. Optional, defaults to `[0, 0]`. + - Default value focuses on the character's graphic midpoint. - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - - `cameraZoom`: The amount to zoom the camera by while focusing on this character as they die. Optional, defaults to `1`. - - `preTransitionDelay`: The delay between when the character reaches `0` health and when the death animation plays. Optional, defaults to `0`. +- `cameraZoom`: The amount to zoom the camera by while focusing on this character as they die. Optional, defaults to `1`. +- `preTransitionDelay`: The delay between when the character reaches `0` health and when the death animation plays. Optional, defaults to `0`. Animation data is structured like so: - `name`: The internal animation name for the game to use. - `prefix`: The animation name as specified by your spritesheet. - - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. - - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. + + - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. + - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. - `offsets`: Some animations may need their positions to be corrected relative to the idle animation. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. + + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `looped`: Whether to loop this animation in-game. If false, the animation will pause when it ends, until the game commands the character to do something else. - `flipX`: Whether to flip the sprites of this animation horizontally in-game. - `flipY`: Whether to flip the sprites of this animation vertically in-game. - `frameRate`: A frame rate value, defaulting to `24`. - `frameIndices`: Optionally specify an array of frame numbers (starting at frame 0!) to use from a given prefix for this animation. - - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. + + - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. - `assetPath`: For the `multisparrow` asset type specifically. Define a secondary Sparrow spritesheet which will be loaded, and which contains the frames for this animation. @@ -181,9 +192,11 @@ The animation names the game uses by default are: - `singLEFT`, `singDOWN`, `singUP`, `singRIGHT`: The animations for playing notes, when the character is a player or opponent. - `singLEFTmiss`, `singDOWNmiss`, `singUPmiss`, `singRIGHTmiss`: The animations for missing notes, when the character is a player. - Adding a new singing animation with the name of an existing animation with `-hold` at the end will play the animation after the first one ends, while the character is still singing. - - As a good example, you can copy the `singLEFT` animation to make a `singLEFT-hold` animation, which has `looped` as true and `frameIndices` as the last few frames of the singing animation. + + - As a good example, you can copy the `singLEFT` animation to make a `singLEFT-hold` animation, which has `looped` as true and `frameIndices` as the last few frames of the singing animation. - Adding a new singing animation with the name of an existing animation with `-end` at the end will play an animation before returning to idle. - - For example, you can define a new `singLEFT-end` animation to cleanly transition into the idle animation. + + - For example, you can define a new `singLEFT-end` animation to cleanly transition into the idle animation. - You can add other animations by name, but you'll have to play them with a script, or a `Play Animation` song event in the Chart Editor. When the game starts, it queries the list of possible characters by searching in the `data/characters` folder for JSON files. This gets used to preload data which is used later when the character is loaded in a stage. @@ -227,6 +240,6 @@ The UI will show you all of the possible controls and shortcuts, to make your pr Once you are happy with your result, simply press `ESC` on your keyboard to save the `Character Data` file. - Currently there is a bug which makes the file saving system not automatically put character's ID in the file name, which you will have to do yourself. Simply name the file the ID of your character followed by `.json`. -From the beginning of this chapter you will know, that you have to place this character data JSON file in `data/characters`. Then, you can simply use [Hot Reloading](#stub) to check the offsets without restarting the game. +From the beginning of this chapter you will know, that you have to place this character data JSON file in `data/characters`. Then, you can simply use [Hot Reloading](../Introduction/1.Introduction.md#hot-reloading) to check the offsets without restarting the game. > Author: [EliteMasterEric](https://github.com/EliteMasterEric) \ No newline at end of file diff --git a/assets/content/cookbook/Introduction/4.CustomStages.md b/assets/content/cookbook/Introduction/4.CustomStages.md index 1be926c0..03f9d13f 100644 --- a/assets/content/cookbook/Introduction/4.CustomStages.md +++ b/assets/content/cookbook/Introduction/4.CustomStages.md @@ -71,6 +71,7 @@ Below is the "Main Stage" json file from Week 1 `assets/data/stages/mainStage.js ``` The available fields are: + - `version`: The version number for the Stage data file format. Leave this at `1.0.1`. - `name`: The readable name for the stage, used in places like the Chart Editor. - `cameraZoom`: The default camera zoom level for the stage. Optional, defaults to `1.0`. @@ -78,6 +79,8 @@ The available fields are: - `characters`: Data on how characters in the stage should be positioned. Stage prop data is structured like so: + + - `name`: An internal name for this prop. Good for keeping track of things. Keep each prop name unique! - You can access a stage prop in a script using `PlayState.instance.currentStage.getNamedProp(name)`. - `assetPath`: The asset used to display the prop. This can be either an image or a color. @@ -90,77 +93,95 @@ Stage prop data is structured like so: - `scale`: Specify the size of the prop relative to the original size. For example, `2.0` makes the sprite twice as big. Defaults to `1.0` if unspecified. - `alpha`: Specify the opacity of the prop, with `1.0` being fully opaque and `0.0` being completely transparent. Optional, defaults to `1.0`. - `scroll`: Specify how much scroll factor, or how much the prop moves relative to the camera horizontally and vertically. Defaults to `[0.0, 0.0]` if unspecified. - - A value of `[0, 0]` causes the prop to not move at all in relation to the camera. - - A value of `[1, 1]` causes the prop to move 1-to-1 with the camera. Characters usually have a scroll factor of `[1, 1]`. - - A value of `[0, 1]` causes the prop to only move vertically in relation to the camera as focus changes. - - A value of `[0.5, 0.5]` causes the prop to move less relative to props configured to move 1-to-1 - - A value of `[2, 2]` is valid and causes the prop to move 2-to-1 as the camera moves. + + - A value of `[0, 0]` causes the prop to not move at all in relation to the camera. + - A value of `[1, 1]` causes the prop to move 1-to-1 with the camera. Characters usually have a scroll factor of `[1, 1]`. + - A value of `[0, 1]` causes the prop to only move vertically in relation to the camera as focus changes. + - A value of `[0.5, 0.5]` causes the prop to move less relative to props configured to move 1-to-1 + - A value of `[2, 2]` is valid and causes the prop to move 2-to-1 as the camera moves. - `animType`: If the prop you choose is animated, specify `sparrow` or `packer` for which animation type you're using. - - Most of the game's spritesheets are Sparrow v2 sheets exported from Adobe Animate. + + - Most of the game's spritesheets are Sparrow v2 sheets exported from Adobe Animate. - `animations`: A list of animation data objects for the stage prop. - `startingAnimation`: The animation to play on the prop when the stage starts. If the animation is configured to loop, it will play forever unless a script calls a different one (or `danceEvery` is greater than 0). If unspecified, no animation will play unless a script does so. - `danceEvery`: If non-zero, this prop will play an animation every X beats of the song. Defaults to `0.0`, or no bopping. - - This tries to play the `idle` animation. - - If `danceLeft` and `danceRight ` animations are specified, the game will alternate between these instead. - - This value supports precision up to `0.25`, where `0.25` plays the animation four times per beat. + + - This tries to play the `idle` animation. + - If `danceLeft` and `danceRight ` animations are specified, the game will alternate between these instead. + - This value supports precision up to `0.25`, where `0.25` plays the animation four times per beat. Stage prop animation data is structured like so: + - `name`: The internal animation name for the game to use. - `prefix`: The animation name as specified by your spritesheet. - - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. - - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. + + - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. + - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. - `offsets`: Some animations may need their positions to be corrected relative to the idle animation. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. + + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `looped`: Whether to loop this animation in-game. If false, the animation will pause when it ends, until the game commands the character to do something else. - `flipX`: Whether to flip the sprites of this animation horizontally in-game. - `flipY`: Whether to flip the sprites of this animation vertically in-game. - `frameRate`: A frame rate value, defaulting to `24`. - `frameIndices`: Optionally specify an array of frame numbers (starting at frame 0!) to use from a given prefix for this animation. - - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. + + - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. - `assetPath`: For the `multisparrow` asset type specifically. Define a secondary Sparrow spritesheet which will be loaded, and which contains the frames for this animation. Character data is structured like so: + - `bf`: Data about the stage's player character. - - `zIndex`: A value describing the relative position of the player character. Elements with higher values get placed in front of those with lower values. - - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. - - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. - - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. + + - `zIndex`: A value describing the relative position of the player character. Elements with higher values get placed in front of those with lower values. + - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. + - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. + - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. - `dad`: Data about the stage's opponent character. - - `zIndex`: A value describing the relative position of the opponent character. Elements with higher values get placed in front of those with lower values. - - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. - - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. - - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. + + - `zIndex`: A value describing the relative position of the opponent character. Elements with higher values get placed in front of those with lower values. + - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. + - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. + - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. - `gf`: Data about the stage's background character. - - `zIndex`: A value describing the relative position of the background character. Elements with higher values get placed in front of those with lower values. - - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. - - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. - - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. + + - `zIndex`: A value describing the relative position of the background character. Elements with higher values get placed in front of those with lower values. + - `position`: The X and Y position where the character should be positioned, relative to other props in the stage. + - `scale`: The relative scale to display the character at. For example, `0.5` makes the character half as big as the default. + - `cameraOffsets`: When the camera focuses on this character, focus on the character's center, then apply camera offsets to shift the camera focus to the desired spot. Animation data is structured like so: + - `name`: The internal animation name for the game to use. - `prefix`: The animation name as specified by your spritesheet. - - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. - - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. + + - For Sparrow or Packer, check inside the data file to see what each set of frames is named, and use that as the prefix, excluding the frame numbers at the end. + - For Animate Atlases, use either the frame label or the symbol name of the animation you want to play. - `offsets`: Some animations may need their positions to be corrected relative to the idle animation. - - Use an array of two decimal values, the first for horizontal position and the second for vertical position. + + - Use an array of two decimal values, the first for horizontal position and the second for vertical position. - `looped`: Whether to loop this animation in-game. If false, the animation will pause when it ends, until the game commands the character to do something else. - `flipX`: Whether to flip the sprites of this animation horizontally in-game. - `flipY`: Whether to flip the sprites of this animation vertically in-game. - `frameRate`: A frame rate value, defaulting to `24`. - `frameIndices`: Optionally specify an array of frame numbers (starting at frame 0!) to use from a given prefix for this animation. - - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. + + - For example, specifying `[0, 1, 2, 3]` will make this animation only use the first 4 frames of the given prefix. - `assetPath`: For the `multisparrow` asset type specifically. Define a secondary Sparrow spritesheet which will be loaded, and which contains the frames for this animation. The animation names the game uses by default are: + - `idle`: For the idle animation. - `danceLeft` and `danceRight`: Supercedes the idle animation with one that toggles between two animations. - `singLEFT`, `singDOWN`, `singUP`, `singRIGHT`: The animations for playing notes, when the character is a player or opponent. - `singLEFTmiss`, `singDOWNmiss`, `singUPmiss`, `singRIGHTmiss`: The animations for missing notes, when the character is a player. - Adding a new singing animation with the name of an existing animation with `-hold` at the end will play the animation after the first one ends, while the character is still singing. - - As a good example, you can copy the `singLEFT` animation to make a `singLEFT-hold` animation, which has `looped` as true and `frameIndices` as the last few frames of the singing animation. + + - As a good example, you can copy the `singLEFT` animation to make a `singLEFT-hold` animation, which has `looped` as true and `frameIndices` as the last few frames of the singing animation. - Adding a new singing animation with the name of an existing animation with `-end` at the end will play an animation before returning to idle. - - For example, you can define a new `singLEFT-end` animation to cleanly transition into the idle animation. + + - For example, you can define a new `singLEFT-end` animation to cleanly transition into the idle animation. - You can add other animations by name, but you'll have to play them with a script, or a `Play Animation` song event in the Chart Editor. When the game starts, it queries the list of possible characters by searching in the `data/characters` folder for JSON files. This gets used to preload data which is used later when the character is loaded in a stage. diff --git a/assets/content/cookbook/Introduction/5.AppendingAndMerge.md b/assets/content/cookbook/Introduction/5.AppendingAndMerge.md index 71d1a081..dd46b119 100644 --- a/assets/content/cookbook/Introduction/5.AppendingAndMerge.md +++ b/assets/content/cookbook/Introduction/5.AppendingAndMerge.md @@ -61,7 +61,7 @@ And Polymod will mutate it to get this result: } ``` -If you want something more particular, see [Merging into JSON Files](./10-02-merging-files.md#merging-into-json-files) for a more powerful and flexible approach. +If you want something more particular, see [Merging into JSON Files](#merging-into-json-files) for a more powerful and flexible approach. # Merging @@ -78,7 +78,7 @@ CSV and TSV files can be merged as well. In this case, the mod loader will look ### Merging into XML Files -*NOTE: The behavior of Merging XML files may change significantly in the near future.* +> NOTE: The behavior of Merging XML files may change significantly in the near future. For XML, you must create an XML document containing the desired, values, with additional information to inform Polymod about where to insert it. diff --git a/assets/includes/css/styles.css b/assets/includes/css/styles.css index da51daee..a0777e9e 100644 --- a/assets/includes/css/styles.css +++ b/assets/includes/css/styles.css @@ -8,6 +8,10 @@ body { height: 100vh; } +html { + scroll-padding-top:50px; +} + body, body p, body td, body li { line-height: 1.5; } diff --git a/assets/includes/css/styles.min.css b/assets/includes/css/styles.min.css index 255806a6..b6c1bb9d 100644 --- a/assets/includes/css/styles.min.css +++ b/assets/includes/css/styles.min.css @@ -1 +1 @@ -body{font-family:"Open Sans",sans-serif;font-weight:400;font-size:16px;color:#1e1e1e;display:flex;flex-direction:column;height:100vh}body,body li,body p,body td{line-height:1.5}.btn,.btn-large,.btn-medium,.btn-small{border-radius:4px!important;margin-right:5px}.main-content{flex:1 0 auto}h1{font-weight:400}#title,h1,h2,h3,h4,h5,h6{font-weight:400}article h4{font-weight:700}h3 code{font-size:20px}pre code{font-size:14px}#title{font-size:38.5px}article h1,article h2,article h3,article h4,article h5,article h6{margin-bottom:20px}article h2,article h3,article h4,article h5,article h6{margin-top:20px}article h3{border-bottom:1px dotted #ddd}article h2{border-bottom:1px dotted #aaa}a,a:hover,a>code{color:#257fc2}.contribution{color:#ccc}.contribution a{color:#444}.contribution .fa{color:#999}.authors img{margin-bottom:2px}.contributors a{margin-bottom:2px}.crumb span[itemprop=itemListElement]:not(:last-child):after{content:' › '}@media (max-width:767px){body{padding:0}.container{padding:0 20px;margin:0}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{margin-left:0;margin-right:0}main.container section{display:flex;flex-direction:column}main.container section article{order:1}main.container section nav{order:2}nav#sidebar{margin-top:20px}nav#sidebar.sidebar-toc li li{display:none}nav#sidebar.sidebar-toc br{display:none}nav#sidebar.sidebar-tags li{display:inline-block;border-left:0;margin-right:20px}}@media (max-width:500px){body .hero-unit h3{font-size:90%}body .hero-unit{padding:2em}body .hero-unit h3 br{display:none}}@media (min-width:979px){.hero-unit,.hero-unit-small{margin-top:49px}body .hero-unit h3 br{display:block}}.hero-unit,.hero-unit-small{background:#fbc707;background-repeat:no-repeat;background:-webkit-gradient(radial,50% 80%,0,center center,100,from(183,77,49),to(100,33,38));background:-webkit-radial-gradient(50% 80%,circle,#b74d31,#642126);background:-moz-radial-gradient(50% 80%,circle,#b74d31,#642126);background:-ms-radial-gradient(50% 80%,circle,#b74d31,#642126);color:#f0f0f0;text-align:center;border-radius:0}.hero-unit{padding:4em;margin-bottom:0;box-shadow:inset 0 0 50px rgba(0,0,0,.35)}.hero-unit-small{padding:2em 0;margin-bottom:1.5em;border-bottom:15px solid #eee;box-shadow:inset 0 0 50px rgba(0,0,0,.3)}#title,.hero-unit h1,.hero-unit-small h1{color:#fff;text-shadow:2px 2px 2px rgba(0,0,0,.15)}#title small,.hero-unit h1 small,.hero-unit-small h1 small{color:#c06b69}.hero-unit-small #title,.hero-unit-small h1{margin-bottom:0}.logo{width:80%;max-width:140px;max-height:230px;margin:1em}.hero-unit-small .logo{margin:1%;margin:0;max-width:401px;max-height:90px}.hero-unit h3.lead{color:#ea8220}.hero-unit a,.hero-unit a:hover{color:#fbc707;text-decoration:none;border-bottom:1px dashed #fff}.dark{background:#141419;color:#fff}.dark-section{background:#141419;color:#fff;padding:2em 1em}footer{margin-top:40px;font-size:14px;flex-shrink:0}.copyright{padding:6px;overflow:hidden;text-align:center;margin:40px 0}.reading-time{position:relative;top:-1em;font-style:italic;font-size:90%}blockquote{margin-left:30px;border-left:4px solid #eee;font-style:italic;padding:15px 15px 15px 30px}blockquote.author-info{border-left:4px solid #ea8220}.dark a,.dark a:active,.dark a:hover{color:#ea8220}.dark a.flashdevelop,.dark a.flashdevelop:active,.dark a.flashdevelop:hover{color:#eee;text-decoration:underline}.btn-success{background:#ea8220}.btn-success.active,.btn-success:active,.btn-success:focus,.btn-success:hover{color:#fff;background:#e5801f}nav#sidebar *{line-height:1.5em}nav#sidebar li.active{font-weight:700}nav#sidebar li.active li{font-weight:400}nav#sidebar li{border-left:1px solid #ccc;padding-left:10px}nav#sidebar li li{border-left:0;font-size:14px}nav#sidebar li li a{color:#777}article table{min-width:100%}article table tr:not(:last-child){border-bottom:1px solid #ccc}article table td:not(:first-child),article table th:not(:first-child){border-left:1px solid #ccc}article table td,article table th{padding:3px 5px;text-align:left}article table td:first-child,article table th:first-child{width:140px}code.prettyprint{padding:.5em;display:block}.tag{padding-left:5px;padding-right:10px}.tag small{color:#999;font-size:80%}.tag a{color:#a84b38}.tag a:hover{color:#ea8220}.fa{color:#555}.fa-big{font-size:32px;color:#555;padding-left:15px;padding-right:15px}.btn{margin-bottom:5px}.try-haxe{width:100%;height:350px;margin:0;border:0}.page-list-item:not(last-child){margin-bottom:20px}.page-list-item p{margin-left:10px}.page-list h4{font-weight:400}.page-list-item{padding:1px 15px 15px 15px;border:1px solid #eee;border-radius:5px;background:#fdfdfd}#___plus_0,.g-plus{vertical-align:text-bottom!important}.twitter-share-button{vertical-align:text-bottom!important}.flex-video{position:relative;padding-top:25px;padding-bottom:67.5%;height:0;margin-bottom:16px;overflow:hidden}.flex-video.widescreen{padding-bottom:57.25%}.flex-video.vimeo{padding-top:0}.flex-video embed,.flex-video iframe,.flex-video object{position:absolute;top:0;left:0;width:100%;height:100%}@media only screen and (max-device-width:800px),only screen and (device-width:1024px) and (device-height:600px),only screen and (width:1280px) and (orientation:landscape),only screen and (device-width:800px),only screen and (max-width:767px){.flex-video{padding-top:0}} \ No newline at end of file +body{font-family:"Open Sans",sans-serif;font-weight:400;font-size:16px;color:#1e1e1e;display:flex;flex-direction:column;height:100vh}html {scroll-padding-top:50px;}body,body li,body p,body td{line-height:1.5}.btn,.btn-large,.btn-medium,.btn-small{border-radius:4px!important;margin-right:5px}.main-content{flex:1 0 auto}h1{font-weight:400}#title,h1,h2,h3,h4,h5,h6{font-weight:400}article h4{font-weight:700}h3 code{font-size:20px}pre code{font-size:14px}#title{font-size:38.5px}article h1,article h2,article h3,article h4,article h5,article h6{margin-bottom:20px}article h2,article h3,article h4,article h5,article h6{margin-top:20px}article h3{border-bottom:1px dotted #ddd}article h2{border-bottom:1px dotted #aaa}a,a:hover,a>code{color:#257fc2}.contribution{color:#ccc}.contribution a{color:#444}.contribution .fa{color:#999}.authors img{margin-bottom:2px}.contributors a{margin-bottom:2px}.crumb span[itemprop=itemListElement]:not(:last-child):after{content:' › '}@media (max-width:767px){body{padding:0}.container{padding:0 20px;margin:0}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{margin-left:0;margin-right:0}main.container section{display:flex;flex-direction:column}main.container section article{order:1}main.container section nav{order:2}nav#sidebar{margin-top:20px}nav#sidebar.sidebar-toc li li{display:none}nav#sidebar.sidebar-toc br{display:none}nav#sidebar.sidebar-tags li{display:inline-block;border-left:0;margin-right:20px}}@media (max-width:500px){body .hero-unit h3{font-size:90%}body .hero-unit{padding:2em}body .hero-unit h3 br{display:none}}@media (min-width:979px){.hero-unit,.hero-unit-small{margin-top:49px}body .hero-unit h3 br{display:block}}.hero-unit,.hero-unit-small{background:#fbc707;background-repeat:no-repeat;background:-webkit-gradient(radial,50% 80%,0,center center,100,from(183,77,49),to(100,33,38));background:-webkit-radial-gradient(50% 80%,circle,#b74d31,#642126);background:-moz-radial-gradient(50% 80%,circle,#b74d31,#642126);background:-ms-radial-gradient(50% 80%,circle,#b74d31,#642126);color:#f0f0f0;text-align:center;border-radius:0}.hero-unit{padding:4em;margin-bottom:0;box-shadow:inset 0 0 50px rgba(0,0,0,.35)}.hero-unit-small{padding:2em 0;margin-bottom:1.5em;border-bottom:15px solid #eee;box-shadow:inset 0 0 50px rgba(0,0,0,.3)}#title,.hero-unit h1,.hero-unit-small h1{color:#fff;text-shadow:2px 2px 2px rgba(0,0,0,.15)}#title small,.hero-unit h1 small,.hero-unit-small h1 small{color:#c06b69}.hero-unit-small #title,.hero-unit-small h1{margin-bottom:0}.logo{width:80%;max-width:140px;max-height:230px;margin:1em}.hero-unit-small .logo{margin:1%;margin:0;max-width:401px;max-height:90px}.hero-unit h3.lead{color:#ea8220}.hero-unit a,.hero-unit a:hover{color:#fbc707;text-decoration:none;border-bottom:1px dashed #fff}.dark{background:#141419;color:#fff}.dark-section{background:#141419;color:#fff;padding:2em 1em}footer{margin-top:40px;font-size:14px;flex-shrink:0}.copyright{padding:6px;overflow:hidden;text-align:center;margin:40px 0}.reading-time{position:relative;top:-1em;font-style:italic;font-size:90%}blockquote{margin-left:30px;border-left:4px solid #eee;font-style:italic;padding:15px 15px 15px 30px}blockquote.author-info{border-left:4px solid #ea8220}.dark a,.dark a:active,.dark a:hover{color:#ea8220}.dark a.flashdevelop,.dark a.flashdevelop:active,.dark a.flashdevelop:hover{color:#eee;text-decoration:underline}.btn-success{background:#ea8220}.btn-success.active,.btn-success:active,.btn-success:focus,.btn-success:hover{color:#fff;background:#e5801f}nav#sidebar *{line-height:1.5em}nav#sidebar li.active{font-weight:700}nav#sidebar li.active li{font-weight:400}nav#sidebar li{border-left:1px solid #ccc;padding-left:10px}nav#sidebar li li{border-left:0;font-size:14px}nav#sidebar li li a{color:#777}article table{min-width:100%}article table tr:not(:last-child){border-bottom:1px solid #ccc}article table td:not(:first-child),article table th:not(:first-child){border-left:1px solid #ccc}article table td,article table th{padding:3px 5px;text-align:left}article table td:first-child,article table th:first-child{width:140px}code.prettyprint{padding:.5em;display:block}.tag{padding-left:5px;padding-right:10px}.tag small{color:#999;font-size:80%}.tag a{color:#a84b38}.tag a:hover{color:#ea8220}.fa{color:#555}.fa-big{font-size:32px;color:#555;padding-left:15px;padding-right:15px}.btn{margin-bottom:5px}.try-haxe{width:100%;height:350px;margin:0;border:0}.page-list-item:not(last-child){margin-bottom:20px}.page-list-item p{margin-left:10px}.page-list h4{font-weight:400}.page-list-item{padding:1px 15px 15px 15px;border:1px solid #eee;border-radius:5px;background:#fdfdfd}#___plus_0,.g-plus{vertical-align:text-bottom!important}.twitter-share-button{vertical-align:text-bottom!important}.flex-video{position:relative;padding-top:25px;padding-bottom:67.5%;height:0;margin-bottom:16px;overflow:hidden}.flex-video.widescreen{padding-bottom:57.25%}.flex-video.vimeo{padding-top:0}.flex-video embed,.flex-video iframe,.flex-video object{position:absolute;top:0;left:0;width:100%;height:100%}@media only screen and (max-device-width:800px),only screen and (device-width:1024px) and (device-height:600px),only screen and (width:1280px) and (orientation:landscape),only screen and (device-width:800px),only screen and (max-width:767px){.flex-video{padding-top:0}} \ No newline at end of file diff --git a/src/Generator.hx b/src/Generator.hx index ac1fb86a..3449c938 100644 --- a/src/Generator.hx +++ b/src/Generator.hx @@ -12,6 +12,7 @@ import sys.io.File; import templo.Template; import util.GitUtil.GitAuthorInfo; import Config.*; +using Lambda; using StringTools; @@ -402,7 +403,54 @@ class Generator { return content; } } - + + private function replaceMarkdownLinks(page:Page, content:String) { + var linkRegex:EReg = ~/\[([^\]]+)\]\(([^)]+)\)/g; + + var result:String = ""; + var rest:String = content; + + // this code is definitely something... but hey, at least it works + while (linkRegex.match(rest)) { + var start = linkRegex.matchedPos().pos; + var end = linkRegex.matchedPos().pos + linkRegex.matchedPos().len; + + result += rest.substring(0, start); + + var text = linkRegex.matched(1); + var url = linkRegex.matched(2); + + if (url.startsWith("#")) { + url = page.absoluteUrl + url; + result += '[$text]($url)'; + rest = rest.substr(end); + continue; + } + + var anchorIndex = url.indexOf("#"); + var anchor = ""; + if (anchorIndex != -1) { + anchor = url.substr(anchorIndex); + url = url.substr(0, anchorIndex); + } + + if (url != "" && !url.startsWith("http")) { + url = url.replace("../", "").replace("./", "").toLowerCase(); + var contains = ["introduction", "intermediate", "advanced"].exists(function(item) return url.indexOf(item) != -1); + if (!url.startsWith("category/") && !contains) url = Path.directory(page.absoluteUrl) + "/" + url; + else url = "category/" + url; + } + + if (url.endsWith(".md")) url = url.replace(".md", ".html"); + + result += '[$text]($url$anchor)'; + rest = rest.substr(end); + } + + result += rest; + return result; + } + private function getCategory(sitemap:Array, page:Page):Category { for (category in sitemap) { if (category.pages.indexOf(page) != -1 ) { @@ -478,6 +526,7 @@ class Generator { markdown = replaceYoutubeTags(markdown); markdown = replaceTryHaxeTags(markdown); markdown = replaceAuthor(page, markdown); + markdown = replaceMarkdownLinks(page, markdown); try { // replace windows line endings with unix, and split var lines = ~/(\r\n|\r)/g.replace(markdown, '\n').split("\n"); @@ -513,6 +562,14 @@ class Generator { page.description = new EReg("<(.*?)>", "g").replace(description, "").replace('"', "").replace('\n', " "); // break; } + if ((el.tag == "h1" || el.tag == "h2" || el.tag == "h3") && !el.isEmpty()) + { + var heading = new markdown.HtmlRenderer().render(el.children); + var id = heading.toLowerCase().replace(" ", "-"); + var regex = new EReg("[^a-z0-9\\-]", "g"); + id = regex.replace(id, ""); + el.attributes.set("id", id); + } #if test_snippets // TODO: Move to its own class?