Former-commit-id: 9738d12e5a468b71142745fbf0ce02fcf1ca623c
Former-commit-id: a26b80a1990996d9c05b0909128c210e0f897312
This commit is contained in:
Song Minjae
2016-05-13 20:17:31 +09:00
parent d3e1b17abd
commit 46a3065423
17 changed files with 211 additions and 63 deletions

View File

@@ -8,6 +8,9 @@
### Physics ### ### Physics ###
### System ###
# Resolved # # Resolved #

Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 KiB

After

Width:  |  Height:  |  Size: 347 KiB

View File

@@ -416,12 +416,11 @@ constructor() : BasicGameState() {
/** /**
* Check for duplicates, append actor and sort the list * Check for duplicates, append actor and sort the list
*/ */
fun addActor(actor: Actor): Boolean { fun addActor(actor: Actor) {
if (hasActor(actor.referenceID)) if (hasActor(actor.referenceID))
throw RuntimeException("Actor with ID ${actor.referenceID} already exists.") throw RuntimeException("Actor with ID ${actor.referenceID} already exists.")
actorContainer.add(actor) actorContainer.add(actor)
insertionSortLastElem(actorContainer) // we can do this as we are only adding single actor insertionSortLastElem(actorContainer) // we can do this as we are only adding single actor
return true
} }
/** /**
@@ -445,7 +444,7 @@ constructor() : BasicGameState() {
var index: Int = arr.size - 1 var index: Int = arr.size - 1
x = arr[index] x = arr[index]
j = index - 1 j = index - 1
while (j > 0 && arr[j].referenceID > x.referenceID) { while (j > 0 && arr[j] > x) {
arr[j + 1] = arr[j] arr[j + 1] = arr[j]
j -= 1 j -= 1
} }

View File

@@ -0,0 +1,6 @@
|Range|Description|
|-----|-----------|
|0..4095|Tiles|
|4096..32767|Items|
|32768..0x7FFFFFFF|Actors|
|0x80000000L..0xFFFFFFFFL|Faction|

View File

@@ -2,6 +2,7 @@ package net.torvald.terrarum.gameactors
import net.torvald.random.HQRNG import net.torvald.random.HQRNG
import net.torvald.terrarum.Terrarum import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.itemproperties.ItemPropCodex
import org.newdawn.slick.GameContainer import org.newdawn.slick.GameContainer
/** /**
@@ -21,11 +22,13 @@ abstract class Actor : Comparable<Actor>, Runnable {
override fun equals(other: Any?) = referenceID == (other as Actor).referenceID override fun equals(other: Any?) = referenceID == (other as Actor).referenceID
override fun hashCode() = referenceID override fun hashCode() = referenceID
override fun toString() = if (actorValue.getAsString(AVKey.NAME).isNullOrEmpty()) override fun toString() = "Actor, " + if (actorValue.getAsString(AVKey.NAME).isNullOrEmpty())
"ID: ${hashCode()}" "ID: ${hashCode()}"
else else
"ID: ${hashCode()} (${actorValue.getAsString(AVKey.NAME)})" "ID: ${hashCode()} (${actorValue.getAsString(AVKey.NAME)})"
override fun compareTo(other: Actor): Int = this.referenceID - other.referenceID override fun compareTo(other: Actor): Int = (this.referenceID - other.referenceID).sign()
fun Int.sign(): Int = if (this > 0) 1 else if (this < 0) -1 else this
/** /**
* Usage: * Usage:
@@ -33,11 +36,10 @@ abstract class Actor : Comparable<Actor>, Runnable {
* override var referenceID: Int = generateUniqueReferenceID() * override var referenceID: Int = generateUniqueReferenceID()
*/ */
fun generateUniqueReferenceID(): Int { fun generateUniqueReferenceID(): Int {
fun Int.abs() = if (this < 0) -this else this
var ret: Int var ret: Int
do { do {
ret = HQRNG().nextInt().abs() // set new ID ret = HQRNG().nextInt().and(0x7FFFFFFF) // set new ID
} while (Terrarum.game.hasActor(ret)) // check for collision } while (Terrarum.game.hasActor(ret) || ret < ItemPropCodex.ITEM_UNIQUE_MAX) // check for collision
return ret return ret
} }
} }

View File

@@ -91,7 +91,7 @@ open class ActorWithBody constructor() : Actor(), Visible {
actorValue[AVKey.BASEMASS] = value actorValue[AVKey.BASEMASS] = value
} }
/** Valid range: [0, 1] */ /** Valid range: [0, 1] */
var elasticity = 0.0 var elasticity: Double = 0.0
set(value) { set(value) {
if (value < 0) if (value < 0)
throw IllegalArgumentException("[ActorWithBody] Invalid elasticity value: $value; valid elasticity value is [0, 1].") throw IllegalArgumentException("[ActorWithBody] Invalid elasticity value: $value; valid elasticity value is [0, 1].")
@@ -103,6 +103,18 @@ open class ActorWithBody constructor() : Actor(), Visible {
field = value * ELASTICITY_MAX field = value * ELASTICITY_MAX
} }
@Transient private val ELASTICITY_MAX = 0.993 // No perpetual motion! @Transient private val ELASTICITY_MAX = 0.993 // No perpetual motion!
/**
* what pretty much every physics engine has, instead of my 'elasticity'
*
* This is just a simple macro for 'elasticity'.
*
* Formula: restitution = 1.0 - elasticity
*/
var restitution: Double
set(value) { elasticity = 1.0 - value }
get() = 1.0 - elasticity
private var density = 1000.0 private var density = 1000.0
/** /**
@@ -175,9 +187,11 @@ open class ActorWithBody constructor() : Actor(), Visible {
@Transient val DYNAMIC = 2 @Transient val DYNAMIC = 2
@Transient val STATIC = 3 @Transient val STATIC = 3
private val SLEEP_THRE = 0.125 private val SLEEP_THRE = 1.0 / 16.0
private val CCD_THRE = 1.0 private val CCD_TICK = 1.0 / 16.0
private val CCD_TICK = 0.125
internal var walledLeft = false
internal var walledRight = false
init { init {
@@ -297,6 +311,9 @@ open class ActorWithBody constructor() : Actor(), Visible {
clampNextHitbox() clampNextHitbox()
clampHitbox() clampHitbox()
} }
walledLeft = isColliding(CONTACT_AREA_LEFT, -1, 0)
walledRight = isColliding(CONTACT_AREA_RIGHT, 1, 0)
} }
} }
@@ -534,11 +551,34 @@ open class ActorWithBody constructor() : Actor(), Visible {
val delta: Vector2 = Vector2(hitbox.toVector() - nextHitbox.toVector()) // we need to traverse back, so may as well negate at the first place val delta: Vector2 = Vector2(hitbox.toVector() - nextHitbox.toVector()) // we need to traverse back, so may as well negate at the first place
val ccdDelta = delta.setMagnitude(CCD_TICK) val ccdDelta = delta.setMagnitude(CCD_TICK)
while (isColliding(CONTACT_AREA_LEFT) || isColliding(CONTACT_AREA_RIGHT) if (ccdDelta.x.abs() >= SLEEP_THRE || ccdDelta.y.abs() >= SLEEP_THRE) { // regular situation
|| isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_BOTTOM) // CCD to delta while still colliding
) { while (isColliding(CONTACT_AREA_LEFT) || isColliding(CONTACT_AREA_RIGHT)
// while still colliding, CCD to the 'delta' || isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_BOTTOM)
nextHitbox.translate(ccdDelta) ) {
nextHitbox.translate(ccdDelta)
}
}
else { // stuck while standing still
// CCD upward
var upwardDelta = 0.0
while (isColliding(CONTACT_AREA_LEFT) || isColliding(CONTACT_AREA_RIGHT)
|| isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_BOTTOM)
) {
nextHitbox.translate(0.0, -CCD_TICK)
upwardDelta += CCD_TICK
if (upwardDelta >= TSIZE) break
/* TODO CCD in order of:
.. 10 11 12 13 14 ..
.. 08 03 04 05 09 ..
.. 06 01 [] 02 07 ..
until the stucking is resolved
*/
}
} }
} }
} }
@@ -546,10 +586,9 @@ open class ActorWithBody constructor() : Actor(), Visible {
private fun applyNormalForce() { private fun applyNormalForce() {
if (!isNoCollideWorld) { if (!isNoCollideWorld) {
// axis Y // axis Y
if (veloY >= 0) { // check downward if (moveDelta.y >= 0) { // check downward
if (isColliding(CONTACT_AREA_BOTTOM) || isColliding(CONTACT_AREA_BOTTOM, 0, 1)) { if (isColliding(CONTACT_AREA_BOTTOM) || isColliding(CONTACT_AREA_BOTTOM, 0, 1)) {
// the actor is hitting the ground // the actor is hitting the ground
//veloY = 0.0 // reset veloY, simulating normal force
hitAndReflectY() hitAndReflectY()
grounded = true grounded = true
} }
@@ -557,33 +596,30 @@ open class ActorWithBody constructor() : Actor(), Visible {
grounded = false grounded = false
} }
} }
else if (veloY < 0) { // check upward else if (moveDelta.y < 0) { // check upward
grounded = false grounded = false
if (isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_TOP, 0, -1)) { if (isColliding(CONTACT_AREA_TOP) || isColliding(CONTACT_AREA_TOP, 0, -1)) {
// the actor is hitting the ceiling // the actor is hitting the ceiling
//veloY = 0.0 // reset veloY, simulating normal force
hitAndReflectY() hitAndReflectY()
} }
else { // the actor is not grounded at all else { // the actor is not grounded at all
} }
} }
// axis X // axis X
if (veloX >= 0.5) { // check right if (moveDelta.x > 0) { // check right
if ((isColliding(CONTACT_AREA_RIGHT) && !isColliding(CONTACT_AREA_LEFT)) if ((isColliding(CONTACT_AREA_RIGHT) && !isColliding(CONTACT_AREA_LEFT))
|| (isColliding(CONTACT_AREA_RIGHT, 1, 0) && !isColliding(CONTACT_AREA_LEFT, 0, -1))) { || (isColliding(CONTACT_AREA_RIGHT, 1, 0) && !isColliding(CONTACT_AREA_LEFT, 0, -1))) {
// the actor is hitting the right wall // the actor is hitting the right wall
//veloX = 0.0 // reset veloX, simulating normal force
hitAndReflectX() hitAndReflectX()
} }
else { else {
} }
} }
else if (veloX <= -0.5) { // check left else if (moveDelta.x < 0) { // check left
// System.out.println("collidingleft"); // System.out.println("collidingleft");
if ((isColliding(CONTACT_AREA_LEFT) && !isColliding(CONTACT_AREA_RIGHT)) if ((isColliding(CONTACT_AREA_LEFT) && !isColliding(CONTACT_AREA_RIGHT))
|| (isColliding(CONTACT_AREA_LEFT, -1, 0) && !isColliding(CONTACT_AREA_RIGHT, 1, 0))) { || (isColliding(CONTACT_AREA_LEFT, -1, 0) && !isColliding(CONTACT_AREA_RIGHT, 1, 0))) {
// the actor is hitting the left wall // the actor is hitting the left wall
//veloX = 0.0 // reset veloX, simulating normal force
hitAndReflectX() hitAndReflectX()
} }
else { else {
@@ -597,18 +633,22 @@ open class ActorWithBody constructor() : Actor(), Visible {
private fun hitAndReflectX() { private fun hitAndReflectX() {
if ((veloX * elasticity).abs() > SLEEP_THRE) { if ((veloX * elasticity).abs() > SLEEP_THRE) {
veloX *= -elasticity veloX *= -elasticity
walkX *= -elasticity
} }
else { else {
veloX = 0.0 veloX = 0.0
walkX = 0.0
} }
} }
private fun hitAndReflectY() { private fun hitAndReflectY() {
if ((veloY * elasticity).abs() > SLEEP_THRE) { if ((veloY * elasticity).abs() > SLEEP_THRE) {
veloY *= -elasticity veloY *= -elasticity
walkY *= -elasticity
} }
else { else {
veloY = 0.0 veloY = 0.0
walkY *= 0.0
} }
} }

View File

@@ -16,7 +16,7 @@ class DroppedItem constructor(itemID: Int) : ActorWithBody() {
isVisible = true isVisible = true
mass = if (itemID < 4096) mass = if (itemID < TilePropCodex.TILE_UNIQUE_MAX)
TilePropCodex.getProp(itemID).density / 1000.0 TilePropCodex.getProp(itemID).density / 1000.0
else else
ItemPropCodex.getProp(itemID).mass ItemPropCodex.getProp(itemID).mass

View File

@@ -73,7 +73,7 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan
} }
companion object { companion object {
@Transient internal const val ACCEL_MULT_IN_FLIGHT: Double = 0.31 @Transient internal const val ACCEL_MULT_IN_FLIGHT: Double = 0.21 // TODO air control still too 'slippery' with 0.31, lower the value!
@Transient internal const val WALK_ACCEL_BASE: Double = 0.67 @Transient internal const val WALK_ACCEL_BASE: Double = 0.67
@Transient const val PLAYER_REF_ID: Int = 0x51621D @Transient const val PLAYER_REF_ID: Int = 0x51621D
@@ -130,33 +130,35 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan
* @author minjaesong * @author minjaesong
*/ */
private fun walkHorizontal(left: Boolean, absAxisVal: Float) { private fun walkHorizontal(left: Boolean, absAxisVal: Float) {
readonly_totalX = //veloX + if ((!walledLeft && left) || (!walledRight && !left)) {
/*actorValue.getAsDouble(AVKey.ACCEL)!! * readonly_totalX = //veloX +
/*actorValue.getAsDouble(AVKey.ACCEL)!! *
actorValue.getAsDouble(AVKey.ACCELMULT)!! * actorValue.getAsDouble(AVKey.ACCELMULT)!! *
Math.sqrt(scale) * Math.sqrt(scale) *
applyAccelRealism(walkPowerCounter) * applyAccelRealism(walkPowerCounter) *
(if (left) -1 else 1).toFloat() * (if (left) -1 else 1).toFloat() *
absAxisVal*/ absAxisVal*/
actorValue.getAsDouble(AVKey.ACCEL)!! * actorValue.getAsDouble(AVKey.ACCEL)!! *
actorValue.getAsDouble(AVKey.ACCELMULT)!! * actorValue.getAsDouble(AVKey.ACCELMULT)!! *
Math.sqrt(scale) * Math.sqrt(scale) *
applyVelo(walkCounter) * applyVelo(walkCounter) *
(if (left) -1 else 1).toFloat() * (if (left) -1 else 1).toFloat() *
absAxisVal absAxisVal
//applyForce(Vector2(readonly_totalX, 0.0)) //applyForce(Vector2(readonly_totalX, 0.0))
walkX += readonly_totalX walkX += readonly_totalX
walkX = absClamp(walkX, actorValue.getAsDouble(AVKey.SPEED)!! * actorValue.getAsDouble(AVKey.SPEEDMULT)!!) walkX = absClamp(walkX, actorValue.getAsDouble(AVKey.SPEED)!! * actorValue.getAsDouble(AVKey.SPEEDMULT)!!)
walkCounter += 1 walkCounter += 1
// Heading flag // Heading flag
if (left) if (left)
walkHeading = LEFT walkHeading = LEFT
else else
walkHeading = RIGHT walkHeading = RIGHT
println("$walkCounter: ${readonly_totalX}") // println("$walkCounter: ${readonly_totalX}")
}
} }
/** /**
@@ -243,7 +245,9 @@ class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, Lan
} }
/** /**
* See ./work_files/Jump\ power\ by\ pressing\ time.gcx * See ./work_files/Jump power by pressing time.gcx
*
* TODO linear function (play Super Mario Bros. and you'll get what I'm talking about)
*/ */
private fun jump() { private fun jump() {
if (jumping) { if (jumping) {

View File

@@ -7,17 +7,16 @@ import java.util.HashSet
/** /**
* Created by minjaesong on 16-02-15. * Created by minjaesong on 16-02-15.
*/ */
class Faction(factionName: String) { class Faction(name: String) : Comparable<Faction> {
lateinit var factionName: String var factionName: String = name
lateinit var factionAmicable: HashSet<String> lateinit var factionAmicable: HashSet<String>
lateinit var factionNeutral: HashSet<String> lateinit var factionNeutral: HashSet<String>
lateinit var factionHostile: HashSet<String> lateinit var factionHostile: HashSet<String>
lateinit var factionFearful: HashSet<String> lateinit var factionFearful: HashSet<String>
var factionID: Long = generateUniqueID() var referenceID: Long = generateUniqueID()
init { init {
this.factionName = factionName
factionAmicable = HashSet<String>() factionAmicable = HashSet<String>()
factionNeutral = HashSet<String>() factionNeutral = HashSet<String>()
factionHostile = HashSet<String>() factionHostile = HashSet<String>()
@@ -60,8 +59,18 @@ class Faction(factionName: String) {
factionFearful.remove(faction) factionFearful.remove(faction)
} }
fun generateUniqueID(): Long { private fun generateUniqueID(): Long {
fun Long.abs() = if (this < 0) -this else this var ret: Long
return HQRNG().nextLong().abs() // set new ID do {
ret = HQRNG().nextLong().or(0x80000000L).and(0xFFFFFFFFL) // guaranteed to be 2147483648..4294967295
} while (FactionCodex.hasFaction(ret)) // check for collision
return ret
} }
override fun equals(other: Any?) = referenceID == (other as Faction).referenceID
override fun hashCode() = (referenceID - 0x80000000L).toInt()
override fun toString() = "Faction, ID: $referenceID ($factionName)"
override fun compareTo(other: Faction): Int = (this.referenceID - other.referenceID).toInt().sign()
fun Int.sign(): Int = if (this > 0) 1 else if (this < 0) -1 else this
} }

View File

@@ -0,0 +1,66 @@
package net.torvald.terrarum.gameactors.faction
import net.torvald.terrarum.Terrarum
import java.util.*
/**
* Created by minjaesong on 16-05-09.
*/
object FactionCodex {
val factionContainer = ArrayList<Faction>()
fun hasFaction(ID: Long): Boolean =
if (factionContainer.size == 0)
false
else
factionContainer.binarySearch(ID) >= 0
fun addFaction(faction: Faction) {
if (hasFaction(faction.referenceID))
throw RuntimeException("Faction with ID ${faction.referenceID} already exists.")
factionContainer.add(faction)
insertionSortLastElem(factionContainer) // we can do this as we are only adding single actor
}
fun getFactionByID(ID: Long): Faction {
if (factionContainer.size == 0) throw IllegalArgumentException("Faction with ID $ID does not exist.")
val index = factionContainer.binarySearch(ID)
if (index < 0)
throw IllegalArgumentException("Faction with ID $ID does not exist.")
else
return factionContainer[index]
}
private fun insertionSortLastElem(arr: ArrayList<Faction>) {
var x: Faction
var j: Int
var index: Int = arr.size - 1
x = arr[index]
j = index - 1
while (j > 0 && arr[j] > x) {
arr[j + 1] = arr[j]
j -= 1
}
arr[j + 1] = x
}
private fun ArrayList<Faction>.binarySearch(ID: Long): Int {
// code from collections/Collections.kt
var low = 0
var high = factionContainer.size - 1
while (low <= high) {
val mid = (low + high).ushr(1) // safe from overflows
val midVal = get(mid)
if (ID > midVal.referenceID)
low = mid + 1
else if (ID < midVal.referenceID)
high = mid - 1
else
return mid // key found
}
return -(low + 1) // key not found
}
}

View File

@@ -20,7 +20,6 @@ object FactionFactory {
val jsonObj = JsonFetcher.readJson(JSONPATH + filename) val jsonObj = JsonFetcher.readJson(JSONPATH + filename)
val factionObj = Faction(jsonObj.get("factionname").asString) val factionObj = Faction(jsonObj.get("factionname").asString)
jsonObj.get("factionamicable").asJsonArray.forEach { s -> factionObj.addFactionAmicable(s.asString) } jsonObj.get("factionamicable").asJsonArray.forEach { s -> factionObj.addFactionAmicable(s.asString) }
jsonObj.get("factionneutral").asJsonArray.forEach { s -> factionObj.addFactionNeutral(s.asString) } jsonObj.get("factionneutral").asJsonArray.forEach { s -> factionObj.addFactionNeutral(s.asString) }
jsonObj.get("factionhostile").asJsonArray.forEach { s -> factionObj.addFactionHostile(s.asString) } jsonObj.get("factionhostile").asJsonArray.forEach { s -> factionObj.addFactionHostile(s.asString) }

View File

@@ -50,7 +50,7 @@ class MapLayer(var width: Int, var height: Int) : Iterable<Byte> {
private fun uint8ToInt32(x: Byte): Int = java.lang.Byte.toUnsignedInt(x) private fun uint8ToInt32(x: Byte): Int = java.lang.Byte.toUnsignedInt(x)
companion object { companion object {
@Transient val RANGE = 256 @Transient const val RANGE = 256
} }
} }

View File

@@ -81,6 +81,6 @@ class PairedMapLayer(width: Int, var height: Int) : Iterable<Byte> {
companion object { companion object {
@Transient val RANGE = 16 @Transient const val RANGE = 16
} }
} }

View File

@@ -95,6 +95,7 @@ object MapCamera {
, TileNameCode.SANDSTONE_RED , TileNameCode.SANDSTONE_RED
, TileNameCode.SANDSTONE_WHITE , TileNameCode.SANDSTONE_WHITE
, TileNameCode.SANDSTONE_GREEN , TileNameCode.SANDSTONE_GREEN
, TileNameCode.DAYLIGHT_CAPACITOR
) )
/** /**

View File

@@ -1,6 +1,7 @@
package net.torvald.terrarum.realestate package net.torvald.terrarum.realestate
import net.torvald.terrarum.Terrarum import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameactors.faction.FactionCodex
/** /**
* Created by minjaesong on 16-03-27. * Created by minjaesong on 16-03-27.
@@ -11,4 +12,13 @@ object RealEstateUtility {
fun resolveAbsoluteTileNumber(t: Long): Pair<Int, Int> = fun resolveAbsoluteTileNumber(t: Long): Pair<Int, Int> =
Pair((t % Terrarum.game.map.width).toInt(), (t / Terrarum.game.map.width).toInt()) Pair((t % Terrarum.game.map.width).toInt(), (t / Terrarum.game.map.width).toInt())
/**
* Get owner ID as an Actor/Faction
*/
fun resolveOwner(id: Long): Any =
if (id < 0x80000000L)
Terrarum.game.getActorByID(id.toInt())
else
FactionCodex.getFactionByID(id)
} }

View File

@@ -13,7 +13,7 @@ import java.io.IOException
class TilePropCodex { class TilePropCodex {
init { init {
tileProps = Array<TileProp>(MapLayer.RANGE * PairedMapLayer.RANGE + 1, tileProps = Array<TileProp>(TILE_UNIQUE_MAX + 1,
{i -> TileProp() } {i -> TileProp() }
) )
@@ -44,6 +44,8 @@ class TilePropCodex {
val CSV_PATH = "./src/net/torvald/terrarum/tileproperties/tileprop.csv" val CSV_PATH = "./src/net/torvald/terrarum/tileproperties/tileprop.csv"
const val TILE_UNIQUE_MAX = MapLayer.RANGE * PairedMapLayer.RANGE
fun getProp(index: Int, damage: Int): TileProp { fun getProp(index: Int, damage: Int): TileProp {
try { try {
tileProps[idDamageToIndex(index, damage)].id tileProps[idDamageToIndex(index, damage)].id

View File

@@ -45,7 +45,7 @@
"11"; "1";"TILE_TORCH_FROST" ; "8396808"; "0"; "N/A"; "0"; "0"; "0"; "81916159"; "11"; "1"; "0";"16" "11"; "1";"TILE_TORCH_FROST" ; "8396808"; "0"; "N/A"; "0"; "0"; "0"; "81916159"; "11"; "1"; "0";"16"
"12"; "0";"TILE_TORCH" ; "8396808"; "0"; "N/A"; "0"; "0"; "0"; "0"; "11"; "0"; "0";"16" "12"; "0";"TILE_TORCH" ; "8396808"; "0"; "N/A"; "0"; "0"; "0"; "0"; "11"; "0"; "0";"16"
"12"; "1";"TILE_TORCH_FROST" ; "8396808"; "0"; "N/A"; "0"; "0"; "0"; "0"; "11"; "1"; "0";"16" "12"; "1";"TILE_TORCH_FROST" ; "8396808"; "0"; "N/A"; "0"; "0"; "0"; "0"; "11"; "1"; "0";"16"
"13"; "0";"TILE_ILLUMINATOR_WHITE" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "246656235"; "13"; "0"; "0";"16" "13"; "0";"TILE_ILLUMINATOR_WHITE" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "248768744"; "13"; "0"; "0";"16"
"13"; "1";"TILE_ILLUMINATOR_YELLOW" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "246656000"; "13"; "1"; "0";"16" "13"; "1";"TILE_ILLUMINATOR_YELLOW" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "246656000"; "13"; "1"; "0";"16"
"13"; "2";"TILE_ILLUMINATOR_ORANGE" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "246602752"; "13"; "2"; "0";"16" "13"; "2";"TILE_ILLUMINATOR_ORANGE" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "246602752"; "13"; "2"; "0";"16"
"13"; "3";"TILE_ILLUMINATOR_RED" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "246415360"; "13"; "3"; "0";"16" "13"; "3";"TILE_ILLUMINATOR_RED" ; "8396808"; "0"; "N/A"; "0"; "1"; "1"; "246415360"; "13"; "3"; "0";"16"
@@ -119,23 +119,30 @@
"255"; "14";"TILE_WATER" ; "27282445"; "100";"1000"; "1"; "0"; "0"; "0"; "N/A"; "N/A"; "0";"16" "255"; "14";"TILE_WATER" ; "27282445"; "100";"1000"; "1"; "0"; "0"; "0"; "N/A"; "N/A"; "0";"16"
"255"; "15";"TILE_WATER" ; "27282445"; "100";"1000"; "1"; "0"; "0"; "0"; "N/A"; "N/A"; "0";"16" "255"; "15";"TILE_WATER" ; "27282445"; "100";"1000"; "1"; "0"; "0"; "0"; "N/A"; "N/A"; "0";"16"
"256"; "0";"TILE_NULL" ; "0"; "-1";"2600"; "0"; "0"; "0"; "0"; "N/A"; "N/A"; "0";"16" "256"; "0";"TILE_NULL" ; "0"; "-1";"2600"; "0"; "0"; "0"; "0"; "N/A"; "N/A"; "0";"16"
## Notes ##
# Friction: 0: frictionless, <16: slippery, 16: regular, >16: sticky # Friction: 0: frictionless, <16: slippery, 16: regular, >16: sticky
# Opacity/Lumcolor: 40-step RGB # Opacity/Lumcolor: 40-step RGB
# Solid: whether the tile has full collision # Solid: whether the tile has full collision
# movr: Movement resistance, (walkspeedmax) / (1 + (n/16)), 16 halves movement speed # movr: Movement resistance, (walkspeedmax) / (1 + (n/16)), 16 halves movement speed
# dsty: density. As we are putting water an 1000, it is identical to specific gravity. [g/l] # dsty: density. As we are putting water an 1000, it is identical to specific gravity. [g/l]
# Sunstone: Artificial sunlight, change colour over time in sync with sunlight
# Sunlight capacitor: daylight at 11h of 22h day
## Illuminants ##
# Illuminant white: RGB(237,250,232), simulation of mercury-vapour lamp (If you want high CRI lamp, collect a daylight!)
# Defalut torch : L 70 a 51 b 59; real candlelight colour taken from properly configured camera. # Defalut torch : L 70 a 51 b 59; real candlelight colour taken from properly configured camera.
# Sunstone: Artificial sunlight, change colour over time in sync with sunlight. Set by game's code.
# Sunlight capacitor: daylight at 11h of 22h day. Set by game's code.
## Tiles ##
# 16 colour palette : Old Apple Macintosh 16-colour palette # 16 colour palette : Old Apple Macintosh 16-colour palette
# Magical ice: theoretical __metallic__ ice that might form under super-high pressure (> 5 TPa). Its density is a wild guess. # Magical ice: theoretical __metallic__ ice that might form under super-high pressure (> 5 TPa). Its density is a wild guess.
# Off illuminator: NO OPACITY! this is intended!
# References: ## References ##
# * Density of various woods : http://www.engineeringtoolbox.com/wood-density-d_40.html # * Density of various woods : http://www.engineeringtoolbox.com/wood-density-d_40.html
# * Density of various phases of ice : http://www1.lsbu.ac.uk/water/ice_phases.html # * Density of various phases of ice : http://www1.lsbu.ac.uk/water/ice_phases.html
Can't render this file because it contains an unexpected character in line 1 and column 18.