mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-10 05:41:51 +09:00
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:
BIN
assets/mods/basegame/sprites/fixtures/door_basegame-48.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/door_basegame-48.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/door_basegame-49.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/door_basegame-49.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/door_basegame-50.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/door_basegame-50.tga
LFS
Normal file
Binary file not shown.
BIN
assets/mods/basegame/sprites/fixtures/door_basegame-51.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/door_basegame-51.tga
LFS
Normal file
Binary file not shown.
@@ -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")
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
BIN
work_files/UI/machine_label_font_square.kra
LFS
Normal file
BIN
work_files/UI/machine_label_font_square.kra
LFS
Normal file
Binary file not shown.
BIN
work_files/graphics/sprites/fixtures/door_wooden.kra
LFS
Normal file
BIN
work_files/graphics/sprites/fixtures/door_wooden.kra
LFS
Normal file
Binary file not shown.
Reference in New Issue
Block a user