diff --git a/src/net/torvald/terrarum/Game.kt b/src/net/torvald/terrarum/Game.kt index 048bf1617..dbec44650 100644 --- a/src/net/torvald/terrarum/Game.kt +++ b/src/net/torvald/terrarum/Game.kt @@ -1,5 +1,6 @@ package net.torvald.terrarum +import net.torvald.imagefont.GameFontBase import net.torvald.terrarum.gameactors.* import net.torvald.terrarum.console.Authenticator import net.torvald.terrarum.gamecontroller.GameController @@ -146,31 +147,11 @@ constructor() : BasicGameState() { MapCamera.update(gc, delta) // determine whether the inactive actor should be re-active - actorContainerInactive.forEach { actor -> - if (actor is Visible && distToActorSqr(actor, player) <= ACTOR_UPDATE_RANGE.sqr()) { - addActor(actor) - } - } - actorContainer.forEach { if (actorContainerInactive.contains(it)) - actorContainerInactive.remove(it) - } + wakeDormantActors() - actorContainer.forEach { actor -> // update actors - // determine whether the actor should be active by their distance from the player - // will put inactive actors to list specifically for them - if (actor is Visible && distToActorSqr(actor, player) > ACTOR_UPDATE_RANGE.sqr()) { - actorContainerInactive.add(actor) - } - else { - // update our remaining active actors - actor.update(gc, delta) - if (actor is Visible) { - actor.updateBodySprite(gc, delta) - actor.updateGlowSprite(gc, delta) - } - } - } - actorContainerInactive.forEach { removeActor(it.referenceID) } + // determine whether the actor should be active or dormant + // also updates active actors + inactivateDistantActors(gc, delta) uiContainer.forEach { ui -> ui.update(gc, delta) } consoleHandler.update(gc, delta) @@ -184,12 +165,9 @@ constructor() : BasicGameState() { private fun setAppTitle() { Terrarum.appgc.setTitle( - "Simple Slick Game — FPS: " - + Terrarum.appgc.fps + " (" - + Terrarum.TARGET_INTERNAL_FPS.toString() - + ") — " - + memInUse.toString() + "M / " - + totalVMMem.toString() + "M") + "Simple Slick Game" + + " — FPS: ${Terrarum.appgc.fps} (${Terrarum.TARGET_INTERNAL_FPS})" + + " — ${memInUse}M / ${totalVMMem}M") } override fun render(gc: GameContainer, sbg: StateBasedGame, g: Graphics) { @@ -210,10 +188,7 @@ constructor() : BasicGameState() { // draw actors actorContainer.forEach { actor -> - if (actor is Visible && - distToActorSqr(actor, player) <= (Terrarum.WIDTH.plus(actor.hitbox.width.div(2)).sqr() + - Terrarum.HEIGHT.plus(actor.hitbox.height.div(2)).sqr()) - ) { // if visible and within screen + if (actor is Visible && actor.inScreen()) { // if visible and within screen actor.drawBody(gc, g) } } @@ -235,10 +210,7 @@ constructor() : BasicGameState() { // draw actor glows actorContainer.forEach { actor -> - if (actor is Visible && - distToActorSqr(actor, player) <= (Terrarum.WIDTH.plus(actor.hitbox.width.div(2)).sqr() + - Terrarum.HEIGHT.plus(actor.hitbox.height.div(2)).sqr()) - ) { + if (actor is Visible && actor.inScreen()) { // if visible and within screen actor.drawGlow(gc, g) } } @@ -255,6 +227,15 @@ constructor() : BasicGameState() { actor.hitbox.posX, actor.hitbox.pointedY + 4 ) + + if (DEBUG_ARRAY) { + g.color = GameFontBase.codeToCol["g"] + g.drawString( + i.toString(), + actor.hitbox.posX, + actor.hitbox.pointedY + 4 + 10 + ) + } } } } @@ -329,6 +310,45 @@ constructor() : BasicGameState() { notifinator.setAsOpening() } + fun wakeDormantActors() { + // determine whether the inactive actor should be re-active + var actorContainerSize = actorContainerInactive.size + var i = 0 + while (i < actorContainerSize) { // loop thru actorContainerInactive + val actor = actorContainerInactive[i] + val actorIndex = i + if (actor is Visible && actor.inUpdateRange()) { + addActor(actor) + actorContainerInactive.removeAt(actorIndex) + actorContainerSize -= 1 + i-- // array removed 1 elem, so also decrement counter by 1 + } + i++ + } + } + + fun inactivateDistantActors(gc: GameContainer, delta: Int) { + var actorContainerSize = actorContainer.size + var i = 0 + // determine whether the actor should be active or dormant by its distance from the player + // will put dormant actors to list specifically for them + // if the actor is not to be dormant, update it + while (i < actorContainerSize) { // loop thru actorContainer + val actor = actorContainer[i] + val actorIndex = i + if (actor is Visible && !actor.inUpdateRange()) { + actorContainerInactive.add(actor) + actorContainer.removeAt(actorIndex) + actorContainerSize -= 1 + i-- // array removed 1 elem, so also decrement counter by 1 + } + else { + actorContainer[i].update(gc, delta) + } + i++ + } + } + private val globalLightByTime: Int get() = getGradientColour(2).getRGB24().rgb24ExpandToRgb30() @@ -342,8 +362,11 @@ constructor() : BasicGameState() { fun Float.sqr() = this * this fun Int.sqr() = this * this - private fun distToActorSqr(a: Visible, p: Player) = + private fun distToActorSqr(a: Visible, p: Player): Float = (a.hitbox.centeredX - p.hitbox.centeredX).sqr() + (a.hitbox.centeredY - p.hitbox.centeredY).sqr() + private fun Visible.inScreen() = distToActorSqr(this, player) <= (Terrarum.WIDTH.plus(this.hitbox.width.div(2)).times(1 / Terrarum.game.screenZoom).sqr() + + Terrarum.HEIGHT.plus(this.hitbox.height.div(2)).times(1 / Terrarum.game.screenZoom).sqr()) + private fun Visible.inUpdateRange() = distToActorSqr(this, player) <= ACTOR_UPDATE_RANGE.sqr() /** * actorContainer extensions */ @@ -353,30 +376,33 @@ constructor() : BasicGameState() { else actorContainer.binarySearch(ID) >= 0 - /** - * Remove actor and sort the list - */ + fun removeActor(actor: Actor) = removeActor(actor.referenceID) + fun removeActor(ID: Int) { - for (actor in actorContainer) { - if (actor.referenceID == ID) { - actorContainer.remove(actor) - actorContainer.sort() - break - } - } + if (ID == player.referenceID) throw IllegalArgumentException("Attemped to remove player.") + // get index of the actor and delete by the index. + // we can do this as the list is guaranteed to be sorted + // and only contains unique values + val indexToDelete = actorContainer.binarySearch(ID) + if (indexToDelete >= 0) actorContainer.removeAt(indexToDelete) } /** * Add actor and sort the list */ - fun addActor(other: Actor): Boolean { - if (hasActor(other.referenceID)) return false - actorContainer.add(other) - actorContainer.sort() + fun addActor(actor: Actor): Boolean { + if (hasActor(actor.referenceID)) throw IllegalArgumentException("Actor with ID ${actor.referenceID} already exists.") + actorContainer.add(actor) + insertionSortLastElem(actorContainer) // we can do this as we only add one actor return true } - fun getActor(ID: Int): Actor { + /** + * Whether the game should display actorContainer elem number when F3 is on + */ + val DEBUG_ARRAY = false + + fun getActorByID(ID: Int): Actor { if (actorContainer.size == 0) throw IllegalArgumentException("Actor with ID $ID does not exist.") val index = actorContainer.binarySearch(ID) @@ -386,7 +412,25 @@ constructor() : BasicGameState() { return actorContainer[index] } + private fun insertionSortLastElem(arr: ArrayList) { + + // 'insertion sort' last element + var x: Actor + var j: Int + var index: Int = arr.size - 1 + x = arr[index] + j = index - 1 + while (j > 0 && arr[j].referenceID > x.referenceID) { + arr[j + 1] = arr[j] + j -= 1 + } + arr[j + 1] = x + } + + private fun ArrayList.binarySearch(actor: Actor) = this.binarySearch(actor.referenceID) + private fun ArrayList.binarySearch(ID: Int): Int { + // code from collections/Collections.kt var low = 0 var high = actorContainer.size - 1 diff --git a/src/net/torvald/terrarum/Terrarum.kt b/src/net/torvald/terrarum/Terrarum.kt index 5cf599252..b4db660b7 100644 --- a/src/net/torvald/terrarum/Terrarum.kt +++ b/src/net/torvald/terrarum/Terrarum.kt @@ -114,9 +114,22 @@ constructor(gamename: String) : StateBasedGame(gamename) { private lateinit var configDir: String + /** + * 0xAA_BB_XXXX + * AA: Major version + * BB: Minor version + * XXXX: Revision + * + * e.g. 0x02010034 can be translated as 2.1.52 + */ + const val VERSION_RAW = 0x00020041 + const val VERSION_STRING: String = + "${VERSION_RAW.ushr(24)}.${VERSION_RAW.and(0xFF0000).ushr(16)}.${VERSION_RAW.and(0xFFFF)}" + const val NAME = "Terrarum" + fun main(args: Array) { try { - appgc = AppGameContainer(Terrarum("Terrarum")) + appgc = AppGameContainer(Terrarum(NAME)) appgc.setDisplayMode(WIDTH, HEIGHT, false) appgc.setTargetFrameRate(TARGET_INTERNAL_FPS) @@ -355,18 +368,6 @@ constructor(gamename: String) : StateBasedGame(gamename) { } } -/** - * 0xAA_BB_XXXX - * AA: Major version - * BB: Minor version - * XXXX: Revision - * - * e.g. 0x02010034 can be translated as 2.1.52 - */ -const val VERSION_RAW = 0x00024000 -const val VERSION_STRING: String = - "${VERSION_RAW.ushr(24)}.${VERSION_RAW.and(0xFF0000).ushr(16)}.${VERSION_RAW.and(0xFFFF)}" - fun main(args: Array) = Terrarum.main(args) fun setBlendMul() { diff --git a/src/net/torvald/terrarum/console/CommandInterpreter.kt b/src/net/torvald/terrarum/console/CommandInterpreter.kt index 8fc0143ba..f05dee44c 100644 --- a/src/net/torvald/terrarum/console/CommandInterpreter.kt +++ b/src/net/torvald/terrarum/console/CommandInterpreter.kt @@ -15,7 +15,7 @@ import java.util.regex.Pattern */ object CommandInterpreter { - private val commandsNoAuth = arrayOf("auth", "qqq", "zoom", "setlocale", "getlocale", "help") + private val commandsNoAuth = arrayOf("auth", "qqq", "zoom", "setlocale", "getlocale", "help", "version") private val ccW = GameFontBase.colToCode["w"] private val ccG = GameFontBase.colToCode["g"] diff --git a/src/net/torvald/terrarum/console/GetAV.kt b/src/net/torvald/terrarum/console/GetAV.kt index feff930b4..1bfd07396 100644 --- a/src/net/torvald/terrarum/console/GetAV.kt +++ b/src/net/torvald/terrarum/console/GetAV.kt @@ -52,7 +52,7 @@ class GetAV : ConsoleCommand { } else { // args[1] is actor ID - val actor = Terrarum.game.getActor(args[1].toInt()) + val actor = Terrarum.game.getActorByID(args[1].toInt()) val av = actor.actorValue val keyset = av.keySet @@ -74,14 +74,14 @@ class GetAV : ConsoleCommand { val id = args[1].toInt() val av = args[2] echo.execute("$ccW$id.$ccM$av $ccW= $ccG" + - Terrarum.game.getActor(id).actorValue[av] + + Terrarum.game.getActorByID(id).actorValue[av] + " $ccO" + - Terrarum.game.getActor(id).actorValue[av]!!.javaClass.simpleName + Terrarum.game.getActorByID(id).actorValue[av]!!.javaClass.simpleName ) println("id.av = " + - Terrarum.game.getActor(id).actorValue[av] + + Terrarum.game.getActorByID(id).actorValue[av] + " " + - Terrarum.game.getActor(id).actorValue[av]!!.javaClass.simpleName + Terrarum.game.getActorByID(id).actorValue[av]!!.javaClass.simpleName ) } } diff --git a/src/net/torvald/terrarum/console/GetFactioning.kt b/src/net/torvald/terrarum/console/GetFactioning.kt index a37965a58..3b3da1108 100644 --- a/src/net/torvald/terrarum/console/GetFactioning.kt +++ b/src/net/torvald/terrarum/console/GetFactioning.kt @@ -24,7 +24,7 @@ class GetFactioning : ConsoleCommand { val echo = Echo() fun printOutFactioning(id: Int) { - val a = Terrarum.game.getActor(id) + val a = Terrarum.game.getActorByID(id) if (a is Factionable) { echo.execute("$ccW== Faction assignment for $ccY${if (id == Player.PLAYER_REF_ID) "player" else id.toString()} $ccW==") println("[GetFactioning] == Faction assignment for '${if (id == Player.PLAYER_REF_ID) "player" else id.toString()}' ==") diff --git a/src/net/torvald/terrarum/console/SetAV.kt b/src/net/torvald/terrarum/console/SetAV.kt index 4ecc7d1a8..cc6a7d76a 100644 --- a/src/net/torvald/terrarum/console/SetAV.kt +++ b/src/net/torvald/terrarum/console/SetAV.kt @@ -77,7 +77,7 @@ internal class SetAV : ConsoleCommand { try { val id = args[1].toInt() val `val` = parseAVInput(args[3]) - val actor = Terrarum.game.getActor(id) + val actor = Terrarum.game.getActorByID(id) // check if av is number if (args[2].isNum()) { diff --git a/src/net/torvald/terrarum/console/Version.kt b/src/net/torvald/terrarum/console/Version.kt index cbdc15bf9..cba04c24d 100644 --- a/src/net/torvald/terrarum/console/Version.kt +++ b/src/net/torvald/terrarum/console/Version.kt @@ -1,13 +1,13 @@ package net.torvald.terrarum.console -import net.torvald.terrarum.VERSION_STRING +import net.torvald.terrarum.Terrarum /** * Created by minjaesong on 16-04-23. */ class Version : ConsoleCommand { override fun execute(args: Array) { - Echo().execute(VERSION_STRING) + Echo().execute("${Terrarum.NAME} ${Terrarum.VERSION_STRING}") } override fun printUsage() { diff --git a/src/net/torvald/terrarum/gameactors/Actor.kt b/src/net/torvald/terrarum/gameactors/Actor.kt index cc5d4136b..0103916dd 100644 --- a/src/net/torvald/terrarum/gameactors/Actor.kt +++ b/src/net/torvald/terrarum/gameactors/Actor.kt @@ -1,5 +1,7 @@ package net.torvald.terrarum.gameactors +import net.torvald.random.HQRNG +import net.torvald.terrarum.Terrarum import org.newdawn.slick.GameContainer /** @@ -19,6 +21,23 @@ abstract class Actor : Comparable { override fun equals(other: Any?) = referenceID == (other as Actor).referenceID override fun hashCode() = referenceID - override fun toString() = "ID: ${hashCode()}" + override fun toString() = if (actorValue.getAsString(AVKey.NAME).isNullOrEmpty()) + "ID: ${hashCode()}" + else + "ID: ${hashCode()} (${actorValue.getAsString(AVKey.NAME)})" override fun compareTo(other: Actor): Int = this.referenceID - other.referenceID + + /** + * Usage: + * + * override var referenceID: Int = generateUniqueReferenceID() + */ + fun generateUniqueReferenceID(): Int { + fun Int.abs() = if (this < 0) -this else this + var ret: Int + do { + ret = HQRNG().nextInt().abs() // set new ID + } while (Terrarum.game.hasActor(ret)) // check for collision + return ret + } } \ No newline at end of file diff --git a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt index da3cb25c0..02c4c3b85 100644 --- a/src/net/torvald/terrarum/gameactors/ActorWithBody.kt +++ b/src/net/torvald/terrarum/gameactors/ActorWithBody.kt @@ -51,7 +51,7 @@ open class ActorWithBody constructor() : Actor(), Visible { internal var baseSpriteWidth: Int = 0 internal var baseSpriteHeight: Int = 0 - override var referenceID: Int = 0 + override var referenceID: Int = generateUniqueReferenceID() /** * Positions: top-left point */ @@ -137,10 +137,6 @@ open class ActorWithBody constructor() : Actor(), Visible { private var posAdjustY = 0 init { - do { - referenceID = HQRNG().nextInt() // set new ID - } while (Terrarum.game.hasActor(referenceID)) // check for collision - map = Terrarum.game.map } @@ -719,19 +715,13 @@ open class ActorWithBody constructor() : Actor(), Visible { fun Float.round() = Math.round(this).toFloat() fun Float.roundToInt(): Int = Math.round(this) fun Float.abs() = FastMath.abs(this) + fun Int.abs() = if (this < 0) -this else this companion object { @Transient private val TSIZE = MapDrawer.TILE_SIZE private var AUTO_CLIMB_RATE = TSIZE / 8 - private fun div16(x: Int): Int { - if (x < 0) { - throw IllegalArgumentException("div16: Positive integer only: " + x.toString()) - } - return x and 0x7FFFFFFF shr 4 - } - private fun div16TruncateToMapWidth(x: Int): Int { if (x < 0) return 0 @@ -750,13 +740,6 @@ open class ActorWithBody constructor() : Actor(), Visible { return y and 0x7FFFFFFF shr 4 } - private fun mod16(x: Int): Int { - if (x < 0) { - throw IllegalArgumentException("mod16: Positive integer only: " + x.toString()) - } - return x and 15 - } - private fun clampCeil(x: Float, ceil: Float): Float { return if (Math.abs(x) > ceil) ceil else x } diff --git a/src/net/torvald/terrarum/itemproperties/ItemPropCodex.kt b/src/net/torvald/terrarum/itemproperties/ItemPropCodex.kt index 06700c816..1c304e621 100644 --- a/src/net/torvald/terrarum/itemproperties/ItemPropCodex.kt +++ b/src/net/torvald/terrarum/itemproperties/ItemPropCodex.kt @@ -33,7 +33,7 @@ object ItemPropCodex { if (code < ITEM_UNIQUE_MAX) return itemCodex[code] else { - val a = Terrarum.game.getActor(code) + val a = Terrarum.game.getActorByID(code) if (a is CanBeAnItem) return a.itemData throw NullPointerException()