fixed a bug where non-solid blocks would still placed indefinitely

This commit is contained in:
minjaesong
2022-07-22 17:19:43 +09:00
parent 6495e741e6
commit c903d48073
7 changed files with 135 additions and 31 deletions

View File

@@ -8,6 +8,7 @@ import net.torvald.terrarum.gameitems.GameItem
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameitems.mouseInInteractableRange import net.torvald.terrarum.gameitems.mouseInInteractableRange
import net.torvald.terrarum.itemproperties.Material import net.torvald.terrarum.itemproperties.Material
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
import net.torvald.terrarum.modulecomputers.gameactors.FixtureHomeComputer import net.torvald.terrarum.modulecomputers.gameactors.FixtureHomeComputer
@@ -36,7 +37,7 @@ class ItemHomeComputer(originalID: ItemID) : GameItem(originalID) {
override fun startPrimaryUse(actor: ActorWithBody, delta: Float) = mouseInInteractableRange(actor) { override fun startPrimaryUse(actor: ActorWithBody, delta: Float) = mouseInInteractableRange(actor) {
val item = FixtureHomeComputer() val item = FixtureHomeComputer()
if (item.spawn(Terrarum.mouseTileX, Terrarum.mouseTileY)) 1L else -1L if (item.spawn(Terrarum.mouseTileX, Terrarum.mouseTileY, if (actor is IngamePlayer) actor.uuid else null)) 1L else -1L
// return true when placed, false when cannot be placed // return true when placed, false when cannot be placed
} }
} }

View File

@@ -51,7 +51,7 @@ class SheetSpriteAnimation(parentActor: ActorWithBody) : SpriteAnimation(parentA
/** /**
* Sets delays for each rows. Array size must be the same as the rows of the sheet * Sets delays for each rows. Array size must be the same as the rows of the sheet
*/ */
var delays: FloatArray = floatArrayOf(0.2f) var delays: FloatArray = FloatArray(64) { 0.2f }
set(value) { set(value) {
if (value.filter { it <= 0f }.isNotEmpty()) { if (value.filter { it <= 0f }.isNotEmpty()) {
throw IllegalArgumentException("Delay array contains zero or negative value: $delays") throw IllegalArgumentException("Delay array contains zero or negative value: $delays")

View File

@@ -5,14 +5,13 @@ import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameactors.ActorID import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gameactors.PhysProperties
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.ui.UICanvas import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.dyn4j.geometry.Vector2 import org.dyn4j.geometry.Vector2
import java.util.*
typealias BlockBoxIndex = Int typealias BlockBoxIndex = Int
@@ -42,6 +41,8 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
@Transient var mainUI: UICanvas? = null @Transient var mainUI: UICanvas? = null
var inventory: FixtureInventory? = null var inventory: FixtureInventory? = null
protected var actorThatInstalledThisFixture: UUID? = null
private constructor() : super(RenderOrder.BEHIND, PhysProperties.IMMOBILE, null) private constructor() : super(RenderOrder.BEHIND, PhysProperties.IMMOBILE, null)
@@ -118,7 +119,7 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
* @param posY0 tile-wise bottem-centre position of the fixture (usually [Terrarum.mouseTileY]) * @param posY0 tile-wise bottem-centre position of the fixture (usually [Terrarum.mouseTileY])
* @return true if successfully spawned, false if was not (e.g. space to spawn is occupied by something else) * @return true if successfully spawned, false if was not (e.g. space to spawn is occupied by something else)
*/ */
open fun spawn(posX0: Int, posY0: Int): Boolean { open fun spawn(posX0: Int, posY0: Int, installersUUID: UUID?): Boolean {
// place filler blocks // place filler blocks
// place the filler blocks where: // place the filler blocks where:
// origin posX: centre-left if mouseX is on the right-half of the game window, // origin posX: centre-left if mouseX is on the right-half of the game window,
@@ -169,6 +170,7 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
INGAME.queueActorAddition(this) INGAME.queueActorAddition(this)
spawnRequestedTime = System.nanoTime() spawnRequestedTime = System.nanoTime()
actorThatInstalledThisFixture = installersUUID
return true return true
} }
@@ -183,7 +185,7 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
* @param thbh tile-wise Hitbox height * @param thbh tile-wise Hitbox height
* @return true if successfully spawned, false if was not (e.g. space to spawn is occupied by something else) * @return true if successfully spawned, false if was not (e.g. space to spawn is occupied by something else)
*/ */
open fun spawn(posX0: Int, posY0: Int, thbw: Int, thbh: Int): Boolean { open fun spawn(posX0: Int, posY0: Int, installersUUID: UUID?, thbw: Int, thbh: Int): Boolean {
val posX = (posX0 - thbw.minus(1).div(2)) fmod world!!.width // width.minus(1) so that spawning position would be same as the ghost's position val posX = (posX0 - thbw.minus(1).div(2)) fmod world!!.width // width.minus(1) so that spawning position would be same as the ghost's position
val posY = posY0 - thbh + 1 val posY = posY0 - thbh + 1
@@ -226,6 +228,7 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
INGAME.queueActorAddition(this) INGAME.queueActorAddition(this)
spawnRequestedTime = System.nanoTime() spawnRequestedTime = System.nanoTime()
actorThatInstalledThisFixture = installersUUID
return true return true
} }

View File

@@ -6,11 +6,11 @@ import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.gameactors.Hitbox
import net.torvald.terrarum.gameactors.Lightbox
import net.torvald.terrarum.gameactors.Luminous
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.dyn4j.geometry.Vector2
import java.util.*
import kotlin.math.absoluteValue
/** /**
* @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 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)
@@ -30,6 +30,8 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
open val texturePath = "sprites/fixtures/door_test.tga" open val texturePath = "sprites/fixtures/door_test.tga"
open val textureIdentifier = "fixtures-door_test.tga" open val textureIdentifier = "fixtures-door_test.tga"
open val customNameFun = { "DOOR_BASE" } open val customNameFun = { "DOOR_BASE" }
open val doorClosedHoldLength: Second = 0.1f
open val doorOpenedHoldLength: Second = 0.25f
/* END OF CUTOMISABLE PARAMETERS */ /* END OF CUTOMISABLE PARAMETERS */
private val tilewiseHitboxWidth = tw * 2 - twClosed private val tilewiseHitboxWidth = tw * 2 - twClosed
@@ -42,6 +44,13 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
@Transient override val shadeBoxList: ArrayList<Lightbox> = ArrayList() @Transient override val shadeBoxList: ArrayList<Lightbox> = ArrayList()
protected var doorState = 0 // -1: open toward left, 0: closed, 1: open toward right protected var doorState = 0 // -1: open toward left, 0: closed, 1: open toward right
protected var doorStateTimer: Second = 0f
@Transient private val doorHoldLength: HashMap<Int, Second> = hashMapOf(
-1 to doorClosedHoldLength,
1 to doorClosedHoldLength,
0 to doorOpenedHoldLength
)
// @Transient private var placeActorBlockLatch = false // @Transient private var placeActorBlockLatch = false
@@ -49,6 +58,7 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
BlockBox(BlockBox.FULL_COLLISION, 1, 1), // temporary value, will be overwritten by spawn() BlockBox(BlockBox.FULL_COLLISION, 1, 1), // temporary value, will be overwritten by spawn()
nameFun = { "item not loaded properly, alas!" } nameFun = { "item not loaded properly, alas!" }
) { ) {
nameFun = customNameFun nameFun = customNameFun
density = 1200.0 density = 1200.0
@@ -75,7 +85,7 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
reload() reload()
} }
override fun spawn(posX: Int, posY: Int) = spawn(posX, posY, tilewiseHitboxWidth, tilewiseHitboxHeight) override fun spawn(posX: Int, posY: Int, installersUUID: UUID?): Boolean = spawn(posX, posY, installersUUID, tilewiseHitboxWidth, tilewiseHitboxHeight)
override fun reload() { override fun reload() {
super.reload() super.reload()
@@ -90,18 +100,27 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
} }
open protected fun closeDoor() { open protected fun closeDoor() {
(sprite!! as SheetSpriteAnimation).currentRow = 0 if (doorState != 0) {
doorState = 0 (sprite!! as SheetSpriteAnimation).currentRow = 0
doorState = 0
placeActorBlocks()
}
} }
open protected fun openToRight() { open protected fun openToRight() {
(sprite!! as SheetSpriteAnimation).currentRow = 1 if (doorState != 1) {
doorState = 1 (sprite!! as SheetSpriteAnimation).currentRow = 1
doorState = 1
placeActorBlocks()
}
} }
open protected fun openToLeft() { open protected fun openToLeft() {
(sprite!! as SheetSpriteAnimation).currentRow = 2 if (doorState != -1) {
doorState = -1 (sprite!! as SheetSpriteAnimation).currentRow = 2
doorState = -1
placeActorBlocks()
}
} }
/*override fun forEachBlockbox(action: (Int, Int, Int, Int) -> Unit) { /*override fun forEachBlockbox(action: (Int, Int, Int, Int) -> Unit) {
@@ -142,22 +161,96 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
} }
override fun update(delta: Float) { private fun mouseOnLeftSide(): Boolean {
/*if (placeActorBlockLatch) { val mouseRelX = Terrarum.mouseX - hitbox.hitboxStart.x
placeActorBlockLatch = false val mouseRelY = Terrarum.mouseY - hitbox.hitboxStart.y
placeActorBlocks() return 0.0 <= mouseRelX && mouseRelX < hitbox.width / 2 && mouseRelY in 0.0..hitbox.height
}*/ }
private fun mouseOnRightSide(): Boolean {
val mouseRelX = Terrarum.mouseX - hitbox.hitboxStart.x
val mouseRelY = Terrarum.mouseY - hitbox.hitboxStart.y
return hitbox.width / 2 < mouseRelX && mouseRelX <= hitbox.width && mouseRelY in 0.0..hitbox.height
}
private fun ActorWithBody.ontheLeftSideOfDoor(): Boolean {
return this.hitbox.centeredX < this@FixtureSwingingDoorBase.hitbox.centeredX
}
private fun ActorWithBody.ontheRightSideOfDoor(): Boolean {
return this.hitbox.centeredX > this@FixtureSwingingDoorBase.hitbox.centeredX
}
private fun ActorWithBody.movingTowardsRight(): Boolean {
return ((this.controllerV ?: Vector2()) + this.externalV).x >= PHYS_EPSILON_VELO
}
private fun ActorWithBody.movingTowardsLeft(): Boolean {
return ((this.controllerV ?: Vector2()) + this.externalV).x <= -PHYS_EPSILON_VELO
}
private fun ActorWithBody.notMoving(): Boolean {
return ((this.controllerV ?: Vector2()) + this.externalV).x.absoluteValue < PHYS_EPSILON_VELO
}
override fun update(delta: Float) {
super.update(delta) super.update(delta)
//if (!flagDespawn) placeActorBlocks() if (!flagDespawn && worldBlockPos != null) {
val actors = INGAME.actorContainerActive.filterIsInstance<ActorWithBody>()
when (doorState) { // auto opening and closing
0/*CLOSED*/ -> { // TODO make this work with "player_alies" faction, not just a player
if (!flagDespawn && worldBlockPos != null) { val installer: IngamePlayer? = if (actorThatInstalledThisFixture == null) null else INGAME.actorContainerActive.filterIsInstance<IngamePlayer>().filter { it.uuid == actorThatInstalledThisFixture }.ifEmpty {
INGAME.actorContainerInactive.filterIsInstance<IngamePlayer>().filter { it.uuid == actorThatInstalledThisFixture }
}.getOrNull(0)
// if the door is "owned" by someone, restrict access to its "amicable" (defined using Faction subsystem) actors
// if the door is owned by null, restrict access to ActorHumanoid and actors with "intelligent" actor value set up
if (actorThatInstalledThisFixture == null || installer != null) {
val amicableActors: List<ActorWithBody> = ArrayList(
if (actorThatInstalledThisFixture == null)
actors.filterIsInstance<ActorHumanoid>() union actors.filter { it.actorValue.getAsBoolean("intelligent") == true }
else {
val goodFactions = installer?.faction?.flatMap { it.factionAmicable }?.toHashSet()
if (goodFactions != null)
actors.filterIsInstance<Factionable>().filter {
(it.faction.map { it.factionName } intersect goodFactions).isNotEmpty()
} as List<ActorWithBody>
else
listOf()
}
).also {
// add the installer of the door to the amicableActors if for some reason it was not added
if (installer != null && !it.contains(installer)) it.add(0, installer)
}.filter {
// filter amicableActors so that ones standing near the door remain
it.hitbox.intersects(this.hitbox)
}
// automatic opening/closing
if (doorStateTimer > doorHoldLength[doorState]!!) {
var nobodyIsThere = true
for (actor in amicableActors) {
if (actor.ontheLeftSideOfDoor() && actor.movingTowardsRight()) {
openToRight()
nobodyIsThere = false
break
}
else if (actor.ontheRightSideOfDoor() && actor.movingTowardsLeft()) {
openToLeft()
nobodyIsThere = false
break
}
}
if (nobodyIsThere) {
closeDoor()
}
doorStateTimer = 0f
} }
} }
doorStateTimer += delta
} }
} }
} }

View File

@@ -9,6 +9,7 @@ import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.langpack.Lang import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import java.util.*
import kotlin.properties.Delegates import kotlin.properties.Delegates
/** /**
@@ -44,7 +45,7 @@ internal class FixtureTapestry : FixtureBase {
reload() reload()
} }
override fun spawn(posX: Int, posY: Int) = spawn(posX, posY, tilewiseHitboxWidth, tilewiseHitboxHeight) override fun spawn(posX: Int, posY: Int, installersUUID: UUID?): Boolean = spawn(posX, posY, installersUUID, tilewiseHitboxWidth, tilewiseHitboxHeight)
override fun reload() { override fun reload() {
super.reload() super.reload()

View File

@@ -44,8 +44,13 @@ object BlockBase {
val terrainUnderCursor = ingame.world.getTileFromTerrain(mouseTile.x, mouseTile.y) val terrainUnderCursor = ingame.world.getTileFromTerrain(mouseTile.x, mouseTile.y)
val wallUnderCursor = ingame.world.getTileFromWall(mouseTile.x, mouseTile.y) val wallUnderCursor = ingame.world.getTileFromWall(mouseTile.x, mouseTile.y)
// return false if there is a tile already // return false if there is a same tile already (including non-solid!)
if (isWall && BlockCodex[wallUnderCursor].isSolid || !isWall && (BlockCodex[terrainUnderCursor].isSolid || BlockCodex[terrainUnderCursor].isActorBlock)) if (isWall && wallUnderCursor == itemID || !isWall && terrainUnderCursor == itemID)
return@mouseInInteractableRange -1L
// return false if there is a "solid" tile already
if (isWall && BlockCodex[wallUnderCursor].isSolid ||
!isWall && (BlockCodex[terrainUnderCursor].isSolid || BlockCodex[terrainUnderCursor].isActorBlock))
return@mouseInInteractableRange -1L return@mouseInInteractableRange -1L
// filter passed, do the job // filter passed, do the job

View File

@@ -10,6 +10,7 @@ import net.torvald.terrarum.gameitems.mouseInInteractableRange
import net.torvald.terrarum.itemproperties.Material import net.torvald.terrarum.itemproperties.Material
import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference import java.util.concurrent.atomic.AtomicReference
@@ -86,7 +87,7 @@ open class FixtureItemBase(originalID: ItemID, val fixtureClassName: String) : G
override fun startPrimaryUse(actor: ActorWithBody, delta: Float) = mouseInInteractableRange(actor) { override fun startPrimaryUse(actor: ActorWithBody, delta: Float) = mouseInInteractableRange(actor) {
val item = ghostItem.getAndSet(makeFixture()) // renew the "ghost" otherwise you'll be spawning exactly the same fixture again; old ghost will be returned val item = ghostItem.getAndSet(makeFixture()) // renew the "ghost" otherwise you'll be spawning exactly the same fixture again; old ghost will be returned
if (item.spawn(Terrarum.mouseTileX, Terrarum.mouseTileY)) 1 else -1 if (item.spawn(Terrarum.mouseTileX, Terrarum.mouseTileY, if (actor is IngamePlayer) actor.uuid else null)) 1 else -1
// return true when placed, false when cannot be placed // return true when placed, false when cannot be placed
} }