diff --git a/assets/mods/basegame/items/itemid.csv b/assets/mods/basegame/items/itemid.csv index f43848ce9..69c1c176a 100644 --- a/assets/mods/basegame/items/itemid.csv +++ b/assets/mods/basegame/items/itemid.csv @@ -160,3 +160,4 @@ id;classname;tags # reserved for debug items 16777216;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessWaterBucket;DEBUG,TOOL +16777217;net.torvald.terrarum.modulebasegame.gameitems.ItemBottomlessLavaBucket;DEBUG,TOOL diff --git a/src/com/sudoplay/joise/module/ModuleConstant.kt b/src/com/sudoplay/joise/module/ModuleConstant.kt new file mode 100644 index 000000000..b037c7f8b --- /dev/null +++ b/src/com/sudoplay/joise/module/ModuleConstant.kt @@ -0,0 +1,35 @@ +package com.sudoplay.joise.module + +import com.sudoplay.joise.ModuleInstanceMap +import com.sudoplay.joise.ModuleMap +import com.sudoplay.joise.ModulePropertyMap + +/** + * Created by minjaesong on 2024-09-08. + */ +class ModuleConstant : Module() { + private val constant = ScalarParameter(1.0) + + override fun _writeToMap(map: ModuleMap?) { + val props = ModulePropertyMap(this) + + writeScalar("constant", constant, props, map) + + map!![id] = props + } + + override fun get(x: Double, y: Double) = constant.value + override fun get(x: Double, y: Double, z: Double) = constant.value + override fun get(x: Double, y: Double, z: Double, w: Double) = constant.value + override fun get(x: Double, y: Double, z: Double, w: Double, u: Double, v: Double) = constant.value + + fun setConstant(c: Double) { + constant.set(c) + } + + override fun buildFromPropertyMap(props: ModulePropertyMap?, map: ModuleInstanceMap?): Module { + readScalar("constant", "setConstant", props, map) + + return this + } +} \ No newline at end of file diff --git a/src/com/sudoplay/joise/module/TerrarumModuleCaveLayerClosureGrad.kt b/src/com/sudoplay/joise/module/TerrarumModuleCaveLayerClosureGrad.kt new file mode 100644 index 000000000..f78c3db41 --- /dev/null +++ b/src/com/sudoplay/joise/module/TerrarumModuleCaveLayerClosureGrad.kt @@ -0,0 +1,53 @@ +package com.sudoplay.joise.module + +import com.sudoplay.joise.ModuleInstanceMap +import com.sudoplay.joise.ModuleMap +import com.sudoplay.joise.ModulePropertyMap +import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_DIVISOR +import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_MAGIC + +/** + * Params: + * - H: World height MINUS 100 + * - L: 620 + * + * Created by minjaesong on 2024-09-07. + */ +class TerrarumModuleCaveLayerClosureGrad : Module() { + protected val h = ScalarParameter(17.2) + protected val l = ScalarParameter(3.0) + + + private fun Double.op() = Math.sqrt((-this + h.value - l.value) / l.value).let { if (it.isNaN()) 0.0 else it.coerceIn(0.0, 1.0) } + + override fun get(x: Double, y: Double) = y.op() + override fun get(x: Double, y: Double, z: Double) = y.op()/*.also { + println("$y\t$it") + }*/ + override fun get(x: Double, y: Double, z: Double, w: Double) = y.op() + override fun get(x: Double, y: Double, z: Double, w: Double, u: Double, v: Double) = y.op() + + fun setL(source: Double) { + l.set(source) + } + + fun setH(source: Double) { + h.set(source) + } + + override fun _writeToMap(map: ModuleMap?) { + val props = ModulePropertyMap(this) + + writeScalar("l", l, props, map) + writeScalar("h", h, props, map) + + map!![id] = props + } + + override fun buildFromPropertyMap(props: ModulePropertyMap?, map: ModuleInstanceMap?): Module { + readScalar("l", "setL", props, map) + readScalar("h", "setH", props, map) + + return this + } +} diff --git a/src/com/sudoplay/joise/module/TerrarumModuleLavaFloorGrad.kt b/src/com/sudoplay/joise/module/TerrarumModuleLavaFloorGrad.kt new file mode 100644 index 000000000..1f4a198d2 --- /dev/null +++ b/src/com/sudoplay/joise/module/TerrarumModuleLavaFloorGrad.kt @@ -0,0 +1,54 @@ +package com.sudoplay.joise.module + +import com.sudoplay.joise.ModuleInstanceMap +import com.sudoplay.joise.ModuleMap +import com.sudoplay.joise.ModulePropertyMap +import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_DIVISOR +import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_MAGIC + +/** + * Params: + * - H: World height MINUS 100 + * - L: 620 + * + * Created by minjaesong on 2024-09-07. + */ +class TerrarumModuleLavaFloorGrad : Module() { + protected val h = ScalarParameter(5300.0) + protected val l = ScalarParameter(620.0) + + private fun undoYtransform(yp: Double): Double = yp + (3200 - YHEIGHT_MAGIC) * YHEIGHT_DIVISOR + + private fun Double.op() = Math.sqrt((this - h.value + l.value) / l.value).let { if (it.isNaN()) 0.0 else it } + + override fun get(x: Double, y: Double) = undoYtransform(y).op() + override fun get(x: Double, y: Double, z: Double) = undoYtransform(y).op()/*.also { + println("$y\t$it") + }*/ + override fun get(x: Double, y: Double, z: Double, w: Double) = undoYtransform(y).op() + override fun get(x: Double, y: Double, z: Double, w: Double, u: Double, v: Double) = undoYtransform(y).op() + + fun setL(source: Double) { + l.set(source) + } + + fun setH(source: Double) { + h.set(source) + } + + override fun _writeToMap(map: ModuleMap?) { + val props = ModulePropertyMap(this) + + writeScalar("l", l, props, map) + writeScalar("h", h, props, map) + + map!![id] = props + } + + override fun buildFromPropertyMap(props: ModulePropertyMap?, map: ModuleInstanceMap?): Module { + readScalar("l", "setL", props, map) + readScalar("h", "setH", props, map) + + return this + } +} \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/WorldSimulator.kt b/src/net/torvald/terrarum/modulebasegame/WorldSimulator.kt index 1f33b895d..dd8b67114 100644 --- a/src/net/torvald/terrarum/modulebasegame/WorldSimulator.kt +++ b/src/net/torvald/terrarum/modulebasegame/WorldSimulator.kt @@ -50,7 +50,6 @@ object WorldSimulator { const val FLUID_MAX_COMP = 0.02f // How much excess water a cell can store, compared to the cell above it. A tile of fluid can contain more than MaxMass water. // const val FLUID_MIN_MASS = net.torvald.terrarum.gameworld.FLUID_MIN_MASS //Ignore cells that are almost dry (smaller than epsilon of float16) const val minFlow = 1f / 512f - const val maxSpeed = 1f // max units of water moved out of one block to another, per timestamp // END OF FLUID-RELATED STUFFS @@ -348,6 +347,8 @@ object WorldSimulator { val worldY = y + updateYFrom val remainingType = fluidTypeMap[y][x] + val maxSpeed = 1f / FluidCodex[remainingType].viscosity.sqr() + // check solidity if (!isFlowable(remainingType, worldX, worldY)) continue // check if the fluid is a same kind @@ -386,7 +387,7 @@ object WorldSimulator { if (flow > minFlow) { flow *= 0.5f } - flow = flow.coerceIn(0f, remainingMass) + flow = flow.coerceIn(0f, min(maxSpeed, remainingMass)) fluidNewMap[y][x] -= flow fluidNewMap[y][x - 1] += flow @@ -406,7 +407,7 @@ object WorldSimulator { if (flow > minFlow) { flow *= 0.5f } - flow = flow.coerceIn(0f, remainingMass) + flow = flow.coerceIn(0f, min(maxSpeed, remainingMass)) fluidNewMap[y][x] -= flow fluidNewMap[y][x + 1] += flow diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemBottomlessWaterBucket.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemBottomlessWaterBucket.kt index dcb8a47ba..81161d6e9 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/ItemBottomlessWaterBucket.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/ItemBottomlessWaterBucket.kt @@ -38,4 +38,34 @@ class ItemBottomlessWaterBucket(originalID: ItemID) : GameItem(originalID) { return -1L } } +} + +/** + * Created by minjaesong on 2024-09-07. + */ +class ItemBottomlessLavaBucket(originalID: ItemID) : GameItem(originalID) { + + override var baseToolSize: Double? = PickaxeCore.BASE_MASS_AND_SIZE + override var inventoryCategory = Category.TOOL + override val canBeDynamic = false + override val materialId = "CUPR" + override var baseMass = 2.0 + override var equipPosition = HAND_GRIP + override var originalName = "ITEM_BOTTOMLESS_LAVA_BUCKET" + + init { + stackable = false + isUnique = true + } + + override fun startPrimaryUse(actor: ActorWithBody, delta: Float): Long { + val mx = Terrarum.mouseTileX; val my =Terrarum.mouseTileY + if (!BlockCodex[INGAME.world.getTileFromTerrain(mx, my)].isSolid) { + INGAME.world.setFluid(mx, my, Fluid.LAVA, 1f) + return 0L + } + else { + return -1L + } + } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt index cd296c03b..18e9ea7d2 100644 --- a/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt +++ b/src/net/torvald/terrarum/modulebasegame/worldgenerator/Terragen.kt @@ -256,10 +256,11 @@ interface TerragenParams { val caveBlockageFractalFreq: Double val caveBlockageSelectThre: Double // adjust cave closing-up strength. Lower = more closing val rockBandCutoffFreq: Double -} + + val lavaShapeFreg: Double } data class TerragenParamsAlpha1( - override val terragenTiers: List = listOf(.0, .5, 1.0, 2.5, 11.0), + override val terragenTiers: List = listOf(.0, .5, 1.0, 2.5, 11.0 * 9999), override val featureSize: Double = 333.0, override val lowlandScaleOffset: Double = -0.65, // linearly alters the height @@ -277,10 +278,12 @@ data class TerragenParamsAlpha1( override val caveBlockageSelectThre: Double = 1.40, // adjust cave closing-up strength. Lower = more closing override val rockBandCutoffFreq: Double = 4.0, + + override val lavaShapeFreg: Double = 0.03, ) : TerragenParams data class TerragenParamsAlpha2( - override val terragenTiers: List = listOf(.0, .5, 1.5, 3.75, 11.0), + override val terragenTiers: List = listOf(.0, .5, 1.5, 3.75, 11.0 * 9999), override val featureSize: Double = 333.0, override val lowlandScaleOffset: Double = -0.65, // linearly alters the height @@ -298,4 +301,7 @@ data class TerragenParamsAlpha2( override val caveBlockageSelectThre: Double = 1.40, // adjust cave closing-up strength. Lower = more closing override val rockBandCutoffFreq: Double = 4.0, + + override val lavaShapeFreg: Double = 0.03, + ) : TerragenParams \ No newline at end of file diff --git a/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt b/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt index 9332ff380..fccca37bb 100644 --- a/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt +++ b/src/net/torvald/terrarum/tests/WorldgenNoiseSandbox.kt @@ -19,20 +19,25 @@ import com.sudoplay.joise.ModuleMap import com.sudoplay.joise.ModulePropertyMap import com.sudoplay.joise.module.* import net.torvald.random.HQRNG -import net.torvald.terrarum.* +import net.torvald.terrarum.FlippingSpriteBatch import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.concurrent.ThreadExecutor -import net.torvald.terrarum.modulebasegame.worldgenerator.* +import net.torvald.terrarum.inUse +import net.torvald.terrarum.modulebasegame.worldgenerator.BiomegenParams +import net.torvald.terrarum.modulebasegame.worldgenerator.TerragenParams +import net.torvald.terrarum.modulebasegame.worldgenerator.TerragenParamsAlpha2 +import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_DIVISOR +import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_MAGIC +import net.torvald.terrarum.modulebasegame.worldgenerator.shake +import net.torvald.terrarum.sqr import net.torvald.terrarum.worlddrawer.toRGBA import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap +import java.io.PrintStream +import java.util.* +import java.util.concurrent.Callable import java.util.concurrent.Future import kotlin.math.* import kotlin.random.Random -import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_DIVISOR -import net.torvald.terrarum.modulebasegame.worldgenerator.Worldgen.YHEIGHT_MAGIC -import java.io.PrintStream -import java.util.Calendar -import java.util.concurrent.Callable const val NOISEBOX_WIDTH = 90 * 18 const val NOISEBOX_HEIGHT = 90 * 26 @@ -227,10 +232,8 @@ class WorldgenNoiseSandbox : ApplicationAdapter() { threadExecutor.renew() - callables.forEach { - threadExecutor.submit(it) - } - + callables.shuffle() + threadExecutor.submitAll(callables) threadExecutor.join() worldgenDone = true @@ -388,6 +391,7 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker { private val AMETHYST = 0xee77ffff.toInt() private val ROCKSALT = 0xff00ffff.toInt() private val NITRE = 0xdbd6a1ff.toInt() + private val LAVA = 0xff5900ff.toInt() private val oreCols = listOf( COPPER_ORE, IRON_ORE, COAL_ORE, ZINC_ORE, TIN_ORE, GOLD_ORE, SILVER_ORE, LEAD_ORE, ROCKSALT, QUARTZ, AMETHYST, NITRE @@ -399,16 +403,19 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker { override fun draw(x: Int, y: Int, noiseValue: List, outTex: Pixmap) { val terr = noiseValue[0].tiered(terragenTiers) val cave = if (noiseValue[1] < 0.5) 0 else 1 - val ore = (noiseValue.subList(2, noiseValue.size)).zip(oreCols).firstNotNullOfOrNull { (n, colour) -> if (n > 0.5) colour else null } + val ore = (noiseValue.subList(2, noiseValue.size - 1)).zip(oreCols).firstNotNullOfOrNull { (n, colour) -> if (n > 0.5) colour else null } val isMarble = false // noiseValue[13] > 0.5 val wallBlock = if (isMarble) Block.STONE_MARBLE else groundDepthBlockWall[terr] val terrBlock = if (cave == 0) Block.AIR else if (isMarble) Block.STONE_MARBLE else groundDepthBlockTERR[terr] + val lavaVal = noiseValue.last() + val lava = (lavaVal >= 0.5) outTex.drawPixel(x, y, - if (ore != null && (terrBlock == Block.STONE || terrBlock == Block.STONE_SLATE)) ore + if (lava) LAVA + else if (ore != null && (terrBlock == Block.STONE || terrBlock == Block.STONE_SLATE)) ore else if (wallBlock == Block.AIR && terrBlock == Block.AIR) BACK else blockToCol[terrBlock]!!.toRGBA() ) @@ -650,11 +657,19 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker { it.setOffset(0.0) } - val cavePerturb = ModuleTranslateDomain().also { + val cavePerturb0 = ModuleTranslateDomain().also { it.setSource(caveShapeAttenuate) it.setAxisXSource(cavePerturbScale) } + val caveTerminalClosureGrad = TerrarumModuleCaveLayerClosureGrad() + + val cavePerturb = ModuleCombiner().also { // 0: rock, 1: air + it.setType(ModuleCombiner.CombinerType.MULT) + it.setSource(0, cavePerturb0) + it.setSource(1, caveTerminalClosureGrad) + } + val caveSelect = ModuleSelect().also { it.setLowSource(1.0) it.setHighSource(0.0) @@ -663,7 +678,7 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker { it.setFalloff(0.0) } - val caveBlockageFractal = ModuleFractal().also { + val caveBlockageFractal0 = ModuleFractal().also { it.setType(ModuleFractal.FractalType.RIDGEMULTI) it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) @@ -672,6 +687,11 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker { it.seed = seed shake caveBlockageMagic } + val caveBlockageFractal = ModuleCombiner().also { // 0: air, 1: rock + it.setType(ModuleCombiner.CombinerType.MULT) + it.setSource(0, caveBlockageFractal0) + } + // will only close-up deeper caves. Shallow caves will be less likely to be closed up val caveBlockageAttenuate = ModuleCombiner().also { it.setType(ModuleCombiner.CombinerType.MULT) @@ -759,6 +779,8 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker { Joise(generateRockLayer(groundScalingCached, seed, params, (0..7).map { thicknesses[it] + marblerng.nextTriangularBal() * 0.006 to (2.6 * terragenYscaling) + it * 0.18 + marblerng.nextTriangularBal() * 0.09 })), + + Joise(generateSeaOfLava(seed)), ) } @@ -905,6 +927,59 @@ internal class TerragenTest(val params: TerragenParams) : NoiseMaker { return oreSelect } + private fun generateSeaOfLava(seed: Long): Module { + val lavaPipe = ModuleScaleDomain().also { + it.setSource(ModuleFractal().also { + it.setType(ModuleFractal.FractalType.RIDGEMULTI) + it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + it.setNumOctaves(1) + it.setFrequency(params.lavaShapeFreg) // adjust the "density" of the caves + it.seed = seed shake "LattiaOnLavaa" + }) + it.setScaleY(1.0 / 6.0) + } + + + val lavaPerturbFractal = ModuleFractal().also { + it.setType(ModuleFractal.FractalType.FBM) + it.setAllSourceBasisTypes(ModuleBasisFunction.BasisType.GRADIENT) + it.setAllSourceInterpolationTypes(ModuleBasisFunction.InterpolationType.QUINTIC) + it.setNumOctaves(6) + it.setFrequency(params.lavaShapeFreg * 3.0 / 4.0) + it.seed = seed shake "FloorIsLava" + } + + val lavaPerturbScale = ModuleScaleOffset().also { + it.setSource(lavaPerturbFractal) + it.setScale(23.0) + it.setOffset(0.0) + } + + val lavaPerturb = ModuleTranslateDomain().also { + it.setSource(lavaPipe) + it.setAxisXSource(lavaPerturbScale) + } + // val = sqrt((y-H+L) / L); where H=5300 (world height-100), L=620; + // 100 is the height of the "base lava sheet", 600 is the height of the "transitional layer" + // in this setup, the entire lava layer never exceeds 8 chunks (720 tiles) in height + val lavaGrad = TerrarumModuleLavaFloorGrad().also { + it.setH(5300.0) + it.setL(620.0) + } + + val lavaSelect = ModuleSelect().also { + it.setLowSource(1.0) + it.setHighSource(0.0) + it.setControlSource(lavaPerturb) + it.setThreshold(lavaGrad) + it.setFalloff(0.0) + } + + + return lavaSelect + } + private object DummyModule : Module() { override fun get(x: Double, y: Double) = 0.0