1. Version 1.4.0 released!
  2.  
  3. Version 1.4.0 has landed!
  4.  
  5. This update focuses on a whole host of new modding features and some fixes sprinkled in too.
  6.  
  7.  
  8. New Level commands
  9.  
  10. Added `waitForNoSpecificEntity(string entity, int timeout = -1)`
  11.  
  12. Added `ifNotSpecificEntityOnScreen(string entity, int places)`
  13.  
  14. Added `ifCreditCountBelow(int creditCount, int places)`
  15.  
  16. Added `ifCreditCountAbove(int creditCount, int places)`
  17.  
  18. Added `ifCreditCountEqual(int creditCount, int places)`
  19.  
  20. Added `ifPlayerWeaponIs(int weaponID, int places)`
  21.  
  22. Added `ifPlayerHasPods(int places)`
  23.  
  24. Added `destroyEntityOfType(string entityName, bool isKill)`
  25.  
  26. Added `destroyEntitiesOfType(string entityName, bool isKill)`
  27.  
  28. Added destroyEnemyEntities(bool isKill)
  29.  
  30. Audio Definitions
  31.  
  32. Added `s_pause`: this is a duplicate of `s_star1`
  33.  
  34. Added `s_exit_attract`: this is a duplicate of `s_star1`
  35.  
  36. Added `s_ui_main_toggle_sfx_setting`: this is a duplicate of `s_star1`
  37.  
  38. Added optional `s_fruit_cherry`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
  39.  
  40. Added optional `s_fruit_cherry_small`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
  41.  
  42. Added optional `s_fruit_bananas`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
  43.  
  44. Added optional `s_fruit_bananas_small`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
  45.  
  46. Added optional `s_fruit_grapes`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
  47.  
  48. Added optional `s_fruit_grapes_small`: if not defined, we simply fall back to `s_fruit` (pickup sfx)
  49.  
  50. Added optional `s_fruit_coin`: if not defined, we simply fall back to `s_fruit (pickup sfx
  51.  
  52. Lua API
  53.  
  54. Piped lua's default print function to the game's log
  55.  
  56. Made use of JSONObject fallbacks in `saucer.lua`'s commandArgs
  57.  
  58. Changed `SpawnEntityWorld(entityName, worldPosition, arguments)`: Now returns an integer, this is the entityID
  59.  
  60. Changed `SpawnEntityWorld(entityName, worldPosition, arguments)`: Argument parameter is now optional (no longer requiring creation of an empty JSONObject)
  61.  
  62. Changed `SpawnEntityLocal(entityName, localPosition, arguments)`: Now returns an integer, this is the entityID
  63.  
  64. Changed `SpawnEntityLocal(entityName, localPosition, arguments)`: Argument parameter is now optional (no longer requiring creation of an empty JSONObject)
  65.  
  66. Changed `SpawnEntityChild(entityName, parent, positionOffset, arguments)`: Now returns an integer, this is the entityID
  67.  
  68. Changed `SpawnEntityChild(entityName, parent, positionOffset, arguments)`: Argument parameter is now optional (no longer requiring creation of an empty JSONObject)
  69.  
  70. Added `GetEntity(entityID)`
  71.  
  72. Changed `GetPlayer(index)`: Now expects an integer
  73.  
  74. Added `MoveTowardsAngle(current, target, maxDelta)`
  75.  
  76. Added `DeltaAngle(current, target)`
  77.  
  78. Added `IsOriginalVersion()`
  79.  
  80. Added `GetSpriteDimensions(animationName, spriteIndex)`
  81.  
  82. Added `MakeBonuses(x, y, fruitSetID)`
  83.  
  84. Added `AdjustXToWideScreen(x)`
  85.  
  86. Added `NewDiffDictInt(veryEasy, easy, normal, hard, nasty)`
  87.  
  88. Added `NewDiffDictFloat(veryEasy, easy, normal, hard, nasty)`
  89.  
  90. Added `NewDiffDictBool(veryEasy, easy, normal, hard, nasty)`
  91.  
  92. Added `NewDiffDictString(veryEasy, easy, normal, hard, nasty)`
  93.  
  94. Added `NewDiffDictIntArray(veryEasy, easy, normal, hard, nasty)`
  95.  
  96. Added `NewDiffDictFloatArray(veryEasy, easy, normal, hard, nasty)`
  97.  
  98. Added `NewDiffDictBoolArray(veryEasy, easy, normal, hard, nasty)`
  99.  
  100. Added `NewDiffDictStringArray(veryEasy, easy, normal, hard, nasty)`
  101.  
  102. Added `Globals.isPassiveResistance`
  103.  
  104. Added `Globals.trainEntities`
  105.  
  106. Added `Globals.trainBonus`
  107.  
  108. Added `Globals.trainCounter`
  109.  
  110. Added `Globals.custom`
  111.  
  112. Fixed `Globals.ScrollingSpeed(layer)` being nil
  113.  
  114. Fixed `Globals.firewait` being nil
  115.  
  116. Fixed `Globals.levelLifetime` being nil
  117.  
  118. Fixed `Globals.createSplashes` being nil
  119.  
  120. Fixed `Globals.bonusScores` being nil
  121.  
  122. Fixed `Globals.layerScaleValues` being nil
  123.  
  124. Fixed `Globals.horizonLevels` being nil
  125.  
  126. Fixed `Globals.layerReflections` being nil
  127.  
  128. Fixed `Globals.firingChanceSaucer` being nil
  129.  
  130. Fixed `Globals.firingChanceRandomFishFighter` being nil
  131.  
  132. Added `SpriteAnimator.worldPosition`
  133.  
  134. Added `SpriteAnimator.rotation`
  135.  
  136. Added `SpriteAnimator.enabled`
  137.  
  138. Added `Player.lastUpdateTime`
  139.  
  140. Added `Player.nextUpdateTime`
  141.  
  142. Added `Player.lastPosition`
  143.  
  144. Added `Player.nextPosition`
  145.  
  146. Added `Player.position`
  147.  
  148. Added `Player.worldPosition`
  149.  
  150. Added `Player.isActive`
  151.  
  152. Deprecated `Player.GetPosition()`: use `Player.position` instead
  153.  
  154. Deprecated `Player.GetWorldPosition()`: use `Player.worldPosition` instead
  155.  
  156. Added `BaseEntity.customBehaviourData`
  157.  
  158. Added `BaseEntity.entityID`
  159.  
  160. Added `BaseEntity.lastUpdateTime`
  161.  
  162. Added `BaseEntity.nextUpdateTime`
  163.  
  164. Added `BaseEntity.lastPosition`
  165.  
  166. Added `BaseEntity.nextPosition`
  167.  
  168. Added `BaseEntity.rotation`
  169.  
  170. Added `BaseEntity.defaultOnHitByBulletBehaviour`
  171.  
  172. Added `BaseEntity.defaultOnHitByPlayerBehaviour`
  173.  
  174. Added `BaseEntity.BulletConsume(consumer)`
  175.  
  176. Added `BaseEntity.BulletGetKillCreditIndex()`
  177.  
  178. Added `BaseEntity.EndKillTimer()`
  179.  
  180. Fixed `BaseEntity.GetDamageFrame(maxHitPoints, hitPoints, frameCount)` being nil
  181.  
  182. Fixed `BaseEntity.CheckCollision(collider, playerCollisionCallback?, bulletCollisionCallback?)` behaving incorrectly when passing nil as callbacks
  183.  
  184. Fixed `BaseEntity.SpawnShipDebris(count, mxMin, mxMax, myMin, myMax, xOffset, yOffset, mxSpawnDirectionMin, mxSpawnDirectionMax, mySpawnDirectionMin, mySpawnDirectionMax)` not spawning secondary debris
  185.  
  186. Changed `JSONObject.GetFieldString(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldString(my_name, my_fallback_value)`
  187.  
  188. Changed `JSONObject.GetFieldFloat(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldFloat(my_name, my_fallback_value)`
  189.  
  190. Changed `JSONObject.GetFieldInt(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldInt(my_name, my_fallback_value)`
  191.  
  192. Changed `JSONObject.GetFieldBool(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldBool(my_name, my_fallback_value)`
  193.  
  194. Changed `JSONObject.GetFieldStringArray(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldStringArray(my_name, my_fallback_value)`
  195.  
  196. Changed `JSONObject.GetFieldFloatArray(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldFloatArray(my_name, my_fallback_value)`
  197.  
  198. Changed `JSONObject.GetFieldIntArray(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldIntArray(my_name, my_fallback_value)`
  199.  
  200. Changed `JSONObject.GetFieldBoolArray(name)`: To take an additional `fallback?` parameter: e.g. `GetFieldBoolArray(my_name, my_fallback_value)`
  201.  
  202. Removed `FirePattern.NewFirePatternFromEntityData(data)`: It was nil before, so no compatibility breaks
  203.  
  204. Added `TurretData.CalculateBulletParams(worldPosition, angleOffset)`
  205.  
  206. Added `Collider2D.boolean`
  207.  
  208. Added `Collider2D.SetLogicLayerDefault()`
  209.  
  210. Added `Collider2D.SetLogicLayerTransparentFX()`
  211.  
  212. Added `Collider2D.SetLogicLayerIgnoreRaycast()`
  213.  
  214. Added `Collider2D.SetLogicLayerWater()`
  215.  
  216. Added `Collider2D.SetLogicLayerUI()`
  217.  
  218. Added `Collider2D.SetLogicLayerPlayer()`
  219.  
  220. Added `Collider2D.SetLogicLayerPlayerShot()`
  221.  
  222. Added `Collider2D.SetLogicLayerEnemy()`
  223.  
  224. Added `Collider2D.SetLogicLayerEnemyShot()`
  225.  
  226. Added `Collider2D.SetLogicLayerLoadScreen()`
  227.  
  228. Added `Collider2D.SetLogicLayerPlayerPickupCollider()`
  229.  
  230. Added `Collider2D.SetLogicLayerPickup()`
  231.  
  232. Added Collider2D.SetLogicLayerPlayerShotNoFruit()
  233.  
  234. Lua globals.lua
  235.  
  236. Defined `AnimationType`: Enum for usable values (previously only in the documentation)
  237.  
  238. Defined `GameDifficulty`: Enum for usable values (previously only in the documentation)
  239.  
  240. Defined `ScoreSource`: Enum for usable values (previously only in the documentation)
  241.  
  242. Added `RandRangeF(min, max)`
  243.  
  244. Added `RandRange(min, max)`
  245.  
  246. Added `Round(value)`
  247.  
  248. Added `Clamp(value, min, max)`
  249.  
  250. Added `Lerp(min, max, t)`
  251.  
  252. Added `CreateTurret(entity, xOff, yOff, parent, waiter)`
  253.  
  254. Deprecated `round(value)`: Use `Round(value)` instead
  255.  
  256. Deprecated `clamp(value, min, max)`: Use `Clamp(alue, min, max` instea
  257.  
  258. Example scripts
  259.  
  260. Implemented `car.lua` example script
  261.  
  262. This is the stage one boss in the game
  263.  
  264. Example of turret entities, in this case spawning them manually
  265.  
  266. Example of Global counters
  267.  
  268. Example of multi entity enemies
  269.  
  270. Example of a boss fight
  271.  
  272. Example of custom hit responses using custom colliders
  273.  
  274. Example of linked enemies (movement depending on the next segment)
  275.  
  276. Example of `BaseEntity.IsKilledManually`
  277.  
  278. Example of spawning other entities
  279.  
  280. Example of `EntityData.customBehaviourData`
  281.  
  282. Implemented `enemy_bullet.lua` example script
  283.  
  284. This is the basic bullets fired by saucers and other enemies
  285.  
  286. Example of `EntityData.customBehaviourData`
  287.  
  288. Example of manual sprite frame handling
  289.  
  290. Example of player dependent logic
  291.  
  292. Implemented `reclayed_turret.lua` example script
  293.  
  294. This is the base for most of the turrets used
  295.  
  296. Example of TurretData
  297.  
  298. Example of FirePattern
  299.  
  300. Example of stationary enemy, designed to be attached to another
  301.  
  302. Example of properly spawning bullets
  303.  
  304. Example of `EntityData.customBehaviourData`
  305.  
  306. Example of player dependent logic
  307.  
  308.  
  309. Misc
  310.  
  311. Fixed Boss 1 sometimes not sorting correctly, this was visible on the chain element
  312.  
  313. Fixed `EnemyHomerBullet` corrupting when multiple entities used it with differing `customBehaviourData`
  314.  
  315. Exposed `speed` and `tickTurnDegrees` as `customBehaviourData` in `HomingMissile` behaviour
  316.  
  317. Increased class strictness in LLS definition `types.lua` (Will now warn you if you try to use a field that doesn't exist)
  318.  
  319. Added `Trail` behaviour, functioning as a way to create customizable trails for any entity. See `"exampleTrail"` in `entities.json`
  320.  
  321. Fixed `Lua` behaviours not defaulting to the default layer when reused
  322.  
  323. Fixed `Lua` cleaning up their functions too early (the game expects function pointers to still be valid during the frame kill was called)
  324.  
  325. Updated documentation
  326.