mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-09 10:04:05 +09:00
still wip modularisation, game somehow boots
This commit is contained in:
106
src/net/torvald/terrarum/modulebasegame/EntryPoint.kt
Normal file
106
src/net/torvald/terrarum/modulebasegame/EntryPoint.kt
Normal file
@@ -0,0 +1,106 @@
|
||||
package net.torvald.terrarum.modulebasegame
|
||||
|
||||
import net.torvald.point.Point2d
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.ModuleEntryPoint
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
import net.torvald.terrarum.itemproperties.Material
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorWithPhysics
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2018-06-21.
|
||||
*/
|
||||
class EntryPoint : ModuleEntryPoint() {
|
||||
|
||||
override fun invoke() {
|
||||
|
||||
ModMgr.GameBlockLoader.invoke("basegame")
|
||||
ModMgr.GameItemLoader.invoke("basegame")
|
||||
ModMgr.GameLanguageLoader.invoke("basegame")
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
// load customised item loader //
|
||||
/////////////////////////////////
|
||||
|
||||
println("[ItemCodex] recording item ID ")
|
||||
|
||||
// blocks.csvs are loaded by ModMgr beforehand
|
||||
// block items (blocks and walls are the same thing basically)
|
||||
for (i in ItemCodex.ITEM_TILES + ItemCodex.ITEM_WALLS) {
|
||||
ItemCodex.itemCodex[i] = object : GameItem() {
|
||||
override val originalID = i
|
||||
override var dynamicID = i
|
||||
override val isUnique: Boolean = false
|
||||
override var baseMass: Double = BlockCodex[i].density / 1000.0
|
||||
override var baseToolSize: Double? = null
|
||||
override var equipPosition = EquipPosition.HAND_GRIP
|
||||
override val originalName = BlockCodex[i % ItemCodex.ITEM_WALLS.first].nameKey
|
||||
override var stackable = true
|
||||
override var inventoryCategory = if (i in ItemCodex.ITEM_TILES) Category.BLOCK else Category.WALL
|
||||
override var isDynamic = false
|
||||
override val material = Material(0,0,0,0,0,0,0,0,0,0.0)
|
||||
|
||||
init {
|
||||
print("$originalID ")
|
||||
}
|
||||
|
||||
override fun primaryUse(delta: Float): Boolean {
|
||||
return false
|
||||
// TODO base punch attack
|
||||
}
|
||||
|
||||
override fun secondaryUse(delta: Float): Boolean {
|
||||
val ingame = Terrarum.ingame!! as Ingame
|
||||
|
||||
val mousePoint = Point2d(Terrarum.mouseTileX.toDouble(), Terrarum.mouseTileY.toDouble())
|
||||
|
||||
// check for collision with actors (BLOCK only)
|
||||
if (this.inventoryCategory == Category.BLOCK) {
|
||||
ingame.actorContainer.forEach {
|
||||
if (it is ActorWithPhysics && it.hIntTilewiseHitbox.intersects(mousePoint))
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// return false if the tile is already there
|
||||
if (this.inventoryCategory == Category.BLOCK &&
|
||||
this.dynamicID == ingame.world.getTileFromTerrain(Terrarum.mouseTileX, Terrarum.mouseTileY) ||
|
||||
this.inventoryCategory == Category.WALL &&
|
||||
this.dynamicID - ItemCodex.ITEM_WALLS.start == ingame.world.getTileFromWall(Terrarum.mouseTileX, Terrarum.mouseTileY) ||
|
||||
this.inventoryCategory == Category.WIRE &&
|
||||
this.dynamicID - ItemCodex.ITEM_WIRES.start == ingame.world.getTileFromWire(Terrarum.mouseTileX, Terrarum.mouseTileY)
|
||||
)
|
||||
return false
|
||||
|
||||
// filter passed, do the job
|
||||
// FIXME this is only useful for Player
|
||||
if (i in ItemCodex.ITEM_TILES) {
|
||||
ingame.world.setTileTerrain(
|
||||
Terrarum.mouseTileX,
|
||||
Terrarum.mouseTileY,
|
||||
i
|
||||
)
|
||||
}
|
||||
else {
|
||||
ingame.world.setTileWall(
|
||||
Terrarum.mouseTileX,
|
||||
Terrarum.mouseTileY,
|
||||
i
|
||||
)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
println("Welcome back!")
|
||||
}
|
||||
|
||||
}
|
||||
1504
src/net/torvald/terrarum/modulebasegame/Ingame.kt
Normal file
1504
src/net/torvald/terrarum/modulebasegame/Ingame.kt
Normal file
File diff suppressed because it is too large
Load Diff
50
src/net/torvald/terrarum/modulebasegame/console/AVTracker.kt
Normal file
50
src/net/torvald/terrarum/modulebasegame/console/AVTracker.kt
Normal file
@@ -0,0 +1,50 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.console.EchoError
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.debuggerapp.ActorValueTracker
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-12-29.
|
||||
*/
|
||||
internal object AVTracker : ConsoleCommand {
|
||||
private val jPanelInstances = ArrayList<ActorValueTracker>()
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size < 2) {
|
||||
jPanelInstances.add(ActorValueTracker((Terrarum.ingame!! as Ingame).player))
|
||||
}
|
||||
else {
|
||||
try {
|
||||
val actorID = args[1].toInt()
|
||||
|
||||
if (Terrarum.ingame!!.theGameHasActor(actorID)) {
|
||||
jPanelInstances.add(ActorValueTracker(Terrarum.ingame!!.getActorByID(actorID)))
|
||||
}
|
||||
else {
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
EchoError("Illegal actor ID input")
|
||||
return
|
||||
}
|
||||
catch (e1: IllegalArgumentException) {
|
||||
EchoError("No such actor with specified ID")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Pops up new window that provides real-time information about the actor's actor value")
|
||||
}
|
||||
|
||||
fun update() {
|
||||
jPanelInstances.forEach { it.update() }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.debuggerapp.ActorsLister
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-12-29.
|
||||
*/
|
||||
internal object ActorsList : ConsoleCommand {
|
||||
private val jPanelInstances = ArrayList<ActorsLister>()
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
jPanelInstances.add(ActorsLister(
|
||||
(Terrarum.ingame!! as Ingame).actorContainer,
|
||||
(Terrarum.ingame!! as Ingame).actorContainerInactive)
|
||||
)
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Pops up new window that displays the list of actors currently in the game")
|
||||
}
|
||||
|
||||
fun update() {
|
||||
jPanelInstances.forEach { it.update() }
|
||||
}
|
||||
}
|
||||
32
src/net/torvald/terrarum/modulebasegame/console/CatStdout.kt
Normal file
32
src/net/torvald/terrarum/modulebasegame/console/CatStdout.kt
Normal file
@@ -0,0 +1,32 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import java.io.IOException
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Files
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-02-10.
|
||||
*/
|
||||
internal object CatStdout : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
|
||||
if (args.size == 1) {
|
||||
printUsage()
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
Files.lines(FileSystems.getDefault().getPath(args[1])).forEach({ Echo(it) })
|
||||
}
|
||||
catch (e: IOException) {
|
||||
Echo("CatStdout: could not read file -- IOException")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("usage: cat 'path/to/text/file")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
object CheatWarnTest : ConsoleCommand {
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
(Terrarum.ingame as? Ingame)?.uiCheatMotherfuckerNootNoot?.setAsOpen()
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.ccO
|
||||
import net.torvald.terrarum.console.CommandDict
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
|
||||
import java.util.Formatter
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-16.
|
||||
*/
|
||||
internal object CodexEdictis : ConsoleCommand {
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 1) {
|
||||
printList()
|
||||
}
|
||||
else {
|
||||
try {
|
||||
val commandObj = CommandDict[args[1].toLowerCase()]
|
||||
commandObj.printUsage()
|
||||
}
|
||||
catch (e: NullPointerException) {
|
||||
val sb = StringBuilder()
|
||||
val formatter = Formatter(sb)
|
||||
|
||||
Echo("Codex: " + formatter.format(Lang["DEV_MESSAGE_CONSOLE_COMMAND_UNKNOWN"], args[1]).toString())
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: codex (command)")
|
||||
Echo("shows how to use 'command'")
|
||||
Echo("leave blank to get list of available commands")
|
||||
}
|
||||
|
||||
private fun printList() {
|
||||
Echo(Lang["DEV_MESSAGE_CONSOLE_AVAILABLE_COMMANDS"])
|
||||
CommandDict.dict.forEach { name, cmd ->
|
||||
Echo("$ccO• " + name)
|
||||
cmd.printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
40
src/net/torvald/terrarum/modulebasegame/console/ExportAV.kt
Normal file
40
src/net/torvald/terrarum/modulebasegame/console/ExportAV.kt
Normal file
@@ -0,0 +1,40 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.utils.JsonWriter
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-02-10.
|
||||
*/
|
||||
internal object ExportAV : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 2) {
|
||||
try {
|
||||
JsonWriter.writeToFile(
|
||||
(Terrarum.ingame!! as Ingame).player.actorValue,
|
||||
Terrarum.defaultDir + "/Exports/" + args[1] + ".json")
|
||||
|
||||
Echo("ExportAV: exported to " + args[1] + ".json")
|
||||
}
|
||||
catch (e: IOException) {
|
||||
Echo("ExportAV: IOException raised.")
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Export ActorValue as JSON format.")
|
||||
Echo("Usage: exportav (id) filename-without-extension")
|
||||
Echo("blank ID for player")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.serialise.WriteLayerData
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-07-18.
|
||||
*/
|
||||
object ExportLayerData : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size < 2) {
|
||||
printUsage()
|
||||
return
|
||||
}
|
||||
|
||||
val saveDirectoryName = args[1]
|
||||
|
||||
WriteLayerData(saveDirectoryName)
|
||||
|
||||
Echo("Layer data exported to $saveDirectoryName/${WriteLayerData.META_FILENAME}")
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: exportlayer savename")
|
||||
}
|
||||
}
|
||||
119
src/net/torvald/terrarum/modulebasegame/console/ExportMap.kt
Normal file
119
src/net/torvald/terrarum/modulebasegame/console/ExportMap.kt
Normal file
@@ -0,0 +1,119 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.colourutil.Col4096
|
||||
import net.torvald.terrarum.utils.RasterWriter
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.console.EchoError
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
import java.io.*
|
||||
import java.util.HashMap
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-17.
|
||||
*/
|
||||
internal object ExportMap : ConsoleCommand {
|
||||
|
||||
//private var mapData: ByteArray? = null
|
||||
// private var mapDataPointer = 0
|
||||
|
||||
private val colorTable = HashMap<Int, Col4096>()
|
||||
|
||||
init {
|
||||
colorTable.put(Block.AIR, Col4096(0xCEF))
|
||||
colorTable.put(Block.STONE, Col4096(0x888))
|
||||
colorTable.put(Block.DIRT, Col4096(0x753))
|
||||
colorTable.put(Block.GRASS, Col4096(0x472))
|
||||
|
||||
colorTable.put(Block.ORE_COPPER, Col4096(0x6A8))
|
||||
colorTable.put(Block.ORE_IRON, Col4096(0xC75))
|
||||
colorTable.put(Block.ORE_GOLD, Col4096(0xA87))
|
||||
colorTable.put(Block.ORE_ILMENITE, Col4096(0x8AB))
|
||||
colorTable.put(Block.ORE_AURICHALCUM, Col4096(0xD92))
|
||||
colorTable.put(Block.ORE_SILVER, Col4096(0xDDD))
|
||||
|
||||
colorTable.put(Block.RAW_DIAMOND, Col4096(0x2BF))
|
||||
colorTable.put(Block.RAW_RUBY, Col4096(0xB10))
|
||||
colorTable.put(Block.RAW_EMERALD, Col4096(0x0B1))
|
||||
colorTable.put(Block.RAW_SAPPHIRE, Col4096(0x01B))
|
||||
colorTable.put(Block.RAW_TOPAZ, Col4096(0xC70))
|
||||
colorTable.put(Block.RAW_AMETHYST, Col4096(0x70C))
|
||||
|
||||
colorTable.put(Block.WATER, Col4096(0x038))
|
||||
colorTable.put(Block.LAVA, Col4096(0xF50))
|
||||
|
||||
colorTable.put(Block.SAND, Col4096(0xDDB))
|
||||
colorTable.put(Block.SAND_WHITE, Col4096(0xFFD))
|
||||
colorTable.put(Block.SAND_RED, Col4096(0xA32))
|
||||
colorTable.put(Block.SAND_DESERT, Col4096(0xEDB))
|
||||
colorTable.put(Block.SAND_BLACK, Col4096(0x444))
|
||||
colorTable.put(Block.SAND_GREEN, Col4096(0x9A6))
|
||||
|
||||
colorTable.put(Block.GRAVEL, Col4096(0x664))
|
||||
colorTable.put(Block.GRAVEL_GREY, Col4096(0x999))
|
||||
|
||||
colorTable.put(Block.ICE_NATURAL, Col4096(0x9AB))
|
||||
colorTable.put(Block.ICE_MAGICAL, Col4096(0x7AC))
|
||||
colorTable.put(Block.ICE_FRAGILE, Col4096(0x6AF))
|
||||
colorTable.put(Block.SNOW, Col4096(0xCDE))
|
||||
}
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
val world = (Terrarum.ingame!! as Ingame).world
|
||||
|
||||
if (args.size == 2) {
|
||||
|
||||
var mapData = ByteArray(world.width * world.height * 3)
|
||||
var mapDataPointer = 0
|
||||
|
||||
for (tile in world.terrainIterator()) {
|
||||
val colArray = (colorTable as Map<Int, Col4096>)
|
||||
.getOrElse(tile, { Col4096(0xFFF) }).toByteArray()
|
||||
|
||||
for (i in 0..2) {
|
||||
mapData[mapDataPointer + i] = colArray[i]
|
||||
}
|
||||
|
||||
mapDataPointer += 3
|
||||
}
|
||||
|
||||
val dir = Terrarum.defaultDir + "/Exports/"
|
||||
val dirAsFile = File(dir)
|
||||
if (!dirAsFile.exists()) {
|
||||
dirAsFile.mkdir()
|
||||
}
|
||||
|
||||
try {
|
||||
RasterWriter.writePNG_RGB(
|
||||
world.width, world.height, mapData, dir + args[1] + ".png")
|
||||
Echo("ExportMap: exported to " + args[1] + ".png")
|
||||
|
||||
}
|
||||
catch (e: IOException) {
|
||||
EchoError("ExportMap: IOException raised.")
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
// mapData = null
|
||||
// mapDataPointer = 0
|
||||
|
||||
// Free up some memory
|
||||
System.gc()
|
||||
}
|
||||
else {
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
|
||||
Echo("Usage: export <name>")
|
||||
Echo("Exports current map into echo image.")
|
||||
Echo("The image can be found at %appdata%/terrarum/Exports")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
18
src/net/torvald/terrarum/modulebasegame/console/ForceGC.kt
Normal file
18
src/net/torvald/terrarum/modulebasegame/console/ForceGC.kt
Normal file
@@ -0,0 +1,18 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-18.
|
||||
*/
|
||||
internal object ForceGC : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
System.gc()
|
||||
Echo("Invoked System.gc")
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Invoke garbage collection of JVM.")
|
||||
}
|
||||
}
|
||||
120
src/net/torvald/terrarum/modulebasegame/console/GetAV.kt
Normal file
120
src/net/torvald/terrarum/modulebasegame/console/GetAV.kt
Normal file
@@ -0,0 +1,120 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.console.EchoError
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-19.
|
||||
*/
|
||||
internal object GetAV : ConsoleCommand {
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
try {
|
||||
val ingame = Terrarum.ingame!! as Ingame
|
||||
|
||||
|
||||
if (args.size == 1 && ingame.player != null) {
|
||||
// print all actorvalue of player
|
||||
val av = ingame.player.actorValue
|
||||
val keyset = av.keySet
|
||||
|
||||
Echo("$ccW== ActorValue list for ${ccY}player $ccW==")
|
||||
println("[GetAV] == ActorValue list for 'player' ==")
|
||||
keyset.forEach { elem ->
|
||||
Echo("$ccM$elem $ccW= $ccG${av[elem as String]}")
|
||||
println("[GetAV] $elem = ${av[elem]}")
|
||||
}
|
||||
}
|
||||
else if (args.size != 3 && args.size != 2) {
|
||||
printUsage()
|
||||
}
|
||||
else if (args.size == 2) {
|
||||
// check if args[1] is number or not
|
||||
if (!args[1].isNum()) { // args[1] is ActorValue name
|
||||
Echo("${ccW}player.$ccM${args[1]} $ccW= " +
|
||||
ccG +
|
||||
ingame.player.actorValue[args[1]] +
|
||||
" $ccO" +
|
||||
ingame.player.actorValue[args[1]]!!.javaClass.simpleName
|
||||
)
|
||||
println("[GetAV] player.${args[1]} = " +
|
||||
ingame.player.actorValue[args[1]] +
|
||||
" " +
|
||||
ingame.player.actorValue[args[1]]!!.javaClass.simpleName
|
||||
)
|
||||
}
|
||||
else {
|
||||
// args[1] is actor ID
|
||||
val actor = ingame.getActorByID(args[1].toInt())
|
||||
val av = actor.actorValue
|
||||
val keyset = av.keySet
|
||||
|
||||
Echo("$ccW== ActorValue list for $ccY$actor $ccW==")
|
||||
println("[GetAV] == ActorValue list for '$actor' ==")
|
||||
if (keyset.isEmpty()) {
|
||||
Echo("$ccK(nothing)")
|
||||
println("[GetAV] (nothing)")
|
||||
}
|
||||
else {
|
||||
keyset.forEach { elem ->
|
||||
Echo("$ccM$elem $ccW= $ccG${av[elem as String]}")
|
||||
println("[GetAV] $elem = ${av[elem]}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (args.size == 3) {
|
||||
val id = args[1].toInt()
|
||||
val av = args[2]
|
||||
Echo("$ccW$id.$ccM$av $ccW= $ccG" +
|
||||
ingame.getActorByID(id).actorValue[av] +
|
||||
" $ccO" +
|
||||
ingame.getActorByID(id).actorValue[av]!!.javaClass.simpleName
|
||||
)
|
||||
println("$id.$av = " +
|
||||
ingame.getActorByID(id).actorValue[av] +
|
||||
" " +
|
||||
ingame.getActorByID(id).actorValue[av]!!.javaClass.simpleName
|
||||
)
|
||||
}
|
||||
}
|
||||
catch (e: NullPointerException) {
|
||||
if (args.size == 2) {
|
||||
EchoError(args[1] + ": actor value does not exist.")
|
||||
System.err.println("[GetAV] ${args[1]}: actor value does not exist.")
|
||||
}
|
||||
else if (args.size == 3) {
|
||||
EchoError(args[2] + ": actor value does not exist.")
|
||||
System.err.println("[GetAV] ${args[2]}: actor value does not exist.")
|
||||
}
|
||||
else {
|
||||
throw NullPointerException()
|
||||
}
|
||||
}
|
||||
catch (e1: IllegalArgumentException) {
|
||||
EchoError("${args[1]}: no actor with this ID.")
|
||||
System.err.println("[GetAV] ${args[1]}: no actor with this ID.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun String.isNum(): Boolean {
|
||||
try {
|
||||
this.toInt()
|
||||
return true
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("${ccW}Get desired ActorValue of specific target.")
|
||||
Echo("${ccW}Usage: ${ccY}getav $ccG(id) <av>")
|
||||
Echo("${ccW}blank ID for player")
|
||||
}
|
||||
}
|
||||
120
src/net/torvald/terrarum/modulebasegame/console/GetFactioning.kt
Normal file
120
src/net/torvald/terrarum/modulebasegame/console/GetFactioning.kt
Normal file
@@ -0,0 +1,120 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.console.EchoError
|
||||
import net.torvald.terrarum.gameactors.Factionable
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.Player
|
||||
import net.torvald.terrarumsansbitmap.gdx.GameFontBase
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-02-17.
|
||||
*/
|
||||
internal object GetFactioning : ConsoleCommand {
|
||||
val ccW = GameFontBase.toColorCode(0xFFFF)
|
||||
val ccY = GameFontBase.toColorCode(0xFE8F)
|
||||
val ccM = GameFontBase.toColorCode(0xEAFF)
|
||||
val ccG = GameFontBase.toColorCode(0x8F8F)
|
||||
val ccK = GameFontBase.toColorCode(0x888F)
|
||||
|
||||
private val PRINT_INDENTATION = "$ccK --> $ccW"
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
|
||||
val error = Error()
|
||||
|
||||
fun printOutFactioning(id: Int) {
|
||||
val a = Terrarum.ingame!!.getActorByID(id)
|
||||
if (a is Factionable) {
|
||||
Echo("$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()}' ==")
|
||||
|
||||
// get all factioning data of player
|
||||
val factionSet = a.faction
|
||||
|
||||
if (factionSet.isEmpty()) {
|
||||
Echo("The actor has empty faction set.")
|
||||
println("[GetFactioning] The actor has empty faction set.")
|
||||
return
|
||||
}
|
||||
|
||||
val count = factionSet.size
|
||||
Echo("$ccG${count.toString()} $ccW${Lang.pluralise(" faction", count)} assigned.")
|
||||
println("[GetFactioning] ${count.toString()} ${Lang.pluralise(" faction", count)} assigned.")
|
||||
|
||||
for (faction in factionSet) {
|
||||
Echo("${ccW}faction $ccM${faction.factionName}")
|
||||
println("[GetFactioning] faction '${faction.factionName}'")
|
||||
Echo("$ccY Amicable")
|
||||
println("[GetFactioning] Amicable")
|
||||
faction.factionAmicable.forEach { s ->
|
||||
Echo(PRINT_INDENTATION + s)
|
||||
println("[GetFactioning] --> $s")
|
||||
}
|
||||
|
||||
Echo("$ccY Explicit neutral")
|
||||
println("[GetFactioning] Explicit neutral")
|
||||
faction.factionNeutral.forEach { s ->
|
||||
Echo(PRINT_INDENTATION + s)
|
||||
println("[GetFactioning] --> $s")
|
||||
}
|
||||
|
||||
Echo("$ccY Hostile")
|
||||
println("[GetFactioning] Hostile")
|
||||
faction.factionHostile.forEach { s ->
|
||||
Echo(PRINT_INDENTATION + s)
|
||||
println("[GetFactioning] --> $s")
|
||||
}
|
||||
|
||||
Echo("$ccY Fearful")
|
||||
println("[GetFactioning] Fearful")
|
||||
faction.factionFearful.forEach { s ->
|
||||
Echo(PRINT_INDENTATION + s)
|
||||
println("[GetFactioning] --> $s")
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
EchoError("The actor is not factionable.")
|
||||
System.err.println("[GetFactioning] The actor is not factionable.")
|
||||
}
|
||||
}
|
||||
|
||||
if (args.size == 1) {
|
||||
printOutFactioning(Player.PLAYER_REF_ID)
|
||||
}
|
||||
else {
|
||||
if (!args[1].isNum()) {
|
||||
EchoError("Invalid actor ID input.")
|
||||
System.err.println("[GetFactioning] Invalid actor ID input.")
|
||||
return
|
||||
}
|
||||
try {
|
||||
val actorID = args[1].toInt()
|
||||
printOutFactioning(actorID)
|
||||
}
|
||||
catch (e: IllegalArgumentException) {
|
||||
EchoError("${args[1]}: no actor with this ID.")
|
||||
System.err.println("[GetFactioning] ${args[1]}: no actor with this ID.")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun String.isNum(): Boolean {
|
||||
try {
|
||||
this.toInt()
|
||||
return true
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
|
||||
}
|
||||
}
|
||||
25
src/net/torvald/terrarum/modulebasegame/console/GetLocale.kt
Normal file
25
src/net/torvald/terrarum/modulebasegame/console/GetLocale.kt
Normal file
@@ -0,0 +1,25 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-22.
|
||||
*/
|
||||
internal object GetLocale : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
Echo(
|
||||
"Locale: "
|
||||
+ Lang["MENU_LANGUAGE_THIS"]
|
||||
+ " ("
|
||||
+ Lang["MENU_LANGUAGE_THIS_EN"]
|
||||
+ ")")
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
|
||||
Echo("Usage: getlocale")
|
||||
Echo("Get name of locale currently using.")
|
||||
}
|
||||
}
|
||||
21
src/net/torvald/terrarum/modulebasegame/console/GetTime.kt
Normal file
21
src/net/torvald/terrarum/modulebasegame/console/GetTime.kt
Normal file
@@ -0,0 +1,21 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-03-20.
|
||||
*/
|
||||
internal object GetTime : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
|
||||
val worldTime = (Terrarum.ingame!! as Ingame).world.time
|
||||
Echo(worldTime.getFormattedTime())
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Print current world time in convenient form")
|
||||
}
|
||||
}
|
||||
49
src/net/torvald/terrarum/modulebasegame/console/GsonTest.kt
Normal file
49
src/net/torvald/terrarum/modulebasegame/console/GsonTest.kt
Normal file
@@ -0,0 +1,49 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import com.google.gson.Gson
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
import java.io.BufferedWriter
|
||||
import java.io.FileWriter
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-02-10.
|
||||
*/
|
||||
internal object GsonTest : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 2) {
|
||||
val avelem = Gson().toJsonTree((Terrarum.ingame!! as Ingame).player)
|
||||
|
||||
val jsonString = avelem.toString()
|
||||
|
||||
val bufferedWriter: BufferedWriter
|
||||
val writer: FileWriter
|
||||
try {
|
||||
writer = FileWriter(Terrarum.defaultDir + "/Exports/" + args[1] + ".json")
|
||||
bufferedWriter = BufferedWriter(writer)
|
||||
|
||||
bufferedWriter.write(jsonString)
|
||||
bufferedWriter.close()
|
||||
|
||||
Echo("GsonTest: exported to " + args[1] + ".json")
|
||||
}
|
||||
catch (e: IOException) {
|
||||
Echo("GsonTest: IOException raised.")
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
|
||||
Echo("Usage: gsontest filename-without-extension")
|
||||
}
|
||||
}
|
||||
27
src/net/torvald/terrarum/modulebasegame/console/Help.kt
Normal file
27
src/net/torvald/terrarum/modulebasegame/console/Help.kt
Normal file
@@ -0,0 +1,27 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-03-22.
|
||||
*/
|
||||
internal object Help : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
|
||||
if (args.size == 1) {
|
||||
for (i in 1..6) Echo(Lang["HELP_OTF_MAIN_$i"])
|
||||
}
|
||||
else if (args[1].toLowerCase() == "slow") {
|
||||
for (i in 1..4) Echo(Lang["HELP_OTF_SLOW_$i"])
|
||||
}
|
||||
else {
|
||||
for (i in 1..6) Echo(Lang["HELP_OTF_MAIN_$i"])
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Prints some utility functions assigned to function row of the keyboard.")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.serialise.ReadLayerData
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import java.io.FileInputStream
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-07-18.
|
||||
*/
|
||||
object ImportLayerData : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size < 2) {
|
||||
ExportLayerData.printUsage()
|
||||
return
|
||||
}
|
||||
|
||||
//val fis = GZIPInputStream(FileInputStream(args[1])) // this gzip is kaput
|
||||
val fis = FileInputStream(args[1])
|
||||
(Terrarum.ingame!! as Ingame).world = ReadLayerData(fis)
|
||||
(Terrarum.ingame!! as Ingame).player.setPosition(
|
||||
(Terrarum.ingame!! as Ingame).world.spawnY * FeaturesDrawer.TILE_SIZE.toDouble(),
|
||||
(Terrarum.ingame!! as Ingame).world.spawnX * FeaturesDrawer.TILE_SIZE.toDouble()
|
||||
)
|
||||
fis.close()
|
||||
Echo("Successfully loaded ${args[1]}")
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: importlayer path/to/layer.data")
|
||||
}
|
||||
}
|
||||
79
src/net/torvald/terrarum/modulebasegame/console/Inventory.kt
Normal file
79
src/net/torvald/terrarum/modulebasegame/console/Inventory.kt
Normal file
@@ -0,0 +1,79 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.console.EchoError
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.Player
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-12-12.
|
||||
*/
|
||||
internal object Inventory : ConsoleCommand {
|
||||
|
||||
private var target: Pocketed? = (Terrarum.ingame!! as Ingame).player
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 1) {
|
||||
printUsage()
|
||||
}
|
||||
else {
|
||||
when (args[1]) {
|
||||
"list" -> listInventory()
|
||||
"add" -> if (args.size > 3) addItem(args[2].toInt(), args[3].toInt())
|
||||
else addItem(args[2].toInt())
|
||||
"target" -> setTarget(args[2].toInt())
|
||||
"equip" -> equipItem(args[2].toInt())
|
||||
else -> printUsage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun listInventory() {
|
||||
if (target != null) {
|
||||
if (target!!.inventory.getTotalUniqueCount() == 0) {
|
||||
Echo("(inventory empty)")
|
||||
}
|
||||
else {
|
||||
target!!.inventory.forEach { val (item, amount) = it
|
||||
if (amount == 0) {
|
||||
EchoError("Unexpected zero-amounted item: ID ${item.dynamicID}")
|
||||
}
|
||||
Echo("ID $item${if (amount > 1) " ($amount)" else ""}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setTarget(actorRefId: Int = Player.PLAYER_REF_ID) {
|
||||
val actor = Terrarum.ingame!!.getActorByID(actorRefId)
|
||||
if (actor !is Pocketed) {
|
||||
EchoError("Cannot edit inventory of incompatible actor: $actor")
|
||||
}
|
||||
else {
|
||||
target = actor
|
||||
}
|
||||
}
|
||||
|
||||
private fun addItem(refId: Int, amount: Int = 1) {
|
||||
if (target != null) {
|
||||
target!!.addItem(ItemCodex[refId], amount)
|
||||
}
|
||||
}
|
||||
|
||||
private fun equipItem(refId: Int) {
|
||||
if (target != null) {
|
||||
val item = ItemCodex[refId]
|
||||
target!!.equipItem(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: inventory command arguments")
|
||||
Echo("Available commands:")
|
||||
Echo("list | assign slot | add itemid [amount] | target [actorid] | equip itemid")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.swingapp.IMStringReader
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-02-05.
|
||||
*/
|
||||
|
||||
internal object JavaIMTest : ConsoleCommand {
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
IMStringReader(
|
||||
{ Echo("[JavaIMTest -> IMStringReader] $it") }, // send input to Echo
|
||||
"JavaIMTest"
|
||||
)
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Tests Swing input window to get non-English text input")
|
||||
}
|
||||
}
|
||||
34
src/net/torvald/terrarum/modulebasegame/console/KillActor.kt
Normal file
34
src/net/torvald/terrarum/modulebasegame/console/KillActor.kt
Normal file
@@ -0,0 +1,34 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.console.EchoError
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-01-31.
|
||||
*/
|
||||
internal object KillActor : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 2) {
|
||||
try {
|
||||
val actorid = args[1].toInt()
|
||||
Terrarum.ingame!!.removeActor(actorid)
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
EchoError("Wrong number input.")
|
||||
}
|
||||
catch (e1: RuntimeException) {
|
||||
EchoError(e1.message ?: Lang["ERROR_GENERIC_TEXT"])
|
||||
}
|
||||
}
|
||||
else {
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: kill actorid")
|
||||
}
|
||||
}
|
||||
21
src/net/torvald/terrarum/modulebasegame/console/LangTest.kt
Normal file
21
src/net/torvald/terrarum/modulebasegame/console/LangTest.kt
Normal file
@@ -0,0 +1,21 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-07-11.
|
||||
*/
|
||||
internal object LangTest : ConsoleCommand {
|
||||
override fun printUsage() {
|
||||
Echo("Prints out string in the current lang pack by STRING_ID provided")
|
||||
}
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size < 2)
|
||||
printUsage()
|
||||
else
|
||||
Echo(Lang[args[1].toUpperCase()])
|
||||
}
|
||||
}
|
||||
20
src/net/torvald/terrarum/modulebasegame/console/MoneyDisp.kt
Normal file
20
src/net/torvald/terrarum/modulebasegame/console/MoneyDisp.kt
Normal file
@@ -0,0 +1,20 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
|
||||
object MoneyDisp : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 2) {
|
||||
Echo("¤${0x3000.toChar()}${args[1]}")
|
||||
}
|
||||
else {
|
||||
Echo("¤${0x3000.toChar()}${HQRNG().nextInt(100000)}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: money [amount] — Prints given or random amount of money")
|
||||
}
|
||||
}
|
||||
46
src/net/torvald/terrarum/modulebasegame/console/MusicTest.kt
Normal file
46
src/net/torvald/terrarum/modulebasegame/console/MusicTest.kt
Normal file
@@ -0,0 +1,46 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.audio.Music
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-08-02.
|
||||
*/
|
||||
internal object MusicTest : ConsoleCommand {
|
||||
|
||||
var music: Music? = null
|
||||
|
||||
/**
|
||||
* Args 0: command given
|
||||
* Args 1: first argument
|
||||
*
|
||||
* e.g. in ```setav mass 74```, zeroth args will be ```setav```.
|
||||
*/
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size < 2) {
|
||||
printUsage()
|
||||
return
|
||||
}
|
||||
|
||||
if (args[1] == "stop") {
|
||||
music!!.stop()
|
||||
return
|
||||
}
|
||||
|
||||
val type = args[1].substringAfter('.').toUpperCase()
|
||||
/*AudioLoader.getStreamingAudio(
|
||||
type,
|
||||
File("./assets/sounds/test/${args[1]}").absoluteFile.toURI().toURL()
|
||||
).playAsMusic(1f, 1f, false)*/
|
||||
|
||||
music = Gdx.audio.newMusic(Gdx.files.internal("./assets/sounds/test/${args[1]}"))
|
||||
music!!.play()
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: musictest filename/in/res/sounds/test")
|
||||
Echo("musictest stop to stop playback")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-07-04.
|
||||
*/
|
||||
internal object PrintRandomTips : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
Echo("Nope.")
|
||||
//Echo(Lang["GAME_TIPS_${Random().nextInt(Lang.TIPS_COUNT) + 1}"])
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Prints random tips for game.")
|
||||
}
|
||||
}
|
||||
23
src/net/torvald/terrarum/modulebasegame/console/Seed.kt
Normal file
23
src/net/torvald/terrarum/modulebasegame/console/Seed.kt
Normal file
@@ -0,0 +1,23 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-06-16.
|
||||
*/
|
||||
internal object Seed : ConsoleCommand {
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
Echo("Map$ccW: $ccG${(Terrarum.ingame!! as Ingame).world.generatorSeed}")
|
||||
println("[seed] Map$ccW: $ccG${(Terrarum.ingame!! as Ingame).world.generatorSeed}")
|
||||
// TODO display randomiser seed
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("prints out the generator seed of the current game.")
|
||||
}
|
||||
}
|
||||
106
src/net/torvald/terrarum/modulebasegame/console/SetAV.kt
Normal file
106
src/net/torvald/terrarum/modulebasegame/console/SetAV.kt
Normal file
@@ -0,0 +1,106 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.console.EchoError
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-15.
|
||||
*/
|
||||
internal object SetAV : ConsoleCommand {
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("${ccW}Set actor value of specific target to desired value.")
|
||||
Echo("${ccW}Usage: ${ccY}setav ${ccG}(id) <av> <val>")
|
||||
Echo("${ccW}blank ID for player. Data type will be inferred automatically.")
|
||||
Echo("${ccR}Contaminated (e.g. double -> string) ActorValue will crash the game,")
|
||||
Echo("${ccR}so make sure it will not happen before you issue the command!")
|
||||
Echo("${ccW}Use ${ccG}__true ${ccW}and ${ccG}__false ${ccW}for boolean value.")
|
||||
}
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
fun parseAVInput(arg: String): Any {
|
||||
var inputval: Any
|
||||
|
||||
try {
|
||||
inputval = Integer(arg) // try for integer
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
|
||||
try {
|
||||
inputval = arg.toDouble() // try for double
|
||||
}
|
||||
catch (ee: NumberFormatException) {
|
||||
if (arg.equals("__true", ignoreCase = true)) {
|
||||
inputval = true
|
||||
}
|
||||
else if (arg.equals("__false", ignoreCase = true)) {
|
||||
inputval = false
|
||||
}
|
||||
else {
|
||||
inputval = arg // string if not number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inputval
|
||||
}
|
||||
|
||||
// setav <id, or blank for player> <av> <val>
|
||||
if (args.size != 4 && args.size != 3) {
|
||||
printUsage()
|
||||
}
|
||||
else if (args.size == 3) {
|
||||
val newValue = parseAVInput(args[2])
|
||||
|
||||
// check if av is number
|
||||
if (args[1].isNum()) {
|
||||
EchoError("Illegal ActorValue ${args[1]}: ActorValue cannot be a number.")
|
||||
System.err.println("[SetAV] Illegal ActorValue ${args[1]}: ActorValue cannot be a number.")
|
||||
return
|
||||
}
|
||||
|
||||
(Terrarum.ingame!! as Ingame).player.actorValue[args[1]] = newValue
|
||||
Echo("${ccW}Set $ccM${args[1]} ${ccW}for ${ccY}player ${ccW}to $ccG$newValue")
|
||||
println("[SetAV] set ActorValue '${args[1]}' for player to '$newValue'.")
|
||||
}
|
||||
else if (args.size == 4) {
|
||||
try {
|
||||
val id = args[1].toInt()
|
||||
val newValue = parseAVInput(args[3])
|
||||
val actor = Terrarum.ingame!!.getActorByID(id)
|
||||
|
||||
// check if av is number
|
||||
if (args[2].isNum()) {
|
||||
EchoError("Illegal ActorValue ${args[2]}: ActorValue cannot be a number.")
|
||||
System.err.println("[SetAV] Illegal ActorValue ${args[2]}: ActorValue cannot be a number.")
|
||||
return
|
||||
}
|
||||
|
||||
actor.actorValue[args[2]] = newValue
|
||||
Echo("${ccW}Set $ccM${args[2]} ${ccW}for $ccY$id ${ccW}to $ccG$newValue")
|
||||
println("[SetAV] set ActorValue '${args[2]}' for $actor to '$newValue'.")
|
||||
}
|
||||
catch (e: IllegalArgumentException) {
|
||||
if (args.size == 4) {
|
||||
EchoError("${args[1]}: no actor with this ID.")
|
||||
System.err.println("[SetAV] ${args[1]}: no actor with this ID.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun String.isNum(): Boolean {
|
||||
try {
|
||||
this.toInt()
|
||||
return true
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-23.
|
||||
*/
|
||||
internal object SetBulletin : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
val testMsg = arrayOf(
|
||||
Lang["ERROR_SAVE_CORRUPTED"],
|
||||
Lang["MENU_LABEL_CONTINUE_QUESTION"]
|
||||
)
|
||||
send(testMsg)
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually send notifinator
|
||||
* @param message real message
|
||||
*/
|
||||
fun send(message: Array<String>) {
|
||||
(Terrarum.ingame!! as Ingame).sendNotification(message)
|
||||
println("sent notifinator")
|
||||
}
|
||||
}
|
||||
39
src/net/torvald/terrarum/modulebasegame/console/SetScale.kt
Normal file
39
src/net/torvald/terrarum/modulebasegame/console/SetScale.kt
Normal file
@@ -0,0 +1,39 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.console.EchoError
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorWithPhysics
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-01-20.
|
||||
*/
|
||||
internal object SetScale : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 2 || args.size == 3) {
|
||||
try {
|
||||
val targetID = if (args.size == 3) args[1].toInt() else (Terrarum.ingame!! as Ingame).player.referenceID
|
||||
val scale = args[if (args.size == 3) 2 else 1].toDouble()
|
||||
|
||||
val target = Terrarum.ingame!!.getActorByID(targetID!!)
|
||||
|
||||
if (target !is ActorWithPhysics) {
|
||||
EchoError("Target is not ActorWithPhysics")
|
||||
}
|
||||
else {
|
||||
target.scale = scale
|
||||
}
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
EchoError("Wrong number input")
|
||||
}
|
||||
}
|
||||
else printUsage()
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: setscale scale | setscale actorID scale")
|
||||
}
|
||||
}
|
||||
37
src/net/torvald/terrarum/modulebasegame/console/SetTime.kt
Normal file
37
src/net/torvald/terrarum/modulebasegame/console/SetTime.kt
Normal file
@@ -0,0 +1,37 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.WorldTime
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-03-20.
|
||||
*/
|
||||
internal object SetTime : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
val world = (Terrarum.ingame!! as Ingame).world
|
||||
|
||||
|
||||
if (args.size == 2) {
|
||||
val timeToSet = WorldTime.parseTime(args[1])
|
||||
|
||||
world.time.setTimeOfToday(timeToSet)
|
||||
|
||||
Echo("Set time to ${world.time.todaySeconds} " +
|
||||
"(${world.time.hours}h${formatMin(world.time.minutes)})")
|
||||
}
|
||||
else {
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatMin(min: Int): String {
|
||||
return if (min < 10) "0${min.toString()}" else min.toString()
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("usage: settime <39201-in sec or 13h32-in hour>")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-03-20.
|
||||
*/
|
||||
internal object SetTimeDelta : ConsoleCommand {
|
||||
|
||||
val HARD_LIMIT = 60
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
val world = (Terrarum.ingame!! as Ingame).world
|
||||
|
||||
|
||||
if (args.size == 2) {
|
||||
world.time.timeDelta = args[1].toInt()
|
||||
if (world.time.timeDelta == 0)
|
||||
Echo("時間よ止まれ!ザ・ワルド!!")
|
||||
else
|
||||
Echo("Set time delta to ${world.time.timeDelta}")
|
||||
}
|
||||
else {
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("usage: settimedelta <int>")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.PhysTestBall
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import org.dyn4j.geometry.Vector2
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-03-05.
|
||||
*/
|
||||
internal object SpawnPhysTestBall : ConsoleCommand {
|
||||
@Throws(Exception::class)
|
||||
override fun execute(args: Array<String>) {
|
||||
val world = (Terrarum.ingame!! as Ingame).world
|
||||
|
||||
|
||||
val mouseX = Terrarum.mouseX
|
||||
val mouseY = Terrarum.mouseY
|
||||
|
||||
if (args.size >= 3) {
|
||||
val elasticity = args[1].toDouble()
|
||||
|
||||
val xvel = args[2].toDouble()
|
||||
val yvel = if (args.size >= 4) args[3].toDouble() else 0.0
|
||||
|
||||
val ball = PhysTestBall(world)
|
||||
ball.setPosition(mouseX, mouseY)
|
||||
ball.elasticity = elasticity
|
||||
ball.applyForce(Vector2(xvel, yvel))
|
||||
|
||||
Terrarum.ingame!!.addNewActor(ball)
|
||||
}
|
||||
else if (args.size == 2) {
|
||||
val elasticity = args[1].toDouble()
|
||||
|
||||
val ball = PhysTestBall(world)
|
||||
ball.setPosition(mouseX, mouseY)
|
||||
ball.elasticity = elasticity
|
||||
|
||||
Terrarum.ingame!!.addNewActor(ball)
|
||||
}
|
||||
else {
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("usage: spawnball elasticity [x velocity] [y velocity]")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.PhysTestLuarLander
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2018-01-18.
|
||||
*/
|
||||
internal object SpawnPhysTestLunarLander : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
val mouseX = Terrarum.mouseX
|
||||
val mouseY = Terrarum.mouseY
|
||||
val lander = PhysTestLuarLander((Terrarum.ingame!! as Ingame).world)
|
||||
|
||||
lander.setPosition(mouseX, mouseY)
|
||||
|
||||
Terrarum.ingame!!.addNewActor(lander)
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("control it with arrow keys")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.DecodeTapestry
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-01-14.
|
||||
*/
|
||||
internal object SpawnTapestry : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size < 2) {
|
||||
printUsage()
|
||||
return
|
||||
}
|
||||
|
||||
val tapestry = DecodeTapestry(File(args[1]))
|
||||
Terrarum.ingame!!.addNewActor(tapestry)
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: spawntapestry <tapestry_file>")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureTikiTorch
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-12-17.
|
||||
*/
|
||||
internal object SpawnTikiTorch : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
val torch = FixtureTikiTorch((Terrarum.ingame!! as Ingame).world)
|
||||
torch.setPosition(Terrarum.mouseX, Terrarum.mouseY)
|
||||
|
||||
Terrarum.ingame!!.addNewActor(torch)
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: spawntorch")
|
||||
}
|
||||
}
|
||||
115
src/net/torvald/terrarum/modulebasegame/console/Teleport.kt
Normal file
115
src/net/torvald/terrarum/modulebasegame/console/Teleport.kt
Normal file
@@ -0,0 +1,115 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.console.EchoError
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorWithPhysics
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-24.
|
||||
*/
|
||||
internal object Teleport : ConsoleCommand {
|
||||
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 3) {
|
||||
|
||||
val x: Int
|
||||
val y: Int
|
||||
try {
|
||||
x = args[1].toInt() * FeaturesDrawer.TILE_SIZE + FeaturesDrawer.TILE_SIZE / 2
|
||||
y = args[2].toInt() * FeaturesDrawer.TILE_SIZE + FeaturesDrawer.TILE_SIZE / 2
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
EchoError("Teleport: wrong number input.")
|
||||
return
|
||||
}
|
||||
|
||||
(Terrarum.ingame!! as Ingame).player.setPosition(x.toDouble(), y.toDouble())
|
||||
}
|
||||
else if (args.size == 4) {
|
||||
if (args[2].toLowerCase() != "to") {
|
||||
EchoError("missing 'to' on teleport command")
|
||||
return
|
||||
}
|
||||
val fromActor: ActorWithPhysics
|
||||
val targetActor: ActorWithPhysics
|
||||
try {
|
||||
val fromActorID = args[1].toInt()
|
||||
val targetActorID = if (args[3].toLowerCase() == "player")
|
||||
(Terrarum.ingame!! as Ingame).player.referenceID!!
|
||||
else
|
||||
args[3].toInt()
|
||||
|
||||
// if from == target, ignore the action
|
||||
if (fromActorID == targetActorID) return
|
||||
|
||||
if (Terrarum.ingame!!.getActorByID(fromActorID) !is ActorWithPhysics ||
|
||||
Terrarum.ingame!!.getActorByID(targetActorID) !is ActorWithPhysics) {
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
else {
|
||||
fromActor = Terrarum.ingame!!.getActorByID(fromActorID) as ActorWithPhysics
|
||||
targetActor = Terrarum.ingame!!.getActorByID(targetActorID) as ActorWithPhysics
|
||||
}
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
EchoError("Teleport: illegal number input")
|
||||
return
|
||||
}
|
||||
catch (e1: IllegalArgumentException) {
|
||||
EchoError("Teleport: operation not possible on specified actor(s)")
|
||||
return
|
||||
}
|
||||
|
||||
fromActor.setPosition(
|
||||
targetActor.feetPosVector.x,
|
||||
targetActor.feetPosVector.y
|
||||
)
|
||||
}
|
||||
else if (args.size == 5) {
|
||||
if (args[2].toLowerCase() != "to") {
|
||||
EchoError("missing 'to' on teleport command")
|
||||
return
|
||||
}
|
||||
|
||||
val actor: ActorWithPhysics
|
||||
val x: Int
|
||||
val y: Int
|
||||
try {
|
||||
x = args[3].toInt() * FeaturesDrawer.TILE_SIZE + FeaturesDrawer.TILE_SIZE / 2
|
||||
y = args[4].toInt() * FeaturesDrawer.TILE_SIZE + FeaturesDrawer.TILE_SIZE / 2
|
||||
val actorID = args[1].toInt()
|
||||
|
||||
if (Terrarum.ingame!!.getActorByID(actorID) !is ActorWithPhysics) {
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
else {
|
||||
actor = Terrarum.ingame!!.getActorByID(actorID) as ActorWithPhysics
|
||||
}
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
EchoError("Teleport: illegal number input")
|
||||
return
|
||||
}
|
||||
catch (e1: IllegalArgumentException) {
|
||||
EchoError("Teleport: operation not possible on specified actor")
|
||||
return
|
||||
}
|
||||
|
||||
actor.setPosition(x.toDouble(), y.toDouble())
|
||||
}
|
||||
else {
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: teleport x-tile y-tile")
|
||||
Echo(" teleport actorid to x-tile y-tile")
|
||||
Echo(" teleport actorid to actorid")
|
||||
Echo(" teleport actorid to player")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-19.
|
||||
*/
|
||||
internal object ToggleNoClip : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
val status = (Terrarum.ingame!! as Ingame).player.isNoClip()
|
||||
|
||||
(Terrarum.ingame!! as Ingame).player.setNoClip(!status)
|
||||
Echo("Set no-clip status to " + (!status).toString())
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("toggle no-clip status of player")
|
||||
}
|
||||
}
|
||||
44
src/net/torvald/terrarum/modulebasegame/console/Zoom.kt
Normal file
44
src/net/torvald/terrarum/modulebasegame/console/Zoom.kt
Normal file
@@ -0,0 +1,44 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-25.
|
||||
*/
|
||||
internal object Zoom : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 2) {
|
||||
|
||||
var zoom: Float
|
||||
try {
|
||||
zoom = args[1].toFloat()
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
Echo("Wrong number input.")
|
||||
return
|
||||
}
|
||||
|
||||
if (zoom < Terrarum.ingame!!.ZOOM_MINIMUM) {
|
||||
zoom = Terrarum.ingame!!.ZOOM_MINIMUM
|
||||
}
|
||||
else if (zoom > Terrarum.ingame!!.ZOOM_MAXIMUM) {
|
||||
zoom = Terrarum.ingame!!.ZOOM_MAXIMUM
|
||||
}
|
||||
|
||||
Terrarum.ingame!!.screenZoom = zoom
|
||||
|
||||
System.gc()
|
||||
|
||||
Echo("Set screen zoom to " + zoom.toString())
|
||||
}
|
||||
else {
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: zoom [zoom]")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
package net.torvald.terrarum.modulebasegame.debuggerapp
|
||||
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.gameactors.ActorValue
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.modulebasegame.console.SetAV
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorWithPhysics
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.GridLayout
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
import javax.swing.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-12-29.
|
||||
*/
|
||||
class ActorValueTracker constructor() : JFrame() {
|
||||
|
||||
constructor(actor: Actor?) : this() {
|
||||
setTrackingActor(actor)
|
||||
}
|
||||
|
||||
private val avInfoArea = JTextArea()
|
||||
private val avInfoScroller = JScrollPane(avInfoArea)
|
||||
private val avPosArea = JTextArea()
|
||||
private val avPosScroller = JScrollPane(avPosArea)
|
||||
|
||||
private var actor: ActorWithPhysics? = null
|
||||
private var actorValue: ActorValue? = null
|
||||
|
||||
private val modavInputKey = JTextField()
|
||||
private val modavInputValue = JTextField()
|
||||
|
||||
private val buttonAddAV = JButton("Add/Mod")
|
||||
private val buttonDelAV = JButton("Delete")
|
||||
|
||||
//private val selectedActorLabel = JLabel("Selected actor: ")
|
||||
private val actorIDField = JTextField()
|
||||
private val buttonChangeActor = JButton("Change")
|
||||
|
||||
init {
|
||||
title = "Actor value tracker"
|
||||
defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE
|
||||
|
||||
val divPanel = JPanel()
|
||||
divPanel.layout = BorderLayout(0, 2)
|
||||
|
||||
avInfoArea.highlighter = null // prevent text-drag-crash
|
||||
avPosArea.highlighter = null // prevent text-drag-crash
|
||||
|
||||
avInfoScroller.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
|
||||
avPosScroller.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
|
||||
|
||||
if (actor != null) {
|
||||
actorIDField.text = "${actor!!.referenceID}"
|
||||
}
|
||||
|
||||
// button listener for buttons
|
||||
buttonAddAV.addMouseListener(object : MouseAdapter() {
|
||||
override fun mousePressed(e: MouseEvent?) {
|
||||
if (actor != null && modavInputKey.text.isNotBlank() && modavInputValue.text.isNotBlank()) {
|
||||
SetAV.execute((
|
||||
"setav;" +
|
||||
"${actor!!.referenceID};" +
|
||||
"${modavInputKey.text};" +
|
||||
"${modavInputValue.text}"
|
||||
).split(';').toTypedArray())
|
||||
}
|
||||
}
|
||||
})
|
||||
buttonDelAV.addMouseListener(object : MouseAdapter() {
|
||||
override fun mousePressed(e: MouseEvent?) {
|
||||
if (actorValue != null && modavInputKey.text.isNotBlank()) {
|
||||
actorValue!!.remove(modavInputKey.text)
|
||||
Echo("${ccW}Removed ${ccM}${modavInputKey.text} ${ccW}of ${ccY}${actor!!.referenceID}")
|
||||
println("[ActorValueTracker] Removed ActorValue '${modavInputKey.text}' of $actor")
|
||||
}
|
||||
}
|
||||
})
|
||||
buttonChangeActor.addMouseListener(object : MouseAdapter() {
|
||||
override fun mousePressed(e: MouseEvent?) {
|
||||
if (actorIDField.text.toLowerCase() == "player") {
|
||||
actor = (Terrarum.ingame!! as Ingame).player
|
||||
actorValue = actor!!.actorValue
|
||||
}
|
||||
else if (actorIDField.text.isNotBlank()) {
|
||||
actor = Terrarum.ingame!!.getActorByID(actorIDField.text.toInt()) as ActorWithPhysics
|
||||
actorValue = actor!!.actorValue
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// panel elements
|
||||
val actorNameBar = JPanel()
|
||||
actorNameBar.layout = BorderLayout(2, 0)
|
||||
actorNameBar.add(JLabel("RefID: "), BorderLayout.LINE_START)
|
||||
actorNameBar.add(actorIDField, BorderLayout.CENTER)
|
||||
actorNameBar.add(buttonChangeActor, BorderLayout.LINE_END)
|
||||
|
||||
val posAndAV = JPanel()
|
||||
posAndAV.layout = BorderLayout()
|
||||
posAndAV.add(avPosScroller, BorderLayout.PAGE_START)
|
||||
posAndAV.add(avInfoScroller, BorderLayout.CENTER)
|
||||
|
||||
val toolbox = JPanel()
|
||||
toolbox.layout = BorderLayout()
|
||||
|
||||
val toolpanel = JPanel()
|
||||
toolpanel.layout = GridLayout(1, 0)
|
||||
toolpanel.add(buttonAddAV)
|
||||
toolpanel.add(buttonDelAV)
|
||||
|
||||
val modpanelLabels = JPanel()
|
||||
modpanelLabels.layout = BorderLayout(4, 0)
|
||||
modpanelLabels.add(JLabel("Key"), BorderLayout.PAGE_START)
|
||||
modpanelLabels.add(JLabel("Value"), BorderLayout.CENTER)
|
||||
|
||||
val modpanelFields = JPanel()
|
||||
modpanelFields.layout = BorderLayout(4, 2)
|
||||
modpanelFields.add(modavInputKey, BorderLayout.PAGE_START)
|
||||
modpanelFields.add(modavInputValue, BorderLayout.CENTER)
|
||||
|
||||
val modpanel = JPanel()
|
||||
modpanel.layout = BorderLayout(4, 2)
|
||||
modpanel.add(modpanelLabels, BorderLayout.LINE_START)
|
||||
modpanel.add(modpanelFields, BorderLayout.CENTER)
|
||||
modpanel.add(JLabel(
|
||||
"<html>Messed-up type or careless delete will crash the game.<br>" +
|
||||
"Prepend two underscores for boolean literals.</html>"
|
||||
), BorderLayout.PAGE_END)
|
||||
|
||||
toolbox.add(toolpanel, BorderLayout.PAGE_START)
|
||||
toolbox.add(modpanel, BorderLayout.CENTER)
|
||||
|
||||
divPanel.add(actorNameBar, BorderLayout.PAGE_START)
|
||||
divPanel.add(posAndAV, BorderLayout.CENTER)
|
||||
divPanel.add(toolbox, BorderLayout.PAGE_END)
|
||||
|
||||
|
||||
this.add(divPanel)
|
||||
this.setSize(300, 600)
|
||||
this.isVisible = true
|
||||
}
|
||||
|
||||
fun setTrackingActor(actor: Actor?) {
|
||||
this.actorValue = actor?.actorValue
|
||||
|
||||
this.title = "AVTracker — $actor"
|
||||
|
||||
if (actor is ActorWithPhysics) {
|
||||
this.actor = actor
|
||||
}
|
||||
|
||||
update()
|
||||
}
|
||||
|
||||
fun update() {
|
||||
val sb = StringBuilder()
|
||||
|
||||
if (actor != null) {
|
||||
sb.append("toString: ${actor!!}\n")
|
||||
sb.append("X: ${actor!!.hitbox.canonicalX} (${(actor!!.hitbox.canonicalX / FeaturesDrawer.TILE_SIZE).toInt()})\n")
|
||||
sb.append("Y: ${actor!!.hitbox.canonicalY} (${(actor!!.hitbox.canonicalY / FeaturesDrawer.TILE_SIZE).toInt()})")
|
||||
|
||||
avPosArea.text = "$sb"
|
||||
sb.setLength(0) // clear stringbuffer
|
||||
}
|
||||
|
||||
if (actorValue != null) {
|
||||
for (key in actorValue!!.keySet) {
|
||||
val value = actorValue!![key.toString()]!!
|
||||
val type = value.javaClass.simpleName
|
||||
|
||||
sb.append("$key = $value ($type)\n")
|
||||
}
|
||||
|
||||
if (sb.isNotEmpty()) {
|
||||
sb.deleteCharAt(sb.length - 1) // delete trailing \n
|
||||
}
|
||||
|
||||
avInfoArea.text = "$sb"
|
||||
}
|
||||
else {
|
||||
avInfoArea.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
+--------------------------------+
|
||||
| Actor: [5333533 ] [Change] | LBL TFL BTN
|
||||
+--------------------------------+
|
||||
| X: 65532.655654747 (4095) | TAR
|
||||
| Y: 3050.4935465 (190) |
|
||||
| ... |
|
||||
+--------------------------------+
|
||||
| [ Add/Mod ] [ Delete ] | BTN BTN
|
||||
+--------------------------------+
|
||||
| Key [ ] | LBL TFL
|
||||
| Value [ ] | LBL TFL
|
||||
+--------------------------------+
|
||||
|
||||
|
||||
*/
|
||||
111
src/net/torvald/terrarum/modulebasegame/gameactors/AVKey.kt
Normal file
111
src/net/torvald/terrarum/modulebasegame/gameactors/AVKey.kt
Normal file
@@ -0,0 +1,111 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
/**
|
||||
* See [res/raw/Creature_raw_doc.md] for information about raw.
|
||||
*
|
||||
* Created by minjaesong on 2016-04-02.
|
||||
*/
|
||||
object AVKey {
|
||||
const val BUFF = "buff"
|
||||
|
||||
/** pixels per frame
|
||||
* walking/running speed
|
||||
*/
|
||||
const val SPEED = "speed"
|
||||
const val SPEEDBUFF = "$SPEED$BUFF"
|
||||
/** pixels per frame squared
|
||||
* acceleration of the movement (e.g. running, flying, driving, etc.)
|
||||
*/
|
||||
const val ACCEL = "accel"
|
||||
const val ACCELBUFF = "$ACCEL$BUFF"
|
||||
/** internal value used by ActorHumanoid to implement friction in walkfunction */
|
||||
const val SCALE = "scale"
|
||||
const val SCALEBUFF = "$SCALE$BUFF" // aka PHYSIQUE
|
||||
/** pixels */
|
||||
const val BASEHEIGHT = "baseheight"
|
||||
/** kilogrammes */
|
||||
const val BASEMASS = "basemass"
|
||||
/** pixels per frame */
|
||||
const val JUMPPOWER = "jumppower"
|
||||
const val JUMPPOWERBUFF = "$JUMPPOWER$BUFF"
|
||||
|
||||
/** Int
|
||||
* "Default" value of 1 000
|
||||
*/
|
||||
const val STRENGTH = "strength"
|
||||
const val STRENGTHBUFF = "$STRENGTH$BUFF"
|
||||
const val ENCUMBRANCE = "encumbrance"
|
||||
/** 30-bit RGB (Int)
|
||||
* 0000 0010000000 0010000000 0010000000
|
||||
* ^ Red ^ Green ^ Blue
|
||||
*/
|
||||
const val LUMR = "luminosityred"
|
||||
const val LUMG = "luminositygreen"
|
||||
const val LUMB = "luminosityblue"
|
||||
const val LUMA = "luminosityuv"
|
||||
const val DRAGCOEFF = "dragcoeff"
|
||||
const val FALLDAMPENMULT = "falldampenmult"
|
||||
|
||||
/** String
|
||||
* e.g. Jarppi
|
||||
*/
|
||||
const val NAME = "name"
|
||||
|
||||
/** String
|
||||
* e.g. Duudsoni
|
||||
*/
|
||||
const val RACENAME = "racename"
|
||||
/** String
|
||||
* e.g. Duudsonit
|
||||
*/
|
||||
const val RACENAMEPLURAL = "racenameplural"
|
||||
/** killogrammes
|
||||
* will affect attack strength, speed and inventory label
|
||||
* (see "Attack momentum calculator.numbers")
|
||||
* e.g. Hatchet (tiny)
|
||||
*/
|
||||
const val TOOLSIZE = "toolsize"
|
||||
/** Boolean
|
||||
* whether the player can talk with it
|
||||
*/
|
||||
const val INTELLIGENT = "intelligent"
|
||||
|
||||
/** (unit TBA)
|
||||
* base defence point of the species
|
||||
*/
|
||||
const val BASEDEFENCE = "basedefence"
|
||||
/** (unit TBA)
|
||||
* current defence point of worn armour(s)
|
||||
*/
|
||||
const val ARMOURDEFENCE = "armourdefence"
|
||||
const val ARMOURDEFENCEBUFF = "$ARMOURDEFENCE$BUFF"
|
||||
|
||||
const val MAGICREGENRATE = "magicregenrate"
|
||||
const val MAGICREGENRATEBUFF = "$MAGICREGENRATE$BUFF"
|
||||
|
||||
/** Double
|
||||
*
|
||||
*/
|
||||
const val ACTION_INTERVAL = "actioninterval"
|
||||
|
||||
|
||||
/** String
|
||||
* UUID for certain fixtures
|
||||
*/
|
||||
const val UUID = "uuid"
|
||||
|
||||
|
||||
|
||||
const val __PLAYER_QUICKSLOTSEL = "__quickslotselection"
|
||||
|
||||
/** Double
|
||||
* When using tool/arm/etc. how long action button is held, in milliseconds (Int)
|
||||
* Or for NPCs, how long it has been waiting for next move
|
||||
*/
|
||||
const val __ACTION_TIMER = "__actiontimer"
|
||||
|
||||
|
||||
|
||||
const val HEALTH = "health"
|
||||
const val MAGIC = "magic"
|
||||
}
|
||||
@@ -0,0 +1,648 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.bipolarClamp
|
||||
import net.torvald.terrarum.gameactors.Controllable
|
||||
import net.torvald.terrarum.gameactors.Factionable
|
||||
import net.torvald.terrarum.gameactors.Hitbox
|
||||
import net.torvald.terrarum.gameactors.Luminous
|
||||
import net.torvald.terrarum.gameactors.faction.Faction
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.itemproperties.Material
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Humanoid actor class to provide same controlling function (such as work, jump)
|
||||
* Also applies unreal air friction for movement control
|
||||
*
|
||||
* Created by minjaesong on 2016-10-24.
|
||||
*/
|
||||
open class ActorHumanoid(
|
||||
world: GameWorld,
|
||||
birth: GameDate,
|
||||
death: GameDate? = null,
|
||||
usePhysics: Boolean = true
|
||||
) : HistoricalFigure(world, birth, death, usePhysics = usePhysics), Controllable, Pocketed, Factionable, Luminous, LandHolder {
|
||||
|
||||
|
||||
|
||||
var vehicleRiding: Controllable? = null // usually player only
|
||||
|
||||
|
||||
|
||||
/** Must be set by PlayerFactory */
|
||||
override var inventory: ActorInventory = ActorInventory(this, 2000, ActorInventory.CAPACITY_MODE_WEIGHT) // default constructor
|
||||
|
||||
|
||||
/** Must be set by PlayerFactory */
|
||||
override var faction: HashSet<Faction> = HashSet()
|
||||
/**
|
||||
* Absolute tile index. index(x, y) = y * map.width + x
|
||||
* The arraylist will be saved in JSON format with GSON.
|
||||
*/
|
||||
override var houseDesignation: ArrayList<Long>? = ArrayList()
|
||||
|
||||
override fun addHouseTile(x: Int, y: Int) {
|
||||
if (houseDesignation != null) houseDesignation!!.add(LandUtil.getBlockAddr(world, x, y))
|
||||
}
|
||||
|
||||
override fun removeHouseTile(x: Int, y: Int) {
|
||||
if (houseDesignation != null) houseDesignation!!.remove(LandUtil.getBlockAddr(world, x, y))
|
||||
}
|
||||
|
||||
override fun clearHouseDesignation() {
|
||||
if (houseDesignation != null) houseDesignation!!.clear()
|
||||
}
|
||||
|
||||
override var color: Color
|
||||
get() = Color(
|
||||
(actorValue.getAsFloat(AVKey.LUMR) ?: 0f) / LightmapRenderer.MUL_FLOAT,
|
||||
(actorValue.getAsFloat(AVKey.LUMG) ?: 0f) / LightmapRenderer.MUL_FLOAT,
|
||||
(actorValue.getAsFloat(AVKey.LUMB) ?: 0f) / LightmapRenderer.MUL_FLOAT,
|
||||
(actorValue.getAsFloat(AVKey.LUMA) ?: 0f) / LightmapRenderer.MUL_FLOAT
|
||||
)
|
||||
set(value) {
|
||||
actorValue[AVKey.LUMR] = value.r * LightmapRenderer.MUL_FLOAT
|
||||
actorValue[AVKey.LUMG] = value.g * LightmapRenderer.MUL_FLOAT
|
||||
actorValue[AVKey.LUMB] = value.b * LightmapRenderer.MUL_FLOAT
|
||||
actorValue[AVKey.LUMA] = value.a * LightmapRenderer.MUL_FLOAT
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments:
|
||||
*
|
||||
* Hitbox(x-offset, y-offset, width, height)
|
||||
* (Use ArrayList for normal circumstances)
|
||||
*/
|
||||
override val lightBoxList: List<Hitbox>
|
||||
get() = arrayOf(Hitbox(2.0, 2.0, hitbox.width - 3, hitbox.height - 3)).toList() // things are asymmetric!!
|
||||
// use getter; dimension of the player may change by time.
|
||||
|
||||
@Transient val BASE_DENSITY = 980.0
|
||||
|
||||
companion object {
|
||||
//@Transient internal const val ACCEL_MULT_IN_FLIGHT: Double = 0.21
|
||||
@Transient internal const val WALK_ACCEL_BASE: Double = 0.67
|
||||
|
||||
@Transient const val BASE_HEIGHT = 40
|
||||
// 0.33333 miliseconds
|
||||
@Transient const val BASE_ACTION_INTERVAL = 1.0 / 3.0
|
||||
|
||||
@Transient const val SPRITE_ROW_IDLE = 0
|
||||
@Transient const val SPRITE_ROW_WALK = 1
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// MOVEMENT RELATED FUNCTIONS //
|
||||
////////////////////////////////
|
||||
|
||||
var axisX = 0f
|
||||
var axisY = 0f
|
||||
var axisRX = 0f
|
||||
var axisRY = 0f
|
||||
|
||||
/** empirical value. */
|
||||
@Transient private val JUMP_ACCELERATION_MOD = 51.0 / 10000.0 // (170 * (17/MAX_JUMP_LENGTH)^2) / 10000.0
|
||||
@Transient private val WALK_FRAMES_TO_MAX_ACCEL = 6
|
||||
|
||||
@Transient private val LEFT = 1
|
||||
@Transient private val RIGHT = 2
|
||||
|
||||
@Transient private val KEY_NULL = -1
|
||||
|
||||
/** how long the jump button has down, in frames */
|
||||
internal var jumpCounter = 0
|
||||
internal var jumpAcc = 0.0
|
||||
/** how long the walk button has down, in frames */
|
||||
internal var walkCounterX = 0
|
||||
internal var walkCounterY = 0
|
||||
@Transient private val MAX_JUMP_LENGTH = 25 // manages "heaviness" of the jump control. Higher = heavier
|
||||
|
||||
private var readonly_totalX = 0.0
|
||||
private var readonly_totalY = 0.0
|
||||
|
||||
internal var jumping = false
|
||||
internal var airJumpingAllowed = false
|
||||
|
||||
internal var walkHeading: Int = 0
|
||||
|
||||
@Transient private var prevHMoveKey = KEY_NULL
|
||||
@Transient private var prevVMoveKey = KEY_NULL
|
||||
|
||||
internal var noClip = false
|
||||
|
||||
@Transient private val AXIS_KEYBOARD = -13372f // leetz
|
||||
@Transient private val GAMEPAD_JUMP = 7
|
||||
|
||||
protected var isUpDown = false
|
||||
protected var isDownDown = false
|
||||
protected var isLeftDown = false
|
||||
protected var isRightDown = false
|
||||
protected var isJumpDown = false
|
||||
protected inline val isGamer: Boolean
|
||||
get() = if (Terrarum.ingame == null) false else this == (Terrarum.ingame!! as Ingame).player
|
||||
|
||||
|
||||
private val nullItem = object : GameItem() {
|
||||
override var dynamicID: Int = 0
|
||||
override val originalID = dynamicID
|
||||
override val isUnique: Boolean = false
|
||||
override var baseMass: Double = 0.0
|
||||
override var baseToolSize: Double? = null
|
||||
override var inventoryCategory = "should_not_be_seen"
|
||||
override val originalName: String = actorValue.getAsString(AVKey.NAME) ?: "(no name)"
|
||||
override var stackable = false
|
||||
override val isDynamic = false
|
||||
override val material = Material(0,0,0,0,0,0,0,0,0,0.0)
|
||||
}
|
||||
|
||||
override fun update(delta: Float) {
|
||||
super.update(delta)
|
||||
|
||||
if (vehicleRiding is Player)
|
||||
throw Error("Attempted to 'ride' player object. ($vehicleRiding)")
|
||||
if (vehicleRiding != null && vehicleRiding == this)
|
||||
throw Error("Attempted to 'ride' itself. ($vehicleRiding)")
|
||||
|
||||
|
||||
|
||||
// don't put this into keyPressed; execution order is important!
|
||||
updateGamerControlBox()
|
||||
|
||||
processInput(delta)
|
||||
|
||||
updateSprite(delta)
|
||||
|
||||
if (noClip) {
|
||||
//grounded = true
|
||||
}
|
||||
|
||||
// reset control box of AI
|
||||
if (!isGamer) {
|
||||
isUpDown = false
|
||||
isDownDown = false
|
||||
isLeftDown = false
|
||||
isRightDown = false
|
||||
isJumpDown = false
|
||||
axisX = 0f
|
||||
axisY = 0f
|
||||
axisRX = 0f
|
||||
axisRY = 0f
|
||||
}
|
||||
|
||||
// update inventory items
|
||||
inventory.forEach {
|
||||
if (!inventory.itemEquipped.contains(it.item)) { // unequipped
|
||||
it.item.effectWhileInPocket(delta)
|
||||
}
|
||||
else { // equipped
|
||||
it.item.effectWhenEquipped(delta)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateGamerControlBox() {
|
||||
if (isGamer) {
|
||||
isUpDown = Gdx.input.isKeyPressed(Terrarum.getConfigInt("keyup"))
|
||||
isLeftDown = Gdx.input.isKeyPressed(Terrarum.getConfigInt("keyleft"))
|
||||
isDownDown = Gdx.input.isKeyPressed(Terrarum.getConfigInt("keydown"))
|
||||
isRightDown = Gdx.input.isKeyPressed(Terrarum.getConfigInt("keyright"))
|
||||
isJumpDown = Gdx.input.isKeyPressed(Terrarum.getConfigInt("keyjump"))
|
||||
|
||||
if (Terrarum.controller != null) {
|
||||
axisX = Terrarum.controller!!.getAxisValue(Terrarum.getConfigInt("joypadlstickx"))
|
||||
axisY = Terrarum.controller!!.getAxisValue(Terrarum.getConfigInt("joypadlsticky"))
|
||||
axisRX = Terrarum.controller!!.getAxisValue(Terrarum.getConfigInt("joypadrstickx"))
|
||||
axisRY = Terrarum.controller!!.getAxisValue(Terrarum.getConfigInt("joypadrsticky"))
|
||||
|
||||
// deadzonning
|
||||
if (Math.abs(axisX) < Terrarum.CONTROLLER_DEADZONE) axisX = 0f
|
||||
if (Math.abs(axisY) < Terrarum.CONTROLLER_DEADZONE) axisY = 0f
|
||||
if (Math.abs(axisRX) < Terrarum.CONTROLLER_DEADZONE) axisRX = 0f
|
||||
if (Math.abs(axisRY) < Terrarum.CONTROLLER_DEADZONE) axisRY = 0f
|
||||
|
||||
isJumpDown = Gdx.input.isKeyPressed(Terrarum.getConfigInt("keyjump")) ||
|
||||
Terrarum.controller!!.isButtonPressed(GAMEPAD_JUMP)
|
||||
}
|
||||
}
|
||||
else {
|
||||
isUpDown = axisY < 0f
|
||||
isDownDown = axisY > 0f
|
||||
isLeftDown = axisX < 0f
|
||||
isRightDown = axisX > 0f
|
||||
}
|
||||
}
|
||||
|
||||
private inline val hasController: Boolean
|
||||
get() = if (isGamer) Terrarum.controller != null
|
||||
else true
|
||||
|
||||
private fun processInput(delta: Float) {
|
||||
|
||||
/**
|
||||
* L-R stop
|
||||
*/
|
||||
if (hasController && !isWalkingH) {
|
||||
if (axisX == 0f) {
|
||||
walkHStop()
|
||||
}
|
||||
}
|
||||
// ↑F, ↑S
|
||||
if (isWalkingH && !isLeftDown && !isRightDown) {
|
||||
walkHStop()
|
||||
prevHMoveKey = KEY_NULL
|
||||
}
|
||||
/**
|
||||
* U-D stop
|
||||
*/
|
||||
if (hasController) {
|
||||
if (axisY == 0f) {
|
||||
walkVStop()
|
||||
}
|
||||
}
|
||||
// ↑E
|
||||
// ↑D
|
||||
if (isNoClip() && !isUpDown && !isDownDown) {
|
||||
walkVStop()
|
||||
prevVMoveKey = KEY_NULL
|
||||
}
|
||||
|
||||
/**
|
||||
* Left/Right movement
|
||||
*/
|
||||
|
||||
if (hasController) {
|
||||
if (axisX != 0f) {
|
||||
walkHorizontal(axisX < 0f, axisX.abs())
|
||||
}
|
||||
}
|
||||
// ↑F, ↓S
|
||||
if (isRightDown && !isLeftDown) {
|
||||
walkHorizontal(false, AXIS_KEYBOARD)
|
||||
prevHMoveKey = Terrarum.getConfigInt("keyright")
|
||||
} // ↓F, ↑S
|
||||
else if (isLeftDown && !isRightDown) {
|
||||
walkHorizontal(true, AXIS_KEYBOARD)
|
||||
prevHMoveKey = Terrarum.getConfigInt("keyleft")
|
||||
} // ↓F, ↓S
|
||||
/*else if (isLeftDown && isRightDown) {
|
||||
if (prevHMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_LEFT)) {
|
||||
walkHorizontal(false, AXIS_KEYBOARD)
|
||||
prevHMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_RIGHT)
|
||||
} else if (prevHMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_RIGHT)) {
|
||||
walkHorizontal(true, AXIS_KEYBOARD)
|
||||
prevHMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_LEFT)
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Up/Down movement
|
||||
*/
|
||||
if (noClip || COLLISION_TEST_MODE) {
|
||||
if (hasController) {
|
||||
if (axisY != 0f) {
|
||||
walkVertical(axisY < 0, axisY.abs())
|
||||
}
|
||||
}
|
||||
// ↑E, ↓D
|
||||
if (isDownDown && !isUpDown) {
|
||||
walkVertical(false, AXIS_KEYBOARD)
|
||||
prevVMoveKey = Terrarum.getConfigInt("keydown")
|
||||
} // ↓E, ↑D
|
||||
else if (isUpDown && !isDownDown) {
|
||||
walkVertical(true, AXIS_KEYBOARD)
|
||||
prevVMoveKey = Terrarum.getConfigInt("keyup")
|
||||
} // ↓E, ↓D
|
||||
/*else if (isUpDown && isDownDown) {
|
||||
if (prevVMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_UP)) {
|
||||
walkVertical(false, AXIS_KEYBOARD)
|
||||
prevVMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_DOWN)
|
||||
} else if (prevVMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_DOWN)) {
|
||||
walkVertical(true, AXIS_KEYBOARD)
|
||||
prevVMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_UP)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Jump control
|
||||
*/
|
||||
if (isJumpDown) {
|
||||
if (!noClip) {
|
||||
if (airJumpingAllowed ||
|
||||
(!airJumpingAllowed && walledBottom)) {
|
||||
jumping = true
|
||||
}
|
||||
jump()
|
||||
}
|
||||
else {
|
||||
walkVertical(true, AXIS_KEYBOARD)
|
||||
}
|
||||
}
|
||||
else {
|
||||
jumping = false
|
||||
jumpCounter = 0
|
||||
jumpAcc = 0.0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
// quickslot (quickbar)
|
||||
val quickbarKeys = Terrarum.getConfigIntArray("keyquickbars")
|
||||
if (keycode in quickbarKeys) {
|
||||
actorValue[AVKey.__PLAYER_QUICKSLOTSEL] = quickbarKeys.indexOf(keycode)
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This code directly controls VELOCITY for walking, called walkX and walkY.
|
||||
*
|
||||
* In theory, we must add ACCELERATION to the velocity, but unfortunately it's arduous task
|
||||
* with this simulation code base.
|
||||
*
|
||||
* Reason: we have naïve friction code that is not adaptive at all and to add proper walking code to
|
||||
* this code base, ACCELERATION must be changed (in other words, we must deal with JERK) accordingly
|
||||
* to the FRICTION.
|
||||
*
|
||||
* So I'm adding walkX/Y and getting the ActorWithPhysics.setNewNextHitbox to use the velocity value of
|
||||
* walkX/Y + velocity, which is stored in variable moveDelta.
|
||||
*
|
||||
* Be warned.
|
||||
*
|
||||
* @param left (even if the game is joypad controlled, you must give valid value)
|
||||
* @param absAxisVal (set AXIS_KEYBOARD if keyboard controlled)
|
||||
* @author minjaesong
|
||||
*/
|
||||
private fun walkHorizontal(left: Boolean, absAxisVal: Float) {
|
||||
|
||||
|
||||
if (avAcceleration.isNaN()) {
|
||||
throw Error("avAccelation is NaN")
|
||||
}
|
||||
|
||||
|
||||
if (left && walledLeft || !left && walledRight) return
|
||||
|
||||
|
||||
readonly_totalX =
|
||||
if (absAxisVal == AXIS_KEYBOARD)
|
||||
avAcceleration * applyVelo(walkCounterX) * (if (left) -1f else 1f)
|
||||
else
|
||||
avAcceleration * applyVelo(walkCounterX) * (if (left) -1f else 1f) * absAxisVal
|
||||
|
||||
if (absAxisVal != AXIS_KEYBOARD)
|
||||
controllerMoveDelta?.x?.let { controllerMoveDelta!!.x = controllerMoveDelta!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap * absAxisVal) }
|
||||
else
|
||||
controllerMoveDelta?.x?.let { controllerMoveDelta!!.x = controllerMoveDelta!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap) }
|
||||
|
||||
if (walkCounterX < 1000000) {
|
||||
walkCounterX += 1
|
||||
}
|
||||
|
||||
isWalkingH = true
|
||||
|
||||
|
||||
|
||||
// Heading flag
|
||||
walkHeading = if (left) LEFT else RIGHT
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
* @param up (even if the game is joypad controlled, you must give valid value)
|
||||
* *
|
||||
* @param absAxisVal (set AXIS_KEYBOARD if keyboard controlled)
|
||||
*/
|
||||
private fun walkVertical(up: Boolean, absAxisVal: Float) {
|
||||
if (up && walledTop || !up && walledBottom) return
|
||||
|
||||
|
||||
if (avAcceleration.isNaN()) {
|
||||
throw Error("avAccelation is NaN")
|
||||
}
|
||||
|
||||
|
||||
readonly_totalY =
|
||||
if (absAxisVal == AXIS_KEYBOARD)
|
||||
avAcceleration * applyVelo(walkCounterY) * (if (up) -1f else 1f)
|
||||
else
|
||||
avAcceleration * applyVelo(walkCounterY) * (if (up) -1f else 1f) * absAxisVal
|
||||
|
||||
if (absAxisVal != AXIS_KEYBOARD)
|
||||
controllerMoveDelta?.y?.let { controllerMoveDelta!!.y = controllerMoveDelta!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap * absAxisVal) }
|
||||
else
|
||||
controllerMoveDelta?.y?.let { controllerMoveDelta!!.y = controllerMoveDelta!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap) }
|
||||
|
||||
if (walkCounterY < 1000000) {
|
||||
walkCounterY += 1
|
||||
}
|
||||
|
||||
|
||||
isWalkingV = true
|
||||
}
|
||||
|
||||
private fun applyAccel(x: Int): Double {
|
||||
return if (x < WALK_FRAMES_TO_MAX_ACCEL)
|
||||
Math.sin(Math.PI * x / WALK_FRAMES_TO_MAX_ACCEL)
|
||||
else 0.0
|
||||
}
|
||||
|
||||
private fun applyVelo(x: Int): Double {
|
||||
return if (x < WALK_FRAMES_TO_MAX_ACCEL)
|
||||
0.5 - 0.5 * Math.cos(Math.PI * x / WALK_FRAMES_TO_MAX_ACCEL)
|
||||
else 1.0
|
||||
}
|
||||
|
||||
// stops; let the friction kick in by doing nothing to the velocity here
|
||||
private fun walkHStop() {
|
||||
walkCounterX = 0
|
||||
isWalkingH = false
|
||||
}
|
||||
|
||||
// stops; let the friction kick in by doing nothing to the velocity here
|
||||
private fun walkVStop() {
|
||||
walkCounterY = 0
|
||||
isWalkingV = false
|
||||
}
|
||||
|
||||
private fun getJumpAcc(pwr: Double, timedJumpCharge: Double): Double {
|
||||
return pwr * timedJumpCharge * JUMP_ACCELERATION_MOD * Math.sqrt(scale) // positive value
|
||||
}
|
||||
|
||||
private var oldMAX_JUMP_LENGTH = -1 // init
|
||||
private var oldJUMPPOWER = -1.0 // init
|
||||
private var oldJUMPPOWERBUFF = -1.0 // init
|
||||
private var oldScale = -1.0
|
||||
private var oldDragCoefficient = -1.0
|
||||
val jumpAirTime: Double = -1.0
|
||||
get() {
|
||||
// compare all the affecting variables
|
||||
if (oldMAX_JUMP_LENGTH == MAX_JUMP_LENGTH &&
|
||||
oldJUMPPOWER == actorValue.getAsDouble(AVKey.JUMPPOWER)!! &&
|
||||
oldJUMPPOWERBUFF == actorValue.getAsDouble(AVKey.JUMPPOWERBUFF) ?: 1.0 &&
|
||||
oldScale == scale &&
|
||||
oldDragCoefficient == dragCoefficient) {
|
||||
return field
|
||||
}
|
||||
// if variables are changed, get new value, store it and return it
|
||||
else {
|
||||
oldMAX_JUMP_LENGTH = MAX_JUMP_LENGTH
|
||||
oldJUMPPOWER = actorValue.getAsDouble(AVKey.JUMPPOWER)!!
|
||||
oldJUMPPOWERBUFF = actorValue.getAsDouble(AVKey.JUMPPOWERBUFF) ?: 1.0
|
||||
oldScale = scale
|
||||
oldDragCoefficient = dragCoefficient
|
||||
|
||||
|
||||
var frames = 0
|
||||
|
||||
var simYPos = 0.0
|
||||
var forceVec = Vector2(0.0, 0.0)
|
||||
var jmpCtr = 0
|
||||
while (true) {
|
||||
if (jmpCtr < MAX_JUMP_LENGTH) jmpCtr++
|
||||
|
||||
|
||||
val timedJumpCharge = jumpFunc(MAX_JUMP_LENGTH, jmpCtr)
|
||||
forceVec.y -= getJumpAcc(jumpPower, timedJumpCharge)
|
||||
forceVec.y += getDrag(forceVec).y
|
||||
|
||||
simYPos += forceVec.y // ignoring all the fluid drag OTHER THAN THE AIR
|
||||
|
||||
|
||||
if ((simYPos >= 0.0 && frames > 0) || frames >= 1000) break
|
||||
|
||||
|
||||
frames++
|
||||
}
|
||||
|
||||
|
||||
field = frames * (1.0 / Terrarum.TARGET_FPS)
|
||||
// fixme: looks good but return value is wrong -- 2.25 seconds? when I jump it barely goes past 1 sec
|
||||
|
||||
|
||||
return field
|
||||
}
|
||||
}
|
||||
|
||||
private val jumpPower: Double
|
||||
get() = actorValue.getAsDouble(AVKey.JUMPPOWER)!! * (actorValue.getAsDouble(AVKey.JUMPPOWERBUFF) ?: 1.0)
|
||||
|
||||
private fun jumpFunc(len: Int, counter: Int): Double {
|
||||
// linear time mode
|
||||
val init = (len + 1) / 2.0
|
||||
var timedJumpCharge = init - init / len * counter
|
||||
if (timedJumpCharge < 0) timedJumpCharge = 0.0
|
||||
return timedJumpCharge
|
||||
}
|
||||
|
||||
/**
|
||||
* See ./work_files/Jump power by pressing time.gcx
|
||||
*
|
||||
* TODO linear function (play Super Mario Bros. and you'll get what I'm talking about) -- SCRATCH THAT!
|
||||
*/
|
||||
private fun jump() {
|
||||
if (jumping) {// && jumpable) {
|
||||
// increment jump counter
|
||||
if (jumpCounter < MAX_JUMP_LENGTH) jumpCounter += 1
|
||||
|
||||
val timedJumpCharge = jumpFunc(MAX_JUMP_LENGTH, jumpCounter)
|
||||
|
||||
jumpAcc = getJumpAcc(jumpPower, timedJumpCharge)
|
||||
|
||||
controllerMoveDelta?.y?.let { controllerMoveDelta!!.y -= jumpAcc } // feed negative value to the vector
|
||||
// do not think of resetting this to zero when counter hit the ceiling; that's HOW NOT
|
||||
// newtonian physics work, stupid myself :(
|
||||
|
||||
}
|
||||
// not sure we need this...
|
||||
/*else if (!jumpable) {
|
||||
jumpable = true // this is kind of like "semaphore", we toggle it now
|
||||
grounded = false // just in case...
|
||||
}*/
|
||||
|
||||
// release "jump key" of AIs
|
||||
if (jumpCounter >= MAX_JUMP_LENGTH && !isGamer) {
|
||||
isJumpDown = false
|
||||
jumping = false
|
||||
jumpCounter = 0
|
||||
jumpAcc = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActorValueChange(key: String, value: Any?) {
|
||||
// quickslot implementation
|
||||
if (key == AVKey.__PLAYER_QUICKSLOTSEL && value != null) {
|
||||
// ONLY FOR HAND_GRIPs!!
|
||||
val quickBarItem = inventory.getQuickBar(actorValue.getAsInt(key)!!)?.item
|
||||
|
||||
if (quickBarItem != null && quickBarItem.equipPosition == GameItem.EquipPosition.HAND_GRIP) {
|
||||
equipItem(quickBarItem)
|
||||
}
|
||||
|
||||
// force update inventory UI
|
||||
try {
|
||||
((Terrarum.ingame!! as Ingame).uiInventoryPlayer as UIInventoryFull).rebuildList()
|
||||
}
|
||||
catch (LateInitMyArse: kotlin.UninitializedPropertyAccessException) { }
|
||||
}
|
||||
}
|
||||
|
||||
fun isNoClip(): Boolean {
|
||||
return noClip
|
||||
}
|
||||
|
||||
fun setNoClip(b: Boolean) {
|
||||
noClip = b
|
||||
|
||||
if (b) {
|
||||
externalForce.zero()
|
||||
controllerMoveDelta?.zero()
|
||||
}
|
||||
}
|
||||
|
||||
fun Float.abs() = FastMath.abs(this)
|
||||
|
||||
private fun updateSprite(delta: Float) {
|
||||
sprite?.update(delta)
|
||||
spriteGlow?.update(delta)
|
||||
|
||||
//println("$this\tsprite current frame: ${sprite!!.currentFrame}")
|
||||
|
||||
if (walledBottom) {
|
||||
// set anim row
|
||||
if (controllerMoveDelta?.x != 0.0) {
|
||||
sprite?.switchRow(SPRITE_ROW_WALK)
|
||||
spriteGlow?.switchRow(SPRITE_ROW_WALK)
|
||||
}
|
||||
|
||||
// flipping the sprite
|
||||
if (walkHeading == LEFT) {
|
||||
sprite?.flip(true, false)
|
||||
spriteGlow?.flip(true, false)
|
||||
}
|
||||
else {
|
||||
sprite?.flip(false, false)
|
||||
spriteGlow?.flip(false, false)
|
||||
}
|
||||
}
|
||||
else {
|
||||
sprite?.switchRow(SPRITE_ROW_IDLE)
|
||||
spriteGlow?.switchRow(SPRITE_ROW_IDLE)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex.ITEM_DYNAMIC
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex.ITEM_WALLS
|
||||
import net.torvald.terrarum.itemproperties.ItemID
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import java.util.*
|
||||
import java.util.concurrent.locks.Lock
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-03-15.
|
||||
*/
|
||||
|
||||
class ActorInventory(val actor: Pocketed, var maxCapacity: Int, var capacityMode: Int) {
|
||||
|
||||
companion object {
|
||||
@Transient val CAPACITY_MODE_NO_ENCUMBER = 0
|
||||
@Transient val CAPACITY_MODE_COUNT = 1
|
||||
@Transient val CAPACITY_MODE_WEIGHT = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* List of all equipped items (tools, armours, rings, necklaces, etc.)
|
||||
*/
|
||||
val itemEquipped = Array<GameItem?>(GameItem.EquipPosition.INDEX_MAX, { null })
|
||||
|
||||
/**
|
||||
* Sorted by referenceID.
|
||||
*/
|
||||
val itemList = ArrayList<InventoryPair>()
|
||||
val quickBar = Array<ItemID?>(10, { null }) // 0: Slot 1, 9: Slot 10
|
||||
|
||||
var currency = 0 // unified currency for whole civs; Dwarf Fortress approach seems too complicated
|
||||
|
||||
init {
|
||||
}
|
||||
|
||||
fun add(itemID: ItemID, count: Int = 1) = add(ItemCodex[itemID], count)
|
||||
fun add(item: GameItem, count: Int = 1) {
|
||||
|
||||
println("[ActorInventory] add $item, $count")
|
||||
|
||||
|
||||
// not wall-able walls
|
||||
if (item.inventoryCategory == GameItem.Category.WALL &&
|
||||
!BlockCodex[item.dynamicID - ITEM_WALLS.start].isWallable) {
|
||||
throw IllegalArgumentException("Wall ID ${item.dynamicID - ITEM_WALLS.start} is not wall-able.")
|
||||
}
|
||||
|
||||
|
||||
// other invalid values
|
||||
if (count == 0)
|
||||
throw IllegalArgumentException("Item count is zero.")
|
||||
if (count < 0)
|
||||
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.")
|
||||
if (item.originalID == Player.PLAYER_REF_ID || item.originalID == 0x51621D) // do not delete this magic
|
||||
throw IllegalArgumentException("Attempted to put human player into the inventory.")
|
||||
if (((Terrarum.ingame as? Ingame)?.gameFullyLoaded ?: false) &&
|
||||
(item.originalID == (Terrarum.ingame as? Ingame)?.player?.referenceID))
|
||||
throw IllegalArgumentException("Attempted to put active player into the inventory.")
|
||||
if ((!item.stackable || item.dynamicID in ITEM_DYNAMIC) && count > 1)
|
||||
throw IllegalArgumentException("Attempting to adding stack of item but the item is not stackable; item: $item, count: $count")
|
||||
|
||||
|
||||
|
||||
// If we already have the item, increment the amount
|
||||
// If not, add item with specified amount
|
||||
val existingItem = getByDynamicID(item.dynamicID)
|
||||
|
||||
// if the item already exists
|
||||
if (existingItem != null) {
|
||||
// increment count
|
||||
existingItem.amount += count
|
||||
}
|
||||
// new item
|
||||
else {
|
||||
itemList.add(InventoryPair(item, count))
|
||||
}
|
||||
insertionSortLastElem(itemList)
|
||||
}
|
||||
|
||||
fun remove(itemID: ItemID, count: Int) = remove(ItemCodex[itemID], count)
|
||||
/** Will check existence of the item using its Dynamic ID; careful with command order!
|
||||
* e.g. re-assign after this operation */
|
||||
fun remove(item: GameItem, count: Int = 1) {
|
||||
|
||||
println("[ActorInventory] remove $item, $count")
|
||||
|
||||
if (count == 0)
|
||||
throw IllegalArgumentException("Item count is zero.")
|
||||
if (count < 0)
|
||||
throw IllegalArgumentException("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.")
|
||||
|
||||
|
||||
|
||||
val existingItem = getByDynamicID(item.dynamicID)
|
||||
if (existingItem != null) { // if the item already exists
|
||||
val newCount = existingItem.amount - count
|
||||
|
||||
if (newCount < 0) {
|
||||
throw Error("Tried to remove $count of $item, but the inventory only contains ${existingItem.amount} of them.")
|
||||
}
|
||||
else if (newCount > 0) {
|
||||
// decrement count
|
||||
existingItem.amount = newCount
|
||||
}
|
||||
else {
|
||||
// unequip, if applicable
|
||||
actor.unequipItem(existingItem.item)
|
||||
// depleted item; remove entry from inventory
|
||||
itemList.remove(existingItem)
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw Error("Tried to remove $item, but the inventory does not have it.")
|
||||
}
|
||||
}
|
||||
|
||||
fun setQuickBar(slot: Int, dynamicID: ItemID?) {
|
||||
quickBar[slot] = dynamicID
|
||||
}
|
||||
|
||||
fun getQuickBar(slot: Int): InventoryPair? = getByDynamicID(quickBar[slot])
|
||||
|
||||
/**
|
||||
* HashMap<GameItem, Amounts>
|
||||
*/
|
||||
inline fun forEach(consumer: (InventoryPair) -> Unit) = itemList.forEach(consumer)
|
||||
|
||||
/**
|
||||
* Get capacity of inventory
|
||||
* @return
|
||||
*/
|
||||
val capacity: Double
|
||||
get() = if (capacityMode == CAPACITY_MODE_NO_ENCUMBER)
|
||||
maxCapacity.toDouble()
|
||||
else if (capacityMode == CAPACITY_MODE_WEIGHT)
|
||||
getTotalWeight()
|
||||
else
|
||||
getTotalCount().toDouble()
|
||||
|
||||
fun getTotalWeight(): Double = itemList.map { it.item.mass * it.amount }.sum()
|
||||
|
||||
/**
|
||||
* Real amount
|
||||
*/
|
||||
fun getTotalCount(): Int = itemList.map { it.amount }.sum()
|
||||
|
||||
/**
|
||||
* Unique amount, multiple items are calculated as one
|
||||
*/
|
||||
fun getTotalUniqueCount(): Int = itemList.size
|
||||
|
||||
/**
|
||||
* Check whether the itemList contains too many items
|
||||
* @return
|
||||
*/
|
||||
val isEncumbered: Boolean
|
||||
get() = if (capacityMode == CAPACITY_MODE_NO_ENCUMBER)
|
||||
false
|
||||
else if (capacityMode == CAPACITY_MODE_WEIGHT)
|
||||
maxCapacity < capacity
|
||||
else
|
||||
false
|
||||
|
||||
|
||||
fun consumeItem(actor: Actor, item: GameItem) {
|
||||
if (item.stackable && !item.isDynamic) {
|
||||
remove(item, 1)
|
||||
}
|
||||
else {
|
||||
val newItem: GameItem
|
||||
|
||||
// unpack newly-made dynamic item (e.g. any weapon, floppy disk)
|
||||
if (item.isDynamic && item.originalID == item.dynamicID) {
|
||||
itemEquipped[item.equipPosition] = null
|
||||
remove(item, 1)
|
||||
|
||||
|
||||
newItem = item.clone()
|
||||
newItem.generateUniqueDynamicID(this)
|
||||
|
||||
newItem.stackable = false
|
||||
add(newItem)
|
||||
itemEquipped[newItem.equipPosition] = getByDynamicID(newItem.dynamicID)!!.item // will test if some sketchy code is written. Test fail: kotlinNullpointerException
|
||||
|
||||
// FIXME now damage meter (vital) is broken
|
||||
}
|
||||
else {
|
||||
newItem = item
|
||||
}
|
||||
|
||||
|
||||
|
||||
// calculate damage value
|
||||
val baseDamagePerSwing = if (actor is ActorHumanoid)
|
||||
actor.avStrength / 1000.0
|
||||
else
|
||||
1.0 // TODO variable: scale, strength
|
||||
val swingDmgToFrameDmg = Terrarum.deltaTime.toDouble() / actor.actorValue.getAsDouble(AVKey.ACTION_INTERVAL)!!
|
||||
|
||||
// damage the item
|
||||
newItem.durability -= (baseDamagePerSwing * swingDmgToFrameDmg).toFloat()
|
||||
if (newItem.durability <= 0)
|
||||
remove(newItem, 1)
|
||||
|
||||
//println("[ActorInventory] consumed; ${item.durability}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
fun contains(item: GameItem) = contains(item.dynamicID)
|
||||
fun contains(id: ItemID) =
|
||||
if (itemList.size == 0)
|
||||
false
|
||||
else
|
||||
itemList.binarySearch(id, DYNAMIC_ID) >= 0
|
||||
fun getByDynamicID(id: ItemID?): InventoryPair? {
|
||||
if (itemList.size == 0 || id == null)
|
||||
return null
|
||||
|
||||
val index = itemList.binarySearch(id, DYNAMIC_ID)
|
||||
if (index < 0)
|
||||
return null
|
||||
else
|
||||
return itemList[index]
|
||||
}
|
||||
private fun getByStaticID(id: ItemID): InventoryPair? {
|
||||
if (itemList.size == 0)
|
||||
return null
|
||||
|
||||
val index = itemList.binarySearch(id, STATIC_ID)
|
||||
if (index < 0)
|
||||
return null
|
||||
else
|
||||
return itemList[index]
|
||||
}
|
||||
private fun insertionSortLastElem(arr: ArrayList<InventoryPair>) {
|
||||
lock(ReentrantLock()) {
|
||||
var j = arr.lastIndex - 1
|
||||
val x = arr.last()
|
||||
while (j >= 0 && arr[j].item > x.item) {
|
||||
arr[j + 1] = arr[j]
|
||||
j -= 1
|
||||
}
|
||||
arr[j + 1] = x
|
||||
}
|
||||
}
|
||||
private val STATIC_ID = 41324534
|
||||
private val DYNAMIC_ID = 181643953
|
||||
private fun ArrayList<InventoryPair>.binarySearch(ID: ItemID, searchBy: Int): Int {
|
||||
// code from collections/Collections.kt
|
||||
var low = 0
|
||||
var high = this.size - 1
|
||||
|
||||
while (low <= high) {
|
||||
val mid = (low + high).ushr(1) // safe from overflows
|
||||
|
||||
val midVal = if (searchBy == STATIC_ID) this.get(mid).item.originalID else this.get(mid).item.dynamicID
|
||||
|
||||
if (ID > midVal)
|
||||
low = mid + 1
|
||||
else if (ID < midVal)
|
||||
high = mid - 1
|
||||
else
|
||||
return mid // key found
|
||||
}
|
||||
return -(low + 1) // key not found
|
||||
}
|
||||
inline fun lock(lock: Lock, body: () -> Unit) {
|
||||
lock.lock()
|
||||
try {
|
||||
body()
|
||||
}
|
||||
finally {
|
||||
lock.unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class InventoryPair(val item: GameItem, var amount: Int)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-31.
|
||||
*/
|
||||
interface CanBeAnItem {
|
||||
|
||||
fun getItemWeight(): Double
|
||||
|
||||
fun stopUpdateAndDraw()
|
||||
|
||||
fun resumeUpdateAndDraw()
|
||||
|
||||
var itemData: GameItem
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-02-05.
|
||||
*/
|
||||
|
||||
object CreatureBuilder {
|
||||
|
||||
/**
|
||||
* @Param jsonFileName with extension
|
||||
*/
|
||||
operator fun invoke(world: GameWorld, module: String, jsonFileName: String): ActorWithPhysics {
|
||||
val actor = ActorWithPhysics(world, Actor.RenderOrder.MIDDLE)
|
||||
InjectCreatureRaw(actor.actorValue, module, jsonFileName)
|
||||
|
||||
|
||||
actor.actorValue[AVKey.__ACTION_TIMER] = 0.0
|
||||
|
||||
return actor
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameworld.toUint
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import java.io.File
|
||||
import java.nio.charset.Charset
|
||||
import java.util.*
|
||||
|
||||
object DecodeTapestry {
|
||||
|
||||
val colourIndices64 = arrayOf(
|
||||
0x333.fourBitCol(),
|
||||
0x600.fourBitCol(),
|
||||
0xA36.fourBitCol(),
|
||||
0x636.fourBitCol(),
|
||||
0x73B.fourBitCol(),
|
||||
0x427.fourBitCol(),
|
||||
0x44C.fourBitCol(),
|
||||
0x038.fourBitCol(),
|
||||
0x47B.fourBitCol(),
|
||||
0x466.fourBitCol(),
|
||||
0x353.fourBitCol(),
|
||||
0x453.fourBitCol(),
|
||||
0x763.fourBitCol(),
|
||||
0xA63.fourBitCol(),
|
||||
0x742.fourBitCol(),
|
||||
0x000.fourBitCol(),
|
||||
0x666.fourBitCol(),
|
||||
0xA00.fourBitCol(),
|
||||
0xE2A.fourBitCol(),
|
||||
0xD2F.fourBitCol(),
|
||||
0x92F.fourBitCol(),
|
||||
0x548.fourBitCol(),
|
||||
0x32F.fourBitCol(),
|
||||
0x36F.fourBitCol(),
|
||||
0x588.fourBitCol(),
|
||||
0x390.fourBitCol(),
|
||||
0x5F0.fourBitCol(),
|
||||
0x684.fourBitCol(),
|
||||
0xBA2.fourBitCol(),
|
||||
0xE60.fourBitCol(),
|
||||
0x854.fourBitCol(),
|
||||
0x533.fourBitCol(),
|
||||
0x999.fourBitCol(),
|
||||
0xE00.fourBitCol(),
|
||||
0xE6A.fourBitCol(),
|
||||
0xE6F.fourBitCol(),
|
||||
0x848.fourBitCol(),
|
||||
0x62F.fourBitCol(),
|
||||
0x66F.fourBitCol(),
|
||||
0x4AF.fourBitCol(),
|
||||
0x5BA.fourBitCol(),
|
||||
0x8FE.fourBitCol(),
|
||||
0x7F8.fourBitCol(),
|
||||
0x9E0.fourBitCol(),
|
||||
0xFE0.fourBitCol(),
|
||||
0xEA0.fourBitCol(),
|
||||
0xC85.fourBitCol(),
|
||||
0xE55.fourBitCol(),
|
||||
0xCCC.fourBitCol(),
|
||||
0xFFF.fourBitCol(),
|
||||
0xFDE.fourBitCol(),
|
||||
0xEAF.fourBitCol(),
|
||||
0xA3B.fourBitCol(),
|
||||
0x96F.fourBitCol(),
|
||||
0xAAF.fourBitCol(),
|
||||
0x7AF.fourBitCol(),
|
||||
0x3DF.fourBitCol(),
|
||||
0xBFF.fourBitCol(),
|
||||
0xBFB.fourBitCol(),
|
||||
0xAF6.fourBitCol(),
|
||||
0xFEB.fourBitCol(),
|
||||
0xFD7.fourBitCol(),
|
||||
0xE96.fourBitCol(),
|
||||
0xEBA.fourBitCol()
|
||||
)
|
||||
|
||||
val colourIndices16 = arrayOf(
|
||||
0x000.fourBitCol(),
|
||||
0xfff.fourBitCol(),
|
||||
0x666.fourBitCol(),
|
||||
0xccc.fourBitCol(),
|
||||
0xfe0.fourBitCol(),
|
||||
0xe60.fourBitCol(),
|
||||
0xe00.fourBitCol(),
|
||||
0xe2a.fourBitCol(),
|
||||
0x427.fourBitCol(),
|
||||
0x32f.fourBitCol(),
|
||||
0x4af.fourBitCol(),
|
||||
0x5f0.fourBitCol(),
|
||||
0x390.fourBitCol(),
|
||||
0x353.fourBitCol(),
|
||||
0x533.fourBitCol(),
|
||||
0xa63.fourBitCol()
|
||||
)
|
||||
|
||||
private fun Int.fourBitCol() = Color(
|
||||
this.and(0xF00).shl(20) or this.and(0xF00).shl(16) or
|
||||
this.and(0x0F0).shl(16) or this.and(0x0F0).shl(12) or
|
||||
this.and(0x00F).shl(12) or this.and(0x00F).shl(8) or
|
||||
0xFF
|
||||
)
|
||||
|
||||
val MAGIC = "TEAF".toByteArray(charset = Charset.forName("US-ASCII"))
|
||||
val FORMAT_16 = 1
|
||||
val FORMAT_64 = 2
|
||||
|
||||
operator fun invoke(fileObj: File): TapestryObject {
|
||||
fun magicMismatch(magic: ByteArray, array: ByteArray): Boolean {
|
||||
return !Arrays.equals(array.sliceArray(0..magic.lastIndex), magic)
|
||||
}
|
||||
|
||||
val file = fileObj.readBytes()
|
||||
|
||||
val magic = file.copyOfRange(0, 4)
|
||||
|
||||
if (magicMismatch(MAGIC, magic))
|
||||
throw RuntimeException("Invalid file -- type mismatch: expected header " +
|
||||
"${MAGIC[0]} ${MAGIC[1]} ${MAGIC[2]} ${MAGIC[3]}; got " +
|
||||
"${magic[0]} ${magic[1]} ${magic[2]} ${magic[3]}")
|
||||
|
||||
val colourModel = file[4].toUint()
|
||||
|
||||
if (colourModel != FORMAT_16 && colourModel != FORMAT_64)
|
||||
throw RuntimeException("Invalid colour model: $colourModel")
|
||||
|
||||
val width = file[7].toUint().shl(8) + file[6].toUint()
|
||||
|
||||
val artNameBytes = ArrayList<Byte>()
|
||||
val authorNameBytes = ArrayList<Byte>()
|
||||
|
||||
var readCounter = 8
|
||||
|
||||
while (file[readCounter] != 0x00.toByte()) {
|
||||
artNameBytes.add(file[readCounter])
|
||||
readCounter++
|
||||
}
|
||||
|
||||
readCounter++ // jump over null terminator
|
||||
|
||||
while (file[readCounter] != 0x00.toByte()) {
|
||||
authorNameBytes.add(file[readCounter])
|
||||
readCounter++
|
||||
}
|
||||
|
||||
readCounter++ // jump over null terminator
|
||||
|
||||
|
||||
|
||||
val artName = String(artNameBytes.toByteArray(), charset = Charset.forName("UTF-8"))
|
||||
val authorName = String(authorNameBytes.toByteArray(), charset = Charset.forName("UTF-8"))
|
||||
|
||||
val imageDataSize = file.size - readCounter
|
||||
val height = imageDataSize / width
|
||||
val outImageData = Pixmap(width, height, Pixmap.Format.RGBA8888)
|
||||
val counterOffset = readCounter
|
||||
while (readCounter < file.size) {
|
||||
val ofs = readCounter - counterOffset
|
||||
val palIndex = file[readCounter].toUint()
|
||||
|
||||
if (colourModel == FORMAT_16) {
|
||||
outImageData.setColor(colourIndices16[palIndex])
|
||||
outImageData.drawPixel(ofs % width, ofs / width)
|
||||
}
|
||||
else {
|
||||
outImageData.setColor(colourIndices64[palIndex])
|
||||
outImageData.drawPixel(ofs % width, ofs / width)
|
||||
}
|
||||
|
||||
readCounter++
|
||||
}
|
||||
|
||||
return TapestryObject((Terrarum.ingame!! as Ingame).world, outImageData, artName, authorName)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-03-15.
|
||||
*/
|
||||
open class DroppedItem(world: GameWorld, private val item: GameItem) : ActorWithPhysics(world, RenderOrder.MIDTOP) {
|
||||
|
||||
init {
|
||||
if (item.dynamicID >= ItemCodex.ACTORID_MIN)
|
||||
throw RuntimeException("Attempted to create DroppedItem actor of a real actor; the real actor must be dropped instead.")
|
||||
|
||||
isVisible = true
|
||||
|
||||
avBaseMass = if (item.dynamicID < BlockCodex.TILE_UNIQUE_MAX)
|
||||
BlockCodex[item.dynamicID].density / 1000.0
|
||||
else
|
||||
ItemCodex[item.dynamicID].mass
|
||||
|
||||
scale = ItemCodex[item.dynamicID].scale
|
||||
}
|
||||
|
||||
override fun update(delta: Float) {
|
||||
super.update(delta)
|
||||
}
|
||||
|
||||
override fun drawGlow(batch: SpriteBatch) {
|
||||
super.drawGlow(batch)
|
||||
}
|
||||
|
||||
override fun drawBody(batch: SpriteBatch) {
|
||||
super.drawBody(batch)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-06-17.
|
||||
*/
|
||||
open class FixtureBase(world: GameWorld, physics: Boolean = true) :
|
||||
ActorWithPhysics(world, RenderOrder.BEHIND, immobileBody = true, usePhysics = physics) {
|
||||
/**
|
||||
* 0: Open
|
||||
* 1: Blocked
|
||||
* 2: Platform; can be stood on, press DOWN to go down. Also allows other blocks can be places on top of it (e.g. torch)
|
||||
* 3: Wall_left; blocks rightward movement
|
||||
* 4: Wall_right: blocks leftward movement
|
||||
* 5: Same as 2 but player CANNOT go down
|
||||
* For example, flag of 4 is good for tables; player can stand on, which means
|
||||
* downward movement is blocked within the fixtures' AABB.
|
||||
*/
|
||||
var collisionFlag: Int = 0
|
||||
|
||||
companion object {
|
||||
val COLLISION_OPEN = 0
|
||||
val COLLISION_BLOCKED = 1
|
||||
val COLLISION_PLATFORM = 2
|
||||
val COLLISION_WALL_LEFT = 3
|
||||
val COLLISION_WALL_RIGHT = 4
|
||||
val COLLISION_PLATFORM_NOGODOWN = 5
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.gameactors.Hitbox
|
||||
import net.torvald.terrarum.gameactors.Luminous
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-06-17.
|
||||
*/
|
||||
internal class FixtureTikiTorch(world: GameWorld) : FixtureBase(world), Luminous {
|
||||
|
||||
override var color: Color
|
||||
get() = BlockCodex[Block.TORCH].luminosity
|
||||
set(value) {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override val lightBoxList: ArrayList<Hitbox>
|
||||
|
||||
init {
|
||||
density = 1200.0
|
||||
|
||||
setHitboxDimension(10, 24, 0, 0)
|
||||
|
||||
lightBoxList = ArrayList(1)
|
||||
lightBoxList.add(Hitbox(3.0, 0.0, 4.0, 3.0))
|
||||
|
||||
makeNewSprite(TextureRegionPack(ModMgr.getGdxFile("basegame", "sprites/fixtures/tiki_torch.tga"), 10, 27))
|
||||
sprite!!.delay = 0.2f
|
||||
sprite!!.setRowsAndFrames(1, 1)
|
||||
|
||||
actorValue[AVKey.BASEMASS] = 1.0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.WorldTime
|
||||
|
||||
typealias AnyPlayer = HistoricalFigure
|
||||
|
||||
/**
|
||||
* An actor (NPC) which has life and death,
|
||||
* though death might not exist if it has achieved immortality :)
|
||||
*
|
||||
* NOTE: all canonical NPCs are must be HistoricalFigure!! (double excl mark, bitch)
|
||||
*
|
||||
* Created by minjaesong on 2016-10-10.
|
||||
*/
|
||||
open class HistoricalFigure(
|
||||
world: GameWorld,
|
||||
val born: GameDate,
|
||||
val dead: GameDate? = null,
|
||||
realAirFriction: Boolean = false,
|
||||
usePhysics: Boolean = true
|
||||
) : ActorWithPhysics(world, RenderOrder.MIDDLE, realAirFriction, usePhysics) {
|
||||
|
||||
var historicalFigureIdentifier: Int = generateHistoricalFigureIdentifier()
|
||||
internal set
|
||||
|
||||
private fun generateHistoricalFigureIdentifier(): Int {
|
||||
fun hasCollision(value: Int) =
|
||||
try {
|
||||
(Terrarum.ingame!! as Ingame).historicalFigureIDBucket.contains(value)
|
||||
}
|
||||
catch (gameNotInitialisedException: KotlinNullPointerException) {
|
||||
false
|
||||
}
|
||||
|
||||
var ret: Int
|
||||
do {
|
||||
ret = HQRNG().nextInt() // set new ID
|
||||
} while (hasCollision(ret)) // check for collision
|
||||
return ret
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
this.actorValue["_bornyear"] = born.year
|
||||
this.actorValue["_borndays"] = born.yearlyDay
|
||||
|
||||
if (dead != null) {
|
||||
this.actorValue["_deadyear"] = dead.year
|
||||
this.actorValue["_deaddays"] = dead.yearlyDay
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class GameDate(val year: Int, val yearlyDay: Int) {
|
||||
operator fun plus(other: GameDate): GameDate {
|
||||
var newyd = this.yearlyDay + other.yearlyDay
|
||||
var newy = this.year + other.year
|
||||
|
||||
if (newyd > WorldTime.YEAR_DAYS) {
|
||||
newyd -= WorldTime.YEAR_DAYS
|
||||
newy += 1
|
||||
}
|
||||
|
||||
return GameDate(newy, newyd)
|
||||
}
|
||||
|
||||
operator fun minus(other: GameDate): GameDate {
|
||||
var newyd = this.yearlyDay - other.yearlyDay
|
||||
var newy = this.year - other.year
|
||||
|
||||
if (newyd < 0) {
|
||||
newyd += WorldTime.YEAR_DAYS
|
||||
newy -= 1
|
||||
}
|
||||
|
||||
return GameDate(newy, newyd)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameactors.AIControlled
|
||||
import net.torvald.terrarum.gameactors.ai.ActorAI
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.itemproperties.Material
|
||||
|
||||
/**
|
||||
* @param ai AI class. Use LuaAIWrapper for Lua script
|
||||
*
|
||||
* Created by minjaesong on 2016-01-31.
|
||||
*/
|
||||
open class HumanoidNPC(
|
||||
world: GameWorld,
|
||||
override val ai: ActorAI, // it's there for written-in-Kotlin, "hard-wired" AIs
|
||||
born: GameDate,
|
||||
usePhysics: Boolean = true,
|
||||
forceAssignRefID: Int? = null
|
||||
) : ActorHumanoid(world, born, usePhysics = usePhysics), AIControlled, CanBeAnItem {
|
||||
|
||||
companion object {
|
||||
val DEFAULT_COLLISION_TYPE = COLLISION_DYNAMIC
|
||||
}
|
||||
|
||||
init {
|
||||
collisionType = DEFAULT_COLLISION_TYPE
|
||||
}
|
||||
|
||||
// we're having GameItem data so that this class could be somewhat universal
|
||||
override var itemData: GameItem = object : GameItem() {
|
||||
override var dynamicID = referenceID ?: forceAssignRefID!!
|
||||
override val originalID = dynamicID
|
||||
override val isUnique = true
|
||||
override var baseMass: Double
|
||||
get() = actorValue.getAsDouble(AVKey.BASEMASS)!!
|
||||
set(value) { actorValue[AVKey.BASEMASS] = value }
|
||||
override var baseToolSize: Double? = 0.0
|
||||
override var scale: Double
|
||||
get() = actorValue.getAsDouble(AVKey.SCALE)!!
|
||||
set(value) {
|
||||
actorValue[AVKey.SCALE] = value
|
||||
}
|
||||
override var inventoryCategory = "npc"
|
||||
override val originalName: String = actorValue.getAsString(AVKey.NAME) ?: "NPC"
|
||||
override var stackable = true
|
||||
override val isDynamic = false
|
||||
override val material = Material(0,0,0,0,0,0,0,0,0,0.0)
|
||||
|
||||
override fun secondaryUse(delta: Float): Boolean {
|
||||
try {
|
||||
// place the actor to the world
|
||||
this@HumanoidNPC.setPosition(Terrarum.mouseX, Terrarum.mouseY)
|
||||
Terrarum.ingame!!.addNewActor(this@HumanoidNPC)
|
||||
// successful
|
||||
return true
|
||||
}
|
||||
catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemWeight(): Double {
|
||||
return mass
|
||||
}
|
||||
|
||||
override fun stopUpdateAndDraw() {
|
||||
isUpdate = false
|
||||
isVisible = false
|
||||
}
|
||||
|
||||
override fun resumeUpdateAndDraw() {
|
||||
isUpdate = true
|
||||
isVisible = true
|
||||
}
|
||||
|
||||
override fun update(delta: Float) {
|
||||
ai.update(this, delta)
|
||||
super.update(delta)
|
||||
}
|
||||
|
||||
override fun moveLeft(amount: Float) { // hit the buttons on the controller box
|
||||
axisX = -amount
|
||||
}
|
||||
|
||||
override fun moveRight(amount: Float) { // hit the buttons on the controller box
|
||||
axisX = amount
|
||||
}
|
||||
|
||||
override fun moveUp(amount: Float) { // hit the buttons on the controller box
|
||||
axisY = -amount
|
||||
}
|
||||
|
||||
override fun moveDown(amount: Float) { // hit the buttons on the controller box
|
||||
axisY = amount
|
||||
}
|
||||
|
||||
override fun moveJump(amount: Float) { // hit the buttons on the controller box
|
||||
isJumpDown = true
|
||||
}
|
||||
|
||||
/** fly toward arbitrary angle WARNING: the map is looped! */
|
||||
override fun moveTo(bearing: Double) {
|
||||
// if your NPC should fly, override this
|
||||
throw UnsupportedOperationException("Humans cannot fly :p")
|
||||
}
|
||||
|
||||
/** fly toward arbitrary coord WARNING: the map is looped! */
|
||||
override fun moveTo(toX: Double, toY: Double) {
|
||||
// if your NPC should fly, override this
|
||||
throw UnsupportedOperationException("Humans cannot fly :p")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.utils.JsonFetcher
|
||||
import net.torvald.random.Fudge3
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import com.google.gson.JsonObject
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.gameactors.ActorValue
|
||||
import java.security.SecureRandom
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-03-25.
|
||||
*/
|
||||
object InjectCreatureRaw {
|
||||
|
||||
private const val JSONMULT = "mult" // one appears in JSON files
|
||||
|
||||
/**
|
||||
* 'Injects' creature raw ActorValue to the ActorValue reference provided.
|
||||
*
|
||||
* @param actorValueRef ActorValue object to be injected.
|
||||
* @param jsonFileName with extension
|
||||
*/
|
||||
operator fun invoke(actorValueRef: ActorValue, module: String, jsonFileName: String) {
|
||||
val jsonObj = JsonFetcher(ModMgr.getPath(module, "creatures/$jsonFileName"))
|
||||
|
||||
val elementsInt = arrayOf(AVKey.BASEHEIGHT, AVKey.TOOLSIZE, AVKey.ENCUMBRANCE)
|
||||
val elementsString = arrayOf(AVKey.RACENAME, AVKey.RACENAMEPLURAL)
|
||||
val elementsDouble = arrayOf(AVKey.BASEMASS, AVKey.ACCEL)
|
||||
val elementsDoubleVariable = arrayOf(AVKey.STRENGTH, AVKey.SPEED, AVKey.JUMPPOWER, AVKey.SCALE)
|
||||
val elementsBoolean = arrayOf(AVKey.INTELLIGENT)
|
||||
// val elementsMultiplyFromOne = arrayOf()
|
||||
|
||||
setAVInts(actorValueRef, elementsInt, jsonObj)
|
||||
setAVStrings(actorValueRef, elementsString, jsonObj)
|
||||
setAVDoubles(actorValueRef, elementsDouble, jsonObj)
|
||||
setAVDoublesVariable(actorValueRef, elementsDoubleVariable, jsonObj)
|
||||
// setAVMultiplyFromOne(actorValueRef, elementsMultiplyFromOne, jsonObj)
|
||||
setAVBooleans(actorValueRef, elementsBoolean, jsonObj)
|
||||
|
||||
actorValueRef[AVKey.ACCEL] = ActorHumanoid.WALK_ACCEL_BASE
|
||||
actorValueRef[AVKey.ACCELBUFF] = 1.0
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and set actor values that have 'variable' appended. E.g. strength
|
||||
* @param avRef
|
||||
* *
|
||||
* @param elemSet
|
||||
* *
|
||||
* @param jsonObject
|
||||
*/
|
||||
private fun setAVDoublesVariable(avRef: ActorValue, elemSet: Array<String>, jsonObject: JsonObject) {
|
||||
for (s in elemSet) {
|
||||
val baseValue = jsonObject.get(s).asDouble
|
||||
// roll fudge dice and get value [-3, 3] as [0, 6]
|
||||
val varSelected = Fudge3(SecureRandom()).rollForArray()
|
||||
// get multiplier from json. Assuming percentile
|
||||
val multiplier = jsonObject.get(s + JSONMULT).asJsonArray.get(varSelected).asInt
|
||||
val realValue = baseValue * multiplier / 100.0
|
||||
|
||||
avRef[s] = realValue
|
||||
avRef[s + "buff"] = 1.0 // buffed value: use multiplied value as 'base' for all sort of things
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and set string actor values
|
||||
* @param avRef
|
||||
* *
|
||||
* @param elemSet
|
||||
* *
|
||||
* @param jsonObject
|
||||
*/
|
||||
private fun setAVStrings(avRef: ActorValue, elemSet: Array<String>, jsonObject: JsonObject) {
|
||||
for (s in elemSet) {
|
||||
val key = jsonObject.get(s).asString
|
||||
avRef[s] = Lang[key]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and set double actor values
|
||||
* @param avRef
|
||||
* *
|
||||
* @param elemSet
|
||||
* *
|
||||
* @param jsonObject
|
||||
*/
|
||||
private fun setAVDoubles(avRef: ActorValue, elemSet: Array<String>, jsonObject: JsonObject) {
|
||||
for (s in elemSet) {
|
||||
avRef[s] = jsonObject.get(s).asDouble
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and set int actor values
|
||||
* @param avRef
|
||||
* *
|
||||
* @param elemSet
|
||||
* *
|
||||
* @param jsonObject
|
||||
*/
|
||||
private fun setAVInts(avRef: ActorValue, elemSet: Array<String>, jsonObject: JsonObject) {
|
||||
for (s in elemSet) {
|
||||
avRef[s] = jsonObject.get(s).asInt
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and set actor values that should multiplier be applied to the base value of 1.
|
||||
* @param avRef
|
||||
* *
|
||||
* @param elemSet
|
||||
* *
|
||||
* @param jsonObject
|
||||
*/
|
||||
private fun setAVMultiplyFromOne(avRef: ActorValue, elemSet: Array<String>, jsonObject: JsonObject) {
|
||||
for (s in elemSet) {
|
||||
val baseValue = 1.0
|
||||
// roll fudge dice and get value [-3, 3] as [0, 6]
|
||||
val varSelected = Fudge3(SecureRandom()).rollForArray()
|
||||
// get multiplier from json. Assuming percentile
|
||||
val multiplier = jsonObject.get(s).asJsonArray.get(varSelected).asInt
|
||||
val realValue = baseValue * multiplier / 100.0
|
||||
|
||||
avRef[s] = realValue
|
||||
}
|
||||
}
|
||||
|
||||
private fun setAVBooleans(avRef: ActorValue, elemSet: Array<String>, jsonObject: JsonObject) {
|
||||
for (s in elemSet) {
|
||||
avRef[s] = jsonObject.get(s).asBoolean
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-02-20.
|
||||
*/
|
||||
interface LandHolder {
|
||||
|
||||
/**
|
||||
* Absolute tile index. index(x, y) = y * map.width + x
|
||||
* The arraylist will be saved in JSON format with GSON.
|
||||
*/
|
||||
var houseDesignation: ArrayList<Long>?
|
||||
fun addHouseTile(x: Int, y: Int)
|
||||
fun removeHouseTile(x: Int, y: Int)
|
||||
fun clearHouseDesignation()
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorWithPhysics.Companion.SI_TO_GAME_ACC
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer.TILE_SIZE
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.floorInt
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.Hitbox
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import org.dyn4j.geometry.Vector2
|
||||
|
||||
/**
|
||||
* Actors with static sprites and very simple physics
|
||||
*
|
||||
* Created by minjaesong on 2017-01-20.
|
||||
*/
|
||||
open class ParticleBase(renderOrder: Actor.RenderOrder, val despawnUponCollision: Boolean, maxLifeTime: Second? = null) : Runnable {
|
||||
|
||||
/** Will NOT actually delete from the CircularArray */
|
||||
@Volatile var flagDespawn = false
|
||||
|
||||
override fun run() = update(Terrarum.deltaTime)
|
||||
|
||||
var isNoSubjectToGrav = false
|
||||
var dragCoefficient = 3.0
|
||||
|
||||
private val lifetimeMax = maxLifeTime ?: 5f
|
||||
private var lifetimeCounter = 0f
|
||||
|
||||
open val velocity = Vector2(0.0, 0.0)
|
||||
open val hitbox = Hitbox(0.0, 0.0, 0.0, 0.0)
|
||||
|
||||
open lateinit var body: TextureRegion // you might want to use SpriteAnimation
|
||||
open var glow: TextureRegion? = null
|
||||
|
||||
init {
|
||||
|
||||
}
|
||||
|
||||
fun update(delta: Float) {
|
||||
if (!flagDespawn) {
|
||||
lifetimeCounter += delta
|
||||
if (despawnUponCollision) {
|
||||
if (velocity.isZero ||
|
||||
// simple stuck check
|
||||
BlockCodex[(Terrarum.ingame!! as Ingame).world.getTileFromTerrain(
|
||||
hitbox.canonicalX.div(TILE_SIZE).floorInt(),
|
||||
hitbox.canonicalY.div(TILE_SIZE).floorInt()
|
||||
) ?: Block.STONE].isSolid) {
|
||||
flagDespawn = true
|
||||
}
|
||||
}
|
||||
|
||||
if (lifetimeCounter >= lifetimeMax) {
|
||||
flagDespawn = true
|
||||
}
|
||||
|
||||
// gravity, winds, etc. (external forces)
|
||||
if (!isNoSubjectToGrav) {
|
||||
velocity += (Terrarum.ingame!! as Ingame).world.gravitation / dragCoefficient * SI_TO_GAME_ACC
|
||||
}
|
||||
|
||||
|
||||
// combine external forces
|
||||
hitbox.translate(velocity)
|
||||
}
|
||||
}
|
||||
|
||||
fun drawBody(batch: SpriteBatch) {
|
||||
if (!flagDespawn) {
|
||||
batch.draw(body, hitbox.startX.toFloat(), hitbox.startY.toFloat(), hitbox.width.toFloat(), hitbox.height.toFloat())
|
||||
}
|
||||
}
|
||||
|
||||
fun drawGlow(batch: SpriteBatch) {
|
||||
if (!flagDespawn && glow != null) {
|
||||
batch.draw(glow, hitbox.startX.toFloat(), hitbox.startY.toFloat(), hitbox.width.toFloat(), hitbox.height.toFloat())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-12-18.
|
||||
*/
|
||||
class ParticleMegaRain(posX: Double, posY: Double) : ParticleBase(Actor.RenderOrder.BEHIND, true, 3.2f) {
|
||||
|
||||
init {
|
||||
body = MegaRainGovernor.get()
|
||||
val w = body.regionWidth.toDouble()
|
||||
val h = body.regionHeight.toDouble()
|
||||
hitbox.setFromWidthHeight(
|
||||
posX - w.times(0.5),
|
||||
posY - h.times(0.5),
|
||||
w, h
|
||||
)
|
||||
|
||||
velocity.y = 11.5 * ActorWithPhysics.SI_TO_GAME_VEL
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object MegaRainGovernor {
|
||||
|
||||
private var reseedTimer = 0f
|
||||
var reseedTime: Second = 90f
|
||||
|
||||
private val body = Pixmap(ModMgr.getGdxFile("basegame", "weathers/raindrop.tga"))
|
||||
private lateinit var bodies: Array<TextureRegion>
|
||||
|
||||
private var withdrawCounter = 0
|
||||
|
||||
init {
|
||||
seed()
|
||||
}
|
||||
|
||||
private fun seed() {
|
||||
val w = body.width
|
||||
val h = body.height
|
||||
|
||||
bodies = Array(1024) {
|
||||
//val pixmap = Pixmap(Terrarum.WIDTH * 2, Terrarum.HEIGHT / 4, Pixmap.Format.RGBA8888)
|
||||
val pixmap = Pixmap(64, 64, Pixmap.Format.RGBA8888)
|
||||
|
||||
val rng = HQRNG()
|
||||
|
||||
repeat(rng.nextInt(2) + 3) { // 3 or 4
|
||||
val rndX = rng.nextInt(pixmap.width - body.width)
|
||||
val rndY = rng.nextInt(pixmap.height - body.height)
|
||||
|
||||
pixmap.drawPixmap(body, rndX, rndY)
|
||||
}
|
||||
|
||||
// return composed (mega)pixmap
|
||||
val region = TextureRegion(Texture(pixmap))
|
||||
region.flip(false, true)
|
||||
|
||||
/*return*/region
|
||||
}
|
||||
|
||||
// randomise
|
||||
bodies.shuffle()
|
||||
}
|
||||
|
||||
fun get(): TextureRegion {
|
||||
if (withdrawCounter >= bodies.size) {
|
||||
withdrawCounter = 0
|
||||
//bodies.shuffle() // if pre-rendered random set is sufficiently large, it'd look random enough
|
||||
}
|
||||
|
||||
return bodies[withdrawCounter++]
|
||||
}
|
||||
|
||||
@Deprecated("re-seeding freezes the game a little and large enough randomnesses ought to be good")
|
||||
fun update(delta: Float) {
|
||||
if (reseedTimer >= reseedTime) {
|
||||
seed()
|
||||
reseedTimer -= reseedTime
|
||||
}
|
||||
|
||||
reseedTimer += delta
|
||||
}
|
||||
|
||||
fun resize() {
|
||||
seed()
|
||||
withdrawCounter = 0
|
||||
reseedTimer = 0f
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun Array<TextureRegion>.shuffle() {
|
||||
for (i in this.size - 1 downTo 1) {
|
||||
val rndIndex = (Math.random() * (i + 1)).toInt()
|
||||
|
||||
val t = this[rndIndex]
|
||||
this[rndIndex] = this[i]
|
||||
this[i] = t
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-01-20.
|
||||
*/
|
||||
class ParticleTestRain(posX: Double, posY: Double) : ParticleBase(Actor.RenderOrder.BEHIND, true, 6f) {
|
||||
|
||||
init {
|
||||
body = TextureRegion(Texture(ModMgr.getGdxFile("basegame", "weathers/raindrop.tga")))
|
||||
val w = body.regionWidth.toDouble()
|
||||
val h = body.regionHeight.toDouble()
|
||||
hitbox.setFromWidthHeight(
|
||||
posX - w.times(0.5),
|
||||
posY - h.times(0.5),
|
||||
w, h
|
||||
)
|
||||
|
||||
velocity.y = 10.0
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.RoguelikeRandomiser
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-03-05.
|
||||
*/
|
||||
class PhysTestBall(world: GameWorld) : ActorWithPhysics(world, RenderOrder.MIDDLE, immobileBody = true) {
|
||||
|
||||
private var color = Color.GOLD
|
||||
|
||||
init {
|
||||
setHitboxDimension(16, 16, 0, 0)
|
||||
avBaseMass = 10.0
|
||||
density = 200.0
|
||||
|
||||
color = RoguelikeRandomiser.composeColourFrom(RoguelikeRandomiser.POTION_PRIMARY_COLSET)
|
||||
}
|
||||
|
||||
override fun drawBody(batch: SpriteBatch) {
|
||||
Terrarum.inShapeRenderer {
|
||||
it.color = color
|
||||
it.circle(
|
||||
hitbox.startX.toFloat() - 1f,
|
||||
hitbox.startY.toFloat() - 1f,
|
||||
hitbox.width.toFloat()
|
||||
)
|
||||
|
||||
it.circle(
|
||||
hitbox.startX.toFloat() + (Terrarum.ingame!! as Ingame).world.width * TILE_SIZE - 1f,
|
||||
hitbox.startY.toFloat() - 1f,
|
||||
hitbox.width.toFloat()
|
||||
)
|
||||
|
||||
it.circle(
|
||||
hitbox.startX.toFloat() - (Terrarum.ingame!! as Ingame).world.width * TILE_SIZE - 1f,
|
||||
hitbox.startY.toFloat() - 1f,
|
||||
hitbox.width.toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
//println(moveDelta)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.gameactors.Controllable
|
||||
import net.torvald.terrarum.gameactors.Hitbox
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2018-01-17.
|
||||
*/
|
||||
class PhysTestLuarLander(world: GameWorld) : ActorWithPhysics(world, RenderOrder.MIDTOP), Controllable {
|
||||
|
||||
private val texture = Texture(ModMgr.getGdxFile("basegame", "sprites/phystest_lunarlander.tga"))
|
||||
|
||||
override val hitbox: Hitbox
|
||||
|
||||
init {
|
||||
hitbox = Hitbox(0.0, 0.0, 0.0, 0.0)
|
||||
setHitboxDimension(texture.width, texture.height, 0, 0)
|
||||
|
||||
actorValue[AVKey.SPEED] = 8.0
|
||||
avBaseMass = 18650.0
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
super.run()
|
||||
}
|
||||
|
||||
override fun update(delta: Float) {
|
||||
super.update(delta)
|
||||
|
||||
if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
|
||||
controllerMoveDelta!!.y = avSpeedCap
|
||||
}
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun drawGlow(batch: SpriteBatch) {
|
||||
}
|
||||
|
||||
override fun drawBody(batch: SpriteBatch) {
|
||||
batch.color = Color.WHITE
|
||||
batch.draw(texture, hitbox.startX.toFloat(), hitbox.endY.toFloat(), hitbox.width.toFloat(), -hitbox.height.toFloat())
|
||||
}
|
||||
|
||||
override fun onActorValueChange(key: String, value: Any?) {
|
||||
super.onActorValueChange(key, value)
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
super.dispose()
|
||||
texture.dispose()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.gameactors.Controllable
|
||||
|
||||
/**
|
||||
* A wrapper to support instant player changing (or possessing other NPCs maybe)
|
||||
*
|
||||
* @param actor : here you 'attach' the actor you wish to control
|
||||
* Created by minjaesong on 2016-10-23.
|
||||
*/
|
||||
class PlayableActorDelegate(val actor: ActorHumanoid) {
|
||||
|
||||
init {
|
||||
if (actor !is Controllable)
|
||||
throw IllegalArgumentException("Player must be 'Controllable'!")
|
||||
}
|
||||
|
||||
|
||||
fun update(delta: Float) {
|
||||
//val oldTilewisePos = actor.hIntTilewiseHitbox
|
||||
|
||||
actor.update(delta)
|
||||
|
||||
// fire lightmap recalculate event upon tilewise pos change
|
||||
//val newTilewisePos = actor.hIntTilewiseHitbox
|
||||
//if (oldTilewisePos != newTilewisePos) {
|
||||
// LightmapRenderer.fireRecalculateEvent()
|
||||
//}
|
||||
// not going to work: think about stationery tiki torches, global lights, etc
|
||||
}
|
||||
}
|
||||
35
src/net/torvald/terrarum/modulebasegame/gameactors/Player.kt
Normal file
35
src/net/torvald/terrarum/modulebasegame/gameactors/Player.kt
Normal file
@@ -0,0 +1,35 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
|
||||
|
||||
/**
|
||||
* Game player (YOU!)
|
||||
*
|
||||
* Created by minjaesong on 2015-12-31.
|
||||
*/
|
||||
|
||||
class Player(world: GameWorld, born: GameDate) : ActorHumanoid(world, born) {
|
||||
|
||||
companion object {
|
||||
@Transient const val PLAYER_REF_ID: Int = 0x91A7E2
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new Player instance with empty elements (sprites, actorvalue, etc.).
|
||||
|
||||
* **Use PlayerFactory to build player!**
|
||||
|
||||
* @throws SlickException
|
||||
*/
|
||||
init {
|
||||
referenceID = PLAYER_REF_ID // forcibly set ID
|
||||
density = BASE_DENSITY
|
||||
collisionType = COLLISION_KINEMATIC
|
||||
}
|
||||
|
||||
override fun update(delta: Float) {
|
||||
super.update(delta)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-02-03.
|
||||
*/
|
||||
object PlayerBuilder {
|
||||
|
||||
operator fun invoke(): Actor {
|
||||
val p: Actor = Player((Terrarum.ingame!! as Ingame).world, (Terrarum.ingame!! as Ingame).world.time.currentTimeAsGameDate)
|
||||
InjectCreatureRaw(p.actorValue, "basegame", "CreatureHuman.json")
|
||||
|
||||
// attach sprite
|
||||
|
||||
// do etc.
|
||||
p.actorValue[AVKey.__PLAYER_QUICKSLOTSEL] = 0
|
||||
p.actorValue[AVKey.__ACTION_TIMER] = 0.0
|
||||
p.actorValue[AVKey.ACTION_INTERVAL] = ActorHumanoid.BASE_ACTION_INTERVAL
|
||||
|
||||
return p
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameactors.ai.NullAI
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-03-25.
|
||||
*/
|
||||
object PlayerBuilderCynthia {
|
||||
|
||||
operator fun invoke(): ActorWithPhysics {
|
||||
//val p: Player = Player(GameDate(100, 143)) // random value thrown
|
||||
val p: HumanoidNPC = HumanoidNPC(
|
||||
(Terrarum.ingame!! as Ingame).world,
|
||||
NullAI(),
|
||||
GameDate(100, 143)) // random value thrown
|
||||
InjectCreatureRaw(p.actorValue, "basegame", "CreatureHuman.json")
|
||||
|
||||
|
||||
p.actorValue[AVKey.__PLAYER_QUICKSLOTSEL] = 0
|
||||
p.actorValue[AVKey.__ACTION_TIMER] = 0.0
|
||||
p.actorValue[AVKey.ACTION_INTERVAL] = ActorHumanoid.BASE_ACTION_INTERVAL
|
||||
p.actorValue[AVKey.NAME] = "Cynthia"
|
||||
|
||||
|
||||
p.makeNewSprite(TextureRegionPack(ModMgr.getGdxFile("basegame", "sprites/test_player_2.tga"), 26, 42))
|
||||
p.sprite!!.delay = 0.2f
|
||||
p.sprite!!.setRowsAndFrames(1, 1)
|
||||
|
||||
p.setHitboxDimension(15, p.actorValue.getAsInt(AVKey.BASEHEIGHT) ?: ActorHumanoid.BASE_HEIGHT, 9, 0)
|
||||
|
||||
p.setPosition(4096.0 * FeaturesDrawer.TILE_SIZE, 300.0 * FeaturesDrawer.TILE_SIZE)
|
||||
|
||||
|
||||
|
||||
|
||||
p.referenceID = 321321321
|
||||
|
||||
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameactors.faction.FactionFactory
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-02-03.
|
||||
*/
|
||||
|
||||
object PlayerBuilderSigrid {
|
||||
|
||||
operator fun invoke(): Player {
|
||||
val p = Player((Terrarum.ingame!! as Ingame).world, GameDate(-2147483648, 0)) // XD
|
||||
|
||||
p.referenceID = 0x51621D // the only constant of this procedural universe
|
||||
p.historicalFigureIdentifier = 0x51621D // the only constant of this procedural universe
|
||||
|
||||
|
||||
p.makeNewSprite(TextureRegionPack(ModMgr.getGdxFile("basegame", "sprites/test_player.tga"), 28, 51))
|
||||
p.sprite!!.delay = 0.2f
|
||||
p.sprite!!.setRowsAndFrames(1, 1)
|
||||
|
||||
p.makeNewSpriteGlow(TextureRegionPack(ModMgr.getGdxFile("basegame", "sprites/test_player_glow.tga"), 28, 51))
|
||||
p.spriteGlow!!.delay = 0.2f
|
||||
p.spriteGlow!!.setRowsAndFrames(1, 1)
|
||||
|
||||
p.actorValue[AVKey.SCALE] = 1.0
|
||||
p.actorValue[AVKey.SPEED] = 4.0
|
||||
p.actorValue[AVKey.SPEEDBUFF] = 1.0
|
||||
p.actorValue[AVKey.ACCEL] = ActorHumanoid.WALK_ACCEL_BASE
|
||||
p.actorValue[AVKey.ACCELBUFF] = 1.0
|
||||
p.actorValue[AVKey.JUMPPOWER] = 13.0
|
||||
|
||||
p.actorValue[AVKey.BASEMASS] = 80.0
|
||||
p.actorValue[AVKey.SCALEBUFF] = 1.0 // Constant 1.0 for player, meant to be used by random mobs
|
||||
/**
|
||||
* fixed value, or 'base value', from creature strength of Dwarf Fortress.
|
||||
* Human race uses 1000. (see CreatureHuman.json)
|
||||
*/
|
||||
p.actorValue[AVKey.STRENGTH] = 1414 // this is test character, after all.
|
||||
p.actorValue[AVKey.ENCUMBRANCE] = 1000
|
||||
p.actorValue[AVKey.BASEHEIGHT] = 46
|
||||
|
||||
p.actorValue[AVKey.NAME] = "Sigrid"
|
||||
|
||||
p.actorValue[AVKey.INTELLIGENT] = true
|
||||
|
||||
//p.actorValue[AVKey.LUMR] = 0.84
|
||||
//p.actorValue[AVKey.LUMG] = 0.93
|
||||
//p.actorValue[AVKey.LUMB] = 1.37
|
||||
p.actorValue[AVKey.LUMA] = 1.93
|
||||
|
||||
p.actorValue[AVKey.BASEDEFENCE] = 141
|
||||
|
||||
p.actorValue[AVKey.__PLAYER_QUICKSLOTSEL] = 0
|
||||
p.actorValue[AVKey.__ACTION_TIMER] = 0.0
|
||||
p.actorValue[AVKey.ACTION_INTERVAL] = ActorHumanoid.BASE_ACTION_INTERVAL
|
||||
p.actorValue["__aimhelper"] = true // TODO when you'll gonna implement it?
|
||||
|
||||
p.setHitboxDimension(15, p.actorValue.getAsInt(AVKey.BASEHEIGHT)!!, 11, 0)
|
||||
|
||||
p.inventory = ActorInventory(p, 0, ActorInventory.CAPACITY_MODE_NO_ENCUMBER)
|
||||
|
||||
p.faction.add(FactionFactory.create("basegame", "factions/FactionSigrid.json"))
|
||||
|
||||
|
||||
|
||||
// Test fill up inventory
|
||||
val blocks = arrayOf(
|
||||
Block.AIR, Block.DIRT, Block.GLASS_CRUDE,
|
||||
Block.GRASS, Block.GRAVEL, Block.ICE_MAGICAL, Block.LANTERN,
|
||||
Block.PLANK_BIRCH, Block.PLANK_BLOODROSE, Block.PLANK_EBONY, Block.PLANK_NORMAL,
|
||||
Block.SANDSTONE, Block.SANDSTONE_BLACK, Block.SANDSTONE_GREEN,
|
||||
Block.SANDSTONE_RED, Block.STONE, Block.STONE_BRICKS,
|
||||
Block.STONE_QUARRIED, Block.STONE_TILE_WHITE, Block.TORCH,
|
||||
Block.DAYLIGHT_CAPACITOR, Block.ICE_FRAGILE,
|
||||
Block.ILLUMINATOR_WHITE, Block.ILLUMINATOR_BLACK, Block.ILLUMINATOR_ORANGE,
|
||||
Block.ILLUMINATOR_GREEN, Block.ILLUMINATOR_CYAN, Block.SUNSTONE
|
||||
)
|
||||
val walls = arrayOf(
|
||||
Block.AIR, Block.DIRT, Block.GLASS_CRUDE,
|
||||
Block.GRASSWALL, Block.ICE_MAGICAL,
|
||||
Block.PLANK_BIRCH, Block.PLANK_BLOODROSE, Block.PLANK_EBONY, Block.PLANK_NORMAL,
|
||||
Block.SANDSTONE, Block.SANDSTONE_BLACK, Block.SANDSTONE_GREEN,
|
||||
Block.SANDSTONE_RED, Block.STONE, Block.STONE_BRICKS,
|
||||
Block.STONE_QUARRIED, Block.STONE_TILE_WHITE
|
||||
)
|
||||
blocks.forEach { p.addItem(it, 999) }
|
||||
walls.forEach { p.addItem(it + 4096, 999) }
|
||||
p.inventory.add(ItemCodex.ITEM_STATIC.first)
|
||||
|
||||
|
||||
|
||||
|
||||
return p
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-02-10.
|
||||
*/
|
||||
object PlayerBuilderTestSubject1 {
|
||||
operator fun invoke(): Player {
|
||||
val p: Player = Player((Terrarum.ingame!! as Ingame).world, GameDate(100, 143)) // random value thrown
|
||||
InjectCreatureRaw(p.actorValue, "basegame", "CreatureHuman.json")
|
||||
|
||||
|
||||
p.actorValue[AVKey.__PLAYER_QUICKSLOTSEL] = 0
|
||||
p.actorValue[AVKey.__ACTION_TIMER] = 0.0
|
||||
p.actorValue[AVKey.ACTION_INTERVAL] = ActorHumanoid.BASE_ACTION_INTERVAL
|
||||
p.actorValue[AVKey.NAME] = "Test Subject 1"
|
||||
|
||||
|
||||
p.makeNewSprite(TextureRegionPack(ModMgr.getGdxFile("basegame", "sprites/npc_template_anim_prototype.tga"), 48, 52))
|
||||
p.sprite!!.delay = 0.2f
|
||||
p.sprite!!.setRowsAndFrames(2, 4)
|
||||
|
||||
p.setHitboxDimension(15, p.actorValue.getAsInt(AVKey.BASEHEIGHT) ?: ActorHumanoid.BASE_HEIGHT, 21, 0)
|
||||
|
||||
p.setPosition(4096.0 * FeaturesDrawer.TILE_SIZE, 300.0 * FeaturesDrawer.TILE_SIZE)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return p
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-15.
|
||||
*/
|
||||
interface Pocketed {
|
||||
|
||||
var inventory: ActorInventory
|
||||
|
||||
/**
|
||||
* Equips an item. If the item is not in the inventory, an error will be thrown.
|
||||
*/
|
||||
fun unequipItem(item: GameItem?) {
|
||||
if (item == null) return
|
||||
|
||||
if (item.equipPosition == GameItem.EquipPosition.NULL)
|
||||
throw Error("Unequipping the item that cannot be equipped in the first place")
|
||||
|
||||
if (!inventory.contains(item)) {
|
||||
//throw Error("Unequipping the item that does not exist in inventory")
|
||||
System.err.println("[Pocketed] Warning -- Unequipping the item that does not exist in inventory")
|
||||
return // just do nothing
|
||||
}
|
||||
|
||||
inventory.itemEquipped[item.equipPosition] = null
|
||||
item.effectOnUnequip(Terrarum.deltaTime)
|
||||
}
|
||||
|
||||
// no need for equipSlot(Int)
|
||||
fun unequipSlot(slot: Int) {
|
||||
if (slot < 0 || slot > GameItem.EquipPosition.INDEX_MAX)
|
||||
throw IllegalArgumentException("Slot index out of range: $slot")
|
||||
|
||||
unequipItem(inventory.itemEquipped[slot])
|
||||
}
|
||||
|
||||
/**
|
||||
* Equips an item. If the item is not in the inventory, adds the item first.
|
||||
*/
|
||||
fun equipItem(item: GameItem) {
|
||||
if (!inventory.contains(item)) {
|
||||
println("[Pocketed] Item does not exist; adding one before equipped")
|
||||
inventory.add(item)
|
||||
}
|
||||
|
||||
if (item.equipPosition >= 0) {
|
||||
inventory.itemEquipped[item.equipPosition] = item
|
||||
item.effectWhenEquipped(Terrarum.deltaTime)
|
||||
}
|
||||
// else do nothing
|
||||
}
|
||||
|
||||
fun equipped(item: GameItem): Boolean {
|
||||
return inventory.itemEquipped[item.equipPosition] == item
|
||||
}
|
||||
|
||||
fun addItem(itemID: Int, count: Int = 1) = inventory.add(ItemCodex[itemID], count)
|
||||
fun addItem(item: GameItem, count: Int = 1) = inventory.add(item, count)
|
||||
fun removeItem(itemID: Int, count: Int = 1) = inventory.remove(ItemCodex[itemID], count)
|
||||
fun removeItem(item: GameItem, count: Int = 1) = inventory.remove(item, count)
|
||||
|
||||
fun hasItem(item: GameItem) = inventory.contains(item.dynamicID)
|
||||
fun hasItem(id: Int) = inventory.contains(id)
|
||||
|
||||
|
||||
fun consumePrimary(item: GameItem) {
|
||||
if (item.primaryUse(Terrarum.deltaTime)) {
|
||||
inventory.consumeItem(this as Actor, item) // consume on successful
|
||||
}
|
||||
}
|
||||
|
||||
fun consumeSecondary(item: GameItem) {
|
||||
if (item.secondaryUse(Terrarum.deltaTime))
|
||||
inventory.consumeItem(this as Actor, item) // consume on successful
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
/**
|
||||
* Projectile marker. Used to kill them when they're far away from the player, instead of making them sleep.
|
||||
*
|
||||
* Created by minjaesong on 2016-09-05.
|
||||
*/
|
||||
interface Projectile {
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import org.dyn4j.geometry.Vector2
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-08-29.
|
||||
*/
|
||||
class ProjectileHoming(
|
||||
world: GameWorld,
|
||||
type: Int,
|
||||
fromPoint: Vector2, // projected coord
|
||||
toPoint: Vector2 // arriving coord
|
||||
) : ProjectileSimple(world, type, fromPoint, toPoint) {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.point.Point2d
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.gameactors.Hitbox
|
||||
import net.torvald.terrarum.gameactors.Luminous
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Simplest projectile.
|
||||
*
|
||||
* Created by minjaesong on 2016-08-29.
|
||||
*/
|
||||
|
||||
// TODO simplified, lightweight physics (does not call PhysicsSolver)
|
||||
open class ProjectileSimple(
|
||||
world: GameWorld,
|
||||
private val type: Int,
|
||||
fromPoint: Vector2, // projected coord
|
||||
toPoint: Vector2 // arriving coord
|
||||
) : ActorWithPhysics(world, RenderOrder.MIDTOP), Luminous, Projectile {
|
||||
|
||||
val damage: Int
|
||||
val displayColour: Color
|
||||
/** scalar part of velocity */
|
||||
val speed: Int
|
||||
|
||||
|
||||
override var color: Color
|
||||
get() = (bulletDatabase[type][OFFSET_LUMINOSITY] as Color).cpy()
|
||||
set(value) {
|
||||
}
|
||||
/**
|
||||
* Arguments:
|
||||
*
|
||||
* Hitbox(x-offset, y-offset, width, height)
|
||||
* (Use ArrayList for normal circumstances)
|
||||
*/
|
||||
override val lightBoxList = ArrayList<Hitbox>()
|
||||
|
||||
private val lifetimeMax = 2500
|
||||
private var lifetimeCounter = 0f
|
||||
|
||||
private val posPre: Point2d
|
||||
|
||||
init {
|
||||
setPosition(fromPoint.x, fromPoint.y)
|
||||
posPre = Point2d(fromPoint.x, fromPoint.y)
|
||||
// lightbox sized 8x8 centered to the bullet
|
||||
lightBoxList.add(Hitbox(-4.0, -4.0, 8.0, 8.0))
|
||||
//this.externalForce.set(velocity)
|
||||
|
||||
damage = bulletDatabase[type][OFFSET_DAMAGE] as Int
|
||||
displayColour = bulletDatabase[type][OFFSET_COL] as Color
|
||||
isNoSubjectToGrav = bulletDatabase[type][OFFSET_NOGRAVITY] as Boolean
|
||||
speed = bulletDatabase[type][OFFSET_SPEED] as Int
|
||||
|
||||
setHitboxDimension(2, 2, 0, 0) // should be following sprite's properties if there IS one
|
||||
|
||||
|
||||
externalForce.set((fromPoint to toPoint).setMagnitude(speed.toDouble()))
|
||||
|
||||
|
||||
|
||||
collisionType = COLLISION_KINEMATIC
|
||||
}
|
||||
|
||||
override fun update(delta: Float) {
|
||||
// hit something and despawn
|
||||
lifetimeCounter += delta
|
||||
if (walledTop || walledBottom || walledRight || walledLeft || lifetimeCounter >= lifetimeMax ||
|
||||
// stuck check
|
||||
BlockCodex[(Terrarum.ingame!! as Ingame).world.getTileFromTerrain(feetPosTile[0], feetPosTile[1]) ?: Block.STONE].isSolid
|
||||
) {
|
||||
flagDespawn()
|
||||
}
|
||||
|
||||
posPre.set(centrePosPoint)
|
||||
|
||||
super.update(delta)
|
||||
}
|
||||
|
||||
/**
|
||||
* WARNING! ends and begins Batch
|
||||
*/
|
||||
override fun drawBody(batch: SpriteBatch) {
|
||||
val colourTail = displayColour.cpy() // clone a colour
|
||||
colourTail.a = 0.16f
|
||||
|
||||
/*batch.end()
|
||||
Terrarum.inShapeRenderer {
|
||||
// draw trail of solid colour (Terraria style maybe?)
|
||||
it.lineWidth = 2f * Terrarum.ingame!!.screenZoom
|
||||
g.drawGradientLine(
|
||||
hitbox.centeredX.toFloat() * Terrarum.ingame!!.screenZoom,
|
||||
hitbox.centeredY.toFloat() * Terrarum.ingame!!.screenZoom,
|
||||
displayColour,
|
||||
posPre.x.toFloat() * Terrarum.ingame!!.screenZoom,
|
||||
posPre.y.toFloat() * Terrarum.ingame!!.screenZoom,
|
||||
colourTail
|
||||
)
|
||||
}
|
||||
batch.begin()*/
|
||||
}
|
||||
|
||||
override fun drawGlow(batch: SpriteBatch) = drawBody(batch)
|
||||
|
||||
companion object {
|
||||
val OFFSET_DAMAGE = 0
|
||||
val OFFSET_COL = 1 // Color or SpriteAnimation
|
||||
val OFFSET_NOGRAVITY = 2
|
||||
val OFFSET_SPEED = 3
|
||||
val OFFSET_LUMINOSITY = 4
|
||||
val bulletDatabase = arrayOf(
|
||||
// damage, display colour, no gravity, speed
|
||||
arrayOf(7, Color(0xFF5429_FF.toInt()), true, 40, 32),
|
||||
arrayOf(8, Color(0xFF5429_FF.toInt()), true, 20, 0)
|
||||
// ...
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-01-07.
|
||||
*/
|
||||
class TapestryObject(world: GameWorld, pixmap: Pixmap, val artName: String, val artAuthor: String) : FixtureBase(world, physics = false) {
|
||||
|
||||
// physics = false only speeds up for ~2 frames with 50 tapestries
|
||||
|
||||
init {
|
||||
val texture = Texture(pixmap)
|
||||
pixmap.dispose()
|
||||
texture.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
|
||||
val texturePack = TextureRegionPack(texture, texture.width, texture.height)
|
||||
|
||||
makeNewSprite(texturePack)
|
||||
setHitboxDimension(texture.width, texture.height, 0, 0)
|
||||
setPosition(Terrarum.mouseX, Terrarum.mouseY)
|
||||
// you CAN'T destroy the image
|
||||
}
|
||||
|
||||
override fun update(delta: Float) {
|
||||
super.update(delta)
|
||||
}
|
||||
|
||||
override fun drawBody(batch: SpriteBatch) {
|
||||
super.drawBody(batch)
|
||||
}
|
||||
|
||||
override var tooltipText: String? = "$artName\n$artAuthor"
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-05-25.
|
||||
*/
|
||||
class ThreadActorUpdate(val startIndex: Int, val endIndex: Int) : Runnable {
|
||||
override fun run() {
|
||||
for (i in startIndex..endIndex) {
|
||||
val it = Terrarum.ingame!!.actorContainer[i]
|
||||
it.update(Terrarum.deltaTime)
|
||||
|
||||
if (it is Pocketed) {
|
||||
it.inventory.forEach { inventoryEntry ->
|
||||
inventoryEntry.item.effectWhileInPocket(Terrarum.deltaTime)
|
||||
if (it.equipped(inventoryEntry.item)) {
|
||||
inventoryEntry.item.effectWhenEquipped(Terrarum.deltaTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import net.torvald.terrarum.gameactors.Hitbox
|
||||
import net.torvald.terrarum.gameactors.Luminous
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-04-26.
|
||||
*/
|
||||
class WeaponSwung(world: GameWorld, val itemID: Int) : ActorWithPhysics(world, RenderOrder.MIDTOP), Luminous {
|
||||
// just let the solver use AABB; it's cheap but works just enough
|
||||
|
||||
/**
|
||||
* Recommended implementation:
|
||||
*
|
||||
override var color: Int
|
||||
get() = actorValue.getAsInt(AVKey.LUMINOSITY) ?: 0
|
||||
set(value) {
|
||||
actorValue[AVKey.LUMINOSITY] = value
|
||||
}
|
||||
*/
|
||||
override var color: Color
|
||||
get() = throw UnsupportedOperationException()
|
||||
set(value) {
|
||||
}
|
||||
/**
|
||||
* Arguments:
|
||||
*
|
||||
* Hitbox(x-offset, y-offset, width, height)
|
||||
* (Use ArrayList for normal circumstances)
|
||||
*/
|
||||
override val lightBoxList: List<Hitbox>
|
||||
get() = throw UnsupportedOperationException()
|
||||
|
||||
init {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors.ai
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.HumanoidNPC
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import net.torvald.terrarum.gameactors.ai.ActorAI
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Slime's stupid AI but can adjust his jump power to smack you as fast as possible
|
||||
* by achieving "allostasis".
|
||||
*
|
||||
* Created by minjaesong on 2017-12-10.
|
||||
*/
|
||||
class SmarterSlimes : ActorAI {
|
||||
|
||||
val memoryCells = IntArray(12, { 0 })
|
||||
// index 0: most recent memory
|
||||
// intentionally making it stupid by using less precise INT
|
||||
// also we're not discrimination different enemies, making it further dumb
|
||||
// stores "overshoot" amount (learn target) of x position
|
||||
|
||||
var maxJumpDist: Double = -1.0
|
||||
|
||||
var cooltime: Second = 5f
|
||||
|
||||
override fun update(actor: Actor, delta: Float) {
|
||||
val actor = actor as HumanoidNPC
|
||||
|
||||
|
||||
// sensor: compare(my X pos, nearest enemy's X pos)
|
||||
maxJumpDist = actor.avSpeedCap * actor.jumpAirTime // speed * air_time
|
||||
// (to be precise, we need simulation just like jumpAirTime, but oh well; we like it LINEAR)
|
||||
|
||||
|
||||
// TEST: just target player
|
||||
val playerXPos = (Terrarum.ingame!! as Ingame).player.centrePosPoint.x
|
||||
val thisXPos = actor.centrePosPoint.x
|
||||
val xDiff = thisXPos - playerXPos
|
||||
|
||||
|
||||
|
||||
// extrapolate from memories:
|
||||
// otherwise linear extp. except the slope is d of 0th and 2nd point
|
||||
|
||||
|
||||
|
||||
if (xDiff > 0) {
|
||||
actor.moveLeft()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors.physicssolver
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorWithPhysics
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-04-22.
|
||||
*/
|
||||
object CollisionSolver {
|
||||
|
||||
private const val STARTPOINT = 1
|
||||
private const val ENDPOINT = 2
|
||||
|
||||
private const val COLL_LIST_SIZE = 256
|
||||
private const val COLL_CANDIDATES_SIZE = 128
|
||||
private const val COLL_FINAL_CANDIDATES_SIZE = 16
|
||||
|
||||
private val collListX = ArrayList<CollisionMarkings>(COLL_LIST_SIZE)
|
||||
private val collListY = ArrayList<CollisionMarkings>(COLL_LIST_SIZE)
|
||||
|
||||
private val collCandidateX = ArrayList<Pair<ActorWithPhysics, ActorWithPhysics>>(COLL_CANDIDATES_SIZE)
|
||||
private val collCandidateY = ArrayList<Pair<ActorWithPhysics, ActorWithPhysics>>(COLL_CANDIDATES_SIZE)
|
||||
private var collCandidates = ArrayList<Pair<ActorWithPhysics, ActorWithPhysics>>(COLL_FINAL_CANDIDATES_SIZE)
|
||||
|
||||
private val collCandidateStack = Stack<CollisionMarkings>()
|
||||
|
||||
/**
|
||||
* to see what's going on here, visit
|
||||
* [this link](https://www.toptal.com/game/video-game-physics-part-ii-collision-detection-for-solid-objects)
|
||||
*/
|
||||
fun process() {
|
||||
// TODO threading X and Y
|
||||
// clean up before we go
|
||||
collListX.clear()
|
||||
collListY.clear()
|
||||
collCandidateX.clear()
|
||||
collCandidateY.clear()
|
||||
|
||||
// mark list x
|
||||
(Terrarum.ingame!! as Ingame).actorContainer.forEach { it ->
|
||||
if (it is ActorWithPhysics) {
|
||||
collListX.add(CollisionMarkings(it.hitbox.hitboxStart.x, STARTPOINT, it))
|
||||
collListX.add(CollisionMarkings(it.hitbox.hitboxEnd.x, ENDPOINT, it))
|
||||
}
|
||||
}
|
||||
// sort list x
|
||||
collListX.sortBy { it.pos }
|
||||
|
||||
// set candidateX
|
||||
collListX.forEach {
|
||||
if (it.kind == STARTPOINT) {
|
||||
collCandidateStack.push(it)
|
||||
}
|
||||
else if (it.kind == ENDPOINT) {
|
||||
val mark_this = it
|
||||
val mark_other = collCandidateStack.pop()
|
||||
// make sure actor with lower ID comes first
|
||||
val collCandidate = if (mark_this.actor < mark_other.actor)
|
||||
Pair(mark_this.actor, mark_other.actor)
|
||||
else
|
||||
Pair(mark_other.actor, mark_this.actor)
|
||||
|
||||
// filter out Pair(E, E); Pair(A, B) if Pair(B, A) exists
|
||||
if (mark_this.actor != mark_other.actor) {
|
||||
collCandidateX.add(collCandidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collCandidateStack.clear()
|
||||
|
||||
// mark list y
|
||||
(Terrarum.ingame!! as Ingame).actorContainer.forEach { it ->
|
||||
if (it is ActorWithPhysics) {
|
||||
collListY.add(CollisionMarkings(it.hitbox.hitboxStart.y, STARTPOINT, it))
|
||||
collListY.add(CollisionMarkings(it.hitbox.hitboxEnd.y, ENDPOINT, it))
|
||||
}
|
||||
}
|
||||
// sort list y
|
||||
collListY.sortBy { it.pos }
|
||||
|
||||
// set candidateY
|
||||
collListY.forEach {
|
||||
if (it.kind == STARTPOINT) {
|
||||
collCandidateStack.push(it)
|
||||
}
|
||||
else if (it.kind == ENDPOINT) {
|
||||
val mark_this = it
|
||||
val mark_other = collCandidateStack.pop()
|
||||
val collCandidate: Pair<ActorWithPhysics, ActorWithPhysics>
|
||||
// make sure actor with lower ID comes first
|
||||
if (mark_this.actor < mark_other.actor)
|
||||
collCandidate = Pair(mark_this.actor, mark_other.actor)
|
||||
else
|
||||
collCandidate = Pair(mark_other.actor, mark_this.actor)
|
||||
|
||||
// filter out Pair(E, E); Pair(A, B) if Pair(B, A) exists
|
||||
if (mark_this.actor != mark_other.actor) {
|
||||
collCandidateY.add(collCandidate)
|
||||
}
|
||||
}
|
||||
}
|
||||
// look for overlaps in candidate X/Y and put them into collCandidates
|
||||
// overlapping in X and Y means they are actually overlapping physically
|
||||
collCandidateY.retainAll(collCandidateX) // list Y will have intersection of X and Y now
|
||||
collCandidates = collCandidateY // renaming. X and Y won't be used anyway.
|
||||
|
||||
//collCandidates.forEach { println(it) }
|
||||
//println("-----------------------")
|
||||
|
||||
// solve collision for actors in collCandidates
|
||||
collCandidates.forEach { solveCollision(it.first, it.second) }
|
||||
}
|
||||
|
||||
private fun pairEqv(a: Pair<Any?, Any?>, b: Pair<Any?, Any?>) =
|
||||
(a.first == b.first && a.second == b.second) ||
|
||||
(a.first == b.second && a.second == b.first)
|
||||
|
||||
/** Mimics java's original behaviour, with user-defined equals function */
|
||||
fun ArrayList<Any?>.containsByFunc(other: Any?, equalsFun: (a: Any?, b: Any?) -> Boolean): Boolean {
|
||||
fun indexOfEqFn(arrayList: ArrayList<Any?>, o: Any?): Int {
|
||||
if (o == null) {
|
||||
for (i in 0..size - 1)
|
||||
if (arrayList[i] == null)
|
||||
return i
|
||||
}
|
||||
else {
|
||||
for (i in 0..size - 1)
|
||||
if (equalsFun(o, arrayList[i]))
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
return indexOfEqFn(this, other) >= 0
|
||||
}
|
||||
|
||||
private fun solveCollision(a: ActorWithPhysics, b: ActorWithPhysics) {
|
||||
// some of the Pair(a, b) are either duplicates or erroneously reported.
|
||||
// e.g. (A, B), (B, C) and then (A, C);
|
||||
// in some situation (A, C) will not making any contact with each other
|
||||
// we are going to filter them
|
||||
if (a isCollidingWith b) {
|
||||
// notify collision, but not solve it yet
|
||||
|
||||
//println("Collision: $a <-> $b")
|
||||
// FIXME does work but has duplication
|
||||
|
||||
// if they actually makes collision (e.g. player vs ball), solve it
|
||||
if (a makesCollisionWith b) {
|
||||
val a_moveDelta = a.externalForce + a.controllerMoveDelta
|
||||
val b_moveDelta = b.externalForce + b.controllerMoveDelta
|
||||
|
||||
val ux_1 = a_moveDelta.x
|
||||
val ux_2 = b_moveDelta.x
|
||||
val uy_1 = a_moveDelta.y
|
||||
val uy_2 = b_moveDelta.y
|
||||
val m1 = a.mass
|
||||
val m2 = b.mass
|
||||
|
||||
val vx_1 = (ux_2 * (m1 - m2) + 2 * m2 * ux_2) / (m1 + m2)
|
||||
val vx_2 = (ux_2 * (m2 - m1) + 2 * m1 * ux_1) / (m1 + m2)
|
||||
val vy_1 = (uy_2 * (m1 - m2) + 2 * m2 * uy_2) / (m1 + m2)
|
||||
val vy_2 = (uy_2 * (m2 - m1) + 2 * m1 * uy_1) / (m1 + m2)
|
||||
|
||||
/*a.veloX = vx_1
|
||||
a.veloY = vy_1
|
||||
b.veloX = vx_2
|
||||
b.veloY = vy_2*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private infix fun ActorWithPhysics.makesCollisionWith(other: ActorWithPhysics) =
|
||||
this.collisionType != ActorWithPhysics.COLLISION_NOCOLLIDE &&
|
||||
other.collisionType != ActorWithPhysics.COLLISION_NOCOLLIDE
|
||||
|
||||
private infix fun ActorWithPhysics.isCollidingWith(other: ActorWithPhysics): Boolean {
|
||||
val ax = this.hitbox.centeredX
|
||||
val ay = this.hitbox.centeredY
|
||||
val bx = other.hitbox.centeredX
|
||||
val by = other.hitbox.centeredY
|
||||
|
||||
// will refer 'actor_dist_t' as 't' afterward
|
||||
val actor_dist_t_sqr = ((ay - by).sqr() + (ax - bx).sqr()) // no sqrt; 'power' is slower than 'times'
|
||||
val dist_x = (ax - bx).abs() // 'tx'
|
||||
val dist_y = (ay - by).abs() // 'ty'
|
||||
val tangent = dist_y / dist_x
|
||||
|
||||
var t_ax: Double; var t_ay: Double
|
||||
if (dist_x > dist_y) {
|
||||
t_ax = this.hitbox.width / 2
|
||||
t_ay = t_ax * tangent
|
||||
}
|
||||
else {
|
||||
t_ay = this.hitbox.height / 2
|
||||
t_ax = t_ay * tangent
|
||||
}
|
||||
|
||||
return (t_ax.sqr() + t_ay.sqr()) < actor_dist_t_sqr
|
||||
}
|
||||
|
||||
fun Double.abs() = if (this < 0) -this else this
|
||||
fun Double.sqr() = this * this
|
||||
|
||||
data class CollisionMarkings(
|
||||
val pos: Double,
|
||||
val kind: Int,
|
||||
val actor: ActorWithPhysics
|
||||
)
|
||||
|
||||
/**
|
||||
* === Some useful physics knowledge ===
|
||||
*
|
||||
* * Momentum = mass × Velocity (p = mv, conserved)
|
||||
*
|
||||
* * Force = mass × acceleration (f = ma, conserved)
|
||||
*
|
||||
* * F_AB = -F_BA (Lex Tertia, does NOT apply to fictitious force like centrifugal)
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors.physicssolver
|
||||
|
||||
/**
|
||||
* multithreaded version of CollisionSolver#solveCollision
|
||||
* Created by minjaesong on 2016-04-26.
|
||||
*/
|
||||
internal class SolveByUnit : Runnable {
|
||||
override fun run() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors.physicssolver
|
||||
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorWithPhysics
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-05-01.
|
||||
*/
|
||||
object VelocitySolver {
|
||||
|
||||
fun process() {
|
||||
|
||||
}
|
||||
|
||||
private fun applyGravity(actor: ActorWithPhysics) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameworld
|
||||
|
||||
import net.torvald.terrarum.gameactors.ActorID
|
||||
|
||||
/**
|
||||
* The whole world is economically isolated system. Economy will be important to make player keep playing,
|
||||
* when all the necessary contents are set and implemented to the production.
|
||||
*
|
||||
* Design goal: keep the inflation rate low, but not negative (Single market)
|
||||
* OR, give each faction (establishment) its own economy and watch them prosper/doomed (DF style)
|
||||
*
|
||||
* Created by minjaesong on 2017-04-23.
|
||||
*/
|
||||
class GameEconomy {
|
||||
|
||||
val transactionHistory = TransanctionHistory()
|
||||
|
||||
}
|
||||
|
||||
class TransanctionHistory {
|
||||
|
||||
private val entries = ArrayList<TransanctionHistory>()
|
||||
|
||||
/**
|
||||
* @param to set 0 to indicate the money was lost to void
|
||||
*/
|
||||
data class TransactionEntry(val from: ActorID, val to: ActorID, val amount: Long) {
|
||||
override fun toString() = "$from -> $to; $amount"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameworld
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.AnyPlayer
|
||||
import net.torvald.terrarum.roundInt
|
||||
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
||||
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.gameworld.FluidCodex
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-08-03.
|
||||
*/
|
||||
object WorldSimulator {
|
||||
/**
|
||||
* In tiles;
|
||||
* square width/height = field * 2
|
||||
*/
|
||||
const val FLUID_UPDATING_SQUARE_RADIUS = 64 // larger value will have dramatic impact on performance
|
||||
const private val DOUBLE_RADIUS = FLUID_UPDATING_SQUARE_RADIUS * 2
|
||||
|
||||
private val fluidMap = Array<ByteArray>(DOUBLE_RADIUS, { ByteArray(DOUBLE_RADIUS) })
|
||||
private val fluidTypeMap = Array<ByteArray>(DOUBLE_RADIUS, { ByteArray(DOUBLE_RADIUS) })
|
||||
|
||||
const val DISPLACE_CAP = 4
|
||||
const val FLUID_MAX = 16
|
||||
|
||||
var updateXFrom = 0
|
||||
var updateXTo = 0
|
||||
var updateYFrom = 0
|
||||
var updateYTo = 0
|
||||
|
||||
val colourNone = Color(0x808080FF.toInt())
|
||||
val colourWater = Color(0x66BBFFFF.toInt())
|
||||
|
||||
private val world = (Terrarum.ingame!! as Ingame).world
|
||||
|
||||
operator fun invoke(p: AnyPlayer?, delta: Float) {
|
||||
if (p != null) {
|
||||
updateXFrom = p.hitbox.centeredX.div(FeaturesDrawer.TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundInt()
|
||||
updateYFrom = p.hitbox.centeredY.div(FeaturesDrawer.TILE_SIZE).minus(FLUID_UPDATING_SQUARE_RADIUS).roundInt()
|
||||
updateXTo = updateXFrom + DOUBLE_RADIUS
|
||||
updateYTo = updateYFrom + DOUBLE_RADIUS
|
||||
}
|
||||
|
||||
moveFluids(delta)
|
||||
displaceFallables(delta)
|
||||
}
|
||||
|
||||
/**
|
||||
* displace fluids. Note that the code assumes the gravity pulls things downward ONLY,
|
||||
* which means you'll need to modify the code A LOT if you're going to implement zero- or
|
||||
* reverse-gravity.
|
||||
*
|
||||
* Procedure: CP world fluidmap -> sim on fluidmap -> CP fluidmap world
|
||||
* TODO multithread
|
||||
*/
|
||||
fun moveFluids(delta: Float) {
|
||||
////////////////////
|
||||
// build fluidmap //
|
||||
////////////////////
|
||||
purgeFluidMap()
|
||||
worldToFluidMap(world)
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// displace fluids. Record displacements into the fluidMap //
|
||||
/////////////////////////////////////////////////////////////
|
||||
for (y in updateYFrom..updateYTo) {
|
||||
for (x in updateXFrom..updateXTo) {
|
||||
val tile = world.getTileFromTerrain(x, y) ?: Block.STONE
|
||||
val tileBottom = world.getTileFromTerrain(x, y + 1) ?: Block.STONE
|
||||
val tileLeft = world.getTileFromTerrain(x - 1, y) ?: Block.STONE
|
||||
val tileRight = world.getTileFromTerrain(x + 1, y) ?: Block.STONE
|
||||
if (tile.isFluid()) {
|
||||
|
||||
// move down if not obstructed
|
||||
/*if (!tileBottom.isSolid()) {
|
||||
val drainage = drain(world, x, y, DISPLACE_CAP)
|
||||
pour(world, x, y + 1, drainage)
|
||||
}
|
||||
// left and right both open
|
||||
else if (!tileLeft.isSolid() && !tileRight.isSolid()) {
|
||||
// half-breaker
|
||||
val moreToTheRight = HQRNG().nextBoolean()
|
||||
val displacement = drain(world, x, y, DISPLACE_CAP)
|
||||
|
||||
if (displacement.isEven()) {
|
||||
pour(world, x - 1, y, displacement shr 1)
|
||||
pour(world, x + 1, y, displacement shr 1)
|
||||
}
|
||||
else {
|
||||
pour(world, x - 1, y, (displacement shr 1) + if (moreToTheRight) 0 else 1)
|
||||
pour(world, x + 1, y, (displacement shr 1) + if (moreToTheRight) 1 else 0)
|
||||
}
|
||||
}
|
||||
// left open
|
||||
else if (!tileLeft.isSolid()) {
|
||||
val displacement = drain(world, x, y, DISPLACE_CAP)
|
||||
pour(world, x - 1, y, displacement)
|
||||
}
|
||||
// right open
|
||||
else if (!tileRight.isSolid()) {
|
||||
val displacement = drain(world, x, y, DISPLACE_CAP)
|
||||
pour(world, x + 1, y, displacement)
|
||||
}
|
||||
// nowhere open; do default (fill top)
|
||||
else {
|
||||
pour(world, x, y - 1, DISPLACE_CAP)
|
||||
}*/
|
||||
if (!tileBottom.isSolid()) {
|
||||
pour(x, y + 1, drain(x, y, FLUID_MAX))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
// replace fluids in the map according to fluidMap //
|
||||
/////////////////////////////////////////////////////
|
||||
fluidMapToWorld(world)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* displace fallable tiles. It is scanned bottom-left first. To achieve the sens ofreal
|
||||
* falling, each tiles are displaced by ONLY ONE TILE below.
|
||||
*/
|
||||
fun displaceFallables(delta: Float) {
|
||||
for (y in updateYFrom..updateYTo) {
|
||||
for (x in updateXFrom..updateXTo) {
|
||||
val tile = world.getTileFromTerrain(x, y) ?: Block.STONE
|
||||
val tileBelow = world.getTileFromTerrain(x, y + 1) ?: Block.STONE
|
||||
|
||||
if (tile.isFallable()) {
|
||||
// displace fluid. This statement must precede isSolid()
|
||||
if (tileBelow.isFluid()) {
|
||||
// remove tileThis to create air pocket
|
||||
world.setTileTerrain(x, y, Block.AIR)
|
||||
|
||||
pour(x, y, drain(x, y, tileBelow.fluidLevel().toInt()))
|
||||
// place our tile
|
||||
world.setTileTerrain(x, y + 1, tile)
|
||||
}
|
||||
else if (!tileBelow.isSolid()) {
|
||||
world.setTileTerrain(x, y, Block.AIR)
|
||||
world.setTileTerrain(x, y + 1, tile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun disperseHeat(delta: Float) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
fun drawFluidMapDebug(batch: SpriteBatch) {
|
||||
batch.color = colourWater
|
||||
|
||||
for (y in 0..fluidMap.size - 1) {
|
||||
for (x in 0..fluidMap[0].size - 1) {
|
||||
val data = fluidMap[y][x]
|
||||
if (BlocksDrawer.tileInCamera(x + updateXFrom, y + updateYFrom)) {
|
||||
if (data == 0.toByte())
|
||||
batch.color = colourNone
|
||||
else
|
||||
batch.color = colourWater
|
||||
|
||||
Terrarum.fontSmallNumbers.draw(batch,
|
||||
data.toString(),
|
||||
updateXFrom.plus(x).times(FeaturesDrawer.TILE_SIZE).toFloat()
|
||||
+ if (data < 10) 4f else 0f,
|
||||
updateYFrom.plus(y).times(FeaturesDrawer.TILE_SIZE) + 4f
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
//if (data > 0) println(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun purgeFluidMap() {
|
||||
for (y in 1..DOUBLE_RADIUS) {
|
||||
for (x in 1..DOUBLE_RADIUS) {
|
||||
fluidMap[y - 1][x - 1] = 0
|
||||
fluidTypeMap[y - 1][x - 1] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun worldToFluidMap(world: GameWorld) {
|
||||
for (y in updateYFrom..updateYTo) {
|
||||
for (x in updateXFrom..updateXTo) {
|
||||
val tile = world.getTileFromTerrain(x, y) ?: Block.STONE
|
||||
if (tile.isFluid()) {
|
||||
fluidMap[y - updateYFrom][x - updateXFrom] = tile.fluidLevel().toByte()
|
||||
fluidTypeMap[y - updateYFrom][x - updateXFrom] = tile.fluidType().toByte()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fluidMapToWorld(world: GameWorld) {
|
||||
for (y in 0..fluidMap.size - 1) {
|
||||
for (x in 0..fluidMap[0].size - 1) {
|
||||
placeFluid(world, updateXFrom + x, updateYFrom + y
|
||||
, FluidCodex.FLUID_WATER, fluidMap[y][x] - 1
|
||||
)
|
||||
// FIXME test code: deals with water only!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Int.isFluid() = BlockCodex[this].isFluid
|
||||
fun Int.isSolid() = this.fluidLevel() == FLUID_MAX || BlockCodex[this].isSolid
|
||||
//fun Int.viscosity() = BlockCodex[this].
|
||||
fun Int.fluidLevel() = if (!this.isFluid()) 0 else (this % FLUID_MAX).plus(1)
|
||||
fun Int.fluidType() = (this / 16) // 0 - 255, 255 being water, 254 being lava
|
||||
fun Int.isEven() = (this and 0x01) == 0
|
||||
fun Int.isFallable() = BlockCodex[this].isFallable
|
||||
|
||||
private fun placeFluid(world: GameWorld, x: Int, y: Int, fluidType: Byte, amount: Int) {
|
||||
if (world.layerTerrain.isInBound(x, y)) {
|
||||
if (amount > 0 && !world.getTileFromTerrain(x, y)!!.isSolid()) {
|
||||
world.setTileTerrain(x, y, fluidType, amount - 1)
|
||||
}
|
||||
else if (amount == 0 && world.getTileFromTerrain(x, y)!!.isFluid()) {
|
||||
world.setTileTerrain(x, y, Block.AIR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x and y: world tile coord
|
||||
* @return amount of fluid actually drained.
|
||||
* (intended drainage - this) will give you how much fluid is not yet drained.
|
||||
* TODO add fluidType support
|
||||
*/
|
||||
private fun drain(x: Int, y: Int, amount: Int): Int {
|
||||
val displacement = Math.min(fluidMap[y - updateYFrom][x - updateXFrom].toInt(), amount)
|
||||
|
||||
fluidMap[y - updateYFrom][x - updateXFrom] =
|
||||
(fluidMap[y - updateYFrom][x - updateXFrom] - displacement).toByte()
|
||||
|
||||
return displacement
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x and y: world tile coord
|
||||
* TODO add fluidType support
|
||||
*/
|
||||
private fun pour(x: Int, y: Int, amount: Int) {
|
||||
/**
|
||||
* @param x and y: world tile coord
|
||||
* @return spillage
|
||||
* TODO add fluidType support
|
||||
*/
|
||||
fun pourInternal(worldXpos: Int, worldYPos: Int, volume: Int): Int {
|
||||
var spil = 0
|
||||
|
||||
val addrX = worldXpos - updateXFrom
|
||||
val addrY = worldYPos - updateYFrom
|
||||
|
||||
if (addrX >= 0 && addrY >= 0 && addrX < DOUBLE_RADIUS && addrY < DOUBLE_RADIUS) {
|
||||
fluidMap[addrY][addrX] = (fluidMap[addrY][addrX] + volume).toByte()
|
||||
if (fluidMap[addrY][addrX] > FLUID_MAX) {
|
||||
spil = fluidMap[addrY][addrX] - FLUID_MAX
|
||||
fluidMap[addrY][addrX] = FLUID_MAX.toByte()
|
||||
}
|
||||
}
|
||||
|
||||
return spil
|
||||
}
|
||||
|
||||
// pour the fluid
|
||||
var spillage = pourInternal(x, y, amount)
|
||||
|
||||
if (spillage <= 0) return
|
||||
|
||||
// deal with the spillage
|
||||
|
||||
val tileUp = world.getTileFromTerrain(x - updateXFrom, y - updateYFrom - 1)
|
||||
val tileDown = world.getTileFromTerrain(x - updateXFrom, y - updateYFrom + 1)
|
||||
|
||||
// try to fill downward
|
||||
if (tileDown != null && !tileDown.isSolid()) {
|
||||
spillage = pourInternal(x, y + 1, spillage)
|
||||
}
|
||||
// else, try to fill upward. if there is no space, just discard
|
||||
if (spillage >= 0 && tileUp != null && !tileUp.isSolid()) {
|
||||
pourInternal(x, y - 1, spillage)
|
||||
}
|
||||
}
|
||||
}
|
||||
187
src/net/torvald/terrarum/modulebasegame/gameworld/WorldTime.kt
Normal file
187
src/net/torvald/terrarum/modulebasegame/gameworld/WorldTime.kt
Normal file
@@ -0,0 +1,187 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameworld
|
||||
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.GameDate
|
||||
|
||||
/**
|
||||
* The World Calendar implementation of Dwarven Calendar, except:
|
||||
* - the year begins with Mondag instead of Sundag (which is ISO standard)
|
||||
* - the first month is Opal instead of Granite (to reduce confusion)
|
||||
*
|
||||
*
|
||||
* Please also see:
|
||||
* https://en.wikipedia.org/wiki/World_Calendar
|
||||
* http://dwarffortresswiki.org/index.php/DF2014:Calendar
|
||||
*
|
||||
* And there is no AM/PM concept, 22-hour clock is forced; no leap years.
|
||||
* (AM 12 is still 00h in this system, again, to reduce confusion)
|
||||
*
|
||||
*
|
||||
* Calendar
|
||||
*
|
||||
* |Mo|Ty|Mi|To|Fr|La|Su|Ve|
|
||||
* |--|--|--|--|--|--|--|--|
|
||||
* | 1| 2| 3| 4| 5| 6| 7| |
|
||||
* | 8| 9|10|11|12|13|14| |
|
||||
* |15|16|17|18|19|20|21| |
|
||||
* |22|23|24|25|26|27|28| |
|
||||
* |29|30|31| 1| 2| 3| 4| |
|
||||
* | 5| 6| 7| 8| 9|10|11| |
|
||||
* |12|13|14|15|16|17|18| |
|
||||
* |19|20|21|22|23|24|25| |
|
||||
* |26|27|28|29|30| 1| 2| |
|
||||
* | 3| 4| 5| 6| 7| 8| 9| |
|
||||
* |10|11|12|13|14|15|16| |
|
||||
* |17|18|19|20|21|22|23| |
|
||||
* |24|25|26|27|28|29|30|31|
|
||||
*
|
||||
* Verddag only appears on the last day of the year (31st Moonstone)
|
||||
*
|
||||
* (Check please:)
|
||||
* - Equinox/Solstice always occur on 21st day of the month
|
||||
*
|
||||
*
|
||||
* Created by minjaesong on 2016-01-24.
|
||||
*/
|
||||
class WorldTime(initTime: Long = 0L) {
|
||||
var TIME_T = 0L // Epoch: Year 125, 1st Opal, 0h00:00 (Mondag) // 125-01-01
|
||||
private set
|
||||
|
||||
init {
|
||||
TIME_T = initTime
|
||||
}
|
||||
|
||||
inline val seconds: Int // 0 - 59
|
||||
get() = TIME_T.toPositiveInt() % MINUTE_SEC
|
||||
inline val minutes: Int // 0 - 59
|
||||
get() = TIME_T.div(MINUTE_SEC).abs().toInt() % HOUR_MIN
|
||||
inline val hours: Int // 0 - 21
|
||||
get() = TIME_T.div(HOUR_SEC).abs().toInt() % HOURS_PER_DAY
|
||||
|
||||
inline val yearlyDays: Int // 0 - 364
|
||||
get() = (TIME_T.toPositiveInt().div(DAY_LENGTH) % YEAR_DAYS)
|
||||
|
||||
inline val days: Int // 1 - 31
|
||||
get() = quarterlyDays + 1 -
|
||||
if (quarterlyMonthOffset == 0) 0
|
||||
else if (quarterlyMonthOffset == 1) 31
|
||||
else 61
|
||||
inline val months: Int // 1 - 12
|
||||
get() = if (yearlyDays == YEAR_DAYS - 1) 12 else
|
||||
quarter * 3 + 1 +
|
||||
if (quarterlyDays < 31) 0
|
||||
else if (quarterlyDays < 61) 1
|
||||
else 2
|
||||
inline val years: Int
|
||||
get() = TIME_T.div(YEAR_DAYS * DAY_LENGTH).abs().toInt() + EPOCH_YEAR
|
||||
|
||||
inline val quarter: Int // 0 - 3
|
||||
get() = if (yearlyDays == YEAR_DAYS - 1) 3 else yearlyDays / QUARTER_LENGTH
|
||||
inline val quarterlyDays: Int // 0 - 90(91)
|
||||
get() = if (yearlyDays == YEAR_DAYS - 1) 91 else (yearlyDays % QUARTER_LENGTH)
|
||||
inline val quarterlyMonthOffset: Int // 0 - 2
|
||||
get() = months.minus(1) % 3
|
||||
|
||||
inline val dayOfWeek: Int //0: Mondag-The first day of weekday (0 - 7)
|
||||
get() = if (yearlyDays == YEAR_DAYS - 1) 7 else yearlyDays % 7
|
||||
|
||||
var timeDelta: Int = 1
|
||||
set(value) {
|
||||
field = if (value < 0) 0 else value
|
||||
}
|
||||
|
||||
inline val moonPhase: Double
|
||||
get() = (TIME_T.plus(1700000L) % LUNAR_CYCLE).toDouble() / LUNAR_CYCLE
|
||||
|
||||
@Transient private var realMillisec: Double = 0.0
|
||||
@Transient private val REAL_SEC_TO_GAME_SECS = 60
|
||||
|
||||
val DAY_NAMES = arrayOf(//daynames are taken from Nynorsk (å -> o)
|
||||
"Mondag", "Tysdag", "Midtveke" //middle-week
|
||||
, "Torsdag", "Fredag", "Laurdag", "Sundag", "Verddag" //From Norsk word 'verd'
|
||||
)
|
||||
val DAY_NAMES_SHORT = arrayOf("Mon", "Tys", "Mid", "Tor", "Fre", "Lau", "Sun", "Ver")
|
||||
|
||||
val MONTH_NAMES = arrayOf(
|
||||
"Opal", "Obsidian", "Granite", "Slate", "Felsite", "Hematite",
|
||||
"Malachite", "Galena", "Limestone", "Sandstone", "Timber", "Moonstone"
|
||||
)
|
||||
val MONTH_NAMES_SHORT = arrayOf("Opal", "Obsi", "Gran", "Slat", "Fels", "Hema",
|
||||
"Mala", "Gale", "Lime", "Sand", "Timb", "Moon")
|
||||
|
||||
inline val currentTimeAsGameDate: GameDate
|
||||
get() = GameDate(years, yearlyDays)
|
||||
|
||||
companion object {
|
||||
/** Each day is 22-hour long */
|
||||
val DAY_LENGTH = 79200 //must be the multiple of 3600
|
||||
|
||||
val HOUR_SEC: Int = 3600
|
||||
val MINUTE_SEC: Int = 60
|
||||
val HOUR_MIN: Int = 60
|
||||
val GAME_MIN_TO_REAL_SEC: Float = 60f
|
||||
val HOURS_PER_DAY = DAY_LENGTH / HOUR_SEC
|
||||
|
||||
val YEAR_DAYS: Int = 365
|
||||
val QUARTER_LENGTH = 91 // as per The World Calendar
|
||||
|
||||
val EPOCH_YEAR = 125
|
||||
|
||||
fun parseTime(s: String): Int =
|
||||
if (s.length >= 4 && s.contains('h')) {
|
||||
s.toLowerCase().substringBefore('h').toInt() * HOUR_SEC +
|
||||
s.toLowerCase().substringAfter('h').toInt() * MINUTE_SEC
|
||||
}
|
||||
else if (s.endsWith("h", true)) {
|
||||
s.toLowerCase().substring(0, s.length - 1).toInt() * HOUR_SEC
|
||||
}
|
||||
else {
|
||||
s.toInt()
|
||||
}
|
||||
|
||||
|
||||
val LUNAR_CYCLE: Int = 2342643// 29 days, 12 hours, 44 minutes, and 3 seconds in-game calendar
|
||||
}
|
||||
|
||||
fun update(delta: Float) {
|
||||
//time
|
||||
realMillisec += delta * 1000.0
|
||||
if (realMillisec >= 1000.0 / REAL_SEC_TO_GAME_SECS) {
|
||||
realMillisec -= 1000.0 / REAL_SEC_TO_GAME_SECS
|
||||
TIME_T += timeDelta
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val todaySeconds: Int
|
||||
get() = TIME_T.toPositiveInt() % DAY_LENGTH
|
||||
|
||||
fun setTimeOfToday(t: Int) {
|
||||
TIME_T = TIME_T - todaySeconds + t
|
||||
}
|
||||
|
||||
fun addTime(t: Int) {
|
||||
TIME_T += t
|
||||
}
|
||||
|
||||
val dayName: String
|
||||
get() = DAY_NAMES[dayOfWeek]
|
||||
|
||||
inline fun Long.toPositiveInt() = this.and(0x7FFFFFFF).toInt()
|
||||
inline fun Long.abs() = Math.abs(this)
|
||||
|
||||
/** Format: "%A, %d %B %Y %X" */
|
||||
fun getFormattedTime() = "${getDayNameShort()}, " +
|
||||
"$days " +
|
||||
"${getMonthNameShort()} " +
|
||||
"$years " +
|
||||
"${String.format("%02d", hours)}:" +
|
||||
"${String.format("%02d", minutes)}:" +
|
||||
"${String.format("%02d", seconds)}"
|
||||
|
||||
fun getDayNameFull() = DAY_NAMES[dayOfWeek]
|
||||
fun getDayNameShort() = DAY_NAMES_SHORT[dayOfWeek]
|
||||
fun getMonthNameFull() = MONTH_NAMES[months - 1]
|
||||
fun getMonthNameShort() = MONTH_NAMES_SHORT[months - 1]
|
||||
|
||||
override fun toString() = getFormattedTime()
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameworld
|
||||
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.GameDate
|
||||
|
||||
/**
|
||||
* The World Calendar implementation of Dwarven Calendar (we're talking about DF!)
|
||||
*
|
||||
* Please see:
|
||||
* https://en.wikipedia.org/wiki/World_Calendar
|
||||
* http://dwarffortresswiki.org/index.php/DF2014:Calendar
|
||||
*
|
||||
* Normal format for day is
|
||||
* Tysdag 12th Granite
|
||||
*
|
||||
* And there is no AM/PM concept, 22-hour clock is forced.
|
||||
*
|
||||
* Created by minjaesong on 2016-01-24.
|
||||
*/
|
||||
@Deprecated("Are you even reading the name?")
|
||||
class YeOldeWorldTime {
|
||||
|
||||
internal var seconds: Int // 0 - 59
|
||||
internal var minutes: Int // 0 - 59
|
||||
internal var hours: Int // 0 - 21
|
||||
|
||||
// days on the year
|
||||
internal var yearlyDays: Int //NOT a calendar day
|
||||
|
||||
internal var days: Int // 1 - 31
|
||||
internal var months: Int // 1 - 12
|
||||
internal var years: Int // 1+
|
||||
|
||||
internal var dayOfWeek: Int //0: Mondag-The first day of weekday (0 - 7)
|
||||
|
||||
internal var timeDelta = 1
|
||||
|
||||
@Transient private var realMillisec: Int
|
||||
|
||||
val DAY_NAMES = arrayOf(//daynames are taken from Nynorsk (å -> o)
|
||||
"Mondag", "Tysdag", "Midvikdag" //From Islenska Miðvikudagur
|
||||
, "Torsdag", "Fredag", "Laurdag", "Sundag", "Verddag" //From Norsk word 'verd'
|
||||
)
|
||||
val DAY_NAMES_SHORT = arrayOf("Mon", "Tys", "Mid", "Tor", "Fre", "Lau", "Sun", "Ver")
|
||||
|
||||
val MONTH_NAMES = arrayOf(
|
||||
"Opal", "Obsidian", "Granite", "Slate", "Felsite", "Hematite",
|
||||
"Malachite", "Galena", "Limestone", "Sandstone", "Timber", "Moonstone"
|
||||
)
|
||||
val MONTH_NAMES_SHORT = arrayOf("Opal", "Obsi", "Gran", "Slat", "Fels", "Hema",
|
||||
"Mala", "Gale", "Lime", "Sand", "Timb", "Moon")
|
||||
|
||||
val currentTimeAsGameDate: GameDate
|
||||
get() = GameDate(years, yearlyDays)
|
||||
|
||||
@Transient val REAL_SEC_IN_MILLI = 1000
|
||||
|
||||
companion object {
|
||||
/** Each day is 22-hour long */
|
||||
val DAY_LENGTH = 79200 //must be the multiple of 3600
|
||||
|
||||
val HOUR_SEC: Int = 3600
|
||||
val MINUTE_SEC: Int = 60
|
||||
val HOUR_MIN: Int = 60
|
||||
val GAME_MIN_TO_REAL_SEC: Float = 60f
|
||||
|
||||
val YEAR_DAYS: Int = 365
|
||||
|
||||
fun parseTime(s: String): Int =
|
||||
if (s.length >= 4 && s.contains('h')) {
|
||||
s.toLowerCase().substringBefore('h').toInt() * WorldTime.HOUR_SEC +
|
||||
s.toLowerCase().substringAfter('h').toInt() * WorldTime.MINUTE_SEC
|
||||
}
|
||||
else if (s.endsWith("h", true)) {
|
||||
s.toLowerCase().substring(0, s.length - 1).toInt() * WorldTime.HOUR_SEC
|
||||
}
|
||||
else {
|
||||
s.toInt()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
// The day when the new world ever is being made.
|
||||
// If we use Multiverse system (which replaces Terraria's "hack"
|
||||
// as a reward rather than a cheat), time of current world's time is
|
||||
// copied to the new world's. (it's Multi-nation rather than Multiverse)
|
||||
seconds = 0
|
||||
minutes = 30
|
||||
hours = 8
|
||||
yearlyDays = 73
|
||||
days = 12
|
||||
months = 3
|
||||
years = 125
|
||||
dayOfWeek = 1 // Tysdag
|
||||
realMillisec = 0
|
||||
}
|
||||
|
||||
fun update(delta: Int) {
|
||||
val oldsec = seconds
|
||||
|
||||
//time
|
||||
realMillisec += delta * timeDelta
|
||||
val newsec = Math.round(GAME_MIN_TO_REAL_SEC / REAL_SEC_IN_MILLI.toFloat() * realMillisec.toFloat())
|
||||
seconds = newsec
|
||||
|
||||
if (realMillisec >= REAL_SEC_IN_MILLI)
|
||||
realMillisec -= REAL_SEC_IN_MILLI
|
||||
|
||||
kickVariables()
|
||||
}
|
||||
|
||||
/**
|
||||
* How much time has passed today, in seconds.
|
||||
* 0 == 6 AM
|
||||
* @return
|
||||
*/
|
||||
val elapsedSeconds: Int
|
||||
get() = (HOUR_SEC * hours + MINUTE_SEC * minutes + seconds) % DAY_LENGTH
|
||||
|
||||
/** Sets time of this day. */
|
||||
fun setTime(t: Int) {
|
||||
days += t / DAY_LENGTH
|
||||
hours = t / HOUR_SEC
|
||||
minutes = (t - HOUR_SEC * hours) / MINUTE_SEC
|
||||
seconds = t - minutes * MINUTE_SEC
|
||||
yearlyDays += t / DAY_LENGTH
|
||||
}
|
||||
|
||||
fun addTime(t: Int) {
|
||||
setTime(elapsedSeconds + t)
|
||||
}
|
||||
|
||||
fun setTimeDelta(d: Int) {
|
||||
timeDelta = if (d < 0) 0 else d
|
||||
}
|
||||
|
||||
val dayName: String
|
||||
get() = DAY_NAMES[dayOfWeek]
|
||||
|
||||
private fun kickVariables() {
|
||||
if (seconds >= MINUTE_SEC) {
|
||||
seconds = 0
|
||||
minutes += 1
|
||||
}
|
||||
|
||||
if (minutes >= HOUR_MIN) {
|
||||
minutes = 0
|
||||
hours += 1
|
||||
}
|
||||
|
||||
if (hours >= DAY_LENGTH / HOUR_SEC) {
|
||||
hours = 0
|
||||
days += 1
|
||||
yearlyDays += 1
|
||||
dayOfWeek += 1
|
||||
}
|
||||
|
||||
//calendar (the world calendar)
|
||||
if (dayOfWeek == 7) {
|
||||
dayOfWeek = 0
|
||||
}
|
||||
if (months == 12 && days == 31) {
|
||||
dayOfWeek = 7
|
||||
}
|
||||
|
||||
if (months == 12 && days == 32) {
|
||||
days = 1
|
||||
months = 1
|
||||
years++
|
||||
}
|
||||
else if ((months == 1 || months == 4 || months == 7 || months == 10) && days > 31) {
|
||||
days = 1
|
||||
months++
|
||||
}
|
||||
else if (days > 30) {
|
||||
days = 1
|
||||
months++
|
||||
}
|
||||
|
||||
if (months > 12) {
|
||||
months = 1
|
||||
years++
|
||||
yearlyDays = 1
|
||||
}
|
||||
}
|
||||
|
||||
/** Format: "%A %d %B %Y %X" */
|
||||
fun getFormattedTime() = "${getDayNameFull()} " +
|
||||
"$days " +
|
||||
"${getMonthNameFull()} " +
|
||||
"$years " +
|
||||
"${String.format("%02d", hours)}:" +
|
||||
"${String.format("%02d", minutes)}:" +
|
||||
"${String.format("%02d", seconds)}"
|
||||
|
||||
fun getDayNameFull() = DAY_NAMES[dayOfWeek]
|
||||
fun getDayNameShort() = DAY_NAMES_SHORT[dayOfWeek]
|
||||
fun getMonthNameFull() = MONTH_NAMES[months - 1]
|
||||
fun getMonthNameShort() = MONTH_NAMES_SHORT[months - 1]
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package net.torvald.terrarum.modulebasegame.imagefont
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.Batch
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-03-24.
|
||||
*/
|
||||
class NewRunes : BitmapFont() {
|
||||
private val runeSize = 12
|
||||
|
||||
// hard-coded encode map
|
||||
private fun codeToEnc(code: Int): Int? = if (code in 0x21..0x3f)
|
||||
code - 0x20
|
||||
else if (code in 0x3001..0x300f)
|
||||
code - 0x3000 + 0x20
|
||||
else if (code in 0x3131..0x3163)
|
||||
code - 0x3130 + 0x30
|
||||
else
|
||||
null
|
||||
|
||||
|
||||
private val runes = TextureRegionPack("./assets/graphics/fonts/newrunes.tga", runeSize, runeSize)
|
||||
|
||||
var scale = 1
|
||||
var linegap = 8
|
||||
|
||||
|
||||
fun getWidth(str: String) = runeSize * str.length
|
||||
|
||||
|
||||
|
||||
override fun draw(batch: Batch, str: CharSequence, x: Float, y: Float): GlyphLayout? {
|
||||
str.forEachIndexed { index, c ->
|
||||
val encodePoint = codeToEnc(c.toInt())
|
||||
|
||||
if (encodePoint != null) {
|
||||
batch.draw(
|
||||
runes.get(encodePoint % 16, encodePoint / 16),
|
||||
x + runeSize * index * scale.toFloat(),
|
||||
y * scale.toFloat()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun usesIntegerPositions() = true
|
||||
override fun ownsTexture() = true
|
||||
override fun getXHeight() = runeSize.toFloat()
|
||||
override fun getCapHeight() = runeSize.toFloat()
|
||||
override fun getLineHeight() = (runeSize + linegap) * scale.toFloat()
|
||||
}
|
||||
|
||||
/*
|
||||
How runes are made:
|
||||
|
||||
The new runes are based on Hangul writing system. The runes had two main goals:
|
||||
- Implement the principle of its design (specifically, how this letter is altered from its base shape)
|
||||
- {KIYEOK, KHIEUKH}, {TIKEUT, THIEUTH, NIEUN}, {PIEUP, PHIEUPH, MIEUM}, {CIEUC, CHIEUCH, SIOS} sets
|
||||
are similar in shape
|
||||
- Aspirated sounds keep similar shape to their base
|
||||
- Vowels are not random; they have rules
|
||||
- In non-assembled writing, IEUNG only appears as "-ng" phoneme, so the shape is based on
|
||||
old Hangul YESIEUNG, which actually had "-ng" sound
|
||||
- "Doensori" are realised by prepending SIOS, much like older Korean orthography
|
||||
- Good enough obfuscation
|
||||
|
||||
|
||||
Notes:
|
||||
- In some letters (e.g. NIEUN-HIEUH), ligatures may applied
|
||||
- EU appear as non-assembled shape; U-shape instead of dash
|
||||
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,47 @@
|
||||
package net.torvald.terrarum.modulebasegame.imagefont
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.Batch
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-06-21.
|
||||
*/
|
||||
|
||||
object Watch7SegMain : BitmapFont() {
|
||||
val charMapping = ('0'..'9')
|
||||
|
||||
internal val W = 11
|
||||
internal val H = 18
|
||||
|
||||
internal val fontSheet = TextureRegionPack(ModMgr.getGdxFile("basegame", "fonts/7segnum.tga"), W, H)
|
||||
|
||||
init {
|
||||
setOwnsTexture(true)
|
||||
}
|
||||
|
||||
override fun draw(batch: Batch, str: CharSequence, x: Float, y: Float): GlyphLayout? {
|
||||
|
||||
str.forEachIndexed { index, c ->
|
||||
batch.draw(
|
||||
if (c != ' ' && c in charMapping)
|
||||
fontSheet.get(1 + (c - '0'), 0)
|
||||
else
|
||||
fontSheet.get(0, 0)
|
||||
, x + W * index, y)
|
||||
}
|
||||
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getLineHeight() = H.toFloat()
|
||||
override fun getCapHeight() = getLineHeight()
|
||||
override fun getXHeight() = getLineHeight()
|
||||
|
||||
override fun dispose() {
|
||||
fontSheet.dispose()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.torvald.terrarum.modulebasegame.imagefont
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.Batch
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-06-21.
|
||||
*/
|
||||
object Watch7SegSmall : BitmapFont() {
|
||||
val charMapping = (' '..'9')
|
||||
|
||||
internal val W = 9
|
||||
internal val H = 12
|
||||
|
||||
internal val fontSheet = TextureRegionPack(ModMgr.getGdxFile("basegame", "fonts/7seg_small.tga"), W, H)
|
||||
|
||||
init {
|
||||
setOwnsTexture(true)
|
||||
}
|
||||
|
||||
override fun draw(batch: Batch, str: CharSequence, x: Float, y: Float): GlyphLayout? {
|
||||
|
||||
str.forEachIndexed { index, c ->
|
||||
if (c in charMapping) {
|
||||
batch.draw(
|
||||
fontSheet.get((c - ' ') % 16, (c - ' ') / 16),
|
||||
x + W * index, y
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getLineHeight() = H.toFloat()
|
||||
override fun getCapHeight() = getLineHeight()
|
||||
override fun getXHeight() = getLineHeight()
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package net.torvald.terrarum.modulebasegame.imagefont
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.Batch
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-06-21.
|
||||
*/
|
||||
object WatchDotAlph : BitmapFont() {
|
||||
val charMapping = ('A'..'Z')
|
||||
|
||||
internal val W = 12
|
||||
internal val H = 10
|
||||
|
||||
internal val fontSheet = TextureRegionPack(ModMgr.getGdxFile("basegame", "fonts/watch_dotalph.tga"), W, H)
|
||||
|
||||
init {
|
||||
setOwnsTexture(true)
|
||||
}
|
||||
|
||||
override fun draw(batch: Batch, str: CharSequence, x: Float, y: Float): GlyphLayout? {
|
||||
|
||||
str.forEachIndexed { index, c ->
|
||||
batch.draw(
|
||||
if (c != ' ' && c in charMapping)
|
||||
fontSheet.get(1 + (c - 'A'), 0)
|
||||
else
|
||||
fontSheet.get(0, 0)
|
||||
, x + W * index, y)
|
||||
}
|
||||
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getLineHeight() = H.toFloat()
|
||||
override fun getCapHeight() = getLineHeight()
|
||||
override fun getXHeight() = getLineHeight()
|
||||
|
||||
override fun dispose() {
|
||||
fontSheet.dispose()
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,13 @@ package net.torvald.terrarum.modulebasegame.items
|
||||
import net.torvald.point.Point2d
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.gameactors.ActorWithPhysics
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.AVKey
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorWithPhysics
|
||||
import net.torvald.terrarum.itemproperties.Calculate
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.itemproperties.ItemID
|
||||
import net.torvald.terrarum.itemproperties.Material
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-07-17.
|
||||
@@ -37,7 +38,7 @@ class PickaxeGeneric(override val originalID: ItemID) : GameItem() {
|
||||
val mouseTileY = Terrarum.mouseTileY
|
||||
|
||||
val mousePoint = Point2d(mouseTileX.toDouble(), mouseTileY.toDouble())
|
||||
val actorvalue = Terrarum.ingame!!.player.actorValue
|
||||
val actorvalue = (Terrarum.ingame!! as Ingame).player.actorValue
|
||||
|
||||
using = true
|
||||
|
||||
@@ -49,15 +50,15 @@ class PickaxeGeneric(override val originalID: ItemID) : GameItem() {
|
||||
})
|
||||
|
||||
// return false if here's no tile
|
||||
if (Block.AIR == Terrarum.ingame!!.world.getTileFromTerrain(mouseTileX, mouseTileY))
|
||||
if (Block.AIR == (Terrarum.ingame!! as Ingame).world.getTileFromTerrain(mouseTileX, mouseTileY))
|
||||
return false
|
||||
|
||||
// filter passed, do the job
|
||||
val swingDmgToFrameDmg = delta.toDouble() / actorvalue.getAsDouble(AVKey.ACTION_INTERVAL)!!
|
||||
|
||||
Terrarum.ingame!!.world.inflictTerrainDamage(
|
||||
(Terrarum.ingame!! as Ingame).world.inflictTerrainDamage(
|
||||
mouseTileX, mouseTileY,
|
||||
Calculate.pickaxePower(Terrarum.ingame!!.player, material) * swingDmgToFrameDmg
|
||||
Calculate.pickaxePower((Terrarum.ingame!! as Ingame).player, material) * swingDmgToFrameDmg
|
||||
)
|
||||
|
||||
return true
|
||||
@@ -66,7 +67,7 @@ class PickaxeGeneric(override val originalID: ItemID) : GameItem() {
|
||||
override fun endPrimaryUse(delta: Float): Boolean {
|
||||
using = false
|
||||
// reset action timer to zero
|
||||
Terrarum.ingame!!.player.actorValue.set(AVKey.__ACTION_TIMER, 0.0)
|
||||
(Terrarum.ingame!! as Ingame).player.actorValue.set(AVKey.__ACTION_TIMER, 0.0)
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package net.torvald.terrarum.modulebasegame.magiccontroller
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* YE OLDE MAGIC IDEA No.0
|
||||
*
|
||||
* Provides MDL interpretation, pre-compilation and stores state of the interpreter
|
||||
*
|
||||
* Created by minjaesong on 2016-07-30.
|
||||
*/
|
||||
class MDLInterpreterState {
|
||||
val stack = MagicArrayStack(20)
|
||||
|
||||
fun interpret(line: String) {
|
||||
|
||||
}
|
||||
|
||||
fun execute(property: MagicWords, power: MagicWords? = null, arg: Int? = null) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum class MagicWords {
|
||||
// properties
|
||||
ELDR, IS, STORMR, HREYFING, LAEKNING, GLEYPI, TJON,
|
||||
//fire, ice, storm, kinesis, heal, absorb, harm
|
||||
|
||||
// reserved words
|
||||
LAEKNINGHRADI, HREYFINGHRADI, LAEKNINGAUKI, HREYFINGAUKI, STOEKKAUKI, HEILSASTIG,
|
||||
// heal rate,movement speed, healratemult,movespeedmult, jump boost, health point
|
||||
// adjectives (power)
|
||||
|
||||
// operators
|
||||
ITA, TOGA, PLUS, MINUS, SINNUM, DEILING, LEIFASTOFN, AFRIT, STAFLISKIPTI, HENNA, NA
|
||||
// push, pop, +, -, *, /, %, dup, swap, drop, fetch
|
||||
}
|
||||
|
||||
class MagicArrayStack {
|
||||
/**
|
||||
* Number of elements in the stack
|
||||
*/
|
||||
var depth: Int = 0
|
||||
private set
|
||||
|
||||
var size: Int
|
||||
get() = data.size
|
||||
set(newSize) {
|
||||
if (newSize > depth) inflate(newSize - data.size)
|
||||
else deflate(data.size - newSize)
|
||||
}
|
||||
|
||||
private lateinit var data: Array<Int?>
|
||||
|
||||
constructor(stackSize: Int) {
|
||||
data = Array(stackSize, { null })
|
||||
}
|
||||
|
||||
constructor(arr: Array<Int?>) {
|
||||
data = arr.copyOf()
|
||||
depth = size
|
||||
}
|
||||
|
||||
fun push(v: Int) {
|
||||
if (depth >= data.size) throw StackOverflowError()
|
||||
data[depth++] = v
|
||||
}
|
||||
|
||||
fun pop(): Int {
|
||||
if (depth == 0) throw EmptyStackException()
|
||||
return data[--depth]!!
|
||||
}
|
||||
|
||||
fun peek(): Int? {
|
||||
if (depth == 0) return null
|
||||
return data[depth - 1]
|
||||
}
|
||||
|
||||
fun dup() {
|
||||
if (depth == 0) throw EmptyStackException()
|
||||
if (depth == data.size) throw StackOverflowError()
|
||||
push(peek()!!)
|
||||
}
|
||||
|
||||
fun swap() {
|
||||
if (depth < 2) throw UnsupportedOperationException("Stack is empty or has only one element.")
|
||||
val up = pop()
|
||||
val dn = pop()
|
||||
push(up)
|
||||
push(dn)
|
||||
}
|
||||
|
||||
fun drop() {
|
||||
if (depth == 0) throw EmptyStackException()
|
||||
--depth
|
||||
}
|
||||
|
||||
fun defineFromArray(arr: Array<Int?>) { data = arr.copyOf() }
|
||||
|
||||
/**
|
||||
* Increase the stack size by a factor.
|
||||
*/
|
||||
fun inflate(sizeToAdd: Int) {
|
||||
if (sizeToAdd < 0) throw UnsupportedOperationException("$sizeToAdd: Cannot deflate the stack with this function. Use deflate(int) instead.")
|
||||
size += sizeToAdd
|
||||
val oldStack = this.asArray()
|
||||
data = Array(size, { if (it < oldStack.size) oldStack[it] else null })
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease the stack size by a factor. Overflowing data will be removed.
|
||||
*/
|
||||
fun deflate(sizeToTake: Int) {
|
||||
if (size - sizeToTake < 1) throw UnsupportedOperationException("$sizeToTake: Cannot deflate the stack to the size of zero or negative.")
|
||||
size -= sizeToTake
|
||||
val oldStack = this.asArray()
|
||||
data = Array(size, { oldStack[it] })
|
||||
if (depth > data.size) depth = data.size
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert stack as array. Index zero is the bottommost element.
|
||||
* @return array of data, with array size equivalent to the stack depth.
|
||||
*/
|
||||
fun asArray() = data.copyOfRange(0, depth - 1)
|
||||
|
||||
fun equalTo(other: MagicArrayStack) = (this.asArray() == other.asArray())
|
||||
|
||||
fun plus() { data[depth - 2] = data[depth - 2]!! + (pop().toInt()) }
|
||||
fun minus() { data[depth - 2] = data[depth - 2]!! - (pop().toInt()) }
|
||||
fun times() { data[depth - 2] = data[depth - 2]!! * (pop().toInt()) }
|
||||
fun div() { data[depth - 2] = data[depth - 2]!! / (pop().toInt()) }
|
||||
fun mod() { data[depth - 2] = data[depth - 2]!! % (pop().toInt()) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package net.torvald.terrarum.modulebasegame.magiccontroller
|
||||
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.AVKey
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
|
||||
/**
|
||||
* "Data Type" describing magical force
|
||||
*
|
||||
* Created by minjaesong on 2018-06-03.
|
||||
*/
|
||||
class TheMagicLanguage(vm: TheMagicMachine) {
|
||||
|
||||
open class MagicException : Exception()
|
||||
class MagicPortReadError : MagicException()
|
||||
class MagicPortWriteError : MagicException()
|
||||
|
||||
|
||||
/**
|
||||
* A vessel contains magical power to be process.
|
||||
*
|
||||
* Negative numbers are tsraoatrsed as if it's negative power (still has >0 amount)
|
||||
*/
|
||||
class MagicAccumulator {
|
||||
private var power = 0.0
|
||||
|
||||
fun pourIn(value: Double) {
|
||||
power += value // positive powers and negative powers will cancel eath other
|
||||
}
|
||||
fun pourOut(value: Double) {
|
||||
power -= value
|
||||
}
|
||||
fun pourOutInto(other: MagicAccumulator, value: Double) {
|
||||
if (power >= 0) {
|
||||
// pour out positive power without inversion; result is positive power
|
||||
if (value >= 0) {
|
||||
val value = minOf(power, value)
|
||||
other.pourIn(value)
|
||||
power -= value
|
||||
}
|
||||
// pour out positive power with inversion; result is negative power
|
||||
else {
|
||||
val value = minOf(-power, value)
|
||||
other.pourIn(value)
|
||||
power += value
|
||||
}
|
||||
}
|
||||
else {
|
||||
// pour out negative power without inversion; result is negative power
|
||||
if (value < 0) {
|
||||
val value = minOf(power, value)
|
||||
other.pourIn(-value)
|
||||
}
|
||||
// pour out negative power with inversion; result is positive power
|
||||
else {
|
||||
val value = minOf(-power, value)
|
||||
other.pourIn(-value)
|
||||
}
|
||||
}
|
||||
}
|
||||
fun dumpAllInto(other: MagicAccumulator) {
|
||||
pourOutInto(other, this.power)
|
||||
}
|
||||
fun empty() {
|
||||
// release residual power as heat or something
|
||||
|
||||
power = 0.0
|
||||
}
|
||||
fun readForPortWrite(): Double {
|
||||
val r = power
|
||||
power = 0.0
|
||||
return r
|
||||
}
|
||||
}
|
||||
|
||||
interface MagicOutputPort {
|
||||
fun read(a: MagicAccumulator): Double?
|
||||
fun write(a: MagicAccumulator)
|
||||
}
|
||||
|
||||
class HealthPort(val output1: Actor) : MagicOutputPort {
|
||||
|
||||
override fun read(a: MagicAccumulator): Double {
|
||||
val value = output1.actorValue.getAsDouble(AVKey.HEALTH) ?: throw MagicPortReadError()
|
||||
a.pourIn(value)
|
||||
return value
|
||||
}
|
||||
|
||||
override fun write(a: MagicAccumulator) {
|
||||
val value = output1.actorValue.getAsDouble(AVKey.HEALTH) ?: throw MagicPortReadError()
|
||||
output1.actorValue[AVKey.HEALTH] = value + a.readForPortWrite()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun opCombine(a: MagicAccumulator, b: MagicAccumulator, c: MagicAccumulator) {
|
||||
b.dumpAllInto(a)
|
||||
c.dumpAllInto(a)
|
||||
}
|
||||
|
||||
fun opRelease(akku: MagicAccumulator, port: MagicOutputPort) {
|
||||
port.write(akku)
|
||||
}
|
||||
|
||||
fun opSiphon(akku: MagicAccumulator, port: MagicOutputPort) {
|
||||
port.read(akku)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.torvald.terrarum.modulebasegame.magiccontroller
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2018-06-03.
|
||||
*/
|
||||
class TheMagicMachine(skill: MagicianSkillDefinition) {
|
||||
|
||||
val akkuPack = Array(skill.numberOfAccumulator, { TheMagicLanguage.MagicAccumulator() })
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
data class MagicianSkillDefinition(
|
||||
var numberOfAccumulator: Int,
|
||||
var useableMagicPower: Double,
|
||||
var runeComprehensionLevel: Int
|
||||
)
|
||||
35
src/net/torvald/terrarum/modulebasegame/ui/AmmoMeterProxy.kt
Normal file
35
src/net/torvald/terrarum/modulebasegame/ui/AmmoMeterProxy.kt
Normal file
@@ -0,0 +1,35 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-04-21.
|
||||
*/
|
||||
object AmmoMeterProxy {
|
||||
|
||||
operator fun invoke(actor: ActorHumanoid, meter: UIVitalMetre) {
|
||||
val currentItem = actor.inventory.itemEquipped[GameItem.EquipPosition.HAND_GRIP]
|
||||
|
||||
if (currentItem == null) {
|
||||
meter.vitalGetterMax = { null }
|
||||
meter.vitalGetterVal = { null }
|
||||
}
|
||||
else {
|
||||
meter.vitalGetterVal = {
|
||||
if (currentItem.stackable && currentItem.maxDurability == GameItem.DURABILITY_NA) {
|
||||
actor.inventory.getByDynamicID(currentItem.dynamicID)!!.amount.toFloat()
|
||||
}
|
||||
else
|
||||
currentItem.durability
|
||||
}
|
||||
|
||||
meter.vitalGetterMax = {
|
||||
if (currentItem.stackable && currentItem.maxDurability == GameItem.DURABILITY_NA)
|
||||
500f
|
||||
else
|
||||
currentItem.maxDurability.toFloat()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.gameactors.ai.toInt
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
|
||||
/**
|
||||
* Make item slot image with number on bottom-right
|
||||
*
|
||||
* Created by minjaesong on 2016-07-20.
|
||||
*/
|
||||
object ItemSlotImageBuilder {
|
||||
|
||||
// FIXME it leaks mem waaaaagh
|
||||
|
||||
val colourBlack = Color(0x404040_FF)
|
||||
val colourWhite = Color(0xC0C0C0_FF.toInt())
|
||||
|
||||
val slotImage = TextureRegionPack(Gdx.files.internal("./assets/graphics/gui/quickbar/item_slots_atlas.tga"), 38, 38) // must have same w/h as slotLarge
|
||||
|
||||
|
||||
private val imageDict = HashMap<Long, Texture>()
|
||||
|
||||
|
||||
fun produce(isBlack: Boolean, number: Int = 10): TextureRegion {
|
||||
return slotImage.get(number, 0 or isBlack.toInt().shl(1))
|
||||
}
|
||||
|
||||
fun produceLarge(isBlack: Boolean, number: Int = 10): TextureRegion {
|
||||
return slotImage.get(number, 1 or isBlack.toInt().shl(1))
|
||||
}
|
||||
|
||||
|
||||
fun dispose() {
|
||||
slotImage.dispose()
|
||||
}
|
||||
|
||||
}
|
||||
79
src/net/torvald/terrarum/modulebasegame/ui/MessageWindow.kt
Normal file
79
src/net/torvald/terrarum/modulebasegame/ui/MessageWindow.kt
Normal file
@@ -0,0 +1,79 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blendNormal
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-27.
|
||||
*/
|
||||
class MessageWindow(override var width: Int, isBlackVariant: Boolean) : UICanvas() {
|
||||
|
||||
private val segment = if (isBlackVariant) SEGMENT_BLACK else SEGMENT_WHITE
|
||||
|
||||
var messagesList = arrayOf("", "")
|
||||
override var height: Int = 0
|
||||
|
||||
private var fontCol: Color = if (!isBlackVariant) Color.BLACK else Color.WHITE
|
||||
private val GLYPH_HEIGHT = Terrarum.fontGame.lineHeight
|
||||
|
||||
override var openCloseTime: Second = OPEN_CLOSE_TIME
|
||||
|
||||
private val LRmargin = 0f // there's "base value" of 8 px for LR (width of segment tile)
|
||||
|
||||
|
||||
fun setMessage(messagesList: Array<String>) {
|
||||
this.messagesList = messagesList
|
||||
}
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
}
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
blendNormal()
|
||||
|
||||
val textWidth = messagesList.map { Terrarum.fontGame.getWidth(it) }.sorted()[1]
|
||||
|
||||
batch.color = Color.WHITE
|
||||
|
||||
batch.draw(segment.get(1, 0), segment.tileW.toFloat(), 0f, 2 * LRmargin + textWidth, segment.tileH.toFloat())
|
||||
batch.draw(segment.get(0, 0), 0f, 0f)
|
||||
batch.draw(segment.get(2, 0), 2 * LRmargin + textWidth, 0f)
|
||||
|
||||
messagesList.forEachIndexed { index, s ->
|
||||
Terrarum.fontGame.draw(batch, s, segment.tileW + LRmargin, (segment.tileH - Terrarum.fontGame.lineHeight) / 2f)
|
||||
}
|
||||
}
|
||||
|
||||
override fun doOpening(delta: Float) {
|
||||
}
|
||||
|
||||
override fun doClosing(delta: Float) {
|
||||
}
|
||||
|
||||
override fun endOpening(delta: Float) {
|
||||
}
|
||||
|
||||
override fun endClosing(delta: Float) {
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
// private int messagesShowingIndex = 0;
|
||||
val MESSAGES_DISPLAY = 2
|
||||
val OPEN_CLOSE_TIME = 0.16f
|
||||
|
||||
|
||||
// will be disposed by Terrarum (application main instance)
|
||||
val SEGMENT_BLACK = TextureRegionPack("assets/graphics/gui/message_black.tga", 8, 56)
|
||||
val SEGMENT_WHITE = TextureRegionPack("assets/graphics/gui/message_white.tga", 8, 56)
|
||||
}
|
||||
}
|
||||
71
src/net/torvald/terrarum/modulebasegame/ui/Notification.kt
Normal file
71
src/net/torvald/terrarum/modulebasegame/ui/Notification.kt
Normal file
@@ -0,0 +1,71 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-01-23.
|
||||
*/
|
||||
class Notification : UICanvas() {
|
||||
|
||||
private val SHOWUP_MAX = 15000
|
||||
|
||||
override var width: Int = 500
|
||||
|
||||
internal var msgUI = MessageWindow(width, true)
|
||||
|
||||
override var height: Int = msgUI.height
|
||||
private val visibleTime = Math.min(
|
||||
Terrarum.getConfigInt("notificationshowuptime"),
|
||||
SHOWUP_MAX
|
||||
)
|
||||
private var displayTimer = 0f
|
||||
|
||||
internal var message: Array<String> = Array(MessageWindow.MESSAGES_DISPLAY, { "" })
|
||||
|
||||
override var openCloseTime: Second = MessageWindow.OPEN_CLOSE_TIME
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
if (handler.isOpened)
|
||||
displayTimer += delta
|
||||
|
||||
if (displayTimer >= visibleTime) {
|
||||
handler.setAsClose()
|
||||
displayTimer = 0f
|
||||
}
|
||||
}
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
msgUI.render(batch, camera)
|
||||
}
|
||||
|
||||
override fun doOpening(delta: Float) {
|
||||
doOpeningFade(this, openCloseTime)
|
||||
}
|
||||
|
||||
override fun doClosing(delta: Float) {
|
||||
doClosingFade(this, openCloseTime)
|
||||
}
|
||||
|
||||
override fun endOpening(delta: Float) {
|
||||
endOpeningFade(this)
|
||||
}
|
||||
|
||||
override fun endClosing(delta: Float) {
|
||||
endClosingFade(this)
|
||||
}
|
||||
|
||||
fun sendNotification(message: Array<String>) {
|
||||
this.message = message
|
||||
msgUI.setMessage(this.message)
|
||||
handler.openCloseCounter = 0f
|
||||
handler.opacity = 0f
|
||||
handler.setAsOpen()
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
}
|
||||
35
src/net/torvald/terrarum/modulebasegame/ui/NullUI.kt
Normal file
35
src/net/torvald/terrarum/modulebasegame/ui/NullUI.kt
Normal file
@@ -0,0 +1,35 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-03-13.
|
||||
*/
|
||||
class NullUI : UICanvas() {
|
||||
override var width: Int = 0
|
||||
override var height: Int = 0
|
||||
override var openCloseTime = 0f
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
}
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
}
|
||||
|
||||
override fun doOpening(delta: Float) {
|
||||
}
|
||||
|
||||
override fun doClosing(delta: Float) {
|
||||
}
|
||||
|
||||
override fun endOpening(delta: Float) {
|
||||
}
|
||||
|
||||
override fun endClosing(delta: Float) {
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
}
|
||||
157
src/net/torvald/terrarum/modulebasegame/ui/UIBasicNotifier.kt
Normal file
157
src/net/torvald/terrarum/modulebasegame/ui/UIBasicNotifier.kt
Normal file
@@ -0,0 +1,157 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.abs
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.roundInt
|
||||
import net.torvald.terrarum.modulebasegame.imagefont.Watch7SegSmall
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-06-10.
|
||||
*/
|
||||
class UIBasicNotifier(private val player: ActorHumanoid?) : UICanvas() {
|
||||
override var width = 116
|
||||
override var height = 24
|
||||
override var openCloseTime: Second = 0f
|
||||
|
||||
private var ELuptimer = 10f // to make the light turned off by default
|
||||
private val ELuptime = 4f
|
||||
private var ELon = false
|
||||
|
||||
private var atlas = TextureRegionPack(ModMgr.getPath("basegame", "gui/basic_meter_atlas.tga"), width, height)
|
||||
|
||||
private var font = Watch7SegSmall
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
if (ELon) {
|
||||
ELuptimer += delta
|
||||
}
|
||||
|
||||
if (mouseUp || Gdx.input.isKeyPressed(Terrarum.getConfigInt("keyinteract"))) {
|
||||
ELuptimer = 0f
|
||||
ELon = true
|
||||
}
|
||||
|
||||
if (ELuptimer >= ELuptime) {
|
||||
ELon = false
|
||||
}
|
||||
}
|
||||
|
||||
private val temperature: Int
|
||||
get() {
|
||||
if (player != null) {
|
||||
val playerTilePos = player.hIntTilewiseHitbox
|
||||
val tempCelsius = -273f + ((Terrarum.ingame as? Ingame)?.world?.getTemperature(playerTilePos.centeredX.toInt(), playerTilePos.centeredY.toInt()) ?: 288f)
|
||||
return if (Terrarum.getConfigBoolean("useamericanunit")) {
|
||||
tempCelsius.times(1.8f).plus(32f).roundInt()
|
||||
}
|
||||
else {
|
||||
tempCelsius.roundInt()
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 888
|
||||
}
|
||||
}
|
||||
private val mailCount: Int
|
||||
get() = 0
|
||||
|
||||
private val lcdLitCol = Color(0x141414_ff)
|
||||
|
||||
fun getTempStr(): String {
|
||||
val sb = StringBuilder()
|
||||
|
||||
if (temperature < 100) {
|
||||
if (temperature < 0)
|
||||
sb.append("-")
|
||||
else
|
||||
sb.append(" ")
|
||||
|
||||
if (temperature.abs() < 10)
|
||||
sb.append(" ")
|
||||
}
|
||||
|
||||
sb.append(temperature.abs())
|
||||
|
||||
if (Terrarum.getConfigBoolean("useamericanunit")) {
|
||||
sb.append('#') // fahrenheit subscript
|
||||
}
|
||||
else {
|
||||
sb.append('"') // celsius superscript
|
||||
}
|
||||
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun getMailStr(): String {
|
||||
val sb = StringBuilder()
|
||||
|
||||
if (mailCount < 10)
|
||||
sb.append(" ")
|
||||
|
||||
sb.append(mailCount)
|
||||
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
// light overlay or EL
|
||||
if (ELon) {
|
||||
blendNormal()
|
||||
batch.draw(atlas.get(0, 2), 0f, 0f)
|
||||
}
|
||||
else {
|
||||
val lightLevel: Color
|
||||
|
||||
if (player != null) {
|
||||
val playerPos = player.hIntTilewiseHitbox
|
||||
lightLevel = (LightmapRenderer.getLight(playerPos.centeredX.toInt(), playerPos.centeredY.toInt()) ?:
|
||||
(Terrarum.ingame!! as Ingame).world.globalLight
|
||||
)
|
||||
}
|
||||
else {
|
||||
lightLevel = (Terrarum.ingame!! as Ingame).world.globalLight
|
||||
}
|
||||
|
||||
|
||||
// backplate
|
||||
batch.color = Color(lightLevel.r, lightLevel.g, lightLevel.b, 1f)
|
||||
batch.draw(atlas.get(0, 0), 0f, 0f)
|
||||
}
|
||||
|
||||
// LCD back
|
||||
blendNormal()
|
||||
batch.draw(atlas.get(0, 3), 0f, 0f)
|
||||
|
||||
|
||||
// LCD contents
|
||||
batch.color = lcdLitCol
|
||||
font.draw(batch, getTempStr(), 21f, 5f)
|
||||
font.draw(batch, getMailStr(), 93f, 5f)
|
||||
}
|
||||
|
||||
override fun doOpening(delta: Float) {
|
||||
}
|
||||
|
||||
override fun doClosing(delta: Float) {
|
||||
}
|
||||
|
||||
override fun endOpening(delta: Float) {
|
||||
}
|
||||
|
||||
override fun endClosing(delta: Float) {
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
atlas.dispose()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.fillRect
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-12-06.
|
||||
*/
|
||||
class UICheatDetected : UICanvas() {
|
||||
|
||||
override var width: Int
|
||||
get() = Terrarum.WIDTH
|
||||
set(value) { throw UnsupportedOperationException() }
|
||||
|
||||
override var height: Int
|
||||
get() = Terrarum.HEIGHT
|
||||
set(value) { throw UnsupportedOperationException() }
|
||||
|
||||
override var openCloseTime: Second = 0f
|
||||
|
||||
|
||||
|
||||
private val backgroundCol = Color(0x181818C0)
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
Terrarum.ingame?.consoleHandler?.setAsClose()
|
||||
Terrarum.ingame?.consoleHandler?.isVisible = false
|
||||
|
||||
batch.color = backgroundCol
|
||||
batch.fillRect(0f, 0f, width.toFloat(), height.toFloat())
|
||||
|
||||
batch.color = Color.WHITE
|
||||
val txt = Lang["ERROR_GENERIC_CHEATING"]
|
||||
val txtW = Terrarum.fontGame.getWidth(txt)
|
||||
val txtH = Terrarum.fontGame.lineHeight.toInt()
|
||||
|
||||
Terrarum.fontGame.draw(batch, txt, width.minus(txtW).ushr(1).toFloat(), height.minus(txtH).ushr(1).toFloat())
|
||||
}
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
}
|
||||
|
||||
override fun doOpening(delta: Float) {
|
||||
}
|
||||
|
||||
override fun doClosing(delta: Float) {
|
||||
}
|
||||
|
||||
override fun endOpening(delta: Float) {
|
||||
}
|
||||
|
||||
override fun endClosing(delta: Float) {
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
}
|
||||
415
src/net/torvald/terrarum/modulebasegame/ui/UIInventory.kt
Normal file
415
src/net/torvald/terrarum/modulebasegame/ui/UIInventory.kt
Normal file
@@ -0,0 +1,415 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-03-13.
|
||||
*/
|
||||
/*class UIInventory(
|
||||
var actor: Pocketed?,
|
||||
override var width: Int,
|
||||
override var height: Int,
|
||||
var categoryWidth: Int,
|
||||
|
||||
toggleKeyLiteral: Int? = null, toggleButtonLiteral: Int? = null,
|
||||
// UI positions itself? (you must g.flush() yourself after the g.translate(Int, Int))
|
||||
customPositioning: Boolean = false, // mainly used by vital meter
|
||||
doNotWarnConstant: Boolean = false
|
||||
) : UICanvas(toggleKeyLiteral, toggleButtonLiteral, customPositioning, doNotWarnConstant) {
|
||||
|
||||
val inventory: ActorInventory?
|
||||
get() = actor?.inventory
|
||||
//val actorValue: ActorValue
|
||||
// get() = (actor as Actor).actorValue
|
||||
|
||||
override var openCloseTime: Second = 0.12f
|
||||
|
||||
val catButtonsToCatIdent = HashMap<String, String>()
|
||||
|
||||
val backgroundColour = Color(0x242424_80)
|
||||
val defaultTextColour = Color(0xeaeaea_ff.toInt())
|
||||
|
||||
init {
|
||||
catButtonsToCatIdent.put("GAME_INVENTORY_WEAPONS", GameItem.Category.WEAPON)
|
||||
catButtonsToCatIdent.put("CONTEXT_ITEM_TOOL_PLURAL", GameItem.Category.TOOL)
|
||||
catButtonsToCatIdent.put("CONTEXT_ITEM_ARMOR", GameItem.Category.ARMOUR)
|
||||
catButtonsToCatIdent.put("GAME_INVENTORY_INGREDIENTS", GameItem.Category.GENERIC)
|
||||
catButtonsToCatIdent.put("GAME_INVENTORY_POTIONS", GameItem.Category.POTION)
|
||||
catButtonsToCatIdent.put("CONTEXT_ITEM_MAGIC", GameItem.Category.MAGIC)
|
||||
catButtonsToCatIdent.put("GAME_INVENTORY_BLOCKS", GameItem.Category.BLOCK)
|
||||
catButtonsToCatIdent.put("GAME_INVENTORY_WALLS", GameItem.Category.WALL)
|
||||
catButtonsToCatIdent.put("GAME_GENRE_MISC", GameItem.Category.MISC)
|
||||
|
||||
// special filter
|
||||
catButtonsToCatIdent.put("MENU_LABEL_ALL", "__all__")
|
||||
|
||||
}
|
||||
|
||||
val itemStripGutterV = 6
|
||||
val itemStripGutterH = 8
|
||||
val itemInterColGutter = 8
|
||||
|
||||
val controlHelpHeight = Terrarum.fontGame.lineHeight.toInt()
|
||||
|
||||
val pageButtonExtraGap = 32
|
||||
|
||||
val pageButtonRealWidth = pageButtonExtraGap + itemStripGutterH
|
||||
|
||||
private val catButtons = UIItemTextButtonList(
|
||||
this,
|
||||
arrayOf(
|
||||
"MENU_LABEL_ALL",
|
||||
"GAME_INVENTORY_BLOCKS",
|
||||
"GAME_INVENTORY_WALLS",
|
||||
"CONTEXT_ITEM_TOOL_PLURAL",
|
||||
"GAME_INVENTORY_WEAPONS",
|
||||
"CONTEXT_ITEM_ARMOR",
|
||||
"GAME_INVENTORY_INGREDIENTS",
|
||||
"GAME_INVENTORY_POTIONS",
|
||||
"CONTEXT_ITEM_MAGIC",
|
||||
"GAME_GENRE_MISC"
|
||||
//"GAME_INVENTORY_FAVORITES",
|
||||
),
|
||||
posX = 0,
|
||||
posY = 0,
|
||||
width = categoryWidth,
|
||||
height = height - controlHelpHeight,
|
||||
verticalGutter = itemStripGutterH,
|
||||
readFromLang = true,
|
||||
textAreaWidth = 100,
|
||||
defaultSelection = 0,
|
||||
iconSpriteSheet = TextureRegionPack("./assets/graphics/gui/inventory/category.tga", 20, 20),
|
||||
iconSpriteSheetIndices = intArrayOf(9,6,7,1,0,2,3,4,5,8),
|
||||
iconCol = defaultTextColour,
|
||||
highlightBackCol = Color(0xb8b8b8_ff.toInt()),
|
||||
highlightBackBlendMode = BlendMode.MULTIPLY,
|
||||
backgroundCol = Color(0), // will use custom background colour!
|
||||
backgroundBlendMode = BlendMode.NORMAL,
|
||||
kinematic = true,
|
||||
inactiveCol = defaultTextColour
|
||||
)
|
||||
|
||||
val itemsStripWidth = ((width - catButtons.width) - (2 * itemStripGutterH + itemInterColGutter)) / 2 - pageButtonExtraGap
|
||||
private val items = Array(
|
||||
((height - controlHelpHeight) / (UIItemInventoryElem.height + itemStripGutterV)) * 2, {
|
||||
UIItemInventoryElem(
|
||||
parentUI = this,
|
||||
posX = pageButtonExtraGap + catButtons.width + if (it % 2 == 0) itemStripGutterH else (itemStripGutterH + itemsStripWidth + itemInterColGutter),
|
||||
posY = itemStripGutterH + it / 2 * (UIItemInventoryElem.height + itemStripGutterV),
|
||||
width = itemsStripWidth,
|
||||
item = null,
|
||||
amount = UIItemInventoryElem.UNIQUE_ITEM_HAS_NO_AMOUNT,
|
||||
itemImage = null,
|
||||
mouseoverBackCol = Color(0x282828_ff),
|
||||
mouseoverBackBlendMode = BlendMode.SCREEN,
|
||||
backCol = Color(0xd4d4d4_ff.toInt()),
|
||||
backBlendMode = BlendMode.MULTIPLY,
|
||||
drawBackOnNull = true,
|
||||
inactiveTextCol = defaultTextColour
|
||||
) })
|
||||
|
||||
|
||||
private val scrollImageButtonAtlas = TextureRegionPack(
|
||||
Gdx.files.internal("assets/graphics/gui/inventory/page_arrow_button.tga"),
|
||||
40, 54
|
||||
)
|
||||
private val scrollLeftButton = UIItemImageButton(this,
|
||||
scrollImageButtonAtlas.get(0, 0),
|
||||
posX = categoryWidth,
|
||||
posY = 0,//(height - controlHelpHeight - scrollImageButtonAtlas.tileH) / 2,
|
||||
width = scrollImageButtonAtlas.tileW,
|
||||
height = height - controlHelpHeight,
|
||||
highlightable = false
|
||||
)
|
||||
private val scrollRightButton = UIItemImageButton(this,
|
||||
scrollImageButtonAtlas.get(1, 0),
|
||||
posX = width - scrollImageButtonAtlas.tileW,
|
||||
posY = 0,//(height - controlHelpHeight - scrollImageButtonAtlas.tileH) / 2,
|
||||
width = scrollImageButtonAtlas.tileW,
|
||||
height = height - controlHelpHeight,
|
||||
highlightable = false
|
||||
)
|
||||
var itemPage = 0
|
||||
var itemPageCount = 1 // TODO total size of current category / items.size
|
||||
|
||||
|
||||
|
||||
var inventorySortList = ArrayList<InventoryPair>()
|
||||
private var rebuildList = true
|
||||
|
||||
private val SP = "${0x3000.toChar()}${0x3000.toChar()}"
|
||||
val listControlHelp: String
|
||||
get() = if (Terrarum.environment == RunningEnvironment.PC)
|
||||
"${0xe006.toChar()} ${Lang["GAME_INVENTORY_USE"]}$SP" +
|
||||
"${0xe011.toChar()}..${0xe010.toChar()} ${Lang["GAME_INVENTORY_REGISTER"]}$SP" +
|
||||
"${0xe034.toChar()} ${Lang["GAME_INVENTORY_DROP"]}"
|
||||
else
|
||||
"$joypadLabelNinY ${Lang["GAME_INVENTORY_USE"]}$SP" +
|
||||
"${0xe011.toChar()}${0xe010.toChar()} ${Lang["GAME_INVENTORY_REGISTER"]}$SP" +
|
||||
"$joypadLabelNinA ${Lang["GAME_INVENTORY_DROP"]}"
|
||||
val listControlClose: String
|
||||
get() = if (Terrarum.environment == RunningEnvironment.PC)
|
||||
"${0xe037.toChar()} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
else
|
||||
"${0xe069.toChar()} ${Lang["GAME_ACTION_CLOSE"]}"
|
||||
|
||||
private var oldCatSelect: Int? = null
|
||||
|
||||
private var encumbrancePerc = 0f
|
||||
private var isEncumbered = false
|
||||
|
||||
|
||||
private val seekLeft: Int; get() = Terrarum.getConfigInt("keyleft") // getter used to support in-game keybind changing
|
||||
private val seekRight: Int; get() = Terrarum.getConfigInt("keyright") // getter used to support in-game keybind changing
|
||||
private val seekUp: Int; get() = Terrarum.getConfigInt("keyup") // getter used to support in-game keybind changing
|
||||
private val seekDown: Int; get() = Terrarum.getConfigInt("keydown") // getter used to support in-game keybind changing
|
||||
|
||||
|
||||
init {
|
||||
// assign actions to the buttons
|
||||
scrollLeftButton.clickOnceListener = { mouseX, mouseY, button -> // click once action doesn't work ?!
|
||||
if (button == Input.Buttons.LEFT) {
|
||||
itemPage = (itemPage - 1) fmod itemPageCount
|
||||
}
|
||||
}
|
||||
scrollRightButton.clickOnceListener = { mouseX, mouseY, button ->
|
||||
if (button == Input.Buttons.LEFT) {
|
||||
itemPage = (itemPage + 1) fmod itemPageCount
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
addItem(scrollLeftButton)
|
||||
addItem(scrollRightButton)
|
||||
}
|
||||
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
|
||||
catButtons.update(delta)
|
||||
|
||||
scrollLeftButton.update(delta)
|
||||
scrollRightButton.update(delta)
|
||||
|
||||
if (actor != null && inventory != null) {
|
||||
// monitor and check if category selection has been changed
|
||||
// OR UI is being opened from closed state
|
||||
if (oldCatSelect != catButtons.selectedIndex ||
|
||||
!rebuildList && handler.openFired) {
|
||||
rebuildList = true
|
||||
}
|
||||
|
||||
// reset item page to start
|
||||
if (oldCatSelect != catButtons.selectedIndex) {
|
||||
itemPage = 0
|
||||
}
|
||||
|
||||
if (rebuildList) {
|
||||
shutUpAndRebuild()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
oldCatSelect = catButtons.selectedIndex
|
||||
}
|
||||
|
||||
private val weightBarWidth = 60f
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
// background
|
||||
blendNormal()
|
||||
batch.color = backgroundColour
|
||||
batch.fillRect(0f, 0f, width.toFloat(), height.toFloat())
|
||||
|
||||
|
||||
// cat bar background
|
||||
blendMul()
|
||||
batch.color = Color(0xcccccc_ff.toInt())
|
||||
batch.fillRect(0f, 0f, catButtons.width.toFloat(), height.toFloat())
|
||||
|
||||
catButtons.render(batch, camera)
|
||||
|
||||
// left/right page mover
|
||||
scrollLeftButton.render(batch, camera)
|
||||
scrollRightButton.render(batch, camera)
|
||||
|
||||
items.forEach {
|
||||
it.render(batch, camera)
|
||||
}
|
||||
|
||||
// texts
|
||||
blendNormal()
|
||||
batch.color = defaultTextColour
|
||||
// W - close
|
||||
Terrarum.fontGame.draw(batch, listControlClose, 4f, height - controlHelpHeight.toFloat())
|
||||
// MouseL - Use ; 1.9 - Register ; T - Drop
|
||||
Terrarum.fontGame.draw(batch, listControlHelp, catButtons.width + 4f, height - controlHelpHeight.toFloat())
|
||||
// encumbrance
|
||||
if (inventory != null) {
|
||||
val encumbranceText = Lang["GAME_INVENTORY_ENCUMBRANCE"]
|
||||
|
||||
Terrarum.fontGame.draw(batch,
|
||||
encumbranceText,
|
||||
width - 9 - Terrarum.fontGame.getWidth(encumbranceText) - weightBarWidth,
|
||||
height - controlHelpHeight.toFloat()
|
||||
)
|
||||
|
||||
// encumbrance bar background
|
||||
blendMul()
|
||||
batch.color = Color(0xa0a0a0_ff.toInt())
|
||||
batch.fillRect(
|
||||
width - 3 - weightBarWidth,
|
||||
height - controlHelpHeight + 3f,
|
||||
weightBarWidth,
|
||||
controlHelpHeight - 6f
|
||||
)
|
||||
// encumbrance bar
|
||||
blendNormal()
|
||||
batch.color = if (isEncumbered) Color(0xff0000_cc.toInt()) else Color(0x00ff00_cc.toInt())
|
||||
batch.fillRect(
|
||||
width - 3 - weightBarWidth,
|
||||
height - controlHelpHeight + 3f,
|
||||
if (actor?.inventory?.capacityMode == CAPACITY_MODE_NO_ENCUMBER)
|
||||
1f
|
||||
else // make sure 1px is always be seen
|
||||
minOf(weightBarWidth, maxOf(1f, weightBarWidth * encumbrancePerc)),
|
||||
controlHelpHeight - 5f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Persuade the UI to rebuild its item list */
|
||||
fun rebuildList() {
|
||||
rebuildList = true
|
||||
}
|
||||
|
||||
|
||||
fun shutUpAndRebuild() {
|
||||
if (catButtons.selectedButton != null) {
|
||||
val filter = catButtonsToCatIdent[catButtons.selectedButton!!.labelText]
|
||||
|
||||
// encumbrance
|
||||
encumbrancePerc = inventory!!.capacity.toFloat() / inventory!!.maxCapacity
|
||||
isEncumbered = inventory!!.isEncumbered
|
||||
|
||||
|
||||
|
||||
inventorySortList = ArrayList<InventoryPair>()
|
||||
|
||||
// filter items
|
||||
inventory?.forEach {
|
||||
if (it.item.inventoryCategory == filter || filter == "__all__")
|
||||
inventorySortList.add(it)
|
||||
}
|
||||
|
||||
rebuildList = false
|
||||
|
||||
// sort if needed
|
||||
// test sort by name
|
||||
inventorySortList.sortBy { it.item.name }
|
||||
|
||||
// map sortList to item list
|
||||
for (k in 0 until items.size) {
|
||||
// we have an item
|
||||
try {
|
||||
val sortListItem = inventorySortList[k + itemPage * items.size]
|
||||
items[k].item = sortListItem.item
|
||||
items[k].amount = sortListItem.amount
|
||||
items[k].itemImage = ItemCodex.getItemImage(sortListItem.item)
|
||||
|
||||
// set quickslot number
|
||||
for (qs in 1..UIQuickBar.SLOT_COUNT) {
|
||||
if (sortListItem.item == actor?.inventory?.getQuickBar(qs - 1)?.item) {
|
||||
items[k].quickslot = qs % 10 // 10 -> 0, 1..9 -> 1..9
|
||||
break
|
||||
}
|
||||
else
|
||||
items[k].quickslot = null
|
||||
}
|
||||
|
||||
// set equippedslot number
|
||||
for (eq in 0..actor!!.inventory.itemEquipped.size - 1) {
|
||||
if (eq < actor!!.inventory.itemEquipped.size) {
|
||||
if (actor!!.inventory.itemEquipped[eq] == items[k].item) {
|
||||
items[k].equippedSlot = eq
|
||||
break
|
||||
}
|
||||
else
|
||||
items[k].equippedSlot = null
|
||||
}
|
||||
}
|
||||
}
|
||||
// we do not have an item, empty the slot
|
||||
catch (e: IndexOutOfBoundsException) {
|
||||
items[k].item = null
|
||||
items[k].amount = 0
|
||||
items[k].itemImage = null
|
||||
items[k].quickslot = null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
itemPageCount = maxOf(1, 1 + (inventorySortList.size.minus(1) / items.size))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////
|
||||
// Inputs //
|
||||
////////////
|
||||
|
||||
|
||||
override fun doOpening(delta: Float) {
|
||||
UICanvas.doOpeningPopOut(this, openCloseTime, UICanvas.Companion.Position.LEFT)
|
||||
}
|
||||
|
||||
override fun doClosing(delta: Float) {
|
||||
UICanvas.doClosingPopOut(this, openCloseTime, UICanvas.Companion.Position.LEFT)
|
||||
}
|
||||
|
||||
override fun endOpening(delta: Float) {
|
||||
UICanvas.endOpeningPopOut(this, UICanvas.Companion.Position.LEFT)
|
||||
}
|
||||
|
||||
override fun endClosing(delta: Float) {
|
||||
UICanvas.endClosingPopOut(this, UICanvas.Companion.Position.LEFT)
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
super.keyDown(keycode)
|
||||
|
||||
items.forEach { if (it.mouseUp) it.keyDown(keycode) }
|
||||
shutUpAndRebuild()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun keyUp(keycode: Int): Boolean {
|
||||
super.keyUp(keycode)
|
||||
|
||||
items.forEach { if (it.mouseUp) it.keyUp(keycode) }
|
||||
shutUpAndRebuild()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
super.touchDown(screenX, screenY, pointer, button)
|
||||
|
||||
items.forEach { if (it.mouseUp) it.touchDown(screenX, screenY, pointer, button) }
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
items.forEach { if (it.mouseUp) it.touchUp(screenX, screenY, pointer, button) }
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
catButtons.dispose()
|
||||
items.forEach { it.dispose() }
|
||||
scrollImageButtonAtlas.dispose()
|
||||
}
|
||||
}
|
||||
*/
|
||||
290
src/net/torvald/terrarum/modulebasegame/ui/UIInventoryFull.kt
Normal file
290
src/net/torvald/terrarum/modulebasegame/ui/UIInventoryFull.kt
Normal file
@@ -0,0 +1,290 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.GL20
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorWithPhysics
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory.Companion.CAPACITY_MODE_NO_ENCUMBER
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-10-21.
|
||||
*/
|
||||
class UIInventoryFull(
|
||||
var actor: Pocketed?,
|
||||
|
||||
toggleKeyLiteral: Int? = null, toggleButtonLiteral: Int? = null,
|
||||
// UI positions itself? (you must g.flush() yourself after the g.translate(Int, Int))
|
||||
customPositioning: Boolean = false, // mainly used by vital meter
|
||||
doNotWarnConstant: Boolean = false
|
||||
) : UICanvas(toggleKeyLiteral, toggleButtonLiteral, customPositioning, doNotWarnConstant) {
|
||||
|
||||
override var width: Int = Terrarum.WIDTH
|
||||
override var height: Int = Terrarum.HEIGHT
|
||||
|
||||
val internalWidth: Int = 630
|
||||
val internalHeight: Int = 558 // grad_begin..grad_end..contents..grad_begin..grad_end
|
||||
|
||||
|
||||
|
||||
internal val catIcons: TextureRegionPack = TextureRegionPack("./assets/graphics/gui/inventory/category.tga", 20, 20)
|
||||
internal val catArrangement: IntArray = intArrayOf(9,6,7,1,0,2,3,4,5,8)
|
||||
|
||||
|
||||
|
||||
private val SP = "${0x3000.toChar()}${0x3000.toChar()}"
|
||||
val listControlHelp: String
|
||||
get() = if (Terrarum.environment == RunningEnvironment.PC)
|
||||
"${0xe031.toChar()} ${Lang["GAME_ACTION_CLOSE"]}$SP" +
|
||||
"${0xe006.toChar()} ${Lang["GAME_INVENTORY_USE"]}$SP" +
|
||||
"${0xe011.toChar()}..${0xe010.toChar()} ${Lang["GAME_INVENTORY_REGISTER"]}$SP" +
|
||||
"${0xe034.toChar()} ${Lang["GAME_INVENTORY_DROP"]}"
|
||||
else
|
||||
"${0xe069.toChar()} ${Lang["GAME_ACTION_CLOSE"]}$SP" +
|
||||
"${Terrarum.joypadLabelNinY} ${Lang["GAME_INVENTORY_USE"]}$SP" +
|
||||
"${0xe011.toChar()}${0xe010.toChar()} ${Lang["GAME_INVENTORY_REGISTER"]}$SP" +
|
||||
"${Terrarum.joypadLabelNinA} ${Lang["GAME_INVENTORY_DROP"]}"
|
||||
val controlHelpHeight = Terrarum.fontGame.lineHeight
|
||||
|
||||
private var encumbrancePerc = 0f
|
||||
private var isEncumbered = false
|
||||
|
||||
|
||||
val catBarWidth = 330
|
||||
val catBar = UIItemInventoryCatBar(
|
||||
this,
|
||||
(Terrarum.WIDTH - catBarWidth) / 2,
|
||||
66 + (Terrarum.HEIGHT - internalHeight) / 2,
|
||||
catBarWidth
|
||||
)
|
||||
val catSelection: Int
|
||||
get() = catBar.selectedIndex
|
||||
val catSelectedIcon: Int
|
||||
get() = catBar.selectedIcon
|
||||
|
||||
override var openCloseTime: Second = 0.0f
|
||||
|
||||
|
||||
private val itemList: UIItemInventoryDynamicList? =
|
||||
if (actor != null) {
|
||||
UIItemInventoryDynamicList(
|
||||
this,
|
||||
actor!!.inventory,
|
||||
0 + (Terrarum.WIDTH - internalWidth) / 2,
|
||||
109 + (Terrarum.HEIGHT - internalHeight) / 2
|
||||
)
|
||||
}
|
||||
else null
|
||||
|
||||
|
||||
private val equipped: UIItemInventoryEquippedView? =
|
||||
if (actor != null) {
|
||||
UIItemInventoryEquippedView(
|
||||
this,
|
||||
actor!!.inventory,
|
||||
actor as ActorWithPhysics,
|
||||
internalWidth - UIItemInventoryEquippedView.width + (Terrarum.WIDTH - internalWidth) / 2,
|
||||
109 + (Terrarum.HEIGHT - internalHeight) / 2
|
||||
)
|
||||
}
|
||||
else null
|
||||
|
||||
|
||||
|
||||
init {
|
||||
addItem(catBar)
|
||||
itemList?.let { addItem(it) }
|
||||
equipped?.let { addItem(it) }
|
||||
|
||||
|
||||
catBar.selectionChangeListener = { old, new -> rebuildList() }
|
||||
|
||||
|
||||
|
||||
rebuildList()
|
||||
|
||||
}
|
||||
|
||||
private var offsetX = ((Terrarum.WIDTH - internalWidth) / 2).toFloat()
|
||||
private var offsetY = ((Terrarum.HEIGHT - internalHeight) / 2).toFloat()
|
||||
|
||||
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
if (handler.openFired) {
|
||||
rebuildList()
|
||||
}
|
||||
|
||||
|
||||
catBar.update(delta)
|
||||
itemList?.update(delta)
|
||||
equipped?.update(delta)
|
||||
}
|
||||
|
||||
private val gradStartCol = Color(0x404040_60)
|
||||
private val gradEndCol = Color(0x000000_70)
|
||||
private val shapeRenderer = ShapeRenderer()
|
||||
private val gradHeight = 48f
|
||||
|
||||
private val weightBarWidth = 60f
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
val xEnd = (Terrarum.WIDTH + internalWidth).div(2).toFloat()
|
||||
val yEnd = (Terrarum.HEIGHT + internalHeight).div(2).toFloat()
|
||||
|
||||
|
||||
// background fill
|
||||
batch.end()
|
||||
Gdx.gl.glEnable(GL20.GL_BLEND) // ending the batch disables blend
|
||||
|
||||
val gradTopStart = (Terrarum.HEIGHT - internalHeight).div(2).toFloat()
|
||||
val gradBottomEnd = Terrarum.HEIGHT - gradTopStart
|
||||
|
||||
shapeRenderer.inUse {
|
||||
shapeRenderer.rect(0f, gradTopStart, Terrarum.WIDTH.toFloat(), gradHeight, gradStartCol, gradStartCol, gradEndCol, gradEndCol)
|
||||
shapeRenderer.rect(0f, gradBottomEnd, Terrarum.WIDTH.toFloat(), -gradHeight, gradStartCol, gradStartCol, gradEndCol, gradEndCol)
|
||||
|
||||
shapeRenderer.rect(0f, gradTopStart + gradHeight, Terrarum.WIDTH.toFloat(), internalHeight - (2 * gradHeight), gradEndCol, gradEndCol, gradEndCol, gradEndCol)
|
||||
|
||||
shapeRenderer.rect(0f, 0f, Terrarum.WIDTH.toFloat(), gradTopStart, gradStartCol, gradStartCol, gradStartCol, gradStartCol)
|
||||
shapeRenderer.rect(0f, Terrarum.HEIGHT.toFloat(), Terrarum.WIDTH.toFloat(), -(Terrarum.HEIGHT.toFloat() - gradBottomEnd), gradStartCol, gradStartCol, gradStartCol, gradStartCol)
|
||||
}
|
||||
|
||||
|
||||
batch.begin()
|
||||
|
||||
// UI items
|
||||
catBar.render(batch, camera)
|
||||
itemList?.render(batch, camera)
|
||||
equipped?.render(batch, camera)
|
||||
|
||||
|
||||
// control hints
|
||||
blendNormal(batch)
|
||||
batch.color = Color.WHITE
|
||||
Terrarum.fontGame.draw(batch, listControlHelp, offsetX, offsetY + internalHeight)
|
||||
|
||||
|
||||
// encumbrance meter
|
||||
if (actor != null) {
|
||||
val encumbranceText = Lang["GAME_INVENTORY_ENCUMBRANCE"]
|
||||
|
||||
Terrarum.fontGame.draw(batch,
|
||||
encumbranceText,
|
||||
xEnd - 9 - Terrarum.fontGame.getWidth(encumbranceText) - weightBarWidth,
|
||||
yEnd
|
||||
)
|
||||
|
||||
// encumbrance bar background
|
||||
blendMul()
|
||||
batch.color = Color(0xa0a0a0_ff.toInt())
|
||||
batch.fillRect(
|
||||
xEnd - 3 - weightBarWidth,
|
||||
yEnd + 3f,
|
||||
weightBarWidth,
|
||||
controlHelpHeight - 6f
|
||||
)
|
||||
// encumbrance bar
|
||||
blendNormal()
|
||||
batch.color = if (isEncumbered) Color(0xff0000_cc.toInt()) else Color(0x00ff00_cc.toInt())
|
||||
batch.fillRect(
|
||||
xEnd - 3 - weightBarWidth,
|
||||
yEnd + 3f,
|
||||
if (actor?.inventory?.capacityMode == CAPACITY_MODE_NO_ENCUMBER)
|
||||
1f
|
||||
else // make sure 1px is always be seen
|
||||
minOf(weightBarWidth, maxOf(1f, weightBarWidth * encumbrancePerc)),
|
||||
controlHelpHeight - 5f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun rebuildList() {
|
||||
itemList?.rebuild()
|
||||
equipped?.rebuild()
|
||||
|
||||
actor?.let {
|
||||
encumbrancePerc = actor!!.inventory.capacity.toFloat() / actor!!.inventory.maxCapacity
|
||||
isEncumbered = actor!!.inventory.isEncumbered
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
catBar.dispose()
|
||||
itemList?.dispose()
|
||||
equipped?.dispose()
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun doOpening(delta: Float) {
|
||||
(Terrarum.ingame as? Ingame)?.setTooltipMessage(null)
|
||||
}
|
||||
|
||||
override fun doClosing(delta: Float) {
|
||||
(Terrarum.ingame as? Ingame)?.setTooltipMessage(null)
|
||||
}
|
||||
|
||||
override fun endOpening(delta: Float) {
|
||||
}
|
||||
|
||||
override fun endClosing(delta: Float) {
|
||||
(Terrarum.ingame as? Ingame)?.setTooltipMessage(null) // required!!
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
super.resize(width, height)
|
||||
|
||||
offsetX = ((Terrarum.WIDTH - internalWidth) / 2).toFloat()
|
||||
offsetY = ((Terrarum.HEIGHT - internalHeight) / 2).toFloat()
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
return super.keyDown(keycode)
|
||||
}
|
||||
|
||||
override fun keyTyped(character: Char): Boolean {
|
||||
return super.keyTyped(character)
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
return super.touchDown(screenX, screenY, pointer, button)
|
||||
}
|
||||
|
||||
override fun keyUp(keycode: Int): Boolean {
|
||||
return super.keyUp(keycode)
|
||||
}
|
||||
|
||||
override fun mouseMoved(screenX: Int, screenY: Int): Boolean {
|
||||
return super.mouseMoved(screenX, screenY)
|
||||
}
|
||||
|
||||
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
|
||||
return super.touchDragged(screenX, screenY, pointer)
|
||||
}
|
||||
|
||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
return super.touchUp(screenX, screenY, pointer, button)
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
return super.scrolled(amount)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.ui.UIItem
|
||||
|
||||
/**
|
||||
* Cross section of two inventory cell types
|
||||
*
|
||||
* Created by minjaesong on 2017-10-22.
|
||||
*/
|
||||
abstract class UIItemInventoryCellBase(
|
||||
parentUI: UIInventoryFull,
|
||||
override var posX: Int,
|
||||
override var posY: Int,
|
||||
open var item: GameItem?,
|
||||
open var amount: Int,
|
||||
open var itemImage: TextureRegion?,
|
||||
open var quickslot: Int? = null,
|
||||
open var equippedSlot: Int? = null
|
||||
) : UIItem(parentUI) {
|
||||
abstract override fun update(delta: Float)
|
||||
abstract override fun render(batch: SpriteBatch, camera: Camera)
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.BlendMode
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.UIItemInventoryElem
|
||||
import net.torvald.terrarum.UIItemInventoryElemSimple
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.InventoryPair
|
||||
import net.torvald.terrarum.ceilInt
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
import net.torvald.terrarum.modulebasegame.Ingame
|
||||
import net.torvald.terrarum.ui.UIItem
|
||||
import net.torvald.terrarum.ui.UIItemImageButton
|
||||
import java.util.ArrayList
|
||||
|
||||
/**
|
||||
* Display either extended or compact list
|
||||
*
|
||||
* Note: everything is pretty much fixed size.
|
||||
*
|
||||
* Dimension of the whole area: 496x384
|
||||
* Number of grids: 9x7
|
||||
* Number of lists: 2x7
|
||||
*
|
||||
* Created by minjaesong on 2017-10-21.
|
||||
*/
|
||||
class UIItemInventoryDynamicList(
|
||||
parentUI: UIInventoryFull,
|
||||
val inventory: ActorInventory,
|
||||
override var posX: Int,
|
||||
override var posY: Int
|
||||
) : UIItem(parentUI) {
|
||||
|
||||
override val width = 496
|
||||
override val height = 384
|
||||
|
||||
private val catArrangement = parentUI.catArrangement
|
||||
|
||||
|
||||
|
||||
val catIconsMeaning = listOf( // sortedBy: catArrangement
|
||||
GameItem.Category.WEAPON,
|
||||
GameItem.Category.TOOL,
|
||||
GameItem.Category.ARMOUR,
|
||||
GameItem.Category.GENERIC,
|
||||
GameItem.Category.POTION,
|
||||
GameItem.Category.MAGIC,
|
||||
GameItem.Category.BLOCK,
|
||||
GameItem.Category.WALL,
|
||||
GameItem.Category.MISC,
|
||||
"__all__"
|
||||
)
|
||||
|
||||
private val inventoryUI = parentUI
|
||||
|
||||
private val selection: Int
|
||||
get() = inventoryUI.catSelection
|
||||
private val selectedIcon: Int
|
||||
get() = inventoryUI.catSelectedIcon
|
||||
|
||||
private val compactViewCat = setOf(3, 4, 6, 7, 9) // ingredients, potions, blocks, walls, all (spritesheet order)
|
||||
|
||||
var itemPage = 0
|
||||
var itemPageCount = 1 // TODO total size of current category / items.size
|
||||
private set
|
||||
|
||||
var inventorySortList = ArrayList<InventoryPair>()
|
||||
private var rebuildList = true
|
||||
|
||||
val defaultTextColour = Color(0xeaeaea_ff.toInt())
|
||||
|
||||
private val listGap = 8
|
||||
private val itemList = Array<UIItemInventoryCellBase>(
|
||||
7 * 2, {
|
||||
UIItemInventoryElem(
|
||||
parentUI = inventoryUI,
|
||||
posX = this.posX + (244 + listGap) * (it % 2),
|
||||
posY = this.posY + (UIItemInventoryElem.height + listGap) * (it / 2),
|
||||
width = 244,
|
||||
item = null,
|
||||
amount = UIItemInventoryElem.UNIQUE_ITEM_HAS_NO_AMOUNT,
|
||||
itemImage = null,
|
||||
mouseoverBackCol = Color(0x282828_ff),
|
||||
mouseoverBackBlendMode = BlendMode.SCREEN,
|
||||
backCol = Color(0x404040_88),
|
||||
backBlendMode = BlendMode.NORMAL,
|
||||
drawBackOnNull = true,
|
||||
inactiveTextCol = defaultTextColour
|
||||
) })
|
||||
private val itemGrid = Array<UIItemInventoryCellBase>(
|
||||
7 * 9, {
|
||||
UIItemInventoryElemSimple(
|
||||
parentUI = inventoryUI,
|
||||
posX = this.posX + (UIItemInventoryElemSimple.height + listGap) * (it % 9),
|
||||
posY = this.posY + (UIItemInventoryElemSimple.height + listGap) * (it / 9),
|
||||
item = null,
|
||||
amount = UIItemInventoryElem.UNIQUE_ITEM_HAS_NO_AMOUNT,
|
||||
itemImage = null,
|
||||
mouseoverBackCol = Color(0x282828_ff),
|
||||
mouseoverBackBlendMode = BlendMode.SCREEN,
|
||||
backCol = Color(0x404040_88),
|
||||
backBlendMode = BlendMode.NORMAL,
|
||||
drawBackOnNull = true,
|
||||
inactiveTextCol = defaultTextColour
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
private var items: Array<UIItemInventoryCellBase>
|
||||
= if (catArrangement[selection] in compactViewCat) itemGrid else itemList // this is INIT code
|
||||
|
||||
var isCompactMode = (catArrangement[selection] in compactViewCat) // this is INIT code
|
||||
set(value) {
|
||||
items = if (value) itemGrid else itemList
|
||||
|
||||
rebuild()
|
||||
|
||||
field = value
|
||||
}
|
||||
|
||||
|
||||
private val iconPosX = posX - 12 - parentUI.catIcons.tileW + 2
|
||||
private fun getIconPosY(index: Int) =
|
||||
posY - 2 + (4 + UIItemInventoryElem.height - (parentUI as UIInventoryFull).catIcons.tileH) * index
|
||||
|
||||
/** Long/compact mode buttons */
|
||||
private val gridModeButtons = Array<UIItemImageButton>(2, { index ->
|
||||
UIItemImageButton(
|
||||
parentUI,
|
||||
parentUI.catIcons.get(index + 14, 0),
|
||||
activeBackCol = Color(0),
|
||||
activeBackBlendMode = BlendMode.NORMAL,
|
||||
posX = iconPosX,
|
||||
posY = getIconPosY(index),
|
||||
highlightable = true
|
||||
)
|
||||
})
|
||||
|
||||
private val scrollUpButton = UIItemImageButton(
|
||||
parentUI,
|
||||
parentUI.catIcons.get(18, 0),
|
||||
activeBackCol = Color(0),
|
||||
activeBackBlendMode = BlendMode.NORMAL,
|
||||
posX = iconPosX,
|
||||
posY = getIconPosY(2),
|
||||
highlightable = false
|
||||
)
|
||||
|
||||
private val scrollDownButton = UIItemImageButton(
|
||||
parentUI,
|
||||
parentUI.catIcons.get(19, 0),
|
||||
activeBackCol = Color(0),
|
||||
activeBackBlendMode = BlendMode.NORMAL,
|
||||
posX = iconPosX,
|
||||
posY = getIconPosY(3),
|
||||
highlightable = false
|
||||
)
|
||||
|
||||
|
||||
init {
|
||||
// initially highlight grid mode buttons
|
||||
gridModeButtons[if (isCompactMode) 1 else 0].highlighted = true
|
||||
|
||||
|
||||
gridModeButtons[0].touchDownListener = { _, _, _, _ ->
|
||||
isCompactMode = false
|
||||
gridModeButtons[0].highlighted = true
|
||||
gridModeButtons[1].highlighted = false
|
||||
itemPage = 0
|
||||
rebuild()
|
||||
}
|
||||
gridModeButtons[1].touchDownListener = { _, _, _, _ ->
|
||||
isCompactMode = true
|
||||
gridModeButtons[0].highlighted = false
|
||||
gridModeButtons[1].highlighted = true
|
||||
itemPage = 0
|
||||
rebuild()
|
||||
}
|
||||
|
||||
scrollUpButton.clickOnceListener = { _, _, _ ->
|
||||
itemPage = (itemPage - 1).fmod(itemPageCount)
|
||||
scrollUpButton.highlighted = false
|
||||
rebuild()
|
||||
}
|
||||
scrollDownButton.clickOnceListener = { _, _, _ ->
|
||||
itemPage = (itemPage + 1).fmod(itemPageCount)
|
||||
scrollDownButton.highlighted = false
|
||||
rebuild()
|
||||
}
|
||||
|
||||
// if (is.mouseUp) handled by this.touchDown()
|
||||
}
|
||||
|
||||
|
||||
private val upDownButtonGapToDots = 7 // apparent gap may vary depend on the texture itself
|
||||
|
||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||
fun getScrollDotYHeight(i: Int) = scrollUpButton.posY + 10 + upDownButtonGapToDots + 10 * i
|
||||
|
||||
scrollDownButton.posY = getScrollDotYHeight(itemPageCount) + upDownButtonGapToDots
|
||||
|
||||
|
||||
|
||||
items.forEach { it.render(batch, camera) }
|
||||
|
||||
gridModeButtons.forEach { it.render(batch, camera) }
|
||||
scrollUpButton.render(batch, camera)
|
||||
scrollDownButton.render(batch, camera)
|
||||
|
||||
// draw scroll dots
|
||||
for (i in 0 until itemPageCount) {
|
||||
val colour = if (i == itemPage) Color.WHITE else Color(0xffffff7f.toInt())
|
||||
|
||||
batch.color = colour
|
||||
batch.draw(
|
||||
(parentUI as UIInventoryFull).catIcons.get(20,0),
|
||||
scrollUpButton.posX.toFloat(),
|
||||
getScrollDotYHeight(i).toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
super.render(batch, camera)
|
||||
}
|
||||
|
||||
|
||||
override fun update(delta: Float) {
|
||||
super.update(delta)
|
||||
|
||||
var tooltipSet = false
|
||||
|
||||
|
||||
|
||||
items.forEach {
|
||||
it.update(delta)
|
||||
|
||||
|
||||
// set tooltip accordingly
|
||||
if (isCompactMode && it.mouseUp && !tooltipSet) {
|
||||
(Terrarum.ingame as? Ingame)?.setTooltipMessage(it.item?.name)
|
||||
tooltipSet = true
|
||||
}
|
||||
}
|
||||
|
||||
if (!tooltipSet) {
|
||||
(Terrarum.ingame as? Ingame)?.setTooltipMessage(null)
|
||||
}
|
||||
|
||||
|
||||
|
||||
gridModeButtons.forEach { it.update(delta) }
|
||||
scrollUpButton.update(delta)
|
||||
scrollDownButton.update(delta)
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal fun rebuild() {
|
||||
//println("Rebuilt inventory")
|
||||
//println("rebuild: actual itempage: $itemPage")
|
||||
|
||||
|
||||
val filter = catIconsMeaning[selectedIcon]
|
||||
|
||||
inventorySortList = ArrayList<InventoryPair>()
|
||||
|
||||
// filter items
|
||||
inventory.forEach {
|
||||
if (it.item.inventoryCategory == filter || filter == "__all__")
|
||||
inventorySortList.add(it)
|
||||
}
|
||||
|
||||
// sort if needed
|
||||
// test sort by name
|
||||
inventorySortList.sortBy { it.item.name }
|
||||
|
||||
// map sortList to item list
|
||||
for (k in 0 until items.size) {
|
||||
// we have an item
|
||||
try {
|
||||
val sortListItem = inventorySortList[k + itemPage * items.size]
|
||||
items[k].item = sortListItem.item
|
||||
items[k].amount = sortListItem.amount
|
||||
items[k].itemImage = ItemCodex.getItemImage(sortListItem.item)
|
||||
|
||||
// set quickslot number
|
||||
for (qs in 1..UIQuickBar.SLOT_COUNT) {
|
||||
if (sortListItem.item == inventory.getQuickBar(qs - 1)?.item) {
|
||||
items[k].quickslot = qs % 10 // 10 -> 0, 1..9 -> 1..9
|
||||
break
|
||||
}
|
||||
else
|
||||
items[k].quickslot = null
|
||||
}
|
||||
|
||||
// set equippedslot number
|
||||
for (eq in 0 until inventory.itemEquipped.size) {
|
||||
if (eq < inventory.itemEquipped.size) {
|
||||
if (inventory.itemEquipped[eq] == items[k].item) {
|
||||
items[k].equippedSlot = eq
|
||||
break
|
||||
}
|
||||
else
|
||||
items[k].equippedSlot = null
|
||||
}
|
||||
}
|
||||
}
|
||||
// we do not have an item, empty the slot
|
||||
catch (e: IndexOutOfBoundsException) {
|
||||
items[k].item = null
|
||||
items[k].amount = 0
|
||||
items[k].itemImage = null
|
||||
items[k].quickslot = null
|
||||
items[k].equippedSlot = null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
itemPageCount = (inventorySortList.size.toFloat() / items.size.toFloat()).ceilInt()
|
||||
|
||||
|
||||
rebuildList = false
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
itemList.forEach { it.dispose() }
|
||||
itemGrid.forEach { it.dispose() }
|
||||
gridModeButtons.forEach { it.dispose() }
|
||||
scrollUpButton.dispose()
|
||||
scrollDownButton.dispose()
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
super.touchDown(screenX, screenY, pointer, button)
|
||||
|
||||
items.forEach { if (it.mouseUp) it.touchDown(screenX, screenY, pointer, button) }
|
||||
gridModeButtons.forEach { if (it.mouseUp) it.touchDown(screenX, screenY, pointer, button) }
|
||||
if (scrollUpButton.mouseUp) scrollUpButton.touchDown(screenX, screenY, pointer, button)
|
||||
if (scrollDownButton.mouseUp) scrollDownButton.touchDown(screenX, screenY, pointer, button)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
items.forEach { if (it.mouseUp) it.touchUp(screenX, screenY, pointer, button) }
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
super.keyDown(keycode)
|
||||
|
||||
items.forEach { if (it.mouseUp) it.keyDown(keycode) }
|
||||
rebuild()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun keyUp(keycode: Int): Boolean {
|
||||
super.keyUp(keycode)
|
||||
|
||||
items.forEach { if (it.mouseUp) it.keyUp(keycode) }
|
||||
rebuild()
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorWithPhysics
|
||||
import net.torvald.terrarum.itemproperties.GameItem
|
||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||
import net.torvald.terrarum.ui.UIItem
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-10-28.
|
||||
*/
|
||||
class UIItemInventoryEquippedView(
|
||||
parentUI: UIInventoryFull,
|
||||
val inventory: ActorInventory,
|
||||
val theActor: ActorWithPhysics,
|
||||
override var posX: Int,
|
||||
override var posY: Int
|
||||
) : UIItem(parentUI) {
|
||||
|
||||
override val width = 104
|
||||
override val height = 384
|
||||
|
||||
companion object {
|
||||
val width = 104
|
||||
val height = 384
|
||||
}
|
||||
|
||||
private val listGap = 8
|
||||
|
||||
var itemPage = 0
|
||||
var itemPageCount = 1 // TODO total size of current category / itemGrid.size
|
||||
|
||||
lateinit var inventorySortList: Array<GameItem?>
|
||||
private var rebuildList = true
|
||||
|
||||
val spriteViewBackCol: Color; get() = Color(0x404040_88.toInt())//Color(0xd4d4d4_ff.toInt())
|
||||
|
||||
private val itemGrid = Array<UIItemInventoryCellBase>(
|
||||
2 * 5, {
|
||||
UIItemInventoryElemSimple(
|
||||
parentUI = parentUI,
|
||||
posX = this.posX + (UIItemInventoryElemSimple.height + listGap) * ((it + 4) % 2),
|
||||
posY = this.posY + (UIItemInventoryElemSimple.height + listGap) * ((it + 4) / 2),
|
||||
item = null,
|
||||
amount = UIItemInventoryElem.UNIQUE_ITEM_HAS_NO_AMOUNT,
|
||||
itemImage = null,
|
||||
mouseoverBackCol = Color(0x282828_ff),
|
||||
mouseoverBackBlendMode = BlendMode.SCREEN,
|
||||
backCol = Color(0x404040_88),
|
||||
backBlendMode = BlendMode.NORMAL,
|
||||
drawBackOnNull = true
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
override fun update(delta: Float) {
|
||||
itemGrid.forEach { it.update(delta) }
|
||||
}
|
||||
|
||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||
// sprite background
|
||||
blendNormal()
|
||||
batch.color = spriteViewBackCol
|
||||
batch.fillRect(
|
||||
posX.toFloat(), posY.toFloat(),
|
||||
width.toFloat(), width.toFloat()
|
||||
)
|
||||
|
||||
// sprite
|
||||
val sprite = theActor.sprite
|
||||
sprite?.let {
|
||||
blendNormal(batch)
|
||||
|
||||
it.render(
|
||||
batch,
|
||||
posX + (width - it.cellWidth).div(2).toFloat(),
|
||||
posY + (width - it.cellHeight).div(2).toFloat()
|
||||
) }
|
||||
|
||||
|
||||
itemGrid.forEach { it.render(batch, camera) }
|
||||
}
|
||||
|
||||
|
||||
internal fun rebuild() {
|
||||
inventorySortList = inventory.itemEquipped.clone()
|
||||
|
||||
|
||||
|
||||
rebuildList = false
|
||||
|
||||
// sort by equip position
|
||||
|
||||
// fill the grid from fastest index, make no gap in-between of slots
|
||||
var listPushCnt = 0
|
||||
for (k in 0 until itemGrid.size) {
|
||||
val it = inventorySortList[k]
|
||||
|
||||
if (it != null) {
|
||||
val itemRecord = inventory.getByDynamicID(it.dynamicID)!!
|
||||
|
||||
itemGrid[listPushCnt].item = it
|
||||
itemGrid[listPushCnt].amount = itemRecord.amount
|
||||
itemGrid[listPushCnt].itemImage = ItemCodex.getItemImage(it)
|
||||
itemGrid[listPushCnt].quickslot = null // don't need to be displayed
|
||||
itemGrid[listPushCnt].equippedSlot = null // don't need to be displayed
|
||||
|
||||
listPushCnt++
|
||||
}
|
||||
}
|
||||
|
||||
// empty out un-filled grids from previous garbage
|
||||
for (m in listPushCnt until itemGrid.size) {
|
||||
itemGrid[m].item = null
|
||||
itemGrid[m].amount = 0
|
||||
itemGrid[m].itemImage = null
|
||||
itemGrid[m].quickslot = null
|
||||
itemGrid[m].equippedSlot = null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun dispose() {
|
||||
itemGrid.forEach { it.dispose() }
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
super.touchDown(screenX, screenY, pointer, button)
|
||||
|
||||
itemGrid.forEach { if (it.mouseUp) it.touchDown(screenX, screenY, pointer, button) }
|
||||
return true
|
||||
}
|
||||
|
||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
itemGrid.forEach { if (it.mouseUp) it.touchUp(screenX, screenY, pointer, button) }
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
super.keyDown(keycode)
|
||||
|
||||
itemGrid.forEach { if (it.mouseUp) it.keyDown(keycode) }
|
||||
rebuild()
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun keyUp(keycode: Int): Boolean {
|
||||
super.keyUp(keycode)
|
||||
|
||||
itemGrid.forEach { if (it.mouseUp) it.keyUp(keycode) }
|
||||
rebuild()
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package net.torvald.terrarum.modulebasegame.ui
|
||||
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blendNormal
|
||||
import net.torvald.terrarum.floor
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.ui.UIItem
|
||||
|
||||
class UIItemModuleInfoCell(
|
||||
parent: UICanvas,
|
||||
var moduleName: String,
|
||||
override val width: Int,
|
||||
override var posX: Int,
|
||||
override var posY: Int
|
||||
) : UIItem(parent) {
|
||||
|
||||
override val height: Int = Terrarum.fontGame.lineHeight.toInt() * 2
|
||||
|
||||
private val numberAreaWidth = Terrarum.fontSmallNumbers.W * 3 + 4
|
||||
|
||||
override fun render(batch: SpriteBatch, camera: Camera) {
|
||||
blendNormal()
|
||||
|
||||
if (ModMgr.moduleInfo.containsKey(moduleName)) {
|
||||
val modInfo = ModMgr.moduleInfo[moduleName]!!
|
||||
|
||||
// print load order index
|
||||
batch.color = Color(0xccccccff.toInt())
|
||||
var strlen = Terrarum.fontSmallNumbers.getWidth(modInfo.order.toString())
|
||||
Terrarum.fontSmallNumbers.draw(batch,
|
||||
modInfo.order.toString(),
|
||||
posX + (numberAreaWidth - strlen).div(2f).floor(),
|
||||
posY + (height - Terrarum.fontSmallNumbers.H).div(2f).floor()
|
||||
)
|
||||
|
||||
// print module name
|
||||
batch.color = Color.WHITE
|
||||
Terrarum.fontGame.draw(batch,
|
||||
"${modInfo.properName} (${modInfo.version})",
|
||||
posX + numberAreaWidth.toFloat(),
|
||||
posY.toFloat()
|
||||
)
|
||||
|
||||
// print author name
|
||||
strlen = Terrarum.fontGame.getWidth(modInfo.author)
|
||||
Terrarum.fontGame.draw(batch,
|
||||
modInfo.author,
|
||||
posX + width - strlen.toFloat(),
|
||||
posY.toFloat()
|
||||
)
|
||||
|
||||
// print description
|
||||
Terrarum.fontGame.draw(batch,
|
||||
modInfo.description,
|
||||
posX + numberAreaWidth.toFloat(),
|
||||
posY + Terrarum.fontGame.lineHeight
|
||||
)
|
||||
|
||||
// print releasedate
|
||||
strlen = Terrarum.fontGame.getWidth(modInfo.releaseDate)
|
||||
Terrarum.fontGame.draw(batch,
|
||||
modInfo.releaseDate,
|
||||
posX + width - strlen.toFloat(),
|
||||
posY + Terrarum.fontGame.lineHeight
|
||||
)
|
||||
|
||||
}
|
||||
else {
|
||||
batch.color = Color(0xff8080_ff.toInt())
|
||||
val str = "InternalError: no such module: '$moduleName'"
|
||||
val strlen = Terrarum.fontSmallNumbers.getWidth(str)
|
||||
Terrarum.fontSmallNumbers.draw(batch,
|
||||
str,
|
||||
posX + (width - numberAreaWidth - strlen).div(2f).floor() + numberAreaWidth,
|
||||
posY + (height - Terrarum.fontSmallNumbers.H).div(2f).floor()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user