still wip modularisation, game somehow boots

This commit is contained in:
minjaesong
2018-06-21 17:33:22 +09:00
parent 6bbfd5d167
commit 8daf0a2c38
266 changed files with 2409 additions and 1122 deletions

View File

@@ -1,106 +0,0 @@
package net.torvald.terrarum.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"
}

View File

@@ -5,6 +5,7 @@ import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.itemproperties.ItemCodex
import net.torvald.terrarum.itemproperties.ItemCodex.ACTORID_MIN
typealias ActorID = Int
/**
@@ -34,48 +35,21 @@ abstract class Actor(val renderOrder: RenderOrder) : Comparable<Actor>, Runnable
* Valid RefID is equal to or greater than 16777216.
* @return Reference ID. (16777216-0x7FFF_FFFF)
*/
open var referenceID: ActorID = generateUniqueReferenceID()
open var referenceID: ActorID? = null
var actorValue = ActorValue(this)
@Volatile var flagDespawn = false
override fun equals(other: Any?) = referenceID == (other as Actor).referenceID
override fun hashCode() = referenceID
override fun hashCode() = referenceID!!
override fun toString() =
if (actorValue.getAsString(AVKey.NAME).isNullOrEmpty())
if (actorValue.getAsString("name").isNullOrEmpty())
"${hashCode()}"
else
"${hashCode()} (${actorValue.getAsString(AVKey.NAME)})"
override fun compareTo(other: Actor): Int = (this.referenceID - other.referenceID).sign()
"${hashCode()} (${actorValue.getAsString("name")})"
override fun compareTo(other: Actor): Int = (this.referenceID!! - other.referenceID!!).sign()
fun Int.sign(): Int = if (this > 0) 1 else if (this < 0) -1 else 0
/**
* Usage:
*
* override var referenceID: Int = generateUniqueReferenceID()
*/
fun generateUniqueReferenceID(): ActorID {
fun hasCollision(value: ActorID) =
try {
Terrarum.ingame!!.theGameHasActor(value) ||
value < ItemCodex.ACTORID_MIN ||
value !in when (renderOrder) {
RenderOrder.BEHIND -> RANGE_BEHIND
RenderOrder.MIDDLE -> RANGE_MIDDLE
RenderOrder.MIDTOP -> RANGE_MIDTOP
RenderOrder.FRONT -> RANGE_FRONT
}
}
catch (gameNotInitialisedException: KotlinNullPointerException) {
false
}
var ret: Int
do {
ret = HQRNG().nextInt().and(0x7FFFFFFF) // set new ID
} while (hasCollision(ret)) // check for collision
return ret
}
/**
* ActorValue change event handler
@@ -83,6 +57,7 @@ abstract class Actor(val renderOrder: RenderOrder) : Comparable<Actor>, Runnable
* @param value null if the key is deleted
*/
abstract @Event fun onActorValueChange(key: String, value: Any?)
}
annotation class Event

View File

@@ -1,642 +0,0 @@
package net.torvald.terrarum.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.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.realestate.LandUtil
import net.torvald.terrarum.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!!.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!!.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)
}
}
}

View File

@@ -1,293 +0,0 @@
package net.torvald.terrarum.gameactors
import com.badlogic.gdx.Gdx
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.ItemCodex.ITEM_DYNAMIC
import net.torvald.terrarum.itemproperties.ItemCodex.ITEM_WALLS
import net.torvald.terrarum.itemproperties.ItemID
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?.gameFullyLoaded ?: false) &&
(item.originalID == Terrarum.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)

View File

@@ -1,6 +1,8 @@
package net.torvald.terrarum.gameactors
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.gameactors.Actor
import net.torvald.terrarum.gameactors.Hitbox
/**
* Actor with visible body

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +0,0 @@
package net.torvald.terrarum.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
}

View File

@@ -1,24 +0,0 @@
package net.torvald.terrarum.gameactors
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
}
}

View File

@@ -1,177 +0,0 @@
package net.torvald.terrarum.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 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!!.world, outImageData, artName, authorName)
}
}

View File

@@ -1,39 +0,0 @@
package net.torvald.terrarum.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, Actor.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)
}
}

View File

@@ -1,30 +0,0 @@
package net.torvald.terrarum.gameactors
import net.torvald.terrarum.gameworld.GameWorld
/**
* Created by minjaesong on 2016-06-17.
*/
open class FixtureBase(world: GameWorld, physics: Boolean = true) :
ActorWithPhysics(world, Actor.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
}
}

View File

@@ -1,38 +0,0 @@
package net.torvald.terrarum.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.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
}
}

View File

@@ -1,82 +0,0 @@
package net.torvald.terrarum.gameactors
import net.torvald.random.HQRNG
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.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, Actor.RenderOrder.MIDDLE, realAirFriction, usePhysics) {
var historicalFigureIdentifier: Int = generateHistoricalFigureIdentifier()
internal set
private fun generateHistoricalFigureIdentifier(): Int {
fun hasCollision(value: Int) =
try {
Terrarum.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)
}
}

View File

@@ -1,119 +0,0 @@
package net.torvald.terrarum.gameactors
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameactors.ai.ActorAI
import net.torvald.terrarum.gameactors.ai.LuaAIWrapper
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
) : ActorHumanoid(world, born, usePhysics = usePhysics), AIControlled, CanBeAnItem {
constructor(world: GameWorld, luaAi: LuaAIWrapper, born: GameDate) : this(world, luaAi as ActorAI, born) {
luaAi.attachActor(this)
}
companion object {
val DEFAULT_COLLISION_TYPE = ActorWithPhysics.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
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")
}
}

View File

@@ -1,135 +0,0 @@
package net.torvald.terrarum.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 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
}
}
}

View File

@@ -1,19 +0,0 @@
package net.torvald.terrarum.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()
}

View File

@@ -1,145 +0,0 @@
package net.torvald.terrarum.gameactors
import java.util.*
/**
* 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()) }
}
}

View File

@@ -1,81 +0,0 @@
package net.torvald.terrarum.gameactors
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.TextureRegion
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.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 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!!.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!!.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())
}
}
}

View File

@@ -1,108 +0,0 @@
package net.torvald.terrarum.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.Terrarum
/**
* 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
}
}
}

View File

@@ -1,25 +0,0 @@
package net.torvald.terrarum.gameactors
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.TextureRegion
import net.torvald.terrarum.ModMgr
/**
* 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
}
}

View File

@@ -1,48 +0,0 @@
package net.torvald.terrarum.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.worldgenerator.RoguelikeRandomiser
/**
* Created by minjaesong on 2016-03-05.
*/
class PhysTestBall(world: GameWorld) : ActorWithPhysics(world, Actor.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!!.world.width * TILE_SIZE - 1f,
hitbox.startY.toFloat() - 1f,
hitbox.width.toFloat()
)
it.circle(
hitbox.startX.toFloat() - Terrarum.ingame!!.world.width * TILE_SIZE - 1f,
hitbox.startY.toFloat() - 1f,
hitbox.width.toFloat()
)
}
//println(moveDelta)
}
}

View File

@@ -1,60 +0,0 @@
package net.torvald.terrarum.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.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()
}
}

View File

@@ -1,31 +0,0 @@
package net.torvald.terrarum.gameactors
import net.torvald.terrarum.worlddrawer.LightmapRenderer
/**
* 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
}
}

View File

@@ -1,35 +0,0 @@
package net.torvald.terrarum.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)
}
}

View File

@@ -1,23 +0,0 @@
package net.torvald.terrarum.gameactors
import net.torvald.terrarum.Terrarum
/**
* Created by minjaesong on 2016-02-03.
*/
object PlayerBuilder {
operator fun invoke(): Actor {
val p: Actor = Player(Terrarum.ingame!!.world, Terrarum.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
}
}

View File

@@ -1,48 +0,0 @@
package net.torvald.terrarum.gameactors
import net.torvald.terrarum.ModMgr
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameactors.ai.LuaAIWrapper
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!!.world,
LuaAIWrapper("/net/torvald/terrarum/gameactors/ai/scripts/PokemonNPCAI.lua"),
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
}
}

View File

@@ -1,102 +0,0 @@
package net.torvald.terrarum.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.worlddrawer.FeaturesDrawer
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
/**
* Created by minjaesong on 2016-02-03.
*/
object PlayerBuilderSigrid {
operator fun invoke(): Player {
val p = Player(Terrarum.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
}
}

View File

@@ -1,37 +0,0 @@
package net.torvald.terrarum.gameactors
import net.torvald.terrarum.ModMgr
import net.torvald.terrarum.Terrarum
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!!.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
}
}

View File

@@ -1,81 +0,0 @@
package net.torvald.terrarum.gameactors
import com.badlogic.gdx.Gdx
import net.torvald.terrarum.Terrarum
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
}
}

View File

@@ -1,9 +0,0 @@
package net.torvald.terrarum.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 {
}

View File

@@ -1,18 +0,0 @@
package net.torvald.terrarum.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) {
}

View File

@@ -1,126 +0,0 @@
package net.torvald.terrarum.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.gameworld.GameWorld
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, Actor.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!!.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)
// ...
)
}
}

View File

@@ -1,38 +0,0 @@
package net.torvald.terrarum.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"
}

View File

@@ -1,25 +0,0 @@
package net.torvald.terrarum.gameactors
import com.badlogic.gdx.Gdx
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)
}
}
}
}
}
}

View File

@@ -1,37 +0,0 @@
package net.torvald.terrarum.gameactors
import com.badlogic.gdx.graphics.Color
import net.torvald.terrarum.gameworld.GameWorld
/**
* Created by minjaesong on 2016-04-26.
*/
class WeaponSwung(world: GameWorld, val itemID: Int) : ActorWithPhysics(world, Actor.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 {
}
}

View File

@@ -1,11 +1,10 @@
package net.torvald.terrarum.gameactors.ai
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.TerrarumAppLoader
import net.torvald.terrarum.AppLoader
import net.torvald.terrarum.gameactors.AIControlled
import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.gameactors.ActorWithPhysics
import net.torvald.terrarum.worlddrawer.LightmapRenderer
import net.torvald.terrarum.modulebasegame.gameactors.AVKey
import net.torvald.terrarum.modulebasegame.gameactors.ActorWithPhysics
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.blockproperties.BlockCodex
import org.luaj.vm2.*
@@ -15,7 +14,7 @@ import org.luaj.vm2.lib.ZeroArgFunction
/**
* Created by minjaesong on 2016-10-24.
*/
internal class AILuaAPI(g: Globals, actor: ActorWithPhysics) {
/*internal class AILuaAPI(g: Globals, actor: ActorWithPhysics) {
// FIXME when actor jumps, the actor releases left/right stick
@@ -233,7 +232,7 @@ internal class AILuaAPI(g: Globals, actor: ActorWithPhysics) {
luatable[y - feetTilePos[1]] = LuaTable()
for (x in feetTilePos[0] - radius..feetTilePos[0] + radius) {
val tile = BlockCodex[Terrarum.ingame!!.world.getTileFromTerrain(x, y) ?: Block.NULL]
val tile = BlockCodex[(Terrarum.ingame!! as Ingame).world.getTileFromTerrain(x, y) ?: Block.NULL]
val solidity = tile.isSolid.toInt()
val liquidity = tile.isFluid.toInt()
val gravity = tile.isFallable.toInt()
@@ -277,7 +276,7 @@ internal class AILuaAPI(g: Globals, actor: ActorWithPhysics) {
// search down
var searchDownCounter = 0
while (true) {
val tile = Terrarum.ingame!!.world.getTileFromTerrain(x, feetTilePos[1] + searchDownCounter) ?: Block.STONE
val tile = (Terrarum.ingame!! as Ingame).world.getTileFromTerrain(x, feetTilePos[1] + searchDownCounter) ?: Block.STONE
if (BlockCodex[tile].isSolid || searchDownCounter >= searchDownLimit) {
luatable[x - feetTilePos[0]] = searchDownCounter
break
@@ -320,7 +319,7 @@ internal class AILuaAPI(g: Globals, actor: ActorWithPhysics) {
// search up
var searchUpCounter = 0
while (true) {
val tile = Terrarum.ingame!!.world.getTileFromTerrain(x, feetTilePos[1] - searchUpCounter) ?: Block.STONE
val tile = (Terrarum.ingame!! as Ingame).world.getTileFromTerrain(x, feetTilePos[1] - searchUpCounter) ?: Block.STONE
if (BlockCodex[tile].isSolid || searchUpCounter >= searchUpLimit) {
luatable[x - feetTilePos[0]] = searchUpCounter
break
@@ -362,7 +361,7 @@ internal class AILuaAPI(g: Globals, actor: ActorWithPhysics) {
// search up
var searchUpCounter = 0
while (true) {
val tile = Terrarum.ingame!!.world.getTileFromTerrain(x, feetTilePos[1] - searchUpCounter) ?: Block.STONE
val tile = (Terrarum.ingame!! as Ingame).world.getTileFromTerrain(x, feetTilePos[1] - searchUpCounter) ?: Block.STONE
if (!BlockCodex[tile].isSolid || searchUpCounter >= searchUpLimit) {
luatable[x - feetTilePos[0]] = searchUpCounter
break
@@ -381,16 +380,16 @@ internal class AILuaAPI(g: Globals, actor: ActorWithPhysics) {
class GameVersion : ZeroArgFunction() {
override fun call(): LuaValue {
return TerrarumAppLoader.getVERSION_STRING().toLua()
return AppLoader.getVERSION_STRING().toLua()
}
}
class GameVersionRaw : ZeroArgFunction() {
override fun call(): LuaValue {
return TerrarumAppLoader.VERSION_RAW.toLua()
return AppLoader.VERSION_RAW.toLua()
}
}
}
}*/
fun Double.toLua() = LuaValue.valueOf(this)
fun Int.toLua() = LuaValue.valueOf(this)

View File

@@ -1,10 +1,11 @@
package net.torvald.terrarum.gameactors.ai
import net.torvald.terrarum.gameactors.HumanoidNPC
import net.torvald.terrarum.gameactors.Actor
/**
* Created by minjaesong on 2016-03-02.
*/
interface ActorAI {
fun update(actor: HumanoidNPC, delta: Float)
fun update(actor: Actor, delta: Float)
}

View File

@@ -1,9 +1,6 @@
package net.torvald.terrarum.gameactors.ai
import net.torvald.terrarum.gameactors.Actor
import net.torvald.terrarum.gameactors.ActorHumanoid
import net.torvald.terrarum.gameactors.ActorWithPhysics
import net.torvald.terrarum.gameactors.HumanoidNPC
import org.luaj.vm2.Globals
import org.luaj.vm2.LuaError
import org.luaj.vm2.LuaInteger
@@ -15,7 +12,7 @@ import java.io.Reader
/**
* Created by minjaesong on 2017-02-04.
*/
class LuaAIWrapper(private val scriptPath: String) : ActorAI {
/*class LuaAIWrapper(private val scriptPath: String) : ActorAI {
protected val luag: Globals = JsePlatform.standardGlobals()
@@ -27,14 +24,14 @@ class LuaAIWrapper(private val scriptPath: String) : ActorAI {
private lateinit var aiLuaAPI: AILuaAPI
private lateinit var targetActor: ActorWithPhysics
private lateinit var targetActor: Actor
/**
* The initialiser
*
* Use ```(p.ai as LuaAIWrapper).attachActor(p)```
*/
fun attachActor(actor: ActorWithPhysics) {
fun attachActor(actor: Actor) {
targetActor = actor
luag["io"] = LuaValue.NIL
@@ -47,7 +44,7 @@ class LuaAIWrapper(private val scriptPath: String) : ActorAI {
luaInstance.call()
}
override fun update(actor: HumanoidNPC, delta: Float) {
override fun update(actor: Actor, delta: Float) {
// run "update()" function in the script
luag.get("update").call(delta.toLua())
}
@@ -112,4 +109,4 @@ class LuaAIWrapper(private val scriptPath: String) : ActorAI {
}
fun Float.toLua(): LuaValue = LuaInteger.valueOf(this.toDouble())
}
}*/

View File

@@ -0,0 +1,12 @@
package net.torvald.terrarum.gameactors.ai
import net.torvald.terrarum.gameactors.Actor
/**
* Created by minjaesong on 2018-06-07.
*/
class NullAI : ActorAI {
override fun update(actor: Actor, delta: Float) {
// null AI does nothing
}
}

View File

@@ -1,51 +0,0 @@
package net.torvald.terrarum.gameactors.ai
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameactors.HumanoidNPC
import net.torvald.terrarum.gameactors.Second
/**
* 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: HumanoidNPC, delta: Float) {
// 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!!.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()
}
}
}

View File

@@ -1,222 +0,0 @@
package net.torvald.terrarum.gameactors.physicssolver
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.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!!.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!!.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)
*/
}

View File

@@ -1,11 +0,0 @@
package net.torvald.terrarum.gameactors.physicssolver
/**
* multithreaded version of CollisionSolver#solveCollision
* Created by minjaesong on 2016-04-26.
*/
internal class SolveByUnit : Runnable {
override fun run() {
throw UnsupportedOperationException()
}
}

View File

@@ -1,18 +0,0 @@
package net.torvald.terrarum.gameactors.physicssolver
import net.torvald.terrarum.gameactors.ActorWithPhysics
/**
* Created by minjaesong on 2016-05-01.
*/
object VelocitySolver {
fun process() {
}
private fun applyGravity(actor: ActorWithPhysics) {
}
}