From ae0a2e2564a3c77618eb37680b6bb632886bb4c6 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Thu, 15 Feb 2024 22:05:08 +0900 Subject: [PATCH] boom with particles --- assets/mods/basegame/locales/en/items.json | 1 + assets/mods/basegame/locales/koKR/items.json | 1 + .../torvald/terrarum/gameworld/GameWorld.kt | 9 +- .../terrarum/modulebasegame/BuildingMaker.kt | 2 +- .../modulebasegame/ExplosionManager.kt | 87 ++++++++++--------- .../gameactors/ActorPrimedBomb.kt | 13 +-- .../modulebasegame/gameactors/DroppedItem.kt | 7 +- .../modulebasegame/gameitems/AxeCore.kt | 4 +- .../gameitems/PickaxeGeneric.kt | 64 ++++++++------ 9 files changed, 103 insertions(+), 85 deletions(-) diff --git a/assets/mods/basegame/locales/en/items.json b/assets/mods/basegame/locales/en/items.json index c71496684..07a3e9d44 100644 --- a/assets/mods/basegame/locales/en/items.json +++ b/assets/mods/basegame/locales/en/items.json @@ -1,6 +1,7 @@ { "ITEM_CALENDAR": "Calendar", "ITEM_CHARCOAL": "Charcoal", + "ITEM_CHERRY_BOMB": "Bomb", "ITEM_COAL_COKE": "Coal Coke", "ITEM_DOOR_OAK": "Oak Door", "ITEM_DOOR_EBONY": "Ebony Door", diff --git a/assets/mods/basegame/locales/koKR/items.json b/assets/mods/basegame/locales/koKR/items.json index 4119b8e33..058e332e7 100644 --- a/assets/mods/basegame/locales/koKR/items.json +++ b/assets/mods/basegame/locales/koKR/items.json @@ -1,6 +1,7 @@ { "ITEM_CALENDAR": "달력", "ITEM_CHARCOAL": "목탄", + "ITEM_CHERRY_BOMB": "폭탄", "ITEM_COAL_COKE": "코크스", "ITEM_DOOR_OAK": "나무 문", "ITEM_DOOR_EBONY": "흑단 문", diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index 68f32bab1..fb0d10477 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -642,9 +642,9 @@ open class GameWorld( } /** - * @return true if block is broken + * @return ItemID of the broken block AND ore if the block is broken, `null` otherwise */ - fun inflictTerrainDamage(x: Int, y: Int, damage: Double): ItemID? { + fun inflictTerrainDamage(x: Int, y: Int, damage: Double): Pair { if (damage.isNaN()) throw IllegalArgumentException("Cannot inflict NaN amount of damage at($x, $y)") val damage = damage.toFloat() @@ -667,12 +667,13 @@ open class GameWorld( // remove tile from the world if ((terrainDamages[addr] ?: 0f) >= BlockCodex[getTileFromTerrain(x, y)].strength) { val tileBroke = getTileFromTerrain(x, y) + val oreBroke = getTileFromOre(x, y) setTileTerrain(x, y, Block.AIR, false) terrainDamages.remove(addr) - return tileBroke + return tileBroke.let { if (it == Block.AIR) null else it } to oreBroke.item.let { if (it == Block.AIR) null else it } } - return null + return null to null } fun getTerrainDamage(x: Int, y: Int): Float = terrainDamages[LandUtil.getBlockAddr(this, x, y)] ?: 0f diff --git a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt index c74d9fb73..ba3c6dd19 100644 --- a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt +++ b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt @@ -584,7 +584,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) { if (currentPenTarget and PENTARGET_WALL != 0) world.setTileWall(x, y, Block.AIR, true) if (currentPenTarget and PENTARGET_ORE != 0) - world.setTileOre(x, y, Block.NULL, 0) + world.setTileOre(x, y, Block.AIR, 0) } PENMODE_EYEDROPPER -> { diff --git a/src/net/torvald/terrarum/modulebasegame/ExplosionManager.kt b/src/net/torvald/terrarum/modulebasegame/ExplosionManager.kt index 830337755..ec7ca60c3 100644 --- a/src/net/torvald/terrarum/modulebasegame/ExplosionManager.kt +++ b/src/net/torvald/terrarum/modulebasegame/ExplosionManager.kt @@ -1,11 +1,14 @@ package net.torvald.terrarum.modulebasegame import net.torvald.terrarum.BlockCodex +import net.torvald.terrarum.ItemCodex import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.ceilToInt import net.torvald.terrarum.gameworld.BlockLayerI16 import net.torvald.terrarum.gameworld.GameWorld +import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.gameworld.getOffset +import net.torvald.terrarum.modulebasegame.gameitems.PickaxeCore import net.torvald.unsafe.UnsafeHelper import kotlin.math.* @@ -13,7 +16,7 @@ import kotlin.math.* * Created by minjaesong on 2024-02-13. */ object ExplosionManager { - fun goBoom(world: GameWorld, tx: Int, ty: Int, power: Float, callback: () -> Unit) { + fun goBoom(world: GameWorld, tx: Int, ty: Int, power: Float, dropProbNonOre: Float, dropProbOre: Float, callback: () -> Unit) { val CALC_RADIUS = power.ceilToInt() + 2 val CALC_WIDTH = CALC_RADIUS * 2 + 1 @@ -27,7 +30,7 @@ object ExplosionManager { memcpyFromWorldBreakage(CALC_WIDTH, world, tx - CALC_RADIUS, ty - CALC_RADIUS, line, breakmap) } - createExplosionWorker(CALC_RADIUS, CALC_WIDTH, world, breakmap, tilemap, tx, ty, power, callback).start() + createExplosionWorker(CALC_RADIUS, CALC_WIDTH, world, breakmap, tilemap, tx, ty, power, dropProbNonOre, dropProbOre, callback).start() } private fun memcpyFromWorldTiles(CALC_RADIUS: Int, CALC_WIDTH: Int, world: GameWorld, xStart: Int, yStart: Int, yOff: Int, out: BlockLayerI16) { @@ -119,6 +122,8 @@ object ExplosionManager { tilemap: BlockLayerI16, tx: Int, ty: Int, power: Float, + dropProbNonOre: Float, + dropProbOre: Float, callback: () -> Unit): Thread { return Thread { val mapBoomPow = UnsafeFloatArray(CALC_WIDTH, CALC_WIDTH) // explosion power map @@ -146,7 +151,7 @@ object ExplosionManager { mapBoomPow[x, y] = ambientAccumulator } - fun swipeBoomPower(sx: Int, sy: Int, ex: Int, ey: Int, dx: Int, dy: Int, strengthmap: UnsafeFloatArray, swipeDiag: Boolean) { + fun swipeBoomPower(sx: Int, sy: Int, ex: Int, ey: Int, dx: Int, dy: Int, swipeDiag: Boolean) { var swipeX = sx var swipeY = sy while (swipeX*dx <= ex*dx && swipeY*dy <= ey*dy) { @@ -169,31 +174,31 @@ object ExplosionManager { } } - fun r1(strengthmap: UnsafeFloatArray) { + fun r1() { for (line in 1 until CALC_WIDTH - 1) { - swipeBoomPower(1, line, CALC_WIDTH - 2, line, 1, 0, strengthmap, false) + swipeBoomPower(1, line, CALC_WIDTH - 2, line, 1, 0, false) } } - fun r2(strengthmap: UnsafeFloatArray) { + fun r2() { for (line in 1 until CALC_WIDTH - 1) { - swipeBoomPower(line, 1, line, CALC_WIDTH - 2, 0, 1, strengthmap, false) + swipeBoomPower(line, 1, line, CALC_WIDTH - 2, 0, 1, false) } } - fun r3(strengthmap: UnsafeFloatArray) { + fun r3() { for (i in 0 until CALC_WIDTH + CALC_WIDTH - 5) { swipeBoomPower( max(1, i - CALC_WIDTH + 4), max(1, CALC_WIDTH - 2 - i), min(CALC_WIDTH - 2, i + 1), min(CALC_WIDTH - 2, (CALC_WIDTH + CALC_WIDTH - 5) - i), - 1, 1, strengthmap, true + 1, 1, true ) } } - fun r4(strengthmap: UnsafeFloatArray) { + fun r4() { for (i in 0 until CALC_WIDTH + CALC_WIDTH - 5) { swipeBoomPower( max(1, i - CALC_WIDTH + 4), min(CALC_WIDTH - 2, i + 1), min(CALC_WIDTH - 2, i + 1), max(1, (CALC_WIDTH - 2) - (CALC_WIDTH + CALC_WIDTH - 6) + i), - 1, -1, strengthmap, true + 1, -1, true ) } } @@ -225,45 +230,43 @@ object ExplosionManager { } // simulate explosion like strengthmaprenderer - r1(mapBoomPow);r2(mapBoomPow);r3(mapBoomPow);r4(mapBoomPow) - r1(mapBoomPow);r2(mapBoomPow);r3(mapBoomPow);r4(mapBoomPow) + r1();r2();r3();r4() + r1();r2();r3();r4() //// just write to the damagemap lol - /*for (rawy in worldYstart until worldYstart + CALC_WIDTH) { - for (rawx in worldXstart until worldXstart + CALC_WIDTH) { - val lx = rawx - (tx - CALC_RADIUS - 1) - val ly = rawy - (ty - CALC_RADIUS - 1) - world.inflictTerrainDamage(rawx, rawy, mapBoomPow[lx, ly].blastToDmg().toDouble()) - } - }*/ + for (wy in worldYstart until worldYstart + CALC_WIDTH) { + for (wx in worldXstart until worldXstart + CALC_WIDTH) { + val lx = wx - (tx - CALC_RADIUS - 1) + val ly = wy - (ty - CALC_RADIUS - 1) + world.inflictTerrainDamage(wx, wy, mapBoomPow[lx, ly].blastToDmg().toDouble()).let { (tile, ore) -> + if (ore != null) { + // drop ore + if (Math.random() < dropProbOre) { + PickaxeCore.dropItem(ore, wx, wy) + } + } + else if (tile != null) { + // drop tile + if (Math.random() < dropProbNonOre) { + PickaxeCore.dropItem(tile, wx, wy) + } - // write lightmap to the tilemap and breakmap - for (y in 0 until CALC_WIDTH) { - for (x in 0 until CALC_WIDTH) { - val boompower = mapBoomPow[x, y].blastToDmg() - val tile = world.tileNumberToNameMap[tilemap.unsafeGetTile(x, y).toLong()] - val tileprop = BlockCodex[tile] - val breakage = breakmap[x, y] + PickaxeCore.makeDust(tile, wx, wy, 8 + (5 * Math.random()).toInt()) - // remove tile - if (tileprop.strength - (breakage + boompower) <= 0f) { - tilemap.unsafeSetTile(x, y, world.tileNameToNumberMap[Block.AIR]!!) - breakmap[x, y] = 0f - } - // write new breakage - else { - breakmap[x, y] = breakage + boompower + // drop random disc + val itemprop = ItemCodex[tile] + if (Math.random() < (1.0 / 4096.0) * (dropProbNonOre) && // prob: 1/16384 + (itemprop?.hasTag("CULTIVABLE") == true || + itemprop?.hasTag("SAND") == true || + itemprop?.hasTag("GRAVEL") == true) + ) { + PickaxeCore.dropItem(PickaxeCore.getRandomDisc(), wx, wy) + } + } } } } - // memcpy the tilemap and breakmap to the world - for (line in 0 until CALC_WIDTH) { - memcpyToWorldTiles(CALC_RADIUS, CALC_WIDTH, world, tx - CALC_RADIUS, ty - CALC_RADIUS, line, tilemap) - memcpyToWorldBreakage(CALC_WIDTH, world, tx - CALC_RADIUS, ty - CALC_RADIUS, line, breakmap) - } - - // dispose of the tilemap copy mapBoomPow.destroy() breakmap.destroy() diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorPrimedBomb.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorPrimedBomb.kt index 079416fd0..dc7bdbc99 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorPrimedBomb.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorPrimedBomb.kt @@ -14,8 +14,10 @@ import net.torvald.terrarum.modulebasegame.ExplosionManager * Created by minjaesong on 2024-02-13. */ open class ActorPrimedBomb( - private var explosionPower: Float = 1f, + @Transient private var explosionPower: Float = 1f, private var fuse: Second = 1f, + @Transient private var dropProbNonOre: Float = 0.25f, + @Transient private var dropProbOre: Float = 0.75f ) : ActorWithBody() { init { @@ -53,11 +55,10 @@ open class ActorPrimedBomb( INGAME.world, hitbox.centeredX.div(TILE_SIZED).minus(1.0).toInt(), hitbox.startY.div(TILE_SIZED).minus(1.0).toInt(), - explosionPower - ) { - - - } + explosionPower, + dropProbNonOre, + dropProbOre + ) {} } } diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/DroppedItem.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/DroppedItem.kt index 5be2d5766..701051771 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/DroppedItem.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/DroppedItem.kt @@ -4,11 +4,8 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.TextureRegion import com.jme3.math.FastMath import net.torvald.gdx.graphics.Cvec +import net.torvald.terrarum.* import net.torvald.terrarum.App.printdbg -import net.torvald.terrarum.BlockCodex -import net.torvald.terrarum.INGAME -import net.torvald.terrarum.ItemCodex -import net.torvald.terrarum.Terrarum import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED import net.torvald.terrarum.gameactors.* @@ -56,6 +53,8 @@ open class DroppedItem : ActorWithBody { if (itemID.isActor()) throw RuntimeException("Attempted to create DroppedItem actor of a real actor; the real actor must be dropped instead.") + else if (itemID.isOre()) + this.itemID = OreCodex[itemID].item isVisible = true diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/AxeCore.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/AxeCore.kt index 8c3c1347a..b7fe21b37 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/AxeCore.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/AxeCore.kt @@ -101,7 +101,7 @@ object AxeCore { INGAME.world.inflictTerrainDamage( x, y, Calculate.hatchetPower(actor, item?.material) * swingDmgToFrameDmg - ).let { tileBroken -> + ).let { (tileBroken, _) -> // tile busted if (tileBroken != null) { val drop = BlockCodex[tileBroken].drop @@ -129,7 +129,7 @@ object AxeCore { INGAME.world.inflictTerrainDamage( x, y, Calculate.hatchetPower(actor, item?.material) * swingDmgToFrameDmg - ).let { tileBroken -> + ).let { (tileBroken, _) -> // tile busted if (tileBroken != null) { var upCtr = 0 diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/PickaxeGeneric.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/PickaxeGeneric.kt index 2dfe8a4eb..362954449 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/PickaxeGeneric.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/PickaxeGeneric.kt @@ -3,6 +3,7 @@ package net.torvald.terrarum.modulebasegame.gameitems import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.g2d.TextureRegion import net.torvald.terrarum.* +import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED import net.torvald.terrarum.blockproperties.Block @@ -89,42 +90,43 @@ object PickaxeCore { // filter passed, do the job val actionInterval = actorvalue.getAsDouble(AVKey.ACTION_INTERVAL)!! val swingDmgToFrameDmg = delta.toDouble() / actionInterval - val (oreOnTile, _) = INGAME.world.getTileFromOre(x, y) INGAME.world.inflictTerrainDamage( x, y, Calculate.pickaxePower(actor, item?.material) * swingDmgToFrameDmg - ).let { tileBroken -> - // tile busted - if (tileBroken != null) { + ).let { (tileBroken, oreBroken) -> + + // drop ore + if (oreBroken != null) { if (Math.random() < dropProbability) { - val drop = if (oreOnTile != Block.AIR) - OreCodex[oreOnTile].item - else - BlockCodex[tileBroken].drop - - if (drop.isNotBlank()) { - dropItem(drop, x, y) - } - makeDust(tile, x, y, 9) - makeNoise(actor, tile) + val drop = OreCodex[oreBroken].item + if (drop.isNotBlank()) dropItem(drop, x, y) + } + } + // drop tile + else if (tileBroken != null) { + if (Math.random() < dropProbability) { + val drop = BlockCodex[tileBroken].drop + if (drop.isNotBlank()) dropItem(drop, x, y) } - - // temporary: spawn random record on prob 1/4096 when digging dirts/sands/gravels + // temperary: drop random disc val itemprop = ItemCodex[tileBroken] if (Math.random() < 1.0 / 4096.0 && - (itemprop?.hasTag("CULTIVABLE") == true || - itemprop?.hasTag("SAND") == true || - itemprop?.hasTag("GRAVEL") == true) - ) { - val drop = "item@basegame:${32769 + Math.random().times(9).toInt()}" - dropItem(drop, x, y) + (itemprop?.hasTag("CULTIVABLE") == true || + itemprop?.hasTag("SAND") == true || + itemprop?.hasTag("GRAVEL") == true) + ) { + dropItem(getRandomDisc(), x, y) } - } - // tile not busted - if (Math.random() < actionInterval) { + + // make dust + if (tileBroken != null || oreBroken != null) { + makeDust(tile, x, y, 9) + makeNoise(actor, tile) + } + else { makeDust(tile, x, y, 1) } } @@ -146,6 +148,16 @@ object PickaxeCore { ) } + fun getRandomDisc() = "item@basegame:${32769 + Math.random().times(9).toInt()}" + + private fun makeDustIndices(amount: Int): List { + val ret = ArrayList() + repeat((amount / 9f).ceilToInt()) { + ret.addAll((0..8).toList().shuffled()) + } + return ret.subList(0, amount) + } + private val pixelOffs = intArrayOf(2, 7, 12) // hard-coded assuming TILE_SIZE=16 fun makeDust(tile: ItemID, x: Int, y: Int, density: Int = 9, drawCol: Color = Color.WHITE) { val pw = 3 @@ -162,7 +174,7 @@ object PickaxeCore { } val tileNum = baseTilenum + representativeTilenum // the particle won't match the visible tile anyway because of the seasons stuff - val indices = (0..8).toList().shuffled().subList(0, density) + val indices = makeDustIndices(density) for (it in indices) { val u = pixelOffs[it % 3] val v = pixelOffs[it / 3]