Hello! We're back with another update. This is a big one, as it brings official Luxor: Amun Rising support to the engine! Keep in mind however, that mods for this game aren't supported - only the original game. Don't worry, support for mods will come at some point!
You might have noticed that the releases are getting rarer and rarer. This is unfortunately true, but each release comes packed with more and more features! And this release is no exception - it is the biggest release yet when it comes to added features!
As always, the full list of changes can be found here.
Thank you @bchantech for a few contributions!
Happy matching!
Changelog
Game Support
- The Luxor: Amun Rising support is here!
- The game converter will detect Luxor Amun Rising automatically and will convert the game properly.
Game Development
The Resource Manager has been overhauled, and as such the way resources are loaded has changed. Instead of having to be in a specific folder, the resources now need to have an appropriate extension or, if it's a JSON file, a JSON schema assigned to it.
The resources contained in the root game folder, as well as in config
and maps
subfolders, are not loaded.
This also means that all resources must be now referred to with a full path, starting from the game's root directory. However, assets can be now placed inside maps, which use the special syntax:
map:asset/to/load.json
If you're editing a configuration file inside of a map and want to access a resource in that same map, you can omit the map name:
:asset/to/load.json
You can find out more information about the new syntax here.
-
Changes in game data:
- The files
config/loadlist.json
andconfig/music.json
have been removed. - The
modules
folder has been removed. - Added Color Palettes!
- They were in the game already, but did not have any configuration files assigned to it and needed to be explicitly mentioned in the
config/loadlist.json
file. - They are located in
color_palettes/*.json
by default (notconfig/color_palettes/*.json
!). - Color Palettes, to be registered by the game, need their
$schema
field to end withschemas/color_palette.json
. - The data contains only one field:
image
- The image to be used as a color palette.
- All references to Color Palettes as images must now reference color palettes' configuration files instead. This includes particles and spheres.
- They were in the game already, but did not have any configuration files assigned to it and needed to be explicitly mentioned in the
- Added Music Tracks!
- Similarly to Color Palettes, they were in the game already, but they were all specified in a single file -
config/music.json
. - They are located in
music_tracks/*.json
by default (notconfig/music_tracks/*.json
!). - Music Tracks, to be registered by the game, need their
$schema
field to end withschemas/music_track.json
. - The data is an object with just one field:
audio
- The audio file to be used for this music track.
- You are now supposed to put full paths to the music tracks in order to access them.
- Example:
f.musicVolume("menu", 1)
->f.musicVolume("music_tracks/menu.json", 1)
- Example:
- Similarly to Color Palettes, they were in the game already, but they were all specified in a single file -
- Added Score Events!
- Score Events are objects which contain data about how many points should be given and how this information should be displayed for the user.
- Score Events are stored by default in
score_events/*.json
, notconfig/score_events/*.json
! - Score Events, to be registered by the game, need their
$schema
field to end withschemas/score_event.json
. - They have five fields:
score
- The amount of points to be given with this Score Event. Can be an Expression.ignoreDifficultyMultiplier
(optional) - If set, the score calculated by this Event will not be mutliplied by the current difficulty's score multiplier.text
(optional) - The text which should be displayed instead of the raw score value. Can be an Expression.font
(optional) - The font to be used for the FloatingText. If not specified, no FloatingText will appear.fonts
(optional) - A form used when the Score Event can produce texts with multiple different fonts.- It contains three required fields:
options
- A list of Fonts to choose from.default
- The fallback font if the choice does not pick any of the options.choice
- An integer expression which evaluates to a number. That number is the item index from theoptions
list, starting from 1. If an invalid index is returned, the font specified in thedefault
field is used.
- It contains three required fields:
- Added Path Entities!
- Path Entities are used as a universal superclass for data-driven entities like Bonus Scarabs, Scorpions, Path Introductions, Pyramid Blockers, Black Holes and more.
- They are located in
path_entities/*.json
by default (notconfig/path_entities/*.json
!). - They have A LOT of fields:
sprite
(Sprite) - The sprite to be used by the path entity.shadowSprite
(Sprite) - The shadow sprite to be used by the path entity.spawnPlacement
(string) - Where the path entity will be spawned at, or in relation to that place."start"
- The path entity will be spawned at the beginning of the path, and will move forwards along the path."end"
- The path entity will be spawned at the end of the path, and will move backwards along the path."furthestSpheres"
- The path entity will be spawned at the furthermost sphere on the path. The entity will move forwards along the path.
spawnOffset
(number) - If set, the initial location of the path entity will be moved by this amount in pixels, in the movement direction dictated by thespawnPlacement
field.speed
(number) [>=0] - The starting speed of this path entity, in pixels per second.acceleration
(number) [>=0] - The acceleration of this path entity, in pixels per second squared.maxSpeed
(number) [>=0] - The maximum speed of this path entity, in pixels per second.maxOffset
(number) [>=0] - The maximum distance from the initial location of the path entity, in pixels.destroyOffset
(number) - The offset from either of the path ends this path entity is going towards, when this entity will be destroyed. Defaults to0
.destroyTime
(number) [>0] - If set, this path entity will be destroyed after this many seconds of existence.destroyWhenPathEmpty
(boolean) - If set, this path entity will be destroyed if there are no spheres on that path.destroyAtClearOffset
(boolean) - If set, this path entity will be destroyed once it reaches the path's clear offset (i.e. Bonus Scarabs).particle
(Particle) - The one-time particle that this path entity will be spawning every set amount of pixels.particleSeparation
(number) [>0] - The distance between each particle, in pixels.renderParticlesInTunnels
(boolean) - If set, the trail produced by the entity will be seen over the tunnels.loopSound
(SoundEvent) - A looping sound event which will be played during the path entity's existence. (path_entity)collectibleGenerator
(CollectibleGenerator) - A collectible generator which will periodically generate collectibles from this path entity. (path_entity)collectibleGeneratorSeparation
(number) [>0] - The distance between each collectible generator activation, in pixels.destroyParticle
(Particle) - The one-time particle that this path entity will spawn upon destruction/despawning.destroySound
(SoundEvent) - A sound event which will be played when this path entity is destroyed. (path_entity)destroyScoreEvent
(ScoreEvent) - The score event which will be executed when this path entity is destroyed. (path_entity)destroyCollectibleGenerator
(CollectibleGenerator) - The collectible generator which will generate collectibles when this path entity is destroyed. (path_entity)canDestroySpheres
(boolean) - If set, this path entity will destroy all spheres which are further than this path entity's position.sphereDestroySound
(SoundEvent) - A sound event which will be played when this path entity destroys a sphere. (path_entity, sphere)sphereDestroyScoreEvent
(ScoreEvent) - A score event which will be executed when this path entity destroys a sphere. (path_entity, sphere)maxSpheresDestroyed
(integer) [>0] - If set, this path entity will be destroyed after destroying this amount of spheres.maxSphereChainsDestroyed
(integer) [>0] - If set, this path entity will be destroyed after destroying this amount of sphere chains (scarabs).- All besides
spawnPlacement
andspeed
are optional.
- Added Sphere Selectors!
- They're used to... select spheres. They can be destroyed or their color can be changed.
- They are located in
sphere_selectors/*.json
by default (notconfig/sphere_selectors/*.json
!). - They have one field:
operations
- A list of operations performed in sequence in order to form a list of spheres. Each item is an array, which contains the following fields:type
- A type of an operation. The only currently supported type is"add"
.condition
- A boolean expression evaluated for each sphere on the board. If the expression evaluates totrue
, the sphere is added to the list.- The expression has the
sphere
context, which is a different context than in Path Entities... It contains the following variables:distance
- Only Sphere Selectors which are not referenced from Collectible Effects have this variable. The distance from the selector's position of reference, in pixels.distanceX
- As above, the only difference is that the horizontal axis is taken into account in this case.object
- A special variable, which can be only used in an equality check and has no other use.color
- The sphere's color.isOffscreen
- Whether the sphere is currently offscreen.
- The expression has the
- Added Difficulties!
- They are stored in the
difficulties
folder by default (notconfig/difficulties
!). - They contain two fields:
speedMultiplier
- The multiplier of path speeds in levels when playing with that difficulty.scoreMultiplier
- The score multiplier which will be applied to all Score Events when playing with that difficulty.
- They are stored in the
- The files
-
Changes in
config/gameplay.json
:- A new required section has been added:
ui
. It contains three required fields:buttonClickSound
- The sound event that will be played whenever a button is clicked.buttonHoverSound
- The sound event that will be played whenever a mouse is hovering over a button.levelAdvanceSound
- The sound event that will be played whenever the player advances a level (on the level map).
- A new required
levelSequence
section has been added. It is a list of objects, each of the following format:type
- The type of a single level sequence step. Can be one of the following, and any fields attached to it need to exist alongside this field as well:"wait"
- The sequence will wait for a specified time and move to the next step.delay
- The amount of seconds to wait.
"waitForCollectibles"
- The sequence will move to the next step once there are no collectibles on the board.- Has no parameters.
"pathEntity"
- Spawns one path entity per path.pathEntity
- The Path Entity to be spawned.separatePaths
- Whether the entities should wait until the previous one has been destroyed.launchDelay
- The amount of time to wait between launches. IfseparatePaths
is set, the game will wait this amount after the last path entity has been destroyed. Otherwise, this will be the delay between consecutive spawns.waitUntilFinished
- The sequence will immediately move on to the next step if this is set.skippable
- Does nothing for now, but it's supposed to be able to be skipped if the left mouse button is pressed.
"gameplay"
- The actual level.warmupTime
- The amount of seconds to wait between spawning spheres and giving control to the player.previewFirstShooterColor
- Shows the first shooter color in the reserve slot during the warmup time.onWin
(optional) - The level sequence step (starting from 1) to which the sequence will jump to if the level is won. The sequence will jump to the next step if this is not specified.onFail
(optional) - The level sequence step (starting from 1) to which the sequence will jump to if the endpoint is breached (the level is failed). The sequence will jump to the next step if this is not specified.onObjectivesReached
(optional) - The level sequence index to jump to if all of the level's objectives have been reached. InvalidatesonWin
.
"fail"
- The spheres rush to the endpoint and disappear.waitUntilFinished
- If set, jumps to the next step immediately, otherwise waits until all spheres disappear.skippable
- Doesn't work, it's supposed to be able to be skipped by clicking the left mouse button.
"end"
- Finishes the sequence.status
- Can be"win"
or"fail"
, depending on the level result.
"clearBoard"
- Empties the Shooter and disables the Net.- Has no parameters.
"collectibleEffect"
- Activates a list of Collectible Effects without a position set.effects
- A list of Collectible Effects to be executed.
- The current level sequence step can be seen in the F4 debug menu.
- A new optional section has been added:
lightningStorm
.- Contains 4 fields:
delay
- A number (or a number expression) of seconds between each strike.particle
- A one-time particle effect which will spawn on the destroyed sphere.sound
- A sound effect which will be played when a sphere is destroyed.scoreEvent
- A Score Event executed on the destroyed sphere.- Contains a
score
context with one variable:color
- The sphere color.
- Contains a
- Contains 4 fields:
- In the
net
section, a new field has been added:sound
- A looping sound event that will be played whenever the Net is active.
- The
gameplayBehaviour
field has been renamed togameplayBehavior
. - The
bonusScarab
,scorpion
andpathIntroduction
sections have been removed, as their functions have been replaced by Path Entities. - The
level
section has been removed.
- A new required section has been added:
-
Changes in Level data:
- A new optional field has been added:
failSound
- A sound event which plays when the player loses the level.
- In a
pathsBehavior
entry, a new optional field has been added:forceDifferentColor
- If set, two like-colored clumps cannot have the same color if next to each other. This reduces the likelihood of apparent big clumps of a single color.
- A new optional field has been added:
-
Changes in Map data:
- Each sprite in the
sprites
field:- Added a new optional field:
foreground
- If set, this sprite will be rendered above all spheres, regardless of whether they are hidden or not.
- The
background
field is now optional. - The
internal
field has been removed. Use the new syntax with a colon instead.
- Added a new optional field:
- Each sprite in the
-
Changes in Sphere data:
- Changed a few resources which are referred in the Sphere data:
- Collectible Generators specified in the
destroyCollectible
field: All variables have been moved to thesphere
context.- To update, add a
sphere.
prefix to all variable names that are used there.
- To update, add a
- The
destroySound
sound event now plays regardless of whether the sphere has been crushed, or destroyed via normal means.- To fix this, add a
${[sphere.crushed]}
condition to the sound event. You will need to use the new syntax for Sound Effects (see below).
- To fix this, add a
- Collectible Generators specified in the
- The
destroySphere
,fireball
,colorCloud
andreplaceColor
hit behavior types have been removed.- Instead, two new types have been added:
destroySpheres
will destroy spheres from a Sphere Selector. It has the following parameters:selector
- A Sphere Selector which will select the spheres to be destroyed.scoreEvent
- Optional. A Score Event which will be executed for the entire batch of spheres.- This Score Event will have a
selector
context, which will have the following variable:sphereCount
- The amount of destroyed spheres.
- This Score Event will have a
scoreEventPerSphere
- Optional. A Score Event which will be executed for each sphere separately.- This Score Event will have a
sphere
context, which is yet another differentsphere
context and it just contains one variable:color
- The color of the Sphere.
- This Score Event will have a
recolorSpheres
will change the color of all spheres selected by the provided Sphere Selector. It has the following fields:selector
- A Sphere Selector which will select the spheres of which their color will be changed.color
- The color which the selected Spheres will be changed to.particle
(optional) - A one-time Particle Packet which will be spawned at every selected Sphere.
- Both Sphere Selectors and Score Events references from either a
destroySpheres
orrecolorSpheres
hit behavior have thehitSphere
expression context, with the following variables:object
- A special variable, which can be only used in an equality check and has no other use.color
- The color of a hit sphere.
- Instead, two new types have been added:
- The
lightning
shoot behavior type has been removed.- Instead, a new
destroySpheres
shoot behavior type has been added, with the exactly same parameters as thedestroySpheres
hit behavior type.
- Instead, a new
- Added a new optional field:
doesNotCollideWith
.- It is a list of sphere IDs on the path that the Sphere as a Shot Sphere will not interact with.
- The
type
field is now optional. - The
matchFont
field has been removed.
- Changed a few resources which are referred in the Sphere data:
-
Changes in Sphere Effect data:
- The
destroySound
field no longer accepts a"hardcoded"
value.- This is because the new Sound Event system can handle stuff that previously the default game module was doing.
- The expressions in a sound event referenced in this field have the following variables set:
match.length
(previouslylength
)match.streak
(previouslycombo
)match.streakBoost
(previouslycomboBoost
)match.cascade
(previouslychain
)match.gapCount
- A new field - the amount of gaps the shot sphere has traveled before hitting a match.match.color
- A new field - the color of the sphere that has caused a match. Usually the color of the match.
- These values are now updated before firing the event, not afterwards, which means that you should decrement the
streak
andcascade
values by one in order to preserve the exactly same behavior.
- The Collectible Generator referenced in the
destroyCollectible
field has been changed:- The variable names have been changed.
length
->match.length
comboLv
->match.streak
comboBoost
->match.streakBoost
chainLv
->match.cascade
- The variable names have been changed.
- The
destroyFont
field has been removed. - Added a new field:
destroyScoreEvent
.- Uses the
match
context. See above for details.
- Uses the
- The
-
Changes in Collectible Effect data:
- A few new Collectible Effect types have been introduced:
executeScoreEvent
- Executes a Score Event.- It has one required parameter:
scoreEvent
, which is a path to the Score Event to be executed.
- It has one required parameter:
spawnPathEntity
- Spawns a Path Entity.- It has one required parameter:
pathEntity
- the Path Entity to be spawned.
- It has one required parameter:
destroySpheres
- Destroys all selected spheres. Contains the following parameters:selector
- A Sphere Selector which will select the spheres to be destroyed.scoreEvent
- Optional. A Score Event which will be executed for the entire batch of spheres.- This Score Event will have a
selector
context, which will have the following variable:sphereCount
- The amount of destroyed spheres.
- This Score Event will have a
scoreEventPerSphere
- Optional. A Score Event which will be executed for each sphere separately.- This Score Event will have a
sphere
context, which is yet another differentsphere
context and it just contains one variable:color
- The color of the Sphere.
- This Score Event will have a
removeMultiSphere
- Erases any currently had Multi-Sphere that the Shooter had.- Has no parameters.
- The
grantScore
,spawnScorpion
,destroyAllSpheres
anddestroyColor
effect types have been removed as their functions have been replaced withexecuteScoreEvent
,spawnPathEntity
anddestroySpheres
for the last two, respectively.
- A few new Collectible Effect types have been introduced:
-
Changes in Sprite data:
- The name of the
frame_size
field has been changed toframeSize
. - The
internal
field has been removed.
- The name of the
-
Changes in Sound Event data:
- Sound Events have been overhauled and can now play multiple sounds at once, each with their own parameters and conditions. Old syntax of sound events is still supported.
- Sound Events using stereo sounds no longer need to have their
flat
flag set totrue
, and it is ignored altogether instead to prevent crashing. - The
path
field has been renamed tosound
. - A new optional field has been added:
instances
- Defaults to8
, which mimicks the current behavior. A number of sounds from the same file which can be playing simultaneously.
- Added a new optional field,
sounds
.- Allows setting multiple sounds at once.
- Cannot coexist with other fields.
- Is a list of objects, each with the following fields:
sound
- Path to the sound file.loop
- Whether the sound should loop.flat
- Whether 3D positioning should be ignored for this sound.volume
- The volume of the sound.pitch
- The pitch of the sound.instances
- The number of instances, 8 by default.conditions
- A list of conditions, each of them is an Expression which should evaluate to a boolean value.
- All of the fields, except
sound
, are optional.
-
Changes in Particle data:
- The root tag is no longer a list - it's now an object. It contains a single field:
emitters
- A list of emitters. This is the place where the entire old data should be put.
- The root tag is no longer a list - it's now an object. It contains a single field:
-
Changes in UI scripts:
- Three new functions have been added:
f.levelGetAccuracy()
- Returns the level accuracy as a percentage, from 0 to 1, both inclusive, where0
is 0% accuracy, and1
is 100% accuracy.f.sessionTerminate()
- Ends the game and fires thegameOver
callback.f.levelExecuteScoreEvent(event, pos)
- Executes a Score Event, optionally at a given position.- Has two parameters:
event
- Path to a Score Event resource.pos
(optional) - The event position, as a Vector2.- Since until now the UI script did not utilize Vector2's, you might need to import Vector2 from the game code. I did not test whether that works with the fused executable.
- Has two parameters:
- Added a second, required argument to the
profileNewGame
function:difficulty
- The path to the Difficulty on which this game will be started, e.g."difficulties/easy.json"
.
- Three new functions have been added:
-
Changes in Expressions:
- Added Expression Contexts, which are required in some new (and existing) configuration files to work. They are extremely powerful, but come with a few challenges regarding to usage. You can find some information on Expression Contexts here.
- One Expression Context is available almost all of the time (except when there is no Profile selected):
session
.- Exists when a Profile is selected and that Profile has a Session active (a game in progress or a saved game).
- Has the following variables:
session.lives
- How many lives the player currently has.session.coins
- How many coins the player currently has.session.score
- The current player's score.
- One Expression Context is available almost all of the time (except when there is no Profile selected):
- You can now use
'
's to delimit strings. Useful when you're using a lot of strings in an expression - previously, you needed to have all of the"
's escaped and that looked... ugly. \n
in a string will now properly convert it into a newline character.- A new function has been added:
strnum
.- Converts a number to a string, applying a thousands separator.
- Example:
strnum(100000)
->"100,000"
- Added Expression Contexts, which are required in some new (and existing) configuration files to work. They are extremely powerful, but come with a few challenges regarding to usage. You can find some information on Expression Contexts here.
Gameplay
- The spheres during chain reactions will now stop once there's no predicted match right after the current one. This mostly matches Luxor 1/AR/2's behavior.
- This only applies when the
luxorized
flag inconfig/gameplay.json
is set totrue
, which is the default value for converted games.
- This only applies when the
- The spawn streak has been lowered from 0.45 to 0.3 to better match the original games.
- The fireball radius has been increased from 75 to 100 pixels.
- Matches now start giving additional 100 points starting from combo x3, not x4.
- Color Bombs no longer destroy spheres that are offscreen.
- Color Bomb's and Lightning's score is now properly displayed where the spheres are destroyed, not above the shooter.
- Any powerup that can destroy spheres but destroys none no longer creates a score label that says "0".
- Powerups now have the correct name when activated:
- "WILD!" -> "WILD BALL!"
- "FIREBALL!" -> "FIRE BALL!"
- When the level is cleared, the bonus scarabs will now come out a second later than until now, to better match the original game.
- There can now be multiple Lightning Storms at once and the delay between strikes is randomized.
- Net disappears when Bonus Scarabs appear.
- The Scorpion now correctly registers a chain kill when destroying a chain in which the Scarab was in its own group (isolated from the last destructible sphere).
- The distance from the spawn point where the Scorpion gives up has been decreased from 64 to 16 pixels.
- The danger music will now start instantly instead of fading in, and will also start from beginning if it went completely silent. This clones the Luxor 2's behavior, however it breaks parity with Luxor 1/AR where the danger music fades in (it still starts from the beginning, so that's a progress I guess?)
- The shooter in Luxor/Luxor AR's How To Play screen is now properly animated.
General
- Updated the LOVE2D version from 11.3 to 11.5.
- Font characters and sprites are now only drawn at integer locations, which should mostly eliminate bleeding and blurring of ingame text.
- The engine will no longer crash if it encounters a corrupted file entry in the filesystem.
- Lightning Storm and new group sounds now have proper 3D positioning applied.
Boot Screen
- You can now instantly load a particular game and skip the Boot Screen using the
-g game_name
parameter. - A new option has been added: "Hide unsupported games".
- This option does not work right now.
- The legacy game upgrade code has been removed.
Debug
- Changes to the console (open with
Ctrl + `
):- Three new commands have been added:
help
- Lists all available commands in alphabetical order.ls
- Spawns a Lightning Storm (10 strikes).net
- Spawns a Net (20 seconds).
- The
ex
,expr
andexprt
commands now accept spaces in the expression to be evaluated. - You can now access previously typed in commands by pressing the Up/Down arrows while the console is open.
- You can now paste text into the console input box.
- The console text now has a shadow :)
- Three new commands have been added:
- The F1 debug menu will now display all available debug shortcuts.
- The F2 debug screen (UI tree) has been greatly improved:
- Now works properly with both UI1 and UI2.
- It is now shown regardless of whether a profile exists.
- The formatting is now much cleaner. Widget types are color coded.
- You can scroll the list using a mouse wheel, PgUp/PgDown keys or a scrollbar on the left.
- Each entry in the debug UI tree can now be collapsed by clicking on it.
- You can automatically hide all UI widgets that are invisible at the time - press
Ctrl+F2
to toggle this function on or off (it's extremely powerful!) - Hovering on a UI tree entry will highlight the associated UI node and show its logical position as a crosshair.
- The F4 debug screen will now show the current Level Sequence step and the current level accuracy.
- If the console window is forced to be open (launching from a shell script) even though the console window is disabled in the Boot Screen, that console will not print any text to avoid tanking performance on Windows machines.
Bugfixes
- Fixed a crash when the F2 key was pressed.
- Fixed a crash that could occur when spheres near the path's spawn point were destroyed with the continuous sphere generation enabled.
- Multi-spheres would appear in the shooter immediately after restarting, instead of regular spheres.
- The volume and pitch of the sounds were coupled together (both were controlled from the
volume
field). - [#128] Properly fixed spawning new groups when the objectives have been reached on the same frame - now they won't spawn.