world control hint

This commit is contained in:
minjaesong
2026-02-10 19:14:50 +09:00
parent 232bc0297d
commit 4d9252dd80
7 changed files with 154 additions and 3 deletions

View File

@@ -7,7 +7,9 @@
"CONTEXT_TIME_SECOND_PLURAL": "Seconds",
"COPYRIGHT_ALL_RIGHTS_RESERVED": "All rights reserved",
"COPYRIGHT_GNU_GPL_3": "Distributed under GNU GPL 3",
"GAME_ACTION_CHANGE_COLOR" : "Change color",
"GAME_ACTION_MOVE_VERB" : "Move",
"GAME_ACTION_PUT_DOWN" : "Put down",
"GAME_ACTION_ZOOM" : "Zoom",
"GAME_ACTION_ZOOM_OUT" : "Zoom out",
"MENU_IO_AUTOSAVE": "Autosave",
@@ -54,7 +56,7 @@
"MENU_OPTIONS_SPEAKER_HEADPHONE": "Headphone",
"MENU_OPTIONS_SPEAKER_SETUP": "Speaker Setup",
"MENU_OPTIONS_SPEAKER_STEREO": "Stereo",
"MENU_OPTIONS_STREAMERS_LAYOUT": "Chat Overlay",
"MENU_OPTIONS_STREAMERS_LAYOUT": "Space for Chat Overlay",
"MENU_CREDIT_GPL_DNT" : "GPL",
"MENU_LABEL_JVM_DNT" : "JVM",

View File

@@ -128,6 +128,16 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
* Nullability of this property is believed to be unavoidable (trust me!). I'm sorry for the inconvenience.
*/
open var actorNowPlaying: ActorHumanoid? = null
protected open val currentlyDisplayingControlHints = ControlHint(null, null)
fun setControlHint(primary: String?, secondary: String?) {
currentlyDisplayingControlHints.primary = primary
currentlyDisplayingControlHints.secondary = secondary
}
fun getCurrentControlHint() = currentlyDisplayingControlHints.copy()
/**
* The actual gamer
*/
@@ -635,3 +645,7 @@ class ProtectedActorRemovalException(whatisit: String, caller: Throwable) : Exce
val INGAME: IngameInstance
get() = Terrarum.ingame!!
/**
* Control Hints are always referred against Lang for display. To not display a hint for a specific hand, use `null`
*/
data class ControlHint(var primary: String?, var secondary: String?)

View File

@@ -311,12 +311,16 @@ abstract class GameItem(val originalID: ItemID) : TooltipListener(), Comparable<
/**
* Effects applied (continuously or not) while being equipped (drawn/pulled out)
*/
open fun effectWhileEquipped(actor: ActorWithBody, delta: Float) { }
open fun effectWhileEquipped(actor: ActorWithBody, delta: Float) {
INGAME.setControlHint("GAME_INVENTORY_USE", null) // the most generic control hints
}
/**
* Effects applied only once when unequipped
*/
open fun effectOnUnequip(actor: ActorWithBody) { }
open fun effectOnUnequip(actor: ActorWithBody) {
INGAME.setControlHint(null, null) // hide the control hints
}
override fun toString(): String {

View File

@@ -672,6 +672,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
uiWatchTierOne,
getWearableDeviceUI,
UIScreenZoom(),
UIWorldControlHint(),
uiAutosaveNotifier,
uiInventoryPlayer,

View File

@@ -62,6 +62,9 @@ open class FixtureItemBase(originalID: ItemID, val fixtureClassName: String) : G
override fun effectWhileEquipped(actor: ActorWithBody, delta: Float) {
INGAME.setControlHint("GAME_ACTION_PUT_DOWN", "GAME_ACTION_PICK_UP") // the most generic control hints
// println("ghost: ${ghostItem}; ghostInit = $ghostInit; instance: $hash")
if (!ghostInit.compareAndExchangeAcquire(false, true)) {
ghostItem.set(makeFixture(originalID.getModuleName()))
@@ -92,6 +95,8 @@ open class FixtureItemBase(originalID: ItemID, val fixtureClassName: String) : G
}
override fun effectOnUnequip(actor: ActorWithBody) {
super.effectOnUnequip(actor)
// ghostInit = false
(INGAME as TerrarumIngame).blockMarkingActor.let {

View File

@@ -135,10 +135,12 @@ class WireCutterAll(originalID: ItemID) : GameItem(originalID), FixtureInteracti
}
override fun effectWhileEquipped(actor: ActorWithBody, delta: Float) {
INGAME.setControlHint("GAME_INVENTORY_USE", "GAME_ACTION_CHANGE_COLOR") // the most generic control hints
(Terrarum.ingame!! as TerrarumIngame).selectedWireRenderClass = "wire_render_all"
}
override fun effectOnUnequip(actor: ActorWithBody) {
super.effectOnUnequip(actor)
(Terrarum.ingame!! as TerrarumIngame).selectedWireRenderClass = ""
selectorUI.setAsClose()
}

View File

@@ -0,0 +1,123 @@
package net.torvald.terrarum.modulebasegame.ui
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.OrthographicCamera
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.App
import net.torvald.terrarum.INGAME
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameitems.mouseInInteractableRange
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.modulebasegame.TerrarumIngame
import net.torvald.terrarum.modulebasegame.gameactors.DroppedItem
import net.torvald.terrarum.ui.Movement
import net.torvald.terrarum.ui.Toolkit
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.ui.UINotControllable
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
import net.torvald.unicode.getKeycapPC
import net.torvald.unicode.getMouseButton
import kotlin.math.roundToInt
/**
* Created by minjaesong on 2026-02-10.
*/
@UINotControllable
class UIWorldControlHint : UICanvas() {
init {
handler.allowESCtoClose = false
handler.setAsAlwaysVisible()
}
private fun getHintText(): String {
val control = INGAME.getCurrentControlHint()
return if (control.primary != null && control.secondary != null)
"${getMouseButton(App.getConfigInt("control_mouse_primary"))} ${Lang[control.primary!!]}\u3000" +
"${getMouseButton(App.getConfigInt("control_mouse_secondary"))} ${Lang[control.secondary!!]}"
else if (control.primary != null)
"${getMouseButton(App.getConfigInt("control_mouse_primary"))} ${Lang[control.primary!!]}\u3000"
else if (control.secondary != null)
"${getMouseButton(App.getConfigInt("control_mouse_secondary"))} ${Lang[control.secondary!!]}"
else
""
}
// always use getter to accomodate a language change
private fun getFixtureHintText(): String =
"${getMouseButton(App.getConfigInt("control_mouse_primary"))} ${Lang["GAME_INVENTORY_USE"]}\u3000" +
"${getMouseButton(App.getConfigInt("control_mouse_secondary"))} ${Lang["GAME_ACTION_PICK_UP"]}"
private var cachedText = ""
override var width = 480
override var height = App.fontGame.lineHeight.toInt()
override var openCloseTime = 0.2f
override val mouseUp = false
private var opacityCounter = 0f
private fun hasFixtureUnderMouse(): Boolean {
return mouseInInteractableRange(INGAME.actorNowPlaying ?: INGAME.actorGamer) { mwx, mwy, mtx, mty ->
val actorsUnderMouse = (INGAME as TerrarumIngame).getActorsUnderMouse(mwx, mwy)
val hasPickupableActor = actorsUnderMouse.any {
(it is FixtureBase && it.canBeDespawned && System.nanoTime() - it.spawnRequestedTime > 50000000) // give freshly spawned fixtures 0.05 seconds of immunity
}
if (hasPickupableActor) 0L else -1L
} > -1L
}
override fun updateImpl(delta: Float) {
val fixtureUnderMouse = hasFixtureUnderMouse()
val newText = if (fixtureUnderMouse) getFixtureHintText() else getHintText()
if (newText.isNotEmpty()) {
cachedText = newText
opacityCounter = (opacityCounter + delta).coerceAtMost(openCloseTime)
}
else {
opacityCounter = (opacityCounter - delta).coerceAtLeast(0f)
if (opacityCounter <= 0f) cachedText = ""
}
handler.opacity = opacityCounter / openCloseTime
}
override fun renderImpl(frameDelta: Float, batch: SpriteBatch, camera: OrthographicCamera) {
batch.color = Color.WHITE
val text = cachedText
val offX = Toolkit.drawWidthf - (App.scr.tvSafeGraphicsWidth * 1.25f).roundToInt().toFloat() - App.fontGame.getWidth(text)
val offY = App.scr.height - height - App.scr.tvSafeGraphicsHeight - 4f
App.fontGame.draw(batch, text, offX, offY)
}
override fun dispose() {
}
// overridden to not touch the tooltips
override fun doOpening(delta: Float) {
handler.opacity = handler.openCloseCounter / openCloseTime
}
// overridden to not touch the tooltips
override fun doClosing(delta: Float) {
handler.opacity = handler.openCloseCounter / openCloseTime
}
// overridden to not touch the tooltips
override fun endOpening(delta: Float) {
handler.opacity = 1f
}
// overridden to not touch the tooltips
override fun endClosing(delta: Float) {
handler.opacity = 0f
}
}