Synchrony
Synchrony is a work-in-progress reimplementation of Crypt of the NecroDancer that adds online multiplayer support and an extensive Lua-based modding API.
Join our Discord community for mods, announcements, online multiplayer sessions!
Changelog
v0.5 (2020-10-29)
(Full changelog coming soon)
- Added spectator mode for online sessions
- Added late-joining and re-joining for online sessions
- Added local co-op for both local and online sessions
- Added most weapons, shovels and torches, as well as some headgear, boots and charms
- Added behavior for all remaining Zone 1 enemies
- Added functionality for Zone 1's traps and tiles
- Implemented a full Lua modding API, including a mod loader to create and load packaged mods
v0.4 (2019-09-24)
Multiplayer
- Added Steam integration for online multiplayer
- Create public, friends-only or private lobbies, join friends using the Steam client or use the game browser to find a match
- NecroNecro automatically connects to the Steam client on startup
- Direct IP connection multiplayer servers are still available, and can now be hosted and joined on non-default UDP ports
Gameplay
- Added the Fireball spell
- Added Minotaur behavior
- Added Red Dragon behavior
- Added Armadillo behavior
- Added Zombie behavior
- Levels in All-Zones runs now play their respective song
- Changed the default camera mode to center on the local player at a fixed zoom level, instead of panning and zooming out to show all characters
Menus & User Interface
- Added spell slots to the heads-up display
- Added "Change Soundtrack" menu
Bugfixes
- Fixed binding menu controls and movement directions to the same keys not being allowed
- Fixed blood damage causing the groove chain to be dropped
- Fixed characters occasionally getting stuck in remote data awaiting mode
- Fixed error when spawning a swipe outside of beat processing
- Fixed exit stairs screen fade-out effect cutting off in custom dungeons
- Fixed exit stairs screen fade-out not animating correctly in online games
- Fixed Ghosts and Bats bouncing on movement failure
- Fixed Ghosts ceasing to move when player idles
- Fixed inactive entities performing AI actions
- Fixed key bindings not saving correctly
- Fixed local player's latency not displaying correctly
- Fixed message boxes not being dismissed when pressing Escape
- Fixed non-directional attacks resulting in right-oriented damage
- Fixed non-looping music restarting when unpausing after the song ended
- Fixed tiles in custom dungeons being shifted horizontally by one column
- Fixed procedural dungeons not being regenerated when returning to lobby
- Fixed previous position not resetting on non-movement directional actions
- This is known as the "prevpos" bug in the reference implementation, and may be toggleable in the future via a compatibility flag
- Fixed snapshot rollback errors when experiencing poor network connectivity
- Fixed space being one pixel too wide in small font
- Fixed user interface scale factor incorrectly defaulting to 1 instead of 2
- Fixed Whip weapons dealing directionally incorrect damage
Modding
- Added support for registering custom entity types in Lua
- Template entities allow for the simplified registration of enemies, items and playable characters using a
necrodancer.xml
-like table structure, with optional component modifiers applied afterwards - Entities can also be created manually for full control over the used components, bypassing the internal XML-to-ECS mapping functions entirely
- Template entities allow for the simplified registration of enemies, items and playable characters using a
- Added support for animation variants
- Added directional versions of normal and tell animations
- Added support for object-timed (
offBeat
) animations, running on the object's action timer instead of the song beat- At the end of the object-timed animation, the frames can be looped, the last frame can be sustained, or a lower-priority animation can be used as a fallback
- Added
Damage.inflict
function, replacingCharacter.attack
- Split
previousPosition
into logical and visual previous position- The previous position for movement animations of character sprites is now stored in
hopTween
- The previous position for movement animations of character sprites is now stored in
- Added
objectFacing
event, fired whenever the direction of an object changes (such as when moving or turning around), even for entities without afacingDirection
component - Added
objectMoveFail
event andINVALID
action result, allowing enemy movement failures to be handled without triggering on transient movement failures (re-queued movement) - Added field
active
to componentgameObject
, replacing the formertangibility
component - Added various components:
aiLinearFollowFacingDirection
: causes the linear AI's direction to be set to the entity's facing directionactionDelay
: enforces a delay before executing certain actionsautoCast
and related components: performs actions automatically upon the nearest target entity entering a specific rangebeatDelayBypass
: allows an entity to bypass the beat delay for specific actionsmoveOverride
and related components: controls whether the entity is "charging" in a specific direction, and initiates such a charge automatically if the target entity is in rangeresetBeatDelayOnMoveFail
: resets the beat delay when the entity's movement failsturnOnMoveFail
: causes an entity to face the opposite direction when its movement failsspell
and related components: represents a reusable item that creates one or more spellcast entites upon activationspellcast
and related components: indicates that the entity is spawned upon the activation of a spell, causing a variety of possible effects on the caster or nearby enites and tiles
- Added X and Y scale factors to
Swipe
entity - Added support for cross-module event registration calls at load-time
- Added
LineOfSight
module, implementing Bresenham's line drawing algorithm to perform line-of-sight checks for collisions with solid tiles and/or entities - Added function
Player.getPlayableCharacterTypes
- Added function
AnimationTimer.getAnimationFactor
- Added functions
Inventory.getItemInSlot
andInventory.getItemsInSlot
- Added Lua Table Notation serializer, replacing Serpent
- Added
selectableIf
menu entry key to conditionally control selectability - Added
hideIfDisabled
menu entry key to hide disabled menu entries - Added entity existence checks to ECS accessors, catching use-after-delete errors
- Added support for specifying a separate hit sound for suppressed damage
- Added support for reading/writing arrays and maps from/to the config file
- Added
attributes
parameter toObject.spawn
- Added support for variable item capacities per inventory slot
- Added configuration entries
wos.game.assets.autoReload.delay.*
for asset auto-reload event coalescence- NecroNecro now waits until the application has finished writing to changed files before reloading them to avoid reading corrupted or incomplete files
- On Windows, this check is approximated by waiting until no more file write events are fired for a short amount of time
- Added configuration entry
wos.game.graphics.filterTextures
for controlling whether textures should be linearly interpolated - Added configuration entries
wos.game.debug.logging.*
for controlling logging verbosity and the log file name - Added
spawn
debug command to create entities (single-player only) - Added
char
debug command for changing the player's character class - Added
watch.add
,watch.remove
andwatch.clear
debug commands for visually debugging field values on entities and components- Use F1 to enable the debug overlay and press Shift-F1 to cycle to the watch overlay mode
- Added parameter info to comments for
kill
anddeath
object events - Changed inventory code to store items in the order they were picked up
- Changed rollback snapshot indices to correspond exactly to beat index
- Entity despawns are now deferred to the end of the current beat, instead of being performed immediately
Modding Bugfixes
- Fixed
Action.isOrthogonalDirection
andAction.isDiagonalDirection
returning incorrect results - Fixed
Action.isResultSuccessful
returning incorrect value forFAIL
- Fixed
Action.rotateDirection
interpreting non-directional inputs asRIGHT
- Fixed
penetration
field not being populated in damage event parameters - Fixed entity schema loader not cleaning up unused entities and components
- Fixed error when accessing mutable fields of prototype entities
- Fixed beat delay induced during an action not applying to requeued enemies
- Fixed beat delay not resetting after performing special action
- Fixed non-zero beat delay being reset at the end of an action
- Fixed incorrectly negated menu entry visibility condition
v0.3 (2019-03-21)
Gameplay
- Added All-Zones Mode
- Dungeons are generated procedurally using a random seed
- Based on Mendayen's ndref project
- Procedural dungeons highly resemble those generated by the original game
- Added Seeded All-Zones Mode
- Specific procedural dungeons can be played by entering a seed
- Seeds are compatible with the original game, resulting in (nearly) the same dungeons
- Added lighting system
- Added torch items which provide wall-penetrating light around the player
- Added wall torches which light up areas within the player's field of view
- Added usable exit stairs
- Locked stairs must be unlocked by defeating miniboss first
- Step on unlocked stairs to proceed to the next level
- Stairs grant immunity to damage and coin multiplier loss
- Added monkey behavior
- Monkeys can move onto the player and grab them
- Monkeys are knocked back when they take damage
- Added ghost behavior
- Ghosts fade out, stand still and become unattackable when the nearest player approaches them
- When the nearest player moves away from the ghost, it becomes corporeal, seeking out and attacking the player
- Added green dragon behavior
- Dragons seek out the player, destroying walls within their path
- Added screen flashes when unlocking exit stairs or taking damage
- Added attack pattern for whip weapons
- Added different pickup sound for weapons
- Added boss walls
Menus & User Interface
- Added game mode selection menu to lobby
- Added 'quick restart' hotkey
- Added game controls configuration menu
- The chat box can now be opened from the pause menu
Bugfixes
- Fixed players not being able to move on the very first beat of a song
- Fixed coin multiplier loss when standing still at the beginning of a level
- Fixed decorated Zone 4 walls missing their texture
- Fixed sound groups sometimes repeatedly playing the same sound
- Fixed HUD scaling not applying correctly
- Fixed the session's first input frame sometimes being reported incorrectly
- Fixed incorrect swipe creation order for entities with a base attack
- Fixed incorrect swipe offset at modified camera zoom levels
- Fixed character heads becoming temporarily detached on level transition
- Fixed item pickup HUD animation repeating after level transition
- Fixed chat box opening when pressing chat key while entering text in a menu
- Fixed non-host clients being able to open dungeon selector in lobby
- Fixed occasional 'Inconsistent snapshot' error on level transition
- Fixed animation timer continuing to run when the game is paused
- Fixed game content directory sometimes being misdetected
- Fixed incorrect 'Unpausing in' countdown when rapidly pausing/unpausing
- Fixed whole player list being sent unnecessarily often in multiplayer, causing high bandwidth usage
- Fixed sprite animations frames being recomputed unnecessarily often, causing slowdowns
- Fixed client to server data transfers not being cancelable
Modding
- Added functions to
Graphics
module for drawing rotated boxes and sprites - Added
Color
module for manipulating integer colors- Reworked most graphics functions to accept integer colors in addition to tables
- Added depth sorting/Z-order for sprites
- Replaced
opacity
field withcolor
insprite
component- This allows sprites to be darkened or tinted
- Added
visionRaycast
component - Added
stasis
component for characters - Added weapon material components
- Added generic fade in/out effect component for sprites
- Changed lobby renderer to use bestiary images
- Removed now obsolete
lobby.png
image from assets
- Removed now obsolete
- Added
animateObjects
event for applying object animations - Split
enemyActions
step into separate targeting and AI actions steps - Split
HUD
module into element-specific sub-modules - Added support for partial network data transfers
- This allows only part of a resource to be updated, such as one level of a dungeon
- Added common
removeItem
event for both dropped and destroyed items - Added
tileChange
object event- Fired when the tile beneath an object changes
- Added support for passing
nil
key to enum selectors, accessing all entries - Added support for custom reliable ordering channels to network layer
- Added function
TileTypes.getCrackedTileID
- Added various associative table helper functions to
Utilities
moduleUtilities.getKeyList
: returns a list of keys in an associative table, discarding valuesUtilities.getValueList
: returns a list of values in an associative table, discarding keysUtilities.getKeyValueList
: returns two correlated lists of keys and values of an associative tableUtilities.setKeyAtPath
: modifies a table by recursively following a list of keys
- Added
FileIO.exists
function to check for the existence of a resource - Added optional destination, offset and size arguments to
Array.copy
- Added
id
key to arrays, to retrieve the ID for native code interoperation - Added
startsWith
andendsWith
functions toStringUtilities
module - Added simple query string parser/builder to
StringUtilities
module - Added
StringPool
module for dynamically mapping strings to integers - Added
Bitmap
module for manipulating images - Added virtual Lua resource provider
- This enables the procedural generation of assets, such as images
- Added
CropImage
virtual resource
- Added functions to
Input
module to poll for vertical/horizontal mouse scrolling - Added error logging and more informative error message on level load failure
- Added light map debugger to debug overlay (F1)
- Reworked internal level format and level loader
- Added
LevelUtils
module for manipulating levels in the internal format
- Added
- Move
Colors
module fromconfig
torender
package - Reworked movement animation/tweening code
- Added support for starting animations before an entity's AI is executed
- Added function to look up player character type by XML ID
- Added bestiary images for all playable characters and some enemies
Modding Bugfixes
- Fixed global variables resetting upon full script reload
- Fixed event selectors failing to update after full script reloads
- Fixed key suppression being case sensitive
- Fixed global random number generator (
math.random
) not being seeded on session start - Fixed stack overflow freezing the game for longer than necessary
- Fixed duplicate 'unknown tile ID' log warnings when loading dungeons
- Fixed error in mouse button check functions
- Fixed debug hotkey for content reload using incorrect entity namespace
- Fixed incorrect array copy offsets for multibyte data types
- Fixed entries in configuration file being ordered incorrectly
- Fixed network transfers sometimes being delivered in the wrong order
- Fixed potential name conflict with generated entity schema, interfering with live reloading
v0.2 (2018-10-29)
Gameplay
- Added enemy attacks
- Added enemy health bars
- Added enemy movement priorities
- Added silhouettes for entities outside the player's field of view
- Added coin multiplier
- Added item pickups and equipment HUD
- Added weapons
- Added tile digging
- Implemented shovels of differing strength
- Special shovel effects are not implemented yet
- Added playable characters other than Cadence
- Each character spawns with their default starting items and health
- No character-specific gameplay effects yet
- Added various sound effects
- Hurt and death sounds for enemies and players
- Attack sounds for enemies
- Dig sounds for players
- Added AI for some enemies
- Skeletons
- Slimes
- Bats
- Added attack patterns and swipes for some weapons
- Daggers
- Broadswords
- Longswords
- Added sprite mirroring for moving characters
Multiplayer
- Added movement animation smoothing for online sessions
Menus & User Interface
- Added dungeon selection list
- This replaces the "Enter dungeon name" dialog
- Dungeon selector now opens automatically when trying to start a game with no dungeon selected
- Added character sprite preview to lobby
Bugfixes
- Fixed animations not being cached correctly
- Fixed animations sometimes not working on the first beat of the song
- Fixed movement animation re-playing when performing stand-still action
- Fixed enemies not requeueing after failed movement
- Fixed error when an enemy failed to find a target
- Fixed error when loading a level containing doors or wires
- Fixed error when picking up certain item combinations
- Fixed incorrect stack trace depth on read-only entity field write error
- Fixed incorrect vertical camera offset
- Fixed uninitialized spritesheets rendering with garbled textures
- Fixed pause menu not closing when host restarts the run
- Fixed single player mode setting online name to "Player"
- Fixed objects drawing over walls in the same row
- Fixed some enemy sprites incorrectly rendering horizontally mirrored
- Fixed inaccurate character bounce animation
Modding
- Added support for load-time
require
calls across scripts - Added object event forwarding to all held items
- Event handlers for all involved entities are merged, then evaluated in priority order
- Added customized error stack traces
- Event handlers in the stack trace now display their names, instead of line numbers
- Event selectors now display the name of the event
- Calls to
xpcall
in the context of event handling are now hidden from the stack trace
- Added initial support for level transitions
- Currently implemented as a debug command: press F4 and enter
level(2)
- Currently implemented as a debug command: press F4 and enter
- Added support for cross-beat animation timing
- Added partial support for drawing rotated sprites
- Added generic enemy AI handler and implement
basicSeek
using it - Added sound groups and rollback handling for sound effects
- Added experimental support for specifying numeric ordering for event handlers
- Event handler order is specified using the
priority
field in the key parameter - This feature is experimental and its exact functionality may change in the future
- Event handler order is specified using the
- Added beat synchronization functionality
- This lets the host ensure that all players caught up to each other before switching levels
- Currently, a beat sync request stops all game logic and can only be lifted via level change
- Added
Random
module containing pseudo-random noise functions- Rewrote noise functions in C++ to improve performance and prevent possible desyncs
- Disabled the debug reset hotkey (F2) by default
- It can be enabled or changed in
config.json
(wos.game.debug.reset
)
- It can be enabled or changed in
- Removed intermediate character 'controller' entities
- Removed beat bar entities
- Changed
dbg
functions to also work in release mode - Changed debug commands (F4) to be accessible without the
c.
prefix - Split
Game
module intoInput
,Rollback
andLevelEvents
modules - Split
Audio
module intoSound
andMusic
modules - Moved string conversion functions to
StringUtilities
module - Moved/renamed enum
Character.ActionResult
toAction.Result
- Extracted bit manipulation functions into new module
BitUtilities
Modding Bugfixes
- Fixed auto-reload throwing an error when modifying non-script file
- Fixed cross-module references causing scripts to load multiple times
- Fixed error when deserializing tables with keys containing keywords
- Fixed error when enabling the debug profiler (F6)
- Fixed player actions ignoring beat delay
- Fixed
utils.deepCopy
not supporting cyclic tables
v0.1 (2018-09-05)
- Initial private release