diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index d6dd0fee1..f34980e52 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -17,6 +17,7 @@ import net.torvald.gdx.graphics.Cvec import net.torvald.random.HQRNG import net.torvald.terrarum.App.* import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE +import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED import net.torvald.terrarum.blockproperties.BlockCodex import net.torvald.terrarum.blockproperties.WireCodex import net.torvald.terrarum.gameactors.Actor @@ -258,6 +259,87 @@ object Terrarum : Disposable { val mouseDown: Boolean get() = Gdx.input.isButtonPressed(App.getConfigInt("config_mouseprimary")) + + /** + * Subtile and Vector indices: + * ``` + * 4px 8px + * +-+-----+-+ + * | | 4 | | + * +-+-----+-+ + * |3| 0 |1| + * +-+-----+-+ + * | | 2 | | + * +-+-----+-+ + * ``` + */ + + enum class SubtileVector { + INVALID, CENTRE, LEFT, BOTTOM, RIGHT, TOP + } + + data class MouseSubtile4(val x: Int, val y: Int, val vector: SubtileVector) { + + val nx = when (vector) { + SubtileVector.CENTRE -> x + SubtileVector.RIGHT -> x + 1 + SubtileVector.BOTTOM -> x + SubtileVector.LEFT -> x - 1 + SubtileVector.TOP -> x + else -> throw IllegalArgumentException("Invalid vector index $vector for subtile $this") + } + + val ny = when (vector) { + SubtileVector.CENTRE -> y + SubtileVector.RIGHT -> y + SubtileVector.BOTTOM -> y + 1 + SubtileVector.LEFT -> y + SubtileVector.TOP -> y - 1 + else -> throw IllegalArgumentException("Invalid vector index $vector for subtile $this") + } + + fun getNextTileCoord() = when (vector) { + SubtileVector.CENTRE -> x to y + SubtileVector.RIGHT -> (x + 1) to y + SubtileVector.BOTTOM -> x to (y + 1) + SubtileVector.LEFT -> (x - 1) to y + SubtileVector.TOP -> x to (y - 1) + else -> throw IllegalArgumentException("Invalid vector index $vector for subtile $this") + } + + fun getCurrentTileCoord() = x to y + } + + fun getMouseSubtile4(): MouseSubtile4 { + val SMALLGAP = 4.0 + val LARGEGAP = 8.0 // 2*SMALLGAP + LARGEGAP must be equal to TILE_SIZE + assert(2 * SMALLGAP + LARGEGAP == TILE_SIZED) + + val mx = mouseX + val my = mouseY + val mtx = (mouseX / TILE_SIZE).floorInt() + val mty = (mouseY / TILE_SIZE).floorInt() + val msx = mx fmod TILE_SIZED + val msy = my fmod TILE_SIZED + val vector = if (msx < SMALLGAP) { // X to the left + if (msy < SMALLGAP) SubtileVector.INVALID // TOP LEFT + else if (msy < SMALLGAP + LARGEGAP) SubtileVector.LEFT // LEFT + else SubtileVector.INVALID // BOTTOM LEFT + } + else if (msx < SMALLGAP + LARGEGAP) { // X to the centre + if (msy < SMALLGAP) SubtileVector.TOP // TOP + else if (msy < SMALLGAP + LARGEGAP) SubtileVector.CENTRE // CENTRE + else SubtileVector.BOTTOM // BOTTOM + } + else { // X to the right + if (msy < SMALLGAP) SubtileVector.INVALID // TOP RIGHT + else if (msy < SMALLGAP + LARGEGAP) SubtileVector.RIGHT // RIGHT + else SubtileVector.INVALID // BOTTOM RIGHT + } + + return MouseSubtile4(mtx, mty, vector) + } + /** * Usage: * diff --git a/src/net/torvald/terrarum/gameitems/GameItem.kt b/src/net/torvald/terrarum/gameitems/GameItem.kt index aeabcf176..a7a1a6bce 100644 --- a/src/net/torvald/terrarum/gameitems/GameItem.kt +++ b/src/net/torvald/terrarum/gameitems/GameItem.kt @@ -206,14 +206,14 @@ abstract class GameItem(val originalID: ItemID) : Comparable, Cloneabl * - Screen tap * - XBox controller RT (fixed; LT is for jumping) * - * @return true when used successfully, false otherwise + * @return amount of the item to remove from the inventory -- 0 or greater when used successfully, -1 when failed * * note: DO NOT super() this! * * Consumption function is executed in net.torvald.terrarum.gamecontroller.IngameController, * in which the function itself is defined in net.torvald.terrarum.modulebasegame.gameactors.ActorInventory */ - open fun startPrimaryUse(actor: ActorWithBody, delta: Float): Boolean = false + open fun startPrimaryUse(actor: ActorWithBody, delta: Float): Long = -1 /** * I have decided that left and right clicks must do the same thing, so no secondary use from now on. --Torvald on 2019-05-26 @@ -365,14 +365,14 @@ abstract class GameItem(val originalID: ItemID) : Comparable, Cloneabl * @param actor actor to check the reach * @param action returns true if the action was successfully performed */ -fun mouseInInteractableRange(actor: ActorWithBody, action: () -> Boolean): Boolean { +fun mouseInInteractableRange(actor: ActorWithBody, action: () -> Long): Long { val mousePos1 = Vector2(Terrarum.mouseX, Terrarum.mouseY) val mousePos2 = Vector2(Terrarum.mouseX + INGAME.world.width * TILE_SIZED, Terrarum.mouseY) val mousePos3 = Vector2(Terrarum.mouseX - INGAME.world.width * TILE_SIZED, Terrarum.mouseY) val actorPos = actor.centrePosVector val dist = minOf(actorPos.distanceSquared(mousePos1), actorPos.distanceSquared(mousePos2), actorPos.distanceSquared(mousePos3)) val distMax = actor.actorValue.getAsDouble(AVKey.REACH)!! * (actor.actorValue.getAsDouble(AVKey.REACHBUFF) ?: 1.0) * actor.scale // perform some error checking here - if (dist <= distMax.sqr()) return action() else return false + if (dist <= distMax.sqr()) return action() else return -1 } fun mouseInInteractableRangeTools(actor: ActorWithBody, item: GameItem?, reachMultiplierInTiles: (Int) -> Double = { it.toDouble() }, action: () -> Boolean): Boolean { val mousePos1 = Vector2(Terrarum.mouseX, Terrarum.mouseY) diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index b559134dd..695da11d8 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -217,6 +217,7 @@ open class GameWorld() : Disposable { } fun coerceXY(x: Int, y: Int) = (x fmod width) to (y.coerceIn(0, height - 1)) + fun coerceXY(xy: Pair) = (xy.first fmod width) to (xy.second.coerceIn(0, height - 1)) /** * @return ItemID, WITHOUT wall tag @@ -307,7 +308,7 @@ open class GameWorld() : Disposable { } } - fun setTileWire(x: Int, y: Int, tile: ItemID, bypassEvent: Boolean) { + fun setTileWire(x: Int, y: Int, tile: ItemID, bypassEvent: Boolean, connection: Int) { val (x, y) = coerceXY(x, y) val blockAddr = LandUtil.getBlockAddr(this, x, y) val wireNode = wirings[blockAddr] @@ -323,7 +324,8 @@ open class GameWorld() : Disposable { Terrarum.ingame?.modified(LandUtil.LAYER_WIRE, x, y) } - + /* + // auto-connect-to-the-neighbour wire placement // figure out wiring graphs val matchingNeighbours = WireActor.WIRE_NEARBY.mapIndexed { index, (tx, ty) -> (getAllWiresFrom(x + tx, y + ty)?.contains(tile) == true).toInt() shl index @@ -337,7 +339,10 @@ open class GameWorld() : Disposable { val old = getWireGraphOf(x + tx, y + ty, tile) ?: 0 setWireGraphOf(x + tx, y + ty, tile, old or WIRE_ANTIPOS_MAP[i]) } - } + }*/ + + // scratch-that-i'll-figure-it-out wire placement + setWireGraphOfUnsafe(blockAddr, tile, connection) } fun removeTileWire(x: Int, y: Int, tile: ItemID, bypassEvent: Boolean) { @@ -663,7 +668,7 @@ open class GameWorld() : Disposable { * These values must be updated by none other than [WorldSimulator]() */ data class WiringSimCell( - var cnx: Int = 0, // connections + var cnx: Int = 0, // connections. [1, 2, 4, 8] = [RIGHT, DOWN, LEFT, UP] val emt: Vector2 = Vector2(0.0, 0.0), // i'm emitting this much power val rcv: ArrayList = ArrayList() // how far away are the power sources ) diff --git a/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt b/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt index 694ce44c9..54a505629 100644 --- a/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt +++ b/src/net/torvald/terrarum/modulebasegame/EntryPoint.kt @@ -104,7 +104,7 @@ class EntryPoint : ModuleEntryPoint() { tags.addAll(tile.tags) } - override fun startPrimaryUse(actor: ActorWithBody, delta: Float): Boolean { + override fun startPrimaryUse(actor: ActorWithBody, delta: Float): Long { return BlockBase.blockStartPrimaryUse(actor, this, dynamicID, delta) } diff --git a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt index 10f37b40c..76d5af31d 100644 --- a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt +++ b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt @@ -4,7 +4,6 @@ import com.badlogic.gdx.Gdx import com.badlogic.gdx.Input import com.badlogic.gdx.graphics.Camera import com.badlogic.gdx.graphics.g2d.SpriteBatch -import net.torvald.unicode.EMDASH import net.torvald.terrarum.* import net.torvald.terrarum.App.* import net.torvald.terrarum.Terrarum.getPlayerSaveFiledesc @@ -50,6 +49,7 @@ import net.torvald.terrarum.worlddrawer.BlocksDrawer import net.torvald.terrarum.worlddrawer.FeaturesDrawer import net.torvald.terrarum.worlddrawer.LightmapRenderer.LIGHTMAP_OVERRENDER import net.torvald.terrarum.worlddrawer.WorldCamera +import net.torvald.unicode.EMDASH import net.torvald.util.CircularArray import org.khelekore.prtree.PRTree import java.util.* @@ -631,8 +631,8 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) { // don't want to open the UI and use the item at the same time, would ya? if (!uiOpened && itemOnGrip != null) { val consumptionSuccessful = itemOnGrip.startPrimaryUse(actor, delta) - if (consumptionSuccessful) - (actor as Pocketed).inventory.consumeItem(itemOnGrip) + if (consumptionSuccessful > -1) + (actor as Pocketed).inventory.consumeItem(itemOnGrip, consumptionSuccessful) } // #3. If I'm not holding any item and I can do barehandaction (size big enough that barehandactionminheight check passes), perform it else if (itemOnGrip == null) { @@ -657,8 +657,8 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) { /*override fun worldSecondaryClickStart(delta: Float) { val itemOnGrip = actorNowPlaying?.inventory?.itemEquipped?.get(GameItem.EquipPosition.HAND_GRIP) val consumptionSuccessful = ItemCodex[itemOnGrip]?.startSecondaryUse(delta) ?: false - if (consumptionSuccessful) - actorNowPlaying?.inventory?.consumeItem(ItemCodex[itemOnGrip]!!) + if (consumptionSuccessful > -1) + actorNowPlaying?.inventory?.consumeItem(ItemCodex[itemOnGrip]!!, consumptionSuccessful) } override fun worldSecondaryClickEnd(delta: Float) { diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt index 6454dd053..145e04e6d 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/ActorInventory.kt @@ -66,11 +66,13 @@ class ActorInventory() : FixtureInventory() { fun getQuickslotItem(slot: Int): InventoryPair? = searchByID(quickSlot[slot]) - fun consumeItem(item: GameItem) { + fun consumeItem(item: GameItem, amount: Long = 1L) { val actor = this.actor as Actor + if (item.isDynamic && amount != 1L) throw IllegalArgumentException("Dynamic item must be consumed 'once' (expected 1, got $amount)") + if (item.stackable && !item.isDynamic) { - remove(item, 1) + remove(item, amount) } else if (item.isUnique) { return // don't consume a bike! diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureInventory.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureInventory.kt index 205b33304..5fca12eb4 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureInventory.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureInventory.kt @@ -49,7 +49,8 @@ open class FixtureInventory() { // other invalid values if (count == 0L) - throw IllegalArgumentException("[${this.javaClass.canonicalName}] Item count is zero.") +// throw IllegalArgumentException("[${this.javaClass.canonicalName}] Item count is zero.") + return if (count < 0L) throw IllegalArgumentException("Item count is negative number. If you intended removing items, use remove()\n" + "These commands are NOT INTERCHANGEABLE; they handle things differently according to the context.") @@ -94,7 +95,8 @@ open class FixtureInventory() { println("[ActorInventory] remove $item, $count") if (count == 0L) - throw IllegalArgumentException("[${this.javaClass.canonicalName}] Item count is zero.") +// throw IllegalArgumentException("[${this.javaClass.canonicalName}] Item count is zero.") + return if (count < 0L) throw IllegalArgumentException("[${this.javaClass.canonicalName}] Item count is negative number. If you intended adding items, use add()" + "These commands are NOT INTERCHANGEABLE; they handle things differently according to the context.") diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/BlockBase.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/BlockBase.kt index 6c608b061..996a05833 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/BlockBase.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/BlockBase.kt @@ -34,7 +34,7 @@ object BlockBase { if (it is ActorWithBody && it.physProp.usePhysics && it.intTilewiseHitbox.intersects(mousePoint)) ret1 = false // return is not allowed here } - if (!ret1) return@mouseInInteractableRange ret1 + if (!ret1) return@mouseInInteractableRange -1L } // return false if the tile underneath is: @@ -46,7 +46,7 @@ object BlockBase { gameItem.dynamicID == "wall@" + ingame.world.getTileFromWall(mouseTile.x, mouseTile.y) || BlockCodex[ingame.world.getTileFromTerrain(mouseTile.x, mouseTile.y)].nameKey.contains("ACTORBLOCK_") ) - return@mouseInInteractableRange false + return@mouseInInteractableRange 1L // filter passed, do the job // FIXME this is only useful for Player @@ -67,31 +67,41 @@ object BlockBase { ) } - true + 1L } fun blockEffectWhenEquipped(actor: ActorWithBody, delta: Float) { (Terrarum.ingame!! as TerrarumIngame).selectedWireRenderClass = "" } + private fun Int.shiftByTwo() = this.shl(4).or(this).ushr(2).and(15) + private fun connectedEachOther(one: Int, other: Int) = one.shiftByTwo() and other != 0 + fun wireStartPrimaryUse(actor: ActorWithBody, gameItem: GameItem, delta: Float) = mouseInInteractableRange(actor) { val itemID = gameItem.originalID val ingame = Terrarum.ingame!! as TerrarumIngame - val mouseTile = Point2i(Terrarum.mouseTileX, Terrarum.mouseTileY) + val mouseTile = Terrarum.getMouseSubtile4() - // return false if the tile is already there - if (ingame.world.getAllWiresFrom(mouseTile.x, mouseTile.y)?.searchFor(itemID) != null) - return@mouseInInteractableRange false + val thisTileWires = ingame.world.getAllWiresFrom(mouseTile.x, mouseTile.y) + val otherTileWires = ingame.world.getAllWiresFrom(mouseTile.nx, mouseTile.ny) + val thisTileWireCnx = ingame.world.getWireGraphOf(mouseTile.x, mouseTile.y, itemID) + val otherTileWireCnx = ingame.world.getWireGraphOf(mouseTile.x, mouseTile.y, itemID) - // filter passed, do the job - ingame.world.setTileWire( - mouseTile.x, - mouseTile.y, - itemID, - false - ) + // cases: + // * regardless of vector, this tile was not dragged-on + // -> if this tile is occupied (use thisTileWires?.searchFor(itemID) != null): return -1 + // else: place the tile, then return 1 + // * regardless of vector, this tile was dragged-on, and the oldtile is neighbouring tile + // -> if this tile is occupied and connectivities are already set (use connectedEachOther(thisTileWireCnx, otherTileWireCnx)): return -1 + // else if this tile is occupied: set connectivity, then return 0 + // else: place the tile, set connectivity, then return 1 + // (dragged-on: let net.torvald.terrarum.Terrarum record the tile that the mouse button was just down, + // and the poll again later; if tile now != recorded tile, it is dragged-on) - true + // TODO + + + TODO() } fun wireEffectWhenEquipped(gameItem: GameItem, delta: Float) { diff --git a/src/net/torvald/terrarum/modulebasegame/gameitems/WirePieceSignalWire.kt b/src/net/torvald/terrarum/modulebasegame/gameitems/WirePieceSignalWire.kt index 6ff729e95..408dcfd9b 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameitems/WirePieceSignalWire.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameitems/WirePieceSignalWire.kt @@ -30,7 +30,7 @@ class WirePieceSignalWire(originalID: ItemID, private val atlasID: String, priva super.equipPosition = GameItem.EquipPosition.HAND_GRIP } - override fun startPrimaryUse(actor: ActorWithBody, delta: Float): Boolean { + override fun startPrimaryUse(actor: ActorWithBody, delta: Float): Long { return BlockBase.wireStartPrimaryUse(actor,this, delta) } diff --git a/work_files/wire_node_control_mousing_area.png b/work_files/wire_node_control_mousing_area.png new file mode 100644 index 000000000..cd55e5b8d --- /dev/null +++ b/work_files/wire_node_control_mousing_area.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:06fe29479159c5302520ca80d2b742bb91f054a769a1d654bb057a7354df3120 +size 580