- Version 1.4.0 released!
- Version 1.4.0 has landed!
- This update focuses on a whole host of new modding features and some fixes sprinkled in too.
- New Level commands
- Added `waitForNoSpecificEntity(string entity, int timeout = -1)`
- Added `ifNotSpecificEntityOnScreen(string entity, int places)`
- Added `ifCreditCountBelow(int creditCount, int places)`
- Added `ifCreditCountAbove(int creditCount, int places)`
- Added `ifCreditCountEqual(int creditCount, int places)`
- Added `ifPlayerWeaponIs(int weaponID, int places)`
- Added `ifPlayerHasPods(int places)`
- Added `destroyEntityOfType(string entityName, bool isKill)`
- Added `destroyEntitiesOfType(string entityName, bool isKill)`
- Added destroyEnemyEntities(bool isKill)
- Audio Definitions
- Added `s_pause`: this is a duplicate of `s_star1`
- Added `s_exit_attract`: this is a duplicate of `s_star1`
- Added `s_ui_main_toggle_sfx_setting`: this is a duplicate of `s_star1`
- Added optional `s_fruit_cherry`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
- Added optional `s_fruit_cherry_small`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
- Added optional `s_fruit_bananas`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
- Added optional `s_fruit_bananas_small`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
- Added optional `s_fruit_grapes`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
- Added optional `s_fruit_grapes_small`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
- Added optional `s_fruit_coin`: if not defined, we simply fall back to `s_fruit (pickup sfx
- Lua API
- Piped lua's default print function to the game's log
- Made use of JSONObject fallbacks in `saucer.lua`'s commandArgs
- Changed `SpawnEntityWorld(entityName, worldPosition, arguments)`: Now returns an integer, this is the entityID
- Changed `SpawnEntityWorld(entityName, worldPosition, arguments)`: Argument parameter is now optional (no longer requiring creation of an empty JSONObject)
- Changed `SpawnEntityLocal(entityName, localPosition, arguments)`: Now returns an integer, this is the entityID
- Changed `SpawnEntityLocal(entityName, localPosition, arguments)`: Argument parameter is now optional (no longer requiring creation of an empty JSONObject)
- Changed `SpawnEntityChild(entityName, parent, positionOffset, arguments)`: Now returns an integer, this is the entityID
- Changed `SpawnEntityChild(entityName, parent, positionOffset, arguments)`: Argument parameter is now optional (no longer requiring creation of an empty JSONObject)
- Added `GetEntity(entityID)`
- Changed `GetPlayer(index)`: Now expects an integer
- Added `MoveTowardsAngle(current, target, maxDelta)`
- Added `DeltaAngle(current, target)`
- Added `IsOriginalVersion()`
- Added `GetSpriteDimensions(animationName, spriteIndex)`
- Added `MakeBonuses(x, y, fruitSetID)`
- Added `AdjustXToWideScreen(x)`
- Added `NewDiffDictInt(veryEasy, easy, normal, hard, nasty)`
- Added `NewDiffDictFloat(veryEasy, easy, normal, hard, nasty)`
- Added `NewDiffDictBool(veryEasy, easy, normal, hard, nasty)`
- Added `NewDiffDictString(veryEasy, easy, normal, hard, nasty)`
- Added `NewDiffDictIntArray(veryEasy, easy, normal, hard, nasty)`
- Added `NewDiffDictFloatArray(veryEasy, easy, normal, hard, nasty)`
- Added `NewDiffDictBoolArray(veryEasy, easy, normal, hard, nasty)`
- Added `NewDiffDictStringArray(veryEasy, easy, normal, hard, nasty)`
- Added `Globals.isPassiveResistance`
- Added `Globals.trainEntities`
- Added `Globals.trainBonus`
- Added `Globals.trainCounter`
- Added `Globals.custom`
- Fixed `Globals.ScrollingSpeed(layer)` being nil
- Fixed `Globals.firewait` being nil
- Fixed `Globals.levelLifetime` being nil
- Fixed `Globals.createSplashes` being nil
- Fixed `Globals.bonusScores` being nil
- Fixed `Globals.layerScaleValues` being nil
- Fixed `Globals.horizonLevels` being nil
- Fixed `Globals.layerReflections` being nil
- Fixed `Globals.firingChanceSaucer` being nil
- Fixed `Globals.firingChanceRandomFishFighter` being nil
- Added `SpriteAnimator.worldPosition`
- Added `SpriteAnimator.rotation`
- Added `SpriteAnimator.enabled`
- Added `Player.lastUpdateTime`
- Added `Player.nextUpdateTime`
- Added `Player.lastPosition`
- Added `Player.nextPosition`
- Added `Player.position`
- Added `Player.worldPosition`
- Added `Player.isActive`
- Deprecated `Player.GetPosition()`: use `Player.position` instead
- Deprecated `Player.GetWorldPosition()`: use `Player.worldPosition` instead
- Added `BaseEntity.customBehaviourData`
- Added `BaseEntity.entityID`
- Added `BaseEntity.lastUpdateTime`
- Added `BaseEntity.nextUpdateTime`
- Added `BaseEntity.lastPosition`
- Added `BaseEntity.nextPosition`
- Added `BaseEntity.rotation`
- Added `BaseEntity.defaultOnHitByBulletBehaviour`
- Added `BaseEntity.defaultOnHitByPlayerBehaviour`
- Added `BaseEntity.BulletConsume(consumer)`
- Added `BaseEntity.BulletGetKillCreditIndex()`
- Added `BaseEntity.EndKillTimer()`
- Fixed `BaseEntity.GetDamageFrame(maxHitPoints, hitPoints, frameCount)` being nil
- Fixed `BaseEntity.CheckCollision(collider, playerCollisionCallback?, bulletCollisionCallback?)` behaving incorrectly when passing nil as callbacks
- Fixed `BaseEntity.SpawnShipDebris(count, mxMin, mxMax, myMin, myMax, xOffset, yOffset, mxSpawnDirectionMin, mxSpawnDirectionMax, mySpawnDirectionMin, mySpawnDirectionMax)` not spawning secondary debris
- Changed `JSONObject.GetFieldString(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldString(my_name, my_fallback_value)`
- Changed `JSONObject.GetFieldFloat(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldFloat(my_name, my_fallback_value)`
- Changed `JSONObject.GetFieldInt(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldInt(my_name, my_fallback_value)`
- Changed `JSONObject.GetFieldBool(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldBool(my_name, my_fallback_value)`
- Changed `JSONObject.GetFieldStringArray(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldStringArray(my_name, my_fallback_value)`
- Changed `JSONObject.GetFieldFloatArray(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldFloatArray(my_name, my_fallback_value)`
- Changed `JSONObject.GetFieldIntArray(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldIntArray(my_name, my_fallback_value)`
- Changed `JSONObject.GetFieldBoolArray(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldBoolArray(my_name, my_fallback_value)`
- Removed `FirePattern.NewFirePatternFromEntityData(data)`: It was nil before, so no compatibility breaks
- Added `TurretData.CalculateBulletParams(worldPosition, angleOffset)`
- Added `Collider2D.boolean`
- Added `Collider2D.SetLogicLayerDefault()`
- Added `Collider2D.SetLogicLayerTransparentFX()`
- Added `Collider2D.SetLogicLayerIgnoreRaycast()`
- Added `Collider2D.SetLogicLayerWater()`
- Added `Collider2D.SetLogicLayerUI()`
- Added `Collider2D.SetLogicLayerPlayer()`
- Added `Collider2D.SetLogicLayerPlayerShot()`
- Added `Collider2D.SetLogicLayerEnemy()`
- Added `Collider2D.SetLogicLayerEnemyShot()`
- Added `Collider2D.SetLogicLayerLoadScreen()`
- Added `Collider2D.SetLogicLayerPlayerPickupCollider()`
- Added `Collider2D.SetLogicLayerPickup()`
- Added Collider2D.SetLogicLayerPlayerShotNoFruit()
- Lua globals.lua
- Defined `AnimationType`: Enum for usable values (previously only in the documentation)
- Defined `GameDifficulty`: Enum for usable values (previously only in the documentation)
- Defined `ScoreSource`: Enum for usable values (previously only in the documentation)
- Added `RandRangeF(min, max)`
- Added `RandRange(min, max)`
- Added `Round(value)`
- Added `Clamp(value, min, max)`
- Added `Lerp(min, max, t)`
- Added `CreateTurret(entity, xOff, yOff, parent, waiter)`
- Deprecated `round(value)`: Use `Round(value)` instead
- Deprecated `clamp(value, min, max)`: Use `Clamp(alue, min, max` instea
- Example scripts
- Implemented `car.lua` example script
- This is the stage one boss in the game
- Example of turret entities, in this case spawning them manually
- Example of Global counters
- Example of multi entity enemies
- Example of a boss fight
- Example of custom hit responses using custom colliders
- Example of linked enemies (movement depending on the next segment)
- Example of `BaseEntity.IsKilledManually`
- Example of spawning other entities
- Example of `EntityData.customBehaviourData`
- Implemented `enemy_bullet.lua` example script
- This is the basic bullets fired by saucers and other enemies
- Example of `EntityData.customBehaviourData`
- Example of manual sprite frame handling
- Example of player dependent logic
- Implemented `reclayed_turret.lua` example script
- This is the base for most of the turrets used
- Example of TurretData
- Example of FirePattern
- Example of stationary enemy, designed to be attached to another
- Example of properly spawning bullets
- Example of `EntityData.customBehaviourData`
- Example of player dependent logic
- Misc
- Fixed Boss 1 sometimes not sorting correctly, this was visible on the chain element
- Fixed `EnemyHomerBullet` corrupting when multiple entities used it with differing `customBehaviourData`
- Exposed `speed` and `tickTurnDegrees` as `customBehaviourData` in `HomingMissile` behaviour
- Increased class strictness in LLS definition `types.lua` (Will now warn you if you try to use a field that doesn't exist)
- Added `Trail` behaviour, functioning as a way to create customizable trails for any entity. See `"exampleTrail"` in `entities.json`
- Fixed `Lua` behaviours not defaulting to the default layer when reused
- Fixed `Lua` cleaning up their functions too early (the game expects function pointers to still be valid during the frame kill was called)
- Updated documentation