mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
reorientable gearbox because input and output cannot be on the same location
This commit is contained in:
@@ -119,6 +119,10 @@ class Point2i() {
|
||||
}
|
||||
|
||||
override fun hashCode(): Int = XXHash32.hashGeoCoord(x, y)
|
||||
override fun equals(other: Any?) = if (other is Point2i)
|
||||
this.x == other.x && this.y == other.y
|
||||
else
|
||||
false
|
||||
|
||||
override fun toString() = "Point2i($x, $y)"
|
||||
|
||||
|
||||
@@ -630,7 +630,7 @@ object WorldSimulator {
|
||||
INGAME.getActorsAt(point.x * TILE_SIZED, point.y * TILE_SIZED).filterIsInstance<Electric>().firstOrNull().let { found ->
|
||||
if (found != null) {
|
||||
// get offset from the fixture's origin
|
||||
tileOffsetFromFixture = found.intTilewiseHitbox.let { Point2i(it.startX.toInt(), it.startY.toInt()) } - tilePoint
|
||||
tileOffsetFromFixture = found.worldBlockPos!! - tilePoint
|
||||
|
||||
// println("$tilePoint; ${found.javaClass.canonicalName}, $tileOffsetFromFixture, ${found.getWireSinkAt(tileOffsetFromFixture!!)}")
|
||||
|
||||
|
||||
@@ -100,8 +100,8 @@ open class Electric : FixtureBase {
|
||||
open fun updateSignal() {}
|
||||
|
||||
fun getWireStateAt(offsetX: Int, offsetY: Int, sinkType: WireEmissionType): Vector2 {
|
||||
val wx = offsetX + intTilewiseHitbox.startX.toInt()
|
||||
val wy = offsetY + intTilewiseHitbox.startY.toInt()
|
||||
val wx = offsetX + worldBlockPos!!.x
|
||||
val wy = offsetY + worldBlockPos!!.y
|
||||
|
||||
return WireCodex.getAllWiresThatAccepts(sinkType).fold(Vector2()) { acc, (id, _) ->
|
||||
INGAME.world.getWireEmitStateOf(wx, wy, id).let {
|
||||
@@ -141,8 +141,8 @@ open class Electric : FixtureBase {
|
||||
|
||||
open fun updateOnWireGraphTraversal(offsetX: Int, offsetY: Int, sinkType: WireEmissionType) {
|
||||
val index = pointToBlockBoxIndex(offsetX, offsetY)
|
||||
val wx = offsetX + intTilewiseHitbox.startX.toInt()
|
||||
val wy = offsetY + intTilewiseHitbox.startY.toInt()
|
||||
val wx = offsetX + worldBlockPos!!.x
|
||||
val wy = offsetY + worldBlockPos!!.y
|
||||
|
||||
val new2 = WireCodex.getAllWiresThatAccepts(wireSinkTypes[index] ?: "").fold(Vector2()) { acc, (id, _) ->
|
||||
INGAME.world.getWireEmitStateOf(wx, wy, id).let {
|
||||
@@ -168,8 +168,8 @@ open class Electric : FixtureBase {
|
||||
// get indices of "rising edges"
|
||||
// get indices of "falling edges"
|
||||
|
||||
val wx = x + intTilewiseHitbox.startX.toInt()
|
||||
val wy = y + intTilewiseHitbox.startY.toInt()
|
||||
val wx = x + worldBlockPos!!.x
|
||||
val wy = y + worldBlockPos!!.y
|
||||
val new = WireCodex.getAllWiresThatAccepts(getWireSinkAt(x, y) ?: "").fold(Vector2()) { acc, (id, _) ->
|
||||
INGAME.world.getWireEmitStateOf(wx, wy, id).let {
|
||||
Vector2(acc.x + (it?.x ?: 0.0), acc.y + (it?.y ?: 0.0))
|
||||
|
||||
@@ -183,6 +183,8 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
||||
return (posX until posX + blockBox.width).toList().cartesianProduct((posY until posY + blockBox.height).toList())
|
||||
}
|
||||
|
||||
open fun spawnCustomGetSpawningOffset() = 0 to 0
|
||||
|
||||
/**
|
||||
* Returns BlockBox definition as a list of individual blocks, absolute position in the world.
|
||||
*
|
||||
@@ -306,8 +308,12 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
||||
// posY: bottom of the blockBox
|
||||
// using the actor's hitbox
|
||||
|
||||
val posX = (posX0 - blockBox.width.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 - blockBox.height + 1
|
||||
val (ox, oy) = spawnCustomGetSpawningOffset()
|
||||
val posX0 = posX0 + ox
|
||||
val posY0 = posY0 + oy
|
||||
|
||||
val posX = ox + (posX0 - blockBox.width.minus(1).div(2)) fmod world!!.width // width.minus(1) so that spawning position would be same as the ghost's position
|
||||
val posY = oy + posY0 - blockBox.height + 1
|
||||
|
||||
if (!canSpawnHere(posX0, posY0)) {
|
||||
printdbg(this, "cannot spawn fixture1 ${nameFun()} at F${INGAME.WORLD_UPDATE_TIMER}, has tile collision; xy=($posX,$posY) tDim=(${blockBox.width},${blockBox.height})")
|
||||
@@ -317,10 +323,12 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
||||
printdbg(this, "spawn fixture ${nameFun()} at F${INGAME.WORLD_UPDATE_TIMER}, xy=($posX,$posY) tDim=(${blockBox.width},${blockBox.height})")
|
||||
|
||||
|
||||
// at this point, worldBlockPos was set by the canSpawnHere() function
|
||||
|
||||
|
||||
// fill the area with the filler blocks
|
||||
placeActorBlocks()
|
||||
|
||||
|
||||
this.isVisible = true
|
||||
this.hitbox.setFromWidthHeight(
|
||||
posX * TILE_SIZED,
|
||||
@@ -358,7 +366,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, installersUUID: UUID?, thbw: Int, thbh: Int): Boolean {
|
||||
open fun spawnUsingCustomBoxSize(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
|
||||
|
||||
@@ -453,6 +461,9 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
|
||||
* This function MUST BE super-called for make despawn call to work at all.
|
||||
*/
|
||||
override fun updateImpl(delta: Float) {
|
||||
actorValue.set(AVKey.SCALE, 1.0)
|
||||
actorValue.set(AVKey.SCALEBUFF, 1.0)
|
||||
////////////////////////////////////////////////////////////
|
||||
super.updateImpl(delta)
|
||||
chunkAnchoring = inOperation
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.spriteanimation.SheetSpriteAnimation
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.Point2i
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInductionMotor.Companion.MASS
|
||||
import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase
|
||||
@@ -68,7 +71,7 @@ class FixtureInductionMotor : Electric {
|
||||
/**
|
||||
* Created by minjaesong on 2024-10-05.
|
||||
*/
|
||||
class FixtureGearbox : Electric {
|
||||
class FixtureGearbox : Electric, Reorientable {
|
||||
|
||||
@Transient override val spawnNeedsFloor = true
|
||||
@Transient override val spawnNeedsWall = false
|
||||
@@ -82,95 +85,104 @@ class FixtureGearbox : Electric {
|
||||
return listOf(posX+1 to posY+1)
|
||||
}
|
||||
|
||||
override fun spawnCustomGetSpawningOffset() = 0 to 1
|
||||
|
||||
override fun orientClockwise() {
|
||||
orientation = 1 - orientation
|
||||
reorient(); setEmitterAndSink(); updateSignal()
|
||||
}
|
||||
|
||||
override fun orientAnticlockwise() {
|
||||
orientation = 1 - orientation
|
||||
reorient(); setEmitterAndSink(); updateSignal()
|
||||
}
|
||||
|
||||
override var orientation = 0 // 0 or 1
|
||||
|
||||
private fun reorient() {
|
||||
(sprite as SheetSpriteAnimation).currentRow = orientation
|
||||
}
|
||||
|
||||
private fun setEmitterAndSink() {
|
||||
clearStatus()
|
||||
when (orientation) {
|
||||
0 -> {
|
||||
posVecsIn.forEach { (x, y) ->
|
||||
setWireSinkAt(x, y, "axle")
|
||||
}
|
||||
posVecsOut.forEach { (x, y) ->
|
||||
setWireEmitterAt(x, y, "axle")
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
posVecsIn.forEach { (x, y) ->
|
||||
setWireEmitterAt(x, y, "axle")
|
||||
}
|
||||
posVecsOut.forEach { (x, y) ->
|
||||
setWireSinkAt(x, y, "axle")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
val itemImage = FixtureItemBase.getItemImageFromSingleImage("basegame", "sprites/fixtures/gearbox.tga")
|
||||
|
||||
density = 7874.0
|
||||
setHitboxDimension(TILE_SIZE, TILE_SIZE, 0, TILE_SIZE)
|
||||
setHitboxDimension(TILE_SIZE, TILE_SIZE, 0, 0)
|
||||
|
||||
makeNewSprite(TextureRegionPack(itemImage.texture, TILE_SIZE, TILE_SIZE+1)).let {
|
||||
it.setRowsAndFrames(1,1)
|
||||
it.setRowsAndFrames(2,1)
|
||||
}
|
||||
|
||||
actorValue[AVKey.BASEMASS] = MASS
|
||||
|
||||
posVecs.forEach { (x, y) ->
|
||||
setWireEmitterAt(x, y, "axle")
|
||||
setWireSinkAt(x, y, "axle")
|
||||
}
|
||||
setEmitterAndSink()
|
||||
}
|
||||
|
||||
|
||||
override fun updateImpl(delta: Float) {
|
||||
super.updateImpl(delta)
|
||||
|
||||
// animate the sprite
|
||||
val worldX = intTilewiseHitbox.startX.toInt()
|
||||
val worldY = intTilewiseHitbox.startY.toInt()
|
||||
|
||||
val targetTick = (App.TICK_SPEED / speedMax).let {
|
||||
it.coerceIn(0.0, Long.MAX_VALUE.toDouble())
|
||||
}.roundToLong()
|
||||
|
||||
val sprite = (sprite as SheetSpriteAnimation)
|
||||
|
||||
val phaseShift = if (worldY % 2 == 0)
|
||||
(worldX % 2 == 1)
|
||||
else
|
||||
(worldX % 2 == 0)
|
||||
|
||||
|
||||
if (targetTick > 0) {
|
||||
(INGAME.WORLD_UPDATE_TIMER % (targetTick * 2)).let {
|
||||
sprite.currentFrame =
|
||||
if (phaseShift)
|
||||
(it < targetTick).toInt()
|
||||
else
|
||||
(it >= targetTick).toInt()
|
||||
}
|
||||
// re-position the hitbox because wtf
|
||||
worldBlockPos?.let { (x, y) ->
|
||||
val x = (x+1) * TILE_SIZED; val y = (y+1) * TILE_SIZED
|
||||
hitbox.setFromTwoPoints(x, y, x + TILE_SIZED, y + TILE_SIZED)
|
||||
}
|
||||
|
||||
super.updateImpl(delta)
|
||||
}
|
||||
|
||||
@Transient private var speedMax = 0.0
|
||||
|
||||
private var maxSpeedLoc = ArrayList<Point2i>()
|
||||
private var minTorqueLoc = ArrayList<Point2i>()
|
||||
|
||||
@Transient private val newMaxSpeedLoc = ArrayList<Point2i>()
|
||||
@Transient private val newMinTorqueLoc = ArrayList<Point2i>()
|
||||
|
||||
override fun updateSignal() {
|
||||
val a = when (orientation) {
|
||||
0 -> posVecsIn
|
||||
1 -> posVecsOut
|
||||
else -> throw InternalError()
|
||||
}
|
||||
val b = when (orientation) {
|
||||
0 -> posVecsOut
|
||||
1 -> posVecsIn
|
||||
else -> throw InternalError()
|
||||
}
|
||||
|
||||
|
||||
var torqueMin = Double.POSITIVE_INFINITY
|
||||
newMaxSpeedLoc.clear()
|
||||
newMinTorqueLoc.clear()
|
||||
|
||||
speedMax = 0.0
|
||||
posVecs.forEach {
|
||||
a.forEach {
|
||||
val vec = getWireStateAt(it.x, it.y, "axle")
|
||||
if (!maxSpeedLoc.contains(it) && vec.x >= speedMax) {
|
||||
newMaxSpeedLoc.add(Point2i(it.x, it.y))
|
||||
if (vec.x.absoluteValue >= ELECTRIC_EPSILON_GENERIC && vec.x >= speedMax) {
|
||||
speedMax = vec.x
|
||||
}
|
||||
if (!minTorqueLoc.contains(it) && vec.y.absoluteValue >= ELECTRIC_EPSILON_GENERIC && vec.y <= torqueMin) {
|
||||
newMinTorqueLoc.add(Point2i(it.x, it.y))
|
||||
if (vec.y.absoluteValue >= ELECTRIC_EPSILON_GENERIC && vec.y <= torqueMin) {
|
||||
torqueMin = if (vec.y == Double.POSITIVE_INFINITY) 0.0 else vec.y
|
||||
}
|
||||
|
||||
// FIXME: intTilewiseHitbox discrepancy with spawn position.
|
||||
val wx = it.x + intTilewiseHitbox.startX.toInt()
|
||||
val wy = it.y + intTilewiseHitbox.startY.toInt()
|
||||
print("$wx,$wy\t")
|
||||
|
||||
if (maxSpeedLoc.contains(it))
|
||||
println("$it*\t$vec")
|
||||
else
|
||||
println("$it\t$vec")
|
||||
}
|
||||
println("--------")
|
||||
|
||||
maxSpeedLoc.clear(); maxSpeedLoc.addAll(newMaxSpeedLoc)
|
||||
minTorqueLoc.clear(); minTorqueLoc.addAll(newMinTorqueLoc)
|
||||
if (torqueMin == Double.POSITIVE_INFINITY) torqueMin = 0.0
|
||||
|
||||
posVecs.forEach { (x, y) ->
|
||||
|
||||
b.forEach { (x, y) ->
|
||||
setWireEmissionAt(x, y, Vector2(speedMax, torqueMin))
|
||||
}
|
||||
}
|
||||
@@ -180,10 +192,17 @@ class FixtureGearbox : Electric {
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Transient val posVecs = listOf(
|
||||
Point2i(1, 0),
|
||||
@Transient val posVecsIn = listOf(
|
||||
// Point2i(1, 0),
|
||||
Point2i(0, 1),
|
||||
Point2i(2, 1),
|
||||
// Point2i(1, 2),
|
||||
)
|
||||
|
||||
@Transient val posVecsOut = listOf(
|
||||
Point2i(1, 0),
|
||||
// Point2i(0, 1),
|
||||
// Point2i(2, 1),
|
||||
Point2i(1, 2),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ class FixtureLogicSignalAdder : Electric, Reorientable {
|
||||
|
||||
private val I: Boolean
|
||||
get() = when (orientation) {
|
||||
// 0 -> getWireStateAt(0, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
|
||||
0 -> getWireStateAt(0, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
|
||||
1 -> getWireStateAt(1, 0, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
|
||||
2 -> getWireStateAt(1, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
|
||||
3 -> getWireStateAt(0, 1, "digital_bit").x >= ELECTRIC_THRESHOLD_HIGH
|
||||
|
||||
@@ -143,7 +143,7 @@ open class FixtureSwingingDoorBase : FixtureBase {
|
||||
reload()
|
||||
}
|
||||
|
||||
override fun spawn(posX: Int, posY: Int, installersUUID: UUID?): Boolean = spawn(posX, posY, installersUUID, tilewiseHitboxWidth, tilewiseHitboxHeight)
|
||||
override fun spawn(posX: Int, posY: Int, installersUUID: UUID?): Boolean = spawnUsingCustomBoxSize(posX, posY, installersUUID, tilewiseHitboxWidth, tilewiseHitboxHeight)
|
||||
|
||||
override fun makeNoiseAndDust(posX: Int, posY: Int) {
|
||||
val posYb = posY + blockBox.height - 1
|
||||
|
||||
@@ -50,7 +50,7 @@ internal class FixtureTapestry : FixtureBase {
|
||||
reload()
|
||||
}
|
||||
|
||||
override fun spawn(posX: Int, posY: Int, installersUUID: UUID?): Boolean = spawn(posX, posY, installersUUID, tilewiseHitboxWidth, tilewiseHitboxHeight)
|
||||
override fun spawn(posX: Int, posY: Int, installersUUID: UUID?): Boolean = spawnUsingCustomBoxSize(posX, posY, installersUUID, tilewiseHitboxWidth, tilewiseHitboxHeight)
|
||||
|
||||
override fun reload() {
|
||||
super.reload()
|
||||
@@ -111,7 +111,7 @@ internal class FixtureTapestry : FixtureBase {
|
||||
|
||||
|
||||
// must be re-spawned on reload to make it visible after load
|
||||
spawn(
|
||||
spawnUsingCustomBoxSize(
|
||||
intTilewiseHitbox.canonicalX.toInt(),
|
||||
intTilewiseHitbox.canonicalY.toInt(),
|
||||
actorThatInstalledThisFixture,
|
||||
|
||||
@@ -18,7 +18,6 @@ import net.torvald.terrarum.itemproperties.Item
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.gameitems.ItemTextSignCopper
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIItemInventoryCellCommonRes.tooltipShowing
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import net.torvald.unicode.TIMES
|
||||
import org.dyn4j.geometry.Vector2
|
||||
@@ -71,7 +70,7 @@ class FixtureTextSignCopper : Electric {
|
||||
return item.dynamicID
|
||||
}
|
||||
|
||||
override fun spawn(posX: Int, posY: Int, installersUUID: UUID?): Boolean = spawn(posX, posY, installersUUID, panelCount.coerceAtLeast(2), 2)
|
||||
override fun spawn(posX: Int, posY: Int, installersUUID: UUID?): Boolean = spawnUsingCustomBoxSize(posX, posY, installersUUID, panelCount.coerceAtLeast(2), 2)
|
||||
|
||||
override fun reload() {
|
||||
super.reload()
|
||||
@@ -86,7 +85,7 @@ class FixtureTextSignCopper : Electric {
|
||||
}
|
||||
|
||||
// must be re-spawned on reload to make it visible after load
|
||||
spawn(
|
||||
spawnUsingCustomBoxSize(
|
||||
intTilewiseHitbox.canonicalX.toInt(),
|
||||
intTilewiseHitbox.canonicalY.toInt(),
|
||||
actorThatInstalledThisFixture,
|
||||
|
||||
Reference in New Issue
Block a user