fixed a bug where the player would immediately pick back up the fixture they've just placed one frame ago

This commit is contained in:
minjaesong
2022-07-19 00:25:13 +09:00
parent 23c2d86c27
commit 5fbbf34c10
14 changed files with 260 additions and 23 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -106,4 +106,7 @@ class BlockProp {
* Mainly intended to be used by third-party modules
*/
val extra = Codex()
val isActorBlock: Boolean
get() = nameKey.contains("ACTORBLOCK")
}

View File

@@ -269,7 +269,7 @@ open class GameWorld() : Disposable {
layerWall.unsafeSetTile(x, y, tilenum)
wallDamages.remove(LandUtil.getBlockAddr(this, x, y))
if (!bypassEvent) {
if (!bypassEvent && oldWall != itemID) {
Terrarum.ingame?.queueWallChangedEvent(oldWall, itemID, x, y)
Terrarum.ingame?.modified(LandUtil.LAYER_WALL, x, y)
}
@@ -301,7 +301,7 @@ open class GameWorld() : Disposable {
}
// fluid tiles-item should be modified so that they will also place fluid onto their respective map
if (!bypassEvent) {
if (!bypassEvent && oldTerrain != itemID) {
Terrarum.ingame?.queueTerrainChangedEvent(oldTerrain, itemID, x, y)
Terrarum.ingame?.modified(LandUtil.LAYER_TERR, x, y)
}

View File

@@ -241,7 +241,7 @@ object WorldSimulator {
val currentTile = world.getTileFromTerrain(x, y)
val prop = BlockCodex[currentTile]
// don't let the falling sand destroy the precious storage chest
val isAir = !prop.isSolid && !prop.nameKey.contains("ACTORBLOCK")
val isAir = !prop.isSolid && !prop.isActorBlock
val support = prop.maxSupport
val isFallable = support != -1

View File

@@ -1222,7 +1222,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
fun performBarehandAction(actor: ActorWithBody, delta: Float) {
val canAttackOrDig = actor.scale * actor.baseHitboxH >= actor.actorValue.getAsDouble(AVKey.BAREHAND_MINHEIGHT) ?: 4294967296.0
val canAttackOrDig = actor.scale * actor.baseHitboxH >= (actor.actorValue.getAsDouble(AVKey.BAREHAND_MINHEIGHT) ?: 4294967296.0)
fun getActorsAtVicinity(worldX: Double, worldY: Double, radius: Double): List<ActorWithBody> {
@@ -1249,18 +1249,19 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
actorsUnderMouse.forEach {
if (it is FixtureBase && it.mainUI == null)
fixturesUnderHand.add(it)
else if (it is ActorWithBody)
else
mobsUnderHand.add(it)
}
// pickup a fixture
if (fixturesUnderHand.size > 0 && fixturesUnderHand[0].canBeDespawned) {
if (fixturesUnderHand.size > 0 && fixturesUnderHand[0].canBeDespawned &&
System.nanoTime() - fixturesUnderHand[0].spawnRequestedTime > 500000000) { // don't pick up the fixture if it was recently placed (0.5 seconds)
val fixture = fixturesUnderHand[0]
val fixtureItem = ItemCodex.fixtureToItemID(fixture)
printdbg(this, "Fixture pickup at F${WORLD_UPDATE_TIMER}: ${fixture.javaClass.canonicalName} -> $fixtureItem")
// 1. put the fixture to the inventory
fixture.flagDespawn()
// 2. register this item(fixture) to the quickslot
// 2. register this item(fixture) to the quickslot so that the player sprite would be actually lifting the fixture
if (actor is Pocketed) {
actor.inventory.add(fixtureItem)
actor.equipItem(fixtureItem)

View File

@@ -30,6 +30,10 @@ interface Electric {
*/
open class FixtureBase : ActorWithBody, CuedByTerrainChange {
/** Real time, in nanoseconds */
@Transient var spawnRequestedTime: Long = 0L
private set
lateinit var blockBox: BlockBox // something like TapestryObject will want to redefine this
fun blockBoxIndexToPoint2i(it: BlockBoxIndex): Point2i = this.blockBox.width.let { w -> Point2i(it % w, it / w) }
var blockBoxProps: BlockBoxProps = BlockBoxProps(0)
@@ -72,22 +76,27 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
var worldBlockPos: Point2i? = null
private set
fun forEachBlockbox(action: (Int, Int) -> Unit) {
// something like TapestryObject will want to redefine this
/**
* @param action a function with following arguments: posX, posY, offX, offY
*/
open fun forEachBlockbox(action: (Int, Int, Int, Int) -> Unit) {
worldBlockPos?.let { (posX, posY) ->
for (y in posY until posY + blockBox.height) {
for (x in posX until posX + blockBox.width) {
action(x, y)
action(x, y, x - posX, y - posY)
}
}
}
}
override fun updateForTerrainChange(cue: IngameInstance.BlockChangeQueueItem) {
fillFillerBlock()
placeActorBlocks()
}
private fun fillFillerBlock() {
forEachBlockbox { x, y ->
// something like TapestryObject will want to redefine this
open protected fun placeActorBlocks() {
forEachBlockbox { x, y, _, _ ->
//printdbg(this, "fillerblock ${blockBox.collisionType} at ($x, $y)")
if (blockBox.collisionType == BlockBox.ALLOW_MOVE_DOWN) {
// if the collision type is allow_move_down, only the top surface tile should be "the platform"
@@ -137,17 +146,17 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
}
if (hasCollision) {
printdbg(this, "cannot spawn fixture ${nameFun()}, has tile collision; tilewise dim: (${blockBox.width}, ${blockBox.height}) ")
printdbg(this, "cannot spawn fixture ${nameFun()} at F${INGAME.WORLD_UPDATE_TIMER}, has tile collision; tilewise dim: (${blockBox.width}, ${blockBox.height}) ")
return false
}
printdbg(this, "spawn fixture ${nameFun()}, tilewise dim: (${blockBox.width}, ${blockBox.height})")
printdbg(this, "spawn fixture ${nameFun()} at F${INGAME.WORLD_UPDATE_TIMER}, tilewise dim: (${blockBox.width}, ${blockBox.height})")
// set the position of this actor
worldBlockPos = Point2i(posX, posY)
// fill the area with the filler blocks
fillFillerBlock()
placeActorBlocks()
this.isVisible = true
@@ -160,12 +169,14 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
// actually add this actor into the world
INGAME.queueActorAddition(this)
spawnRequestedTime = System.nanoTime()
return true
}
/** force disable despawn when inventory is not empty */
val canBeDespawned: Boolean get() = inventory?.isEmpty() ?: true
/**
@@ -178,7 +189,7 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
printStackTrace(this)
// remove filler block
forEachBlockbox { x, y ->
forEachBlockbox { x, y, _, _ ->
world!!.setTileTerrain(x, y, Block.AIR, true)
}
@@ -204,19 +215,36 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
INGAME.queueActorAddition(DroppedItem(drop, hitbox.startX, hitbox.startY - 1.0))
}
private var dropItem = false
protected var dropItem = false
override fun update(delta: Float) {
if (!flagDespawn && worldBlockPos != null) {
// FIXME retrieving fixture by mining relied on a quirk that mining a actorblock would also drop the fixture.
// FIXME since that particular method of operation causes so much problems, it is required to implement the
// FIXME said feature "correctly"
/*if (!flagDespawn && worldBlockPos != null) {
// removal-by-player because player is removing the filler block by pick
// no-flagDespawn check is there to prevent item dropping when externally despawned
// (e.g. picked the fixture up in which case the fixture must not drop itself to the world; it must go into the actor's inventory)
forEachBlockbox { x, y ->
if (world!!.getTileFromTerrain(x, y) != blockBox.collisionType) {
forEachBlockbox { x, y, _, _ ->
if (!BlockCodex[world!!.getTileFromTerrain(x, y)].isActorBlock) {
flagDespawn = true
dropItem = true
}
}
}*/
if (!canBeDespawned) flagDespawn = false // actively deny despawning request if cannot be despawned
if (canBeDespawned && flagDespawn) despawn()
if (canBeDespawned && dropItem) dropSelfAsAnItem()
// actual actor removal is performed by the TerrarumIngame.killOrKnockdownActors
super.update(delta)
}
/**
* An alternative to `super.update()`
*/
fun updateWithCustomActorBlockFun(delta: Float, actorBlockFillingFunction: () -> Unit) {
if (!flagDespawn && worldBlockPos != null) {
actorBlockFillingFunction()
}
if (!canBeDespawned) flagDespawn = false
if (canBeDespawned && flagDespawn) despawn()

View File

@@ -0,0 +1,151 @@
package net.torvald.terrarum.modulebasegame.gameactors
import net.torvald.spriteanimation.SheetSpriteAnimation
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
import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.gameactors.Hitbox
import net.torvald.terrarum.gameactors.Lightbox
import net.torvald.terrarum.gameactors.Luminous
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
/**
* @param width of hitbox, in tiles, when the door is opened. Default to 2. Closed door always have width of 1. (this limits how big and thick the door can be)
* @param height of hitbox, in ties. Default to 3.
*
* Created by minjaesong on 2022-07-15.
*/
class FixtureSwingingDoorBase : FixtureBase, Luminous {
/* OVERRIDE THESE TO CUSTOMISE */
open val tw = 2
open val th = 3
open val twClosed = 1
open val opacity = BlockCodex[Block.STONE].opacity
open val isOpacityActuallyLuminosity = false
open val moduleName = "basegame"
open val texturePath = "sprites/fixtures/door_test.tga"
open val textureIdentifier = "fixtures-door_test.tga"
open val customNameFun = { "DOOR_BASE" }
/* END OF CUTOMISABLE PARAMETERS */
@Transient override val lightBoxList: ArrayList<Lightbox> = ArrayList()
@Transient override val shadeBoxList: ArrayList<Lightbox> = ArrayList()
protected var doorState = 0 // -1: open toward left, 0: closed, 1: open toward right
@Transient private var placeActorBlockLatch = false
constructor() : super(
BlockBox(BlockBox.FULL_COLLISION, 1, 3), // temporary value, will be overwritten by reload()
nameFun = { "item not loaded properly, alas!" }
) {
reload()
placeActorBlockLatch = true
}
override fun reload() {
super.reload()
nameFun = customNameFun
val hbw = TILE_SIZE * (tw * 2 - twClosed)
val hbh = TILE_SIZE * th
blockBox = BlockBox(BlockBox.FULL_COLLISION, tw * 2 - twClosed, th)
// loading textures
CommonResourcePool.addToLoadingList("$moduleName-$textureIdentifier") {
TextureRegionPack(ModMgr.getGdxFile(moduleName, texturePath), hbw, hbh)
}
CommonResourcePool.loadAll()
density = 1200.0
actorValue[AVKey.BASEMASS] = 10.0
// setHitboxDimension(hbw, hbh, TILE_SIZE * (tw * 2 - twClosed), 0)
setHitboxDimension(hbw, hbh, TILE_SIZE * ((tw * 2 - twClosed - 1) / 2), 0)
(if (isOpacityActuallyLuminosity) lightBoxList else shadeBoxList).add(
Lightbox(Hitbox(0.0, 0.0, TILE_SIZED, th * TILE_SIZED), opacity))
makeNewSprite(FixtureBase.getSpritesheet(moduleName, texturePath, hbw, hbh)).let {
it.setRowsAndFrames(3,1)
}
placeActorBlockLatch = false
}
open protected fun closeDoor() {
(sprite!! as SheetSpriteAnimation).currentRow = 0
doorState = 0
}
open protected fun openToRight() {
(sprite!! as SheetSpriteAnimation).currentRow = 1
doorState = 1
}
open protected fun openToLeft() {
(sprite!! as SheetSpriteAnimation).currentRow = 2
doorState = -1
}
override fun forEachBlockbox(action: (Int, Int, Int, Int) -> Unit) {
val xStart = worldBlockPos!!.x - ((tw * 2 - twClosed - 1) / 2) // worldBlockPos.x is where the mouse was, of when the tilewise width was 1.
for (y in worldBlockPos!!.y until worldBlockPos!!.y + blockBox.height) {
for (x in xStart until xStart + blockBox.width) {
action(x, y, x - xStart, y - worldBlockPos!!.y)
}
}
}
override fun placeActorBlocks() {
forEachBlockbox { x, y, ox, oy ->
val tile = when (doorState) {
// CLOSED --
// fill the actorBlock so that:
// N..N F N..N (repeated `th` times; N: no collision, F: full collision)
0/*CLOSED*/ -> {
if (ox in tw-1 until tw-1+twClosed) Block.ACTORBLOCK_FULL_COLLISION
else Block.ACTORBLOCK_NO_COLLISION
}
else/*OPENED*/ -> Block.ACTORBLOCK_NO_COLLISION
}
world!!.setTileTerrain(x, y, tile, false)
}
}
override fun flagDespawn() {
super.flagDespawn()
printdbg(this, "flagged to despawn")
printStackTrace(this)
}
override fun updateForTerrainChange(cue: IngameInstance.BlockChangeQueueItem) {
}
override fun update(delta: Float) {
if (placeActorBlockLatch) {
placeActorBlockLatch = false
placeActorBlocks()
}
super.update(delta)
//if (!flagDespawn) placeActorBlocks()
when (doorState) {
0/*CLOSED*/ -> {
if (!flagDespawn && worldBlockPos != null) {
}
}
}
}
}

View File

@@ -8,6 +8,7 @@ import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameitems.mouseInInteractableRange
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
/**
* Created by minjaesong on 2019-05-02.
@@ -32,8 +33,8 @@ object BlockBase {
if (gameItem.inventoryCategory == GameItem.Category.BLOCK) {
var ret1 = true
ingame.actorContainerActive.forEach {
if (it is ActorWithBody && it.physProp.usePhysics && it.intTilewiseHitbox.intersects(mousePoint))
ingame.actorContainerActive.filter { it is ActorWithBody }.forEach { val it = it as ActorWithBody
if ((it is FixtureBase || it.physProp.usePhysics) && it.intTilewiseHitbox.intersects(mousePoint))
ret1 = false // return is not allowed here
}
if (!ret1) return@mouseInInteractableRange -1L
@@ -44,7 +45,7 @@ object BlockBase {
val wallUnderCursor = ingame.world.getTileFromWall(mouseTile.x, mouseTile.y)
// return false if there is a tile already
if (isWall && BlockCodex[wallUnderCursor].isSolid || !isWall && BlockCodex[terrainUnderCursor].isSolid)
if (isWall && BlockCodex[wallUnderCursor].isSolid || !isWall && (BlockCodex[terrainUnderCursor].isSolid || BlockCodex[terrainUnderCursor].isActorBlock))
return@mouseInInteractableRange -1L
// filter passed, do the job

View File

@@ -0,0 +1,35 @@
package net.torvald.terrarum.modulebasegame.gameitems
import com.badlogic.gdx.graphics.g2d.TextureRegion
import net.torvald.terrarum.CommonResourcePool
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.itemproperties.Material
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
import net.torvald.terrarum.modulebasegame.gameactors.FixtureSwingingDoorBase
/**
* Created by minjaesong on 2022-07-15.
*/
class ItemTestDoor(originalID: ItemID) : FixtureItemBase(originalID, "net.torvald.terrarum.modulebasegame.gameactors.FixtureSwingingDoorBase") {
override var dynamicID: ItemID = originalID
override val originalName = "ITEM_DOOR"
override var baseMass = 12.0
override var stackable = true
override var inventoryCategory = Category.MISC
override val isUnique = false
override val isDynamic = false
override val material = Material()
override val itemImage: TextureRegion
get() = CommonResourcePool.getAsTextureRegion("itemplaceholder_16")
override var baseToolSize: Double? = baseMass
init {
equipPosition = EquipPosition.HAND_GRIP
}
override val makeFixture: () -> FixtureBase = {
FixtureSwingingDoorBase()
}
}

Binary file not shown.

Binary file not shown.