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.mouseInInteractableRange
import net.torvald.terrarum.itemproperties.Material
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
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) {
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
}
}

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
*/
var delays: FloatArray = floatArrayOf(0.2f)
var delays: FloatArray = FloatArray(64) { 0.2f }
set(value) {
if (value.filter { it <= 0f }.isNotEmpty()) {
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_SIZED
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameactors.ActorID
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gameactors.PhysProperties
import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.gameitems.ItemID
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import org.dyn4j.geometry.Vector2
import java.util.*
typealias BlockBoxIndex = Int
@@ -42,6 +41,8 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
@Transient var mainUI: UICanvas? = null
var inventory: FixtureInventory? = null
protected var actorThatInstalledThisFixture: UUID? = 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])
* @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 the filler blocks where:
// 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)
spawnRequestedTime = System.nanoTime()
actorThatInstalledThisFixture = installersUUID
return true
}
@@ -183,7 +185,7 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
* @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)
*/
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 posY = posY0 - thbh + 1
@@ -226,6 +228,7 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
INGAME.queueActorAddition(this)
spawnRequestedTime = System.nanoTime()
actorThatInstalledThisFixture = installersUUID
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_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.terrarum.gameactors.*
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)
@@ -30,6 +30,8 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
open val texturePath = "sprites/fixtures/door_test.tga"
open val textureIdentifier = "fixtures-door_test.tga"
open val customNameFun = { "DOOR_BASE" }
open val doorClosedHoldLength: Second = 0.1f
open val doorOpenedHoldLength: Second = 0.25f
/* END OF CUTOMISABLE PARAMETERS */
private val tilewiseHitboxWidth = tw * 2 - twClosed
@@ -42,6 +44,13 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
@Transient override val shadeBoxList: ArrayList<Lightbox> = ArrayList()
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
@@ -49,6 +58,7 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
BlockBox(BlockBox.FULL_COLLISION, 1, 1), // temporary value, will be overwritten by spawn()
nameFun = { "item not loaded properly, alas!" }
) {
nameFun = customNameFun
density = 1200.0
@@ -75,7 +85,7 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
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() {
super.reload()
@@ -90,18 +100,27 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
}
open protected fun closeDoor() {
if (doorState != 0) {
(sprite!! as SheetSpriteAnimation).currentRow = 0
doorState = 0
placeActorBlocks()
}
}
open protected fun openToRight() {
if (doorState != 1) {
(sprite!! as SheetSpriteAnimation).currentRow = 1
doorState = 1
placeActorBlocks()
}
}
open protected fun openToLeft() {
if (doorState != -1) {
(sprite!! as SheetSpriteAnimation).currentRow = 2
doorState = -1
placeActorBlocks()
}
}
/*override fun forEachBlockbox(action: (Int, Int, Int, Int) -> Unit) {
@@ -142,22 +161,96 @@ open class FixtureSwingingDoorBase : FixtureBase, Luminous {
}
override fun update(delta: Float) {
/*if (placeActorBlockLatch) {
placeActorBlockLatch = false
placeActorBlocks()
}*/
private fun mouseOnLeftSide(): Boolean {
val mouseRelX = Terrarum.mouseX - hitbox.hitboxStart.x
val mouseRelY = Terrarum.mouseY - hitbox.hitboxStart.y
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)
//if (!flagDespawn) placeActorBlocks()
when (doorState) {
0/*CLOSED*/ -> {
if (!flagDespawn && worldBlockPos != null) {
val actors = INGAME.actorContainerActive.filterIsInstance<ActorWithBody>()
// auto opening and closing
// TODO make this work with "player_alies" faction, not just a player
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.langpack.Lang
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import java.util.*
import kotlin.properties.Delegates
/**
@@ -44,7 +45,7 @@ internal class FixtureTapestry : FixtureBase {
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() {
super.reload()

View File

@@ -44,8 +44,13 @@ object BlockBase {
val terrainUnderCursor = ingame.world.getTileFromTerrain(mouseTile.x, mouseTile.y)
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 || BlockCodex[terrainUnderCursor].isActorBlock))
// return false if there is a same tile already (including non-solid!)
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
// 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.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
import java.util.concurrent.atomic.AtomicBoolean
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) {
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
}