
# Modding and behavior changes

This document briefly documents what have been added (or removed) regarding modding capabilities or engine behavior(s)

## JSON additions

---------------

### Worldgen
 * Where applicable, Perlin noise now can have custom seed specified
   * Change above allows to explicitly specify universe seed (as `celestial.config:systemTypePerlin:seed`)
 * Perlin noise now can be of arbitrary scale (defaults to `512`, specified with `scale` key, integer type, 2048>=x>=16)

#### Terrain
 * All composing terrain selectors (such as `min`, `displacement`, `rotate`, etc) now can reference other terrain selectors by name (the `.terrain` files) instead of embedding entire config inside them
   * They can be referenced by either specifying corresponding field as string, or as object like so: `{"name": "namedselector"}`
   * `min`, `max` and `minmax` terrain selectors now also accept next format: `{"name": "namedselector", "seedBias": 4}`
 * `mix` terrain selector got `mixSeedBias`, `aSeedBias` and `bSeedBias` fields, whose deviate respective selectors seeds (default to `0`)
 * `displacement` terrain selector has `seedBias` added, which deviate seed of `source` selector (default to `0`)
 * `displacement` terrain selector has `xClamp` added, works like `yClamp`
 * `rotate` terrain selector has `rotationWidth` (defaults to `0.5`) and `rotationHeight` (defaults to `0.0`) added, which are multiplied by world's size and world's height respectively to determine rotation point center
 * `min` terrain selector added, opposite of existing `max` (json format is the same as `max`)
 * `cache` terrain selector removed due it not being documented, and having little practical value
 * `perlin` terrain selector now accepts `type`, `frequency` and `amplitude` values (naming inconsistency fix)
 * `ridgeblocks` terrain selector now accepts `amplitude` and `frequency` values (naming inconsistency fix);
 * `ridgeblocks` has `octaves` added (defaults to `2`), `perlinOctaves` (defaults to `1`)

#### Biomes
 * Tree biome placeables now have `variantsRange` (defaults to `[1, 1]`) and `subVariantsRange` (defaults to `[2, 2]`)
   * `variantsRange` is responsible for "stem-foliage" combinations
   * `subVariantsRange` is responsible for "stem-foliage" hue shift combinations
     * Rolled per each "stem-foliage" combination
     * Also two more properties were added: `sameStemHueShift` (defaults to `true`) and `sameFoliageHueShift` (defaults to `false`), which fixate hue shifts within same "stem-foliage" combination
   * Original engine always generates two tree types when processing placeable items, new engine however, allows to generate any number of trees.

#### Dungeons
 * `front` and `back` brushes now can properly accept detailed data as json object on second position (e.g. `["front", { "material": ... }]`), with following structure (previously, due to oversight in code, it was impossible to specify this structure through any means, because brush definition itself can't be an object):
```kotlin
val material: Registry.Ref<TileDefinition> = BuiltinMetaMaterials.EMPTY.ref
val modifier: Registry.Ref<TileModifierDefinition> = BuiltinMetaMaterials.EMPTY_MOD.ref
val hueShift: Float = 0f
val modHueShift: Float = 0f
val color: TileColor = TileColor.DEFAULT
```
 * `item` brush now can accept proper item descriptors (in json object tag),
   * Previous behavior remains unchanged (if specified as string, creates _randomized_ item, if as object, creates _exactly_ what have been specified)
   * To stop randomizing as Tiled tileset brush, specify `"dont_randomize"` as anything (e.g. as `""`)
 * `liquid` brush now can accept 'level' as second argument
   * Previous behavior is unchanged, `["liquid", "water", true]` will result into infinite water as before, but `["liquid", "water", 0.5, false]` will spawn half-filled water
   * In tiled, you already can do this using `"quantity"` property
 * `dungeonid` brush has been hooked up to legacy dungeons and now can be directly specified inside `"brush"` (previously they were only accessible when using Tiled' tilesets).
   * By default, they mark entire _part_ of dungeon with their ID. To mark specific tile inside dungeon with its own Dungeon ID, supply `true` as third value to brush (e.g `["dungeonid", 40000, true"]`)
   * Tiled map behavior is unchanged, and marks their position only.

---------------

### player.config
 * Inventory bags are no longer limited to 255 slots
   * However, when joining original servers with mod which increase bag size past 255 slots will result in undefined behavior (joining servers with inventory size bag mods will already result in nearly instant desync though, so you may not ever live to see the side effects; and if original server installs said mod, original clients and original server will experience severe desyncs/undefined behavior too)

---------------

### Prototypes
 * `damageTable` can be defined directly, without referencing other JSON file (experimental feature)

#### Items
 * `inventoryIcon` additions if specified as array:
   * `scale`, either as float or as vector (for x and y scales); both in prototype file and in `parameters`.
   * `color` (defaults to white `[255, 255, 255, 255]`)
   * `rotation` (in degrees, defaults to `0`)
   * `mirrored` (defaults to `false`, this is different from setting scale to `-1f` since it obeys center point)
   * `centered` (defaults to `true`)
   * `fullbright` (defaults to `false`)

#### .matierial
 * Implemented `isConnectable`, which was planned by original developers, but scrapped in process (defaults to `true`, by default only next meta-materials have it set to false: `empty`, `null` and `boundary`)
   * Used by object and plant anchoring code to determine valid placement
   * Used by world tile rendering code (render piece rule `Connects`)
   * And finally, used by `canPlaceMaterial` to determine whenever player can place blocks next to it (at least one such tile should be present for player to be able to place blocks next to it)

## Scripting

---------------

#### Random
 * Added `random:randn(deviation: double, mean: double): double`, returns normally distributed double, where `deviation` stands for [Standard deviation](https://en.wikipedia.org/wiki/Standard_deviation), and `mean` specifies middle point
 * Removed `random:addEntropy`

#### animator

 * Added `animator.targetRotationAngle(rotationGroup: string): double`
 * Added `animator.hasRotationGroup(rotationGroup: string): boolean`
 * Added `animator.rotationGroups(): List<string>` (returns valid names for `rotateGroup`, `currentRotationAngle` and `targetRotationAngle`)
 * Added `animator.transformationGroups(): List<string>`
 * Added `animator.particleEmitters(): List<string>`
 * Added `animator.hasParticleEmitter(emitter: string): boolean`
 * Added `animator.lights(): List<string>`
 * Added `animator.hasLight(light: string): boolean`
 * Added `animator.sounds(): List<string>`
 * Added `animator.effects(): List<string>`
 * Added `animator.hasEffect(effect: string): boolean`
 * Added `animator.parts(): List<string>`

## Behavior

---------------

### Worldgen
 * Major dungeon placement on planets is now deterministic
 * Container item population in dungeons is now deterministic and is based on dungeon seed

#### Dungeons
 * All brushes are now deterministic
