mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-17 14:04:05 +09:00
com.torvald → net.torvald
Former-commit-id: 375604da8a20a6ba7cd0a8d05a44add02b2d04f4 Former-commit-id: 287287c5920b07618174d7a7573f049d350ded66
This commit is contained in:
10
src/net/torvald/terrarum/gameactors/AIControlled.kt
Normal file
10
src/net/torvald/terrarum/gameactors/AIControlled.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.terrarum.gameactors.ai.ActorAI
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface AIControlled {
|
||||
fun attachAI(ai: ActorAI)
|
||||
}
|
||||
34
src/net/torvald/terrarum/gameactors/AVKey.kt
Normal file
34
src/net/torvald/terrarum/gameactors/AVKey.kt
Normal file
@@ -0,0 +1,34 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-04-02.
|
||||
*/
|
||||
object AVKey {
|
||||
const val MULT = "mult"
|
||||
|
||||
const val SPEED = "speed"
|
||||
const val SPEEDMULT = "speed$MULT"
|
||||
const val ACCEL = "accel"
|
||||
const val ACCELMULT = "accel$MULT"
|
||||
const val SCALE = "scale"
|
||||
const val BASEHEIGHT = "baseheight"
|
||||
const val BASEMASS = "basemass"
|
||||
const val JUMPPOWER = "jumppower"
|
||||
const val JUMPPOWERMULT = "jumppower$MULT"
|
||||
|
||||
const val STRENGTH = "strength"
|
||||
const val ENCUMBRANCE = "encumbrance"
|
||||
const val LUMINOSITY = "luminosity"
|
||||
const val PHYSIQUEMULT = "physique$MULT"
|
||||
|
||||
const val NAME = "name"
|
||||
|
||||
const val RACENAME = "racename"
|
||||
const val RACENAMEPLURAL = "racenameplural"
|
||||
const val TOOLSIZE = "toolsize"
|
||||
const val INTELLIGENT = "intelligent"
|
||||
|
||||
const val BASEDEFENCE = "basedefence" // creature base
|
||||
const val ARMOURDEFENCE = "armourdefence" // armour points
|
||||
const val ARMOURDEFENCEMULT = "armourdefence$MULT"
|
||||
}
|
||||
19
src/net/torvald/terrarum/gameactors/Actor.kt
Normal file
19
src/net/torvald/terrarum/gameactors/Actor.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import org.newdawn.slick.GameContainer
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface Actor {
|
||||
|
||||
fun update(gc: GameContainer, delta_t: Int)
|
||||
|
||||
/**
|
||||
* Valid RefID is equal to or greater than 32768.
|
||||
* @return Reference ID. (32768-0x7FFF_FFFF_FFFF_FFFF)
|
||||
*/
|
||||
var referenceID: Long
|
||||
|
||||
var actorValue: ActorValue
|
||||
}
|
||||
146
src/net/torvald/terrarum/gameactors/ActorInventory.kt
Normal file
146
src/net/torvald/terrarum/gameactors/ActorInventory.kt
Normal file
@@ -0,0 +1,146 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.terrarum.gameitem.InventoryItem
|
||||
import net.torvald.terrarum.itemproperties.ItemPropCodex
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-15.
|
||||
*/
|
||||
|
||||
class ActorInventory() {
|
||||
|
||||
@Transient val CAPACITY_MAX = 0x7FFFFFFF
|
||||
@Transient val CAPACITY_MODE_NO_ENCUMBER = 0
|
||||
@Transient val CAPACITY_MODE_COUNT = 1
|
||||
@Transient val CAPACITY_MODE_WEIGHT = 2
|
||||
|
||||
|
||||
private var capacityByCount: Int
|
||||
private var capacityByWeight: Int
|
||||
private var capacityMode: Int
|
||||
|
||||
/**
|
||||
* <ReferenceID, Amounts>
|
||||
*/
|
||||
private val itemList: HashMap<Long, Int> = HashMap()
|
||||
|
||||
/**
|
||||
* Default constructor with no encumbrance.
|
||||
*/
|
||||
init {
|
||||
capacityMode = CAPACITY_MODE_NO_ENCUMBER
|
||||
capacityByCount = 0
|
||||
capacityByWeight = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct new inventory with specified capacity.
|
||||
* @param capacity if is_weight is true, killogramme value is required, counts of items otherwise.
|
||||
* *
|
||||
* @param is_weight whether encumbrance should be calculated upon the weight of the inventory. False to use item counts.
|
||||
*/
|
||||
constructor(capacity: Int, is_weight: Boolean) : this() {
|
||||
if (is_weight) {
|
||||
capacityByWeight = capacity
|
||||
capacityMode = CAPACITY_MODE_WEIGHT
|
||||
} else {
|
||||
capacityByCount = capacity
|
||||
capacityMode = CAPACITY_MODE_COUNT
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get capacity of inventory
|
||||
* @return
|
||||
*/
|
||||
fun getCapacity(): Int {
|
||||
if (capacityMode == CAPACITY_MODE_NO_ENCUMBER) {
|
||||
return CAPACITY_MAX
|
||||
}
|
||||
else if (capacityMode == CAPACITY_MODE_WEIGHT) {
|
||||
return capacityByWeight
|
||||
}
|
||||
else {
|
||||
return capacityByCount
|
||||
}
|
||||
}
|
||||
|
||||
fun getCapacityMode(): Int {
|
||||
return capacityMode
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reference to the itemList
|
||||
* @return
|
||||
*/
|
||||
fun getItemList(): Map<Long, Int>? {
|
||||
return itemList
|
||||
}
|
||||
|
||||
/**
|
||||
* Get clone of the itemList
|
||||
* @return
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun getCopyOfItemList(): Map<Long, Int>? {
|
||||
return itemList.clone() as Map<Long, Int>
|
||||
}
|
||||
|
||||
fun getTotalWeight(): Float {
|
||||
var weight = 0f
|
||||
|
||||
for (item in itemList.entries) {
|
||||
weight += ItemPropCodex.getItem(item.key).mass * item.value
|
||||
}
|
||||
|
||||
return weight
|
||||
}
|
||||
|
||||
fun getTotalCount(): Int {
|
||||
var count = 0
|
||||
|
||||
for (item in itemList.entries) {
|
||||
count += item.value
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
fun getTotalUniqueCount(): Int {
|
||||
return itemList.entries.size
|
||||
}
|
||||
|
||||
fun appendToPocket(item: InventoryItem) {
|
||||
appendToPocket(item, 1)
|
||||
}
|
||||
|
||||
fun appendToPocket(item: InventoryItem, count: Int) {
|
||||
val key = item.itemID
|
||||
|
||||
// if (key == Player.PLAYER_REF_ID)
|
||||
// throw new IllegalArgumentException("Attempted to put player into the inventory.");
|
||||
|
||||
if (itemList.containsKey(key))
|
||||
// increment amount if it already has specified item
|
||||
itemList.put(key, itemList[key]!! + count)
|
||||
else
|
||||
// add new entry if it does not have specified item
|
||||
itemList.put(key, count)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the itemList contains too many items
|
||||
* @return
|
||||
*/
|
||||
fun isEncumbered(): Boolean {
|
||||
if (getCapacityMode() == CAPACITY_MODE_WEIGHT) {
|
||||
return capacityByWeight < getTotalWeight()
|
||||
} else if (getCapacityMode() == CAPACITY_MODE_COUNT) {
|
||||
return capacityByCount < getTotalWeight()
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
8
src/net/torvald/terrarum/gameactors/ActorValue.kt
Normal file
8
src/net/torvald/terrarum/gameactors/ActorValue.kt
Normal file
@@ -0,0 +1,8 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.terrarum.KVHashMap
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-19.
|
||||
*/
|
||||
class ActorValue : KVHashMap()
|
||||
779
src/net/torvald/terrarum/gameactors/ActorWithBody.kt
Normal file
779
src/net/torvald/terrarum/gameactors/ActorWithBody.kt
Normal file
@@ -0,0 +1,779 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.gamemap.GameMap
|
||||
import net.torvald.terrarum.mapdrawer.MapDrawer
|
||||
import net.torvald.terrarum.tileproperties.TilePropCodex
|
||||
import net.torvald.spriteanimation.SpriteAnimation
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.tileproperties.TileNameCode
|
||||
import org.newdawn.slick.GameContainer
|
||||
import org.newdawn.slick.Graphics
|
||||
|
||||
/**
|
||||
* Base class for every actor that has physical (or visible) body. This includes furnishings, paintings, gadgets, etc.
|
||||
*
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
open class ActorWithBody constructor() : Actor, Visible, Glowing {
|
||||
|
||||
override var actorValue: ActorValue = ActorValue()
|
||||
|
||||
var hitboxTranslateX: Float = 0.toFloat()// relative to spritePosX
|
||||
var hitboxTranslateY: Float = 0.toFloat()// relative to spritePosY
|
||||
var baseHitboxW: Int = 0
|
||||
var baseHitboxH: Int = 0
|
||||
|
||||
/**
|
||||
* Velocity for newtonian sim.
|
||||
* Fluctuation in, otherwise still, velocity is equal to acceleration.
|
||||
|
||||
* Acceleration: used in code like:
|
||||
* veloY += 3.0
|
||||
* +3.0 is acceleration. You __accumulate__ acceleration to the velocity.
|
||||
*/
|
||||
@Volatile var veloX: Float = 0.toFloat()
|
||||
@Volatile var veloY: Float = 0.toFloat()
|
||||
@Transient private val VELO_HARD_LIMIT = 10000f
|
||||
|
||||
var grounded = false
|
||||
|
||||
@Transient var sprite: SpriteAnimation? = null
|
||||
@Transient var spriteGlow: SpriteAnimation? = null
|
||||
/** Default to 'false' */
|
||||
var isVisible = false
|
||||
/** Default to 'true' */
|
||||
var isUpdate = true
|
||||
|
||||
var isNoSubjectToGrav = false
|
||||
var isNoCollideWorld = false
|
||||
var isNoSubjectToFluidResistance = false
|
||||
|
||||
internal var baseSpriteWidth: Int = 0
|
||||
internal var baseSpriteHeight: Int = 0
|
||||
|
||||
override var referenceID: Long = 0L
|
||||
/**
|
||||
* Positions: top-left point
|
||||
*/
|
||||
val hitbox = Hitbox(0f,0f,0f,0f)
|
||||
@Transient val nextHitbox = Hitbox(0f,0f,0f,0f)
|
||||
|
||||
/**
|
||||
* Physical properties
|
||||
*/
|
||||
@Volatile @Transient var scale = 1f
|
||||
@Volatile @Transient var mass = 2f
|
||||
@Transient private val MASS_LOWEST = 2f
|
||||
/** Valid range: [0, 1] */
|
||||
var elasticity = 0f
|
||||
set(value) {
|
||||
if (value < 0)
|
||||
throw IllegalArgumentException("[ActorWithBody] $value: valid elasticity value is [0, 1].")
|
||||
else if (value > 1) {
|
||||
println("[ActorWithBody] Elasticity were capped to 1.")
|
||||
field = ELASTICITY_MAX
|
||||
}
|
||||
else
|
||||
field = value * ELASTICITY_MAX
|
||||
}
|
||||
@Transient private val ELASTICITY_MAX = 0.993f
|
||||
private var density = 1000f
|
||||
|
||||
/**
|
||||
* Gravitational Constant G. Load from gamemap.
|
||||
* [m / s^2]
|
||||
* s^2 = 1/FPS = 1/60 if FPS is targeted to 60
|
||||
* meter to pixel : 24/FPS
|
||||
*/
|
||||
@Transient private val METER = 24f
|
||||
/**
|
||||
* [m / s^2] * SI_TO_GAME_ACC -> [px / IFrame^2]
|
||||
*/
|
||||
@Transient private val SI_TO_GAME_ACC = METER / FastMath.sqr(Terrarum.TARGET_FPS.toFloat())
|
||||
/**
|
||||
* [m / s] * SI_TO_GAME_VEL -> [px / IFrame]
|
||||
*/
|
||||
@Transient private val SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS
|
||||
|
||||
@Transient private var gravitation: Float = 0.toFloat()
|
||||
@Transient private val DRAG_COEFF = 1f
|
||||
|
||||
@Transient private val CONTACT_AREA_TOP = 0
|
||||
@Transient private val CONTACT_AREA_RIGHT = 1
|
||||
@Transient private val CONTACT_AREA_BOTTOM = 2
|
||||
@Transient private val CONTACT_AREA_LEFT = 3
|
||||
|
||||
@Transient private val UD_COMPENSATOR_MAX = TSIZE
|
||||
@Transient private val LR_COMPENSATOR_MAX = TSIZE
|
||||
@Transient private val TILE_AUTOCLIMB_RATE = 4
|
||||
|
||||
/**
|
||||
* A constant to make falling faster so that the game is more playable
|
||||
*/
|
||||
@Transient private val G_MUL_PLAYABLE_CONST = 1.4142f
|
||||
|
||||
@Transient private val EVENT_MOVE_TOP = 0
|
||||
@Transient private val EVENT_MOVE_RIGHT = 1
|
||||
@Transient private val EVENT_MOVE_BOTTOM = 2
|
||||
@Transient private val EVENT_MOVE_LEFT = 3
|
||||
@Transient private val EVENT_MOVE_NONE = -1
|
||||
|
||||
@Transient internal var eventMoving = EVENT_MOVE_NONE // cannot collide both X-axis and Y-axis, or else jump control breaks up.
|
||||
|
||||
/**
|
||||
* in milliseconds
|
||||
*/
|
||||
@Transient val INVINCIBILITY_TIME = 500
|
||||
|
||||
@Transient private val map: GameMap
|
||||
|
||||
@Transient private val MASS_DEFAULT = 60f
|
||||
|
||||
|
||||
private var posAdjustX = 0
|
||||
private var posAdjustY = 0
|
||||
|
||||
init {
|
||||
do {
|
||||
referenceID = HQRNG().nextLong() // set new ID
|
||||
} while (Terrarum.game.hasActor(referenceID)) // check for collision
|
||||
|
||||
map = Terrarum.game.map
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
* @param w
|
||||
* *
|
||||
* @param h
|
||||
* *
|
||||
* @param tx +: translate drawn sprite to LEFT.
|
||||
* *
|
||||
* @param ty +: translate drawn sprite to DOWN.
|
||||
* *
|
||||
* @see ActorWithBody.drawBody
|
||||
* @see ActorWithBody.drawGlow
|
||||
*/
|
||||
fun setHitboxDimension(w: Int, h: Int, tx: Int, ty: Int) {
|
||||
baseHitboxH = h
|
||||
baseHitboxW = w
|
||||
hitboxTranslateX = tx.toFloat()
|
||||
hitboxTranslateY = ty.toFloat()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set hitbox position from bottom-center point
|
||||
* @param x
|
||||
* *
|
||||
* @param y
|
||||
*/
|
||||
fun setPosition(x: Float, y: Float) {
|
||||
hitbox.set(
|
||||
x - (baseHitboxW / 2 - hitboxTranslateX) * scale,
|
||||
y - (baseHitboxH - hitboxTranslateY) * scale,
|
||||
baseHitboxW * scale,
|
||||
baseHitboxH * scale)
|
||||
|
||||
nextHitbox.set(
|
||||
x - (baseHitboxW / 2 - hitboxTranslateX) * scale,
|
||||
y - (baseHitboxH - hitboxTranslateY) * scale,
|
||||
baseHitboxW * scale,
|
||||
baseHitboxH * scale)
|
||||
}
|
||||
|
||||
private fun updatePhysicalInfos() {
|
||||
scale = actorValue.getAsFloat(AVKey.SCALE) ?: 1f
|
||||
mass = (actorValue.getAsFloat(AVKey.BASEMASS) ?: MASS_DEFAULT) * FastMath.pow(scale, 3f)
|
||||
if (elasticity != 0f) elasticity = 0f
|
||||
}
|
||||
|
||||
override fun update(gc: GameContainer, delta_t: Int) {
|
||||
if (isUpdate) {
|
||||
updatePhysicalInfos()
|
||||
/**
|
||||
* Update variables
|
||||
*/
|
||||
// make NoClip work for player
|
||||
if (this is Player) {
|
||||
isNoSubjectToGrav = isPlayerNoClip
|
||||
isNoCollideWorld = isPlayerNoClip
|
||||
isNoSubjectToFluidResistance = isPlayerNoClip
|
||||
}
|
||||
|
||||
// clamp to the minimum possible mass
|
||||
if (mass < MASS_LOWEST) mass = MASS_LOWEST
|
||||
|
||||
// set sprite dimension vars if there IS sprite for the actor
|
||||
if (sprite != null) {
|
||||
baseSpriteHeight = sprite!!.height
|
||||
baseSpriteWidth = sprite!!.width
|
||||
}
|
||||
|
||||
// copy gravitational constant from the map the actor is in
|
||||
gravitation = map.gravitation
|
||||
|
||||
// Auto climb rate. Clamp to TSIZE
|
||||
AUTO_CLIMB_RATE = Math.min(TSIZE / 8 * FastMath.sqrt(scale), TSIZE.toFloat()).toInt()
|
||||
|
||||
// Actors are subject to the gravity and the buoyancy if they are not levitating
|
||||
if (!isNoSubjectToGrav) {
|
||||
applyGravitation()
|
||||
//applyBuoyancy()
|
||||
}
|
||||
|
||||
// hard limit velocity
|
||||
if (veloX > VELO_HARD_LIMIT) veloX = VELO_HARD_LIMIT
|
||||
if (veloY > VELO_HARD_LIMIT) veloY = VELO_HARD_LIMIT
|
||||
|
||||
// Set 'next' position (hitbox) to fiddle with
|
||||
updateNextHitboxFromVelo()
|
||||
|
||||
// if not horizontally moving then ...
|
||||
//if (Math.abs(veloX) < 0.5) { // fix for special situations (see fig. 1 at the bottom of the source)
|
||||
// updateVerticalPos();
|
||||
// updateHorizontalPos();
|
||||
//}
|
||||
//else {
|
||||
// compensate for colliding
|
||||
updateHorizontalPos()
|
||||
updateVerticalPos()
|
||||
//}
|
||||
|
||||
// apply our compensation to actual hitbox
|
||||
updateHitboxX()
|
||||
updateHitboxY()
|
||||
|
||||
// make sure the actor does not go out of the map
|
||||
clampNextHitbox()
|
||||
clampHitbox()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply gravitation to the every falling body (unless not levitating)
|
||||
|
||||
* Apply only if not grounded; normal force is not implemented (and redundant)
|
||||
* so we manually reset G to zero (not applying G. force) if grounded.
|
||||
*/
|
||||
// FIXME abnormal jump behaviour if mass < 2, same thing happens if mass == 0 (but zero mass is invalid anyway).
|
||||
private fun applyGravitation() {
|
||||
if (!grounded) {
|
||||
/**
|
||||
* weight; gravitational force in action
|
||||
* W = mass * G (9.8 [m/s^2])
|
||||
*/
|
||||
val W = gravitation * mass
|
||||
/**
|
||||
* Drag of atmosphere
|
||||
* D = Cd (drag coefficient) * 0.5 * rho (density) * V^2 (velocity) * A (area)
|
||||
*/
|
||||
val A = scale * scale
|
||||
val D = DRAG_COEFF * 0.5f * 1.292f * veloY * veloY * A
|
||||
|
||||
veloY += clampCeil(
|
||||
(W - D) / mass * SI_TO_GAME_ACC * G_MUL_PLAYABLE_CONST, VELO_HARD_LIMIT)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateVerticalPos() {
|
||||
if (!isNoCollideWorld) {
|
||||
if (veloY >= 0) { // check downward
|
||||
if (isColliding(CONTACT_AREA_BOTTOM)) { // the ground has dug into the body
|
||||
adjustHitBottom()
|
||||
veloY = 0f // reset veloY, simulating normal force
|
||||
elasticReflectY()
|
||||
grounded = true
|
||||
}
|
||||
else if (isColliding(CONTACT_AREA_BOTTOM, 0, 1)) { // the actor is standing ON the ground
|
||||
veloY = 0f // reset veloY, simulating normal force
|
||||
elasticReflectY()
|
||||
grounded = true
|
||||
}
|
||||
else { // the actor is not grounded at all
|
||||
grounded = false
|
||||
}
|
||||
}
|
||||
else if (veloY < 0) { // check upward
|
||||
grounded = false
|
||||
if (isColliding(CONTACT_AREA_TOP)) { // the ceiling has dug into the body
|
||||
adjustHitTop()
|
||||
veloY = 0f // reset veloY, simulating normal force
|
||||
elasticReflectY()
|
||||
}
|
||||
else if (isColliding(CONTACT_AREA_TOP, 0, -1)) { // the actor is touching the ceiling
|
||||
veloY = 0f // reset veloY, simulating normal force
|
||||
elasticReflectY() // reflect on ceiling, for reversed gravity
|
||||
}
|
||||
else { // the actor is not grounded at all
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun adjustHitBottom() {
|
||||
val newX = nextHitbox.pointedX // look carefully, getPos or getPointed
|
||||
// int-ify posY of nextHitbox
|
||||
nextHitbox.setPositionYFromPoint(FastMath.floor(nextHitbox.pointedY).toFloat())
|
||||
|
||||
var newYOff = 0 // always positive
|
||||
|
||||
// count up Y offset until the actor is not touching the ground
|
||||
var colliding: Boolean
|
||||
do {
|
||||
newYOff += 1
|
||||
colliding = isColliding(CONTACT_AREA_BOTTOM, 0, -newYOff)
|
||||
} while (colliding)
|
||||
|
||||
posAdjustY = -newYOff
|
||||
val newY = nextHitbox.pointedY - newYOff
|
||||
nextHitbox.setPositionFromPoint(newX, newY)
|
||||
}
|
||||
|
||||
private fun adjustHitTop() {
|
||||
val newX = nextHitbox.posX
|
||||
// int-ify posY of nextHitbox
|
||||
nextHitbox.setPositionY(FastMath.ceil(nextHitbox.posY).toFloat())
|
||||
|
||||
var newYOff = 0 // always positive
|
||||
|
||||
// count up Y offset until the actor is not touching the ceiling
|
||||
var colliding: Boolean
|
||||
do {
|
||||
newYOff += 1
|
||||
colliding = isColliding(CONTACT_AREA_TOP, 0, newYOff)
|
||||
} while (colliding)
|
||||
|
||||
posAdjustY = newYOff
|
||||
val newY = nextHitbox.posY + newYOff
|
||||
nextHitbox.setPosition(newX, newY)
|
||||
}
|
||||
|
||||
private fun updateHorizontalPos() {
|
||||
if (!isNoCollideWorld) {
|
||||
if (veloX >= 0.5) { // check right
|
||||
if (isColliding(CONTACT_AREA_RIGHT) && !isColliding(CONTACT_AREA_LEFT)) {
|
||||
// the actor is embedded to the wall
|
||||
adjustHitRight()
|
||||
veloX = 0f // reset veloX, simulating normal force
|
||||
elasticReflectX()
|
||||
}
|
||||
else if (isColliding(CONTACT_AREA_RIGHT, 2, 0) && !isColliding(CONTACT_AREA_LEFT, 0, 0)) { // offset by +1, to fix directional quarks
|
||||
// the actor is touching the wall
|
||||
veloX = 0f // reset veloX, simulating normal force
|
||||
elasticReflectX()
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
else if (veloX <= -0.5) { // check left
|
||||
// System.out.println("collidingleft");
|
||||
if (isColliding(CONTACT_AREA_LEFT) && !isColliding(CONTACT_AREA_RIGHT)) {
|
||||
// the actor is embedded to the wall
|
||||
adjustHitLeft()
|
||||
veloX = 0f // reset veloX, simulating normal force
|
||||
elasticReflectX()
|
||||
}
|
||||
else if (isColliding(CONTACT_AREA_LEFT, -1, 0) && !isColliding(CONTACT_AREA_RIGHT, 1, 0)) {
|
||||
// the actor is touching the wall
|
||||
veloX = 0f // reset veloX, simulating normal force
|
||||
elasticReflectX()
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
else { // check both sides?
|
||||
// System.out.println("updatehorizontal - |velo| < 0.5");
|
||||
//if (isColliding(CONTACT_AREA_LEFT) || isColliding(CONTACT_AREA_RIGHT)) {
|
||||
// veloX = 0f // reset veloX, simulating normal force
|
||||
// elasticReflectX()
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun adjustHitRight() {
|
||||
val newY = nextHitbox.posY // look carefully, posY or pointedY
|
||||
// int-ify posY of nextHitbox
|
||||
nextHitbox.setPositionX(FastMath.floor(nextHitbox.posX + nextHitbox.width) - nextHitbox.width)
|
||||
|
||||
var newXOff = 0 // always positive
|
||||
|
||||
// count up Y offset until the actor is not touching the wall
|
||||
var colliding: Boolean
|
||||
do {
|
||||
newXOff += 1
|
||||
colliding = isColliding(CONTACT_AREA_BOTTOM, -newXOff + 1, 0) // offset by +1, to fix directional quarks
|
||||
} while (newXOff < TSIZE && colliding)
|
||||
|
||||
val newX = nextHitbox.posX - newXOff // -1: Q&D way to prevent the actor sticking to the wall and won't detach
|
||||
nextHitbox.setPosition(newX, newY)
|
||||
}
|
||||
|
||||
private fun adjustHitLeft() {
|
||||
val newY = nextHitbox.posY
|
||||
// int-ify posY of nextHitbox
|
||||
nextHitbox.setPositionX(FastMath.ceil(nextHitbox.posX).toFloat())
|
||||
|
||||
var newXOff = 0 // always positive
|
||||
|
||||
// count up Y offset until the actor is not touching the wall
|
||||
var colliding: Boolean
|
||||
do {
|
||||
newXOff += 1
|
||||
colliding = isColliding(CONTACT_AREA_TOP, newXOff, 0)
|
||||
} while (newXOff < TSIZE && colliding)
|
||||
|
||||
posAdjustX = newXOff
|
||||
val newX = nextHitbox.posX + newXOff // +1: Q&D way to prevent the actor sticking to the wall and won't detach
|
||||
nextHitbox.setPosition(newX, newY)
|
||||
}
|
||||
|
||||
private fun elasticReflectX() {
|
||||
if (veloX != 0f && (veloX * elasticity).abs() > 0.5) {
|
||||
veloX = -veloX * elasticity
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun elasticReflectY() {
|
||||
if (veloY != 0f && (veloY * elasticity).abs() > 0.5) {
|
||||
veloY = -veloY * elasticity
|
||||
}
|
||||
}
|
||||
|
||||
private fun isColliding(side: Int, tx: Int = 0, ty: Int = 0): Boolean = getContactingArea(side, tx, ty) > 1
|
||||
|
||||
private fun getContactingArea(side: Int, translateX: Int = 0, translateY: Int = 0): Int {
|
||||
var contactAreaCounter = 0
|
||||
for (i in 0..(if (side % 2 == 0) nextHitbox.width else nextHitbox.height).roundToInt() - 1) {
|
||||
// set tile positions
|
||||
val tileX: Int
|
||||
val tileY: Int
|
||||
if (side == CONTACT_AREA_BOTTOM) {
|
||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt()
|
||||
+ i + translateX)
|
||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxEnd.y.roundToInt() + translateY)
|
||||
}
|
||||
else if (side == CONTACT_AREA_TOP) {
|
||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt()
|
||||
+ i + translateX)
|
||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt() + translateY)
|
||||
}
|
||||
else if (side == CONTACT_AREA_RIGHT) {
|
||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxEnd.x.roundToInt() + translateX)
|
||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt()
|
||||
+ i + translateY)
|
||||
}
|
||||
else if (side == CONTACT_AREA_LEFT) {
|
||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt() + translateX)
|
||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt()
|
||||
+ i + translateY)
|
||||
}
|
||||
else {
|
||||
throw IllegalArgumentException(side.toString() + ": Wrong side input")
|
||||
}
|
||||
|
||||
// evaluate
|
||||
if (TilePropCodex.getProp(map.getTileFromTerrain(tileX, tileY) ?: TileNameCode.STONE).isSolid) {
|
||||
contactAreaCounter += 1
|
||||
}
|
||||
}
|
||||
|
||||
return contactAreaCounter
|
||||
}
|
||||
|
||||
private fun getContactingAreaFluid(side: Int, translateX: Int = 0, translateY: Int = 0): Int {
|
||||
var contactAreaCounter = 0
|
||||
for (i in 0..(if (side % 2 == 0) nextHitbox.width else nextHitbox.height).roundToInt() - 1) {
|
||||
// set tile positions
|
||||
val tileX: Int
|
||||
val tileY: Int
|
||||
if (side == CONTACT_AREA_BOTTOM) {
|
||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt()
|
||||
+ i + translateX)
|
||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxEnd.y.roundToInt() + translateY)
|
||||
}
|
||||
else if (side == CONTACT_AREA_TOP) {
|
||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt()
|
||||
+ i + translateX)
|
||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt() + translateY)
|
||||
}
|
||||
else if (side == CONTACT_AREA_RIGHT) {
|
||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxEnd.x.roundToInt() + translateX)
|
||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt()
|
||||
+ i + translateY)
|
||||
}
|
||||
else if (side == CONTACT_AREA_LEFT) {
|
||||
tileX = div16TruncateToMapWidth(nextHitbox.hitboxStart.x.roundToInt() + translateX)
|
||||
tileY = div16TruncateToMapHeight(nextHitbox.hitboxStart.y.roundToInt()
|
||||
+ i + translateY)
|
||||
}
|
||||
else {
|
||||
throw IllegalArgumentException(side.toString() + ": Wrong side input")
|
||||
}
|
||||
|
||||
// evaluate
|
||||
if (TilePropCodex.getProp(map.getTileFromTerrain(tileX, tileY)).isFluid) {
|
||||
contactAreaCounter += 1
|
||||
}
|
||||
}
|
||||
|
||||
return contactAreaCounter
|
||||
}
|
||||
|
||||
/**
|
||||
* [N] = [kg * m / s^2]
|
||||
* F(bo) = density * submerged_volume * gravitational_acceleration [N]
|
||||
*/
|
||||
/*private fun applyBuoyancy() {
|
||||
val fluidDensity = tileDensity
|
||||
val submergedVolume = submergedVolume
|
||||
|
||||
if (!isPlayerNoClip && !grounded) {
|
||||
// System.out.println("density: "+density);
|
||||
veloY -= ((fluidDensity - this.density).toDouble()
|
||||
* map.gravitation.toDouble() * submergedVolume.toDouble()
|
||||
* Math.pow(mass.toDouble(), -1.0)
|
||||
* SI_TO_GAME_ACC.toDouble()).toFloat()
|
||||
}
|
||||
}*/
|
||||
|
||||
/*private val submergedVolume: Float
|
||||
get() = submergedHeight * hitbox.width * hitbox.width
|
||||
|
||||
private val submergedHeight: Float
|
||||
get() = Math.max(
|
||||
getContactingAreaFluid(CONTACT_AREA_LEFT),
|
||||
getContactingAreaFluid(CONTACT_AREA_RIGHT)
|
||||
).toFloat()*/
|
||||
|
||||
|
||||
/**
|
||||
* Get highest friction value from feet tiles.
|
||||
* @return
|
||||
*/
|
||||
private val tileFriction: Int
|
||||
get() {
|
||||
var friction = 0
|
||||
|
||||
//get highest fluid density
|
||||
val tilePosXStart = (nextHitbox.posX / TSIZE).roundToInt()
|
||||
val tilePosXEnd = (nextHitbox.hitboxEnd.x / TSIZE).roundToInt()
|
||||
val tilePosY = (nextHitbox.pointedY / TSIZE).roundToInt()
|
||||
for (x in tilePosXStart..tilePosXEnd) {
|
||||
val tile = map.getTileFromTerrain(x, tilePosY)
|
||||
if (TilePropCodex.getProp(tile).isFluid) {
|
||||
val thisFluidDensity = TilePropCodex.getProp(tile).friction
|
||||
|
||||
if (thisFluidDensity > friction) friction = thisFluidDensity
|
||||
}
|
||||
}
|
||||
|
||||
return friction
|
||||
}
|
||||
|
||||
/**
|
||||
* Get highest density (specific gravity) value from tiles that the body occupies.
|
||||
* @return
|
||||
*/
|
||||
private val tileDensity: Int
|
||||
get() {
|
||||
var density = 0
|
||||
|
||||
//get highest fluid density
|
||||
val tilePosXStart = (nextHitbox.posX / TSIZE).roundToInt()
|
||||
val tilePosYStart = (nextHitbox.posY / TSIZE).roundToInt()
|
||||
val tilePosXEnd = (nextHitbox.hitboxEnd.x / TSIZE).roundToInt()
|
||||
val tilePosYEnd = (nextHitbox.hitboxEnd.y / TSIZE).roundToInt()
|
||||
for (y in tilePosYStart..tilePosYEnd) {
|
||||
for (x in tilePosXStart..tilePosXEnd) {
|
||||
val tile = map.getTileFromTerrain(x, y)
|
||||
if (TilePropCodex.getProp(tile).isFluid) {
|
||||
val thisFluidDensity = TilePropCodex.getProp(tile).density
|
||||
|
||||
if (thisFluidDensity > density) density = thisFluidDensity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return density
|
||||
}
|
||||
|
||||
private fun mvmtRstcToMultiplier(movementResistanceValue: Int): Float {
|
||||
return 1f / (1 + movementResistanceValue / 16f)
|
||||
}
|
||||
|
||||
private fun clampHitbox() {
|
||||
hitbox.setPositionFromPoint(
|
||||
clampW(hitbox.pointedX), clampH(hitbox.pointedY))
|
||||
}
|
||||
|
||||
private fun clampNextHitbox() {
|
||||
nextHitbox.setPositionFromPoint(
|
||||
clampW(nextHitbox.pointedX), clampH(nextHitbox.pointedY))
|
||||
}
|
||||
|
||||
private fun updateNextHitboxFromVelo() {
|
||||
|
||||
nextHitbox.set(
|
||||
(hitbox.posX + veloX).round()
|
||||
, (hitbox.posY + veloY).round()
|
||||
, (baseHitboxW * scale).round()
|
||||
, (baseHitboxH * scale).round()
|
||||
)
|
||||
/** Full quantisation; wonder what havoc these statements would wreak...
|
||||
*/
|
||||
}
|
||||
|
||||
private fun updateHitboxX() {
|
||||
hitbox.setDimension(
|
||||
nextHitbox.width, nextHitbox.height)
|
||||
hitbox.setPositionX(nextHitbox.posX)
|
||||
}
|
||||
|
||||
private fun updateHitboxY() {
|
||||
hitbox.setDimension(
|
||||
nextHitbox.width, nextHitbox.height)
|
||||
hitbox.setPositionY(nextHitbox.posY)
|
||||
}
|
||||
|
||||
override fun drawGlow(gc: GameContainer, g: Graphics) {
|
||||
if (isVisible && spriteGlow != null) {
|
||||
if (!sprite!!.flippedHorizontal()) {
|
||||
spriteGlow!!.render(g, hitbox.posX - hitboxTranslateX * scale, hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2, scale)
|
||||
} else {
|
||||
spriteGlow!!.render(g, hitbox.posX - scale, hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2, scale)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun drawBody(gc: GameContainer, g: Graphics) {
|
||||
if (isVisible && sprite != null) {
|
||||
if (!sprite!!.flippedHorizontal()) {
|
||||
sprite!!.render(g, hitbox.posX - hitboxTranslateX * scale, hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2, scale)
|
||||
} else {
|
||||
sprite!!.render(g, hitbox.posX - scale, hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2, scale)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateGlowSprite(gc: GameContainer, delta: Int) {
|
||||
if (spriteGlow != null) spriteGlow!!.update(delta)
|
||||
}
|
||||
|
||||
override fun updateBodySprite(gc: GameContainer, delta: Int) {
|
||||
if (sprite != null) sprite!!.update(delta)
|
||||
}
|
||||
|
||||
private fun clampW(x: Float): Float =
|
||||
if (x < TSIZE + nextHitbox.width / 2) {
|
||||
TSIZE + nextHitbox.width / 2
|
||||
} else if (x >= (map.width * TSIZE).toFloat() - TSIZE.toFloat() - nextHitbox.width / 2) {
|
||||
(map.width * TSIZE).toFloat() - 1f - TSIZE.toFloat() - nextHitbox.width / 2
|
||||
} else {
|
||||
x
|
||||
}
|
||||
|
||||
private fun clampH(y: Float): Float =
|
||||
if (y < TSIZE + nextHitbox.height) {
|
||||
TSIZE + nextHitbox.height
|
||||
} else if (y >= (map.height * TSIZE).toFloat() - TSIZE.toFloat() - nextHitbox.height) {
|
||||
(map.height * TSIZE).toFloat() - 1f - TSIZE.toFloat() - nextHitbox.height
|
||||
} else {
|
||||
y
|
||||
}
|
||||
|
||||
private fun clampWtile(x: Int): Int =
|
||||
if (x < 0) {
|
||||
0
|
||||
} else if (x >= map.width) {
|
||||
map.width - 1
|
||||
} else {
|
||||
x
|
||||
}
|
||||
|
||||
private fun clampHtile(x: Int): Int =
|
||||
if (x < 0) {
|
||||
0
|
||||
} else if (x >= map.height) {
|
||||
map.height - 1
|
||||
} else {
|
||||
x
|
||||
}
|
||||
|
||||
private val isPlayerNoClip: Boolean
|
||||
get() = this is Player && this.isNoClip()
|
||||
|
||||
private fun quantiseTSize(v: Float): Int = FastMath.floor(v / TSIZE) * TSIZE
|
||||
|
||||
fun setDensity(density: Int) {
|
||||
if (density < 0)
|
||||
throw IllegalArgumentException("[ActorWithBody] $density: density cannot be negative.")
|
||||
|
||||
this.density = density.toFloat()
|
||||
}
|
||||
|
||||
fun Float.round() = Math.round(this).toFloat()
|
||||
fun Float.roundToInt(): Int = Math.round(this)
|
||||
fun Float.abs() = FastMath.abs(this)
|
||||
|
||||
companion object {
|
||||
|
||||
@Transient private val TSIZE = MapDrawer.TILE_SIZE
|
||||
private var AUTO_CLIMB_RATE = TSIZE / 8
|
||||
|
||||
private fun div16(x: Int): Int {
|
||||
if (x < 0) {
|
||||
throw IllegalArgumentException("div16: Positive integer only: " + x.toString())
|
||||
}
|
||||
return x and 0x7FFFFFFF shr 4
|
||||
}
|
||||
|
||||
private fun div16TruncateToMapWidth(x: Int): Int {
|
||||
if (x < 0)
|
||||
return 0
|
||||
else if (x >= Terrarum.game.map.width shl 4)
|
||||
return Terrarum.game.map.width - 1
|
||||
else
|
||||
return x and 0x7FFFFFFF shr 4
|
||||
}
|
||||
|
||||
private fun div16TruncateToMapHeight(y: Int): Int {
|
||||
if (y < 0)
|
||||
return 0
|
||||
else if (y >= Terrarum.game.map.height shl 4)
|
||||
return Terrarum.game.map.height - 1
|
||||
else
|
||||
return y and 0x7FFFFFFF shr 4
|
||||
}
|
||||
|
||||
private fun mod16(x: Int): Int {
|
||||
if (x < 0) {
|
||||
throw IllegalArgumentException("mod16: Positive integer only: " + x.toString())
|
||||
}
|
||||
return x and 15
|
||||
}
|
||||
|
||||
private fun clampCeil(x: Float, ceil: Float): Float {
|
||||
return if (Math.abs(x) > ceil) ceil else x
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Give new random ReferenceID and initialise ActorValue
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
= = ↑
|
||||
=== ===@!
|
||||
=↑ =↑
|
||||
=↑ =
|
||||
=↑ =
|
||||
=@ (pressing R) =
|
||||
================== ==================
|
||||
|
||||
Fig. 1: the fix was not applied
|
||||
*/
|
||||
20
src/net/torvald/terrarum/gameactors/CanBeAnItem.kt
Normal file
20
src/net/torvald/terrarum/gameactors/CanBeAnItem.kt
Normal file
@@ -0,0 +1,20 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.terrarum.gameitem.InventoryItem
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface CanBeAnItem {
|
||||
|
||||
fun attachItemData()
|
||||
|
||||
fun getItemWeight(): Float
|
||||
|
||||
fun stopUpdateAndDraw()
|
||||
|
||||
fun resumeUpdateAndDraw()
|
||||
|
||||
var itemData: InventoryItem
|
||||
|
||||
}
|
||||
14
src/net/torvald/terrarum/gameactors/Controllable.kt
Normal file
14
src/net/torvald/terrarum/gameactors/Controllable.kt
Normal file
@@ -0,0 +1,14 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import org.newdawn.slick.Input
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface Controllable {
|
||||
|
||||
fun processInput(input: Input)
|
||||
|
||||
fun keyPressed(key: Int, c: Char)
|
||||
|
||||
}
|
||||
27
src/net/torvald/terrarum/gameactors/CreatureBuilder.kt
Normal file
27
src/net/torvald/terrarum/gameactors/CreatureBuilder.kt
Normal file
@@ -0,0 +1,27 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.JsonFetcher
|
||||
import net.torvald.random.Fudge3
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import com.google.gson.JsonObject
|
||||
import org.newdawn.slick.SlickException
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
|
||||
object CreatureBuilder {
|
||||
|
||||
/**
|
||||
* @Param jsonFileName with extension
|
||||
*/
|
||||
@Throws(IOException::class, SlickException::class)
|
||||
fun create(jsonFileName: String): ActorWithBody {
|
||||
val actor = ActorWithBody()
|
||||
CreatureRawInjector.inject(actor.actorValue, jsonFileName)
|
||||
|
||||
return actor
|
||||
}
|
||||
}
|
||||
123
src/net/torvald/terrarum/gameactors/CreatureRawInjector.kt
Normal file
123
src/net/torvald/terrarum/gameactors/CreatureRawInjector.kt
Normal file
@@ -0,0 +1,123 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.JsonFetcher
|
||||
import net.torvald.random.Fudge3
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import com.google.gson.JsonObject
|
||||
import org.newdawn.slick.SlickException
|
||||
import java.io.IOException
|
||||
import java.security.SecureRandom
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-25.
|
||||
*/
|
||||
object CreatureRawInjector {
|
||||
|
||||
const val JSONPATH = "./res/raw/creatures/"
|
||||
private const val MULTIPLIER_RAW_ELEM_SUFFIX = AVKey.MULT
|
||||
|
||||
/**
|
||||
* 'Injects' creature raw ActorValue to the ActorValue reference provided.
|
||||
*
|
||||
* @param actorValueRef ActorValue object to be injected.
|
||||
* @param jsonFileName with extension
|
||||
*/
|
||||
@Throws(IOException::class, SlickException::class)
|
||||
fun inject(actorValueRef: ActorValue, jsonFileName: String) {
|
||||
val jsonObj = JsonFetcher.readJson(JSONPATH + jsonFileName)
|
||||
|
||||
val elementsString = arrayOf(AVKey.RACENAME, AVKey.RACENAMEPLURAL)
|
||||
val elementsFloat = arrayOf(AVKey.BASEHEIGHT, AVKey.BASEMASS, AVKey.ACCEL, AVKey.TOOLSIZE, AVKey.ENCUMBRANCE)
|
||||
val elementsFloatVariable = arrayOf(AVKey.STRENGTH, AVKey.SPEED, AVKey.JUMPPOWER, AVKey.SCALE, AVKey.SPEED)
|
||||
val elementsBoolean = arrayOf(AVKey.INTELLIGENT)
|
||||
// val elementsMultiplyFromOne = arrayOf()
|
||||
|
||||
setAVStrings(actorValueRef, elementsString, jsonObj)
|
||||
setAVFloats(actorValueRef, elementsFloat, jsonObj)
|
||||
setAVFloatsVariable(actorValueRef, elementsFloatVariable, jsonObj)
|
||||
// setAVMultiplyFromOne(actorValueRef, elementsMultiplyFromOne, jsonObj)
|
||||
setAVBooleans(actorValueRef, elementsBoolean, jsonObj)
|
||||
|
||||
actorValueRef[AVKey.ACCEL] = Player.WALK_ACCEL_BASE
|
||||
actorValueRef[AVKey.ACCELMULT] = 1f
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and set actor values that have 'variable' appended. E.g. strength
|
||||
* @param avRef
|
||||
* *
|
||||
* @param elemSet
|
||||
* *
|
||||
* @param jsonObject
|
||||
*/
|
||||
private fun setAVFloatsVariable(avRef: ActorValue, elemSet: Array<String>, jsonObject: JsonObject) {
|
||||
for (s in elemSet) {
|
||||
val baseValue = jsonObject.get(s).asFloat
|
||||
// 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 + MULTIPLIER_RAW_ELEM_SUFFIX).asJsonArray.get(varSelected).asInt
|
||||
val realValue = baseValue * multiplier / 100f
|
||||
|
||||
avRef[s] = realValue
|
||||
avRef[s + MULTIPLIER_RAW_ELEM_SUFFIX] = 1.0f // 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 float actor values
|
||||
* @param avRef
|
||||
* *
|
||||
* @param elemSet
|
||||
* *
|
||||
* @param jsonObject
|
||||
*/
|
||||
private fun setAVFloats(avRef: ActorValue, elemSet: Array<String>, jsonObject: JsonObject) {
|
||||
for (s in elemSet) {
|
||||
avRef[s] = jsonObject.get(s).asFloat
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and set actor values that should multiplier be applied to the base value of 1.
|
||||
* E.g. physiquemult
|
||||
* @param avRef
|
||||
* *
|
||||
* @param elemSet
|
||||
* *
|
||||
* @param jsonObject
|
||||
*/
|
||||
private fun setAVMultiplyFromOne(avRef: ActorValue, elemSet: Array<String>, jsonObject: JsonObject) {
|
||||
for (s in elemSet) {
|
||||
val baseValue = 1f
|
||||
// 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 / 100f
|
||||
|
||||
avRef[s] = realValue
|
||||
}
|
||||
}
|
||||
|
||||
private fun setAVBooleans(avRef: ActorValue, elemSet: Array<String>, jsonObject: JsonObject) {
|
||||
for (s in elemSet) {
|
||||
avRef[s] = jsonObject.get(s).asBoolean
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/net/torvald/terrarum/gameactors/DroppedItem.kt
Normal file
22
src/net/torvald/terrarum/gameactors/DroppedItem.kt
Normal file
@@ -0,0 +1,22 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import org.newdawn.slick.GameContainer
|
||||
import org.newdawn.slick.Graphics
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-15.
|
||||
*/
|
||||
class DroppedItem constructor() : ActorWithBody() {
|
||||
|
||||
init {
|
||||
isVisible = true
|
||||
}
|
||||
|
||||
override fun update(gc: GameContainer, delta_t: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun drawBody(gc: GameContainer, g: Graphics) {
|
||||
drawBody(gc, g)
|
||||
}
|
||||
}
|
||||
13
src/net/torvald/terrarum/gameactors/Factionable.kt
Normal file
13
src/net/torvald/terrarum/gameactors/Factionable.kt
Normal file
@@ -0,0 +1,13 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.terrarum.gameactors.faction.Faction
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface Factionable {
|
||||
|
||||
var faction: HashSet<Faction>
|
||||
|
||||
}
|
||||
13
src/net/torvald/terrarum/gameactors/Glowing.kt
Normal file
13
src/net/torvald/terrarum/gameactors/Glowing.kt
Normal file
@@ -0,0 +1,13 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import org.newdawn.slick.GameContainer
|
||||
import org.newdawn.slick.Graphics
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface Glowing {
|
||||
fun drawGlow(gc: GameContainer, g: Graphics)
|
||||
|
||||
fun updateGlowSprite(gc: GameContainer, delta: Int)
|
||||
}
|
||||
115
src/net/torvald/terrarum/gameactors/Hitbox.kt
Normal file
115
src/net/torvald/terrarum/gameactors/Hitbox.kt
Normal file
@@ -0,0 +1,115 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.point.Point2f
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-01-15.
|
||||
*/
|
||||
class Hitbox(x1: Float, y1: Float, width: Float, height: Float) {
|
||||
|
||||
var hitboxStart: Point2f
|
||||
private set
|
||||
var hitboxEnd: Point2f
|
||||
private set
|
||||
var width: Float = 0.toFloat()
|
||||
private set
|
||||
var height: Float = 0.toFloat()
|
||||
private set
|
||||
|
||||
init {
|
||||
hitboxStart = Point2f(x1, y1)
|
||||
hitboxEnd = Point2f(x1 + width, y1 + height)
|
||||
this.width = width
|
||||
this.height = height
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns bottom-centered point of hitbox.
|
||||
* @return pointX
|
||||
*/
|
||||
val pointedX: Float
|
||||
get() = hitboxStart.x + width / 2
|
||||
|
||||
/**
|
||||
* Returns bottom-centered point of hitbox.
|
||||
* @return pointY
|
||||
*/
|
||||
val pointedY: Float
|
||||
get() = hitboxEnd.y
|
||||
|
||||
/**
|
||||
* Set to the point top left
|
||||
* @param x1
|
||||
* *
|
||||
* @param y1
|
||||
* *
|
||||
* @param width
|
||||
* *
|
||||
* @param height
|
||||
*/
|
||||
operator fun set(x1: Float, y1: Float, width: Float, height: Float) {
|
||||
hitboxStart = Point2f(x1, y1)
|
||||
hitboxEnd = Point2f(x1 + width, y1 + height)
|
||||
this.width = width
|
||||
this.height = height
|
||||
}
|
||||
|
||||
fun setPosition(x1: Float, y1: Float) {
|
||||
hitboxStart = Point2f(x1, y1)
|
||||
hitboxEnd = Point2f(x1 + width, y1 + height)
|
||||
}
|
||||
|
||||
fun setPositionX(x: Float) {
|
||||
setPosition(x, posY)
|
||||
}
|
||||
|
||||
fun setPositionY(y: Float) {
|
||||
setPosition(posX, y)
|
||||
}
|
||||
|
||||
fun setPositionFromPoint(x1: Float, y1: Float) {
|
||||
hitboxStart = Point2f(x1 - width / 2, y1 - height)
|
||||
hitboxEnd = Point2f(hitboxStart.x + width, hitboxStart.y + height)
|
||||
}
|
||||
|
||||
fun setPositionXFromPoint(x: Float) {
|
||||
setPositionFromPoint(x, pointedY)
|
||||
}
|
||||
|
||||
fun setPositionYFromPoint(y: Float) {
|
||||
setPositionFromPoint(pointedX, y)
|
||||
}
|
||||
|
||||
fun translatePosX(d: Float) {
|
||||
setPositionX(posX + d)
|
||||
}
|
||||
|
||||
fun translatePosY(d: Float) {
|
||||
setPositionY(posY + d)
|
||||
}
|
||||
|
||||
fun setDimension(w: Float, h: Float) {
|
||||
width = w
|
||||
height = h
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns x value of start point
|
||||
* @return top-left point posX
|
||||
*/
|
||||
val posX: Float
|
||||
get() = hitboxStart.x
|
||||
|
||||
/**
|
||||
* Returns y value of start point
|
||||
* @return top-left point posY
|
||||
*/
|
||||
val posY: Float
|
||||
get() = hitboxStart.y
|
||||
|
||||
val centeredX: Float
|
||||
get() = (hitboxStart.x + hitboxEnd.x) * 0.5f
|
||||
|
||||
val centeredY: Float
|
||||
get() = (hitboxStart.y + hitboxEnd.y) * 0.5f
|
||||
}
|
||||
19
src/net/torvald/terrarum/gameactors/LandHolder.kt
Normal file
19
src/net/torvald/terrarum/gameactors/LandHolder.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
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<Int>?
|
||||
fun addHouseTile(x: Int, y: Int);
|
||||
fun removeHouseTile(x: Int, y: Int);
|
||||
fun clearHouseDesignation();
|
||||
|
||||
}
|
||||
24
src/net/torvald/terrarum/gameactors/Luminous.kt
Normal file
24
src/net/torvald/terrarum/gameactors/Luminous.kt
Normal file
@@ -0,0 +1,24 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface Luminous {
|
||||
|
||||
/**
|
||||
* Recommended implementation:
|
||||
*
|
||||
override var luminosity: Char
|
||||
get() = if (actorValue.get("luminosity") != null) {
|
||||
actorValue.get("luminosity") as Char
|
||||
}
|
||||
else {
|
||||
0 as Char
|
||||
}
|
||||
set(value) {
|
||||
actorValue.set("luminosity", value)
|
||||
}
|
||||
*/
|
||||
var luminosity: Int
|
||||
|
||||
}
|
||||
102
src/net/torvald/terrarum/gameactors/NPCIntelligentBase.kt
Normal file
102
src/net/torvald/terrarum/gameactors/NPCIntelligentBase.kt
Normal file
@@ -0,0 +1,102 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.gameactors.ai.ActorAI
|
||||
import net.torvald.terrarum.gameactors.faction.Faction
|
||||
import net.torvald.terrarum.gameitem.InventoryItem
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import org.newdawn.slick.GameContainer
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
open class NPCIntelligentBase : ActorWithBody()
|
||||
, AIControlled, Pocketed, CanBeAnItem, Factionable, LandHolder {
|
||||
|
||||
override var itemData: InventoryItem = object : InventoryItem {
|
||||
override var itemID = HQRNG().nextLong()
|
||||
|
||||
override var mass: Float
|
||||
get() = actorValue.get("mass") as Float
|
||||
set(value) {
|
||||
actorValue.set("mass", value)
|
||||
}
|
||||
|
||||
override var scale: Float
|
||||
get() = actorValue.get("scale") as Float
|
||||
set(value) {
|
||||
actorValue.set("scale", value)
|
||||
}
|
||||
|
||||
override fun effectWhileInPocket(gc: GameContainer, delta_t: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun effectWhenPickedUp(gc: GameContainer, delta_t: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun primaryUse(gc: GameContainer, delta_t: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun secondaryUse(gc: GameContainer, delta_t: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun effectWhenThrownAway(gc: GameContainer, delta_t: Int) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Transient private var ai: ActorAI? = null
|
||||
override var inventory: ActorInventory = ActorInventory()
|
||||
|
||||
private val factionSet = HashSet<Faction>()
|
||||
|
||||
override var referenceID: Long = HQRNG().nextLong()
|
||||
|
||||
override var faction: HashSet<Faction> = HashSet()
|
||||
|
||||
override var houseDesignation: ArrayList<Int>? = null
|
||||
/**
|
||||
* Absolute tile index. index(x, y) = y * map.width + x
|
||||
* The arraylist will be saved in JSON format with GSON.
|
||||
*/
|
||||
private var houseTiles = ArrayList<Int>()
|
||||
|
||||
override fun attachItemData() {
|
||||
|
||||
}
|
||||
|
||||
override fun getItemWeight(): Float {
|
||||
return mass
|
||||
}
|
||||
|
||||
override fun addHouseTile(x: Int, y: Int) {
|
||||
houseTiles.add(Terrarum.game.map.width * y + x)
|
||||
}
|
||||
|
||||
override fun removeHouseTile(x: Int, y: Int) {
|
||||
houseTiles.remove(Terrarum.game.map.width * y + x)
|
||||
}
|
||||
|
||||
override fun clearHouseDesignation() {
|
||||
houseTiles.clear()
|
||||
}
|
||||
|
||||
override fun stopUpdateAndDraw() {
|
||||
isUpdate = false
|
||||
isVisible = false
|
||||
}
|
||||
|
||||
override fun resumeUpdateAndDraw() {
|
||||
isUpdate = true
|
||||
isVisible = true
|
||||
}
|
||||
|
||||
override fun attachAI(ai: ActorAI) {
|
||||
this.ai = ai
|
||||
}
|
||||
}
|
||||
31
src/net/torvald/terrarum/gameactors/PBCynthia.kt
Normal file
31
src/net/torvald/terrarum/gameactors/PBCynthia.kt
Normal file
@@ -0,0 +1,31 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.spriteanimation.SpriteAnimation
|
||||
import net.torvald.terrarum.mapdrawer.MapDrawer
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-25.
|
||||
*/
|
||||
object PBCynthia {
|
||||
|
||||
fun create(): Player {
|
||||
val p: Player = Player()
|
||||
CreatureRawInjector.inject(p.actorValue, "CreatureHuman.json")
|
||||
|
||||
p.actorValue["selectedtile"] = 16
|
||||
|
||||
p.sprite = SpriteAnimation()
|
||||
p.sprite!!.setDimension(26, 42)
|
||||
p.sprite!!.setSpriteImage("res/graphics/sprites/test_player_2.png")
|
||||
p.sprite!!.setDelay(200)
|
||||
p.sprite!!.setRowsAndFrames(1, 1)
|
||||
p.sprite!!.setAsVisible()
|
||||
|
||||
p.setHitboxDimension(15, p.actorValue.getAsInt(AVKey.BASEHEIGHT) ?: Player.BASE_HEIGHT, 9, 0)
|
||||
|
||||
p.setPosition((4096 * MapDrawer.TILE_SIZE).toFloat(), (300 * 16).toFloat())
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
}
|
||||
73
src/net/torvald/terrarum/gameactors/PBSigrid.kt
Normal file
73
src/net/torvald/terrarum/gameactors/PBSigrid.kt
Normal file
@@ -0,0 +1,73 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.JsonFetcher
|
||||
import net.torvald.terrarum.gameactors.faction.Faction
|
||||
import net.torvald.spriteanimation.SpriteAnimation
|
||||
import com.google.gson.JsonObject
|
||||
import net.torvald.terrarum.gameactors.faction.FactionFactory
|
||||
import net.torvald.terrarum.mapdrawer.MapDrawer
|
||||
import org.newdawn.slick.SlickException
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
|
||||
object PBSigrid {
|
||||
|
||||
fun create(): Player {
|
||||
val p = Player()
|
||||
|
||||
p.sprite = SpriteAnimation()
|
||||
p.sprite!!.setDimension(28, 51)
|
||||
p.sprite!!.setSpriteImage("res/graphics/sprites/test_player.png")
|
||||
p.sprite!!.setDelay(200)
|
||||
p.sprite!!.setRowsAndFrames(1, 1)
|
||||
p.sprite!!.setAsVisible()
|
||||
|
||||
p.spriteGlow = SpriteAnimation()
|
||||
p.spriteGlow!!.setDimension(28, 51)
|
||||
p.spriteGlow!!.setSpriteImage("res/graphics/sprites/test_player_glow.png")
|
||||
p.spriteGlow!!.setDelay(200)
|
||||
p.spriteGlow!!.setRowsAndFrames(1, 1)
|
||||
p.spriteGlow!!.setAsVisible()
|
||||
|
||||
p.actorValue = ActorValue()
|
||||
p.actorValue[AVKey.SCALE] = 1.0f
|
||||
p.actorValue[AVKey.SPEED] = 4.0f
|
||||
p.actorValue[AVKey.SPEEDMULT] = 1.0f
|
||||
p.actorValue[AVKey.ACCEL] = Player.WALK_ACCEL_BASE
|
||||
p.actorValue[AVKey.ACCELMULT] = 1.0f
|
||||
p.actorValue[AVKey.JUMPPOWER] = 5f
|
||||
|
||||
p.actorValue[AVKey.BASEMASS] = 80f
|
||||
p.actorValue[AVKey.PHYSIQUEMULT] = 1 // 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
|
||||
p.actorValue[AVKey.ENCUMBRANCE] = 1000
|
||||
p.actorValue[AVKey.BASEHEIGHT] = 46
|
||||
|
||||
p.actorValue[AVKey.NAME] = "Sigrid"
|
||||
|
||||
p.actorValue[AVKey.INTELLIGENT] = true
|
||||
|
||||
p.actorValue[AVKey.LUMINOSITY] = 95487100
|
||||
|
||||
p.actorValue[AVKey.BASEDEFENCE] = 141
|
||||
|
||||
p.actorValue["selectedtile"] = 16
|
||||
|
||||
p.setHitboxDimension(15, p.actorValue.getAsInt(AVKey.BASEHEIGHT)!!, 10, 0)
|
||||
|
||||
p.inventory = ActorInventory(0x7FFFFFFF, true)
|
||||
|
||||
p.setPosition((4096 * MapDrawer.TILE_SIZE).toFloat(), (300 * 16).toFloat())
|
||||
|
||||
p.faction.add(FactionFactory.create("FactionSigrid.json"))
|
||||
|
||||
return p
|
||||
}
|
||||
}
|
||||
31
src/net/torvald/terrarum/gameactors/PhysTestBall.kt
Normal file
31
src/net/torvald/terrarum/gameactors/PhysTestBall.kt
Normal file
@@ -0,0 +1,31 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.terrarum.mapgenerator.RoguelikeRandomiser
|
||||
import org.newdawn.slick.Color
|
||||
import org.newdawn.slick.GameContainer
|
||||
import org.newdawn.slick.Graphics
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
class PhysTestBall : ActorWithBody {
|
||||
|
||||
private var color = Color.orange
|
||||
|
||||
constructor(): super() {
|
||||
setHitboxDimension(16, 16, 0, 0)
|
||||
isVisible = true
|
||||
mass = 10f
|
||||
|
||||
color = RoguelikeRandomiser.composeColourFrom(RoguelikeRandomiser.POTION_PRIMARY_COLSET)
|
||||
}
|
||||
|
||||
override fun drawBody(gc: GameContainer, g: Graphics) {
|
||||
g.color = color
|
||||
g.fillOval(
|
||||
hitbox!!.posX,
|
||||
hitbox!!.posY,
|
||||
hitbox!!.width,
|
||||
hitbox!!.height)
|
||||
}
|
||||
}
|
||||
493
src/net/torvald/terrarum/gameactors/Player.kt
Normal file
493
src/net/torvald/terrarum/gameactors/Player.kt
Normal file
@@ -0,0 +1,493 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.terrarum.gameactors.faction.Faction
|
||||
import net.torvald.terrarum.gamecontroller.EnumKeyFunc
|
||||
import net.torvald.terrarum.gamecontroller.KeyMap
|
||||
import net.torvald.terrarum.mapdrawer.MapDrawer
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.spriteanimation.SpriteAnimation
|
||||
import com.jme3.math.FastMath
|
||||
import org.lwjgl.input.Controller
|
||||
import org.lwjgl.input.Controllers
|
||||
import org.newdawn.slick.GameContainer
|
||||
import org.newdawn.slick.Input
|
||||
import org.newdawn.slick.SlickException
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
|
||||
class Player : ActorWithBody, Controllable, Pocketed, Factionable, Luminous, LandHolder {
|
||||
|
||||
/**
|
||||
* empirical value.
|
||||
*/
|
||||
// private transient final float JUMP_ACCELERATION_MOD = ???f / 10000f; //quadratic mode
|
||||
@Transient private val JUMP_ACCELERATION_MOD = 170f / 10000f //linear mode
|
||||
@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
|
||||
|
||||
|
||||
var vehicleRiding: Controllable? = null
|
||||
|
||||
internal var jumpCounter = 0
|
||||
internal var walkPowerCounter = 0
|
||||
@Transient private val MAX_JUMP_LENGTH = 17 // use 17; in internal frames
|
||||
|
||||
private var readonly_totalX = 0f
|
||||
private var readonly_totalY = 0f
|
||||
|
||||
internal var jumping = 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_POSMAX = 1.0f
|
||||
@Transient private val GAMEPAD_JUMP = 5
|
||||
|
||||
@Transient private val TSIZE = MapDrawer.TILE_SIZE
|
||||
|
||||
private val factionSet = HashSet<Faction>()
|
||||
|
||||
@Transient private val BASE_DENSITY = 1020
|
||||
|
||||
/** Must be set by PlayerFactory */
|
||||
override var inventory: ActorInventory = ActorInventory()
|
||||
|
||||
/** Must be set by PlayerFactory */
|
||||
override var faction: HashSet<Faction> = HashSet()
|
||||
|
||||
override var houseDesignation: ArrayList<Int>? = null
|
||||
|
||||
override var luminosity: Int
|
||||
get() = actorValue.getAsInt(AVKey.LUMINOSITY) ?: 0
|
||||
set(value) {
|
||||
actorValue[AVKey.LUMINOSITY] = value
|
||||
}
|
||||
|
||||
companion object {
|
||||
@Transient internal const val ACCEL_MULT_IN_FLIGHT = 0.48f
|
||||
@Transient internal const val WALK_STOP_ACCEL = 0.32f
|
||||
@Transient internal const val WALK_ACCEL_BASE = 0.32f
|
||||
|
||||
@Transient const val PLAYER_REF_ID: Long = 0x51621D
|
||||
@Transient const val BASE_HEIGHT = 40
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new Player instance with empty elements (sprites, actorvalue, etc.).
|
||||
|
||||
* **Use PlayerFactory to build player!**
|
||||
|
||||
* @throws SlickException
|
||||
*/
|
||||
@Throws(SlickException::class)
|
||||
constructor() : super() {
|
||||
isVisible = true
|
||||
referenceID = PLAYER_REF_ID
|
||||
super.setDensity(BASE_DENSITY)
|
||||
}
|
||||
|
||||
override fun update(gc: GameContainer, delta_t: Int) {
|
||||
if (vehicleRiding is Player)
|
||||
throw RuntimeException("Attempted to 'ride' " + "player object.")
|
||||
|
||||
super.update(gc, delta_t)
|
||||
|
||||
updateSprite(delta_t)
|
||||
|
||||
updateMovementControl()
|
||||
|
||||
if (noClip) {
|
||||
grounded = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
* @param left (even if the game is joypad controlled, you must give valid value)
|
||||
* *
|
||||
* @param absAxisVal (set AXIS_POSMAX if keyboard controlled)
|
||||
*/
|
||||
private fun walkHorizontal(left: Boolean, absAxisVal: Float) {
|
||||
//if ((!super.isWalledLeft() && left) || (!super.isWalledRight() && !left)) {
|
||||
readonly_totalX = veloX +
|
||||
actorValue.getAsFloat(AVKey.ACCEL)!! *
|
||||
actorValue.getAsFloat(AVKey.ACCELMULT)!! *
|
||||
FastMath.sqrt(scale) *
|
||||
applyAccelRealism(walkPowerCounter) *
|
||||
(if (left) -1 else 1).toFloat() *
|
||||
absAxisVal
|
||||
|
||||
veloX = readonly_totalX
|
||||
|
||||
if (walkPowerCounter < WALK_FRAMES_TO_MAX_ACCEL) {
|
||||
walkPowerCounter += 1
|
||||
}
|
||||
|
||||
// Clamp veloX
|
||||
veloX = absClamp(veloX, actorValue.getAsFloat(AVKey.SPEED)!!
|
||||
* actorValue.getAsFloat(AVKey.SPEEDMULT)!!
|
||||
* FastMath.sqrt(scale))
|
||||
|
||||
// Heading flag
|
||||
if (left)
|
||||
walkHeading = LEFT
|
||||
else
|
||||
walkHeading = RIGHT
|
||||
//}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
* @param up (even if the game is joypad controlled, you must give valid value)
|
||||
* *
|
||||
* @param absAxisVal (set AXIS_POSMAX if keyboard controlled)
|
||||
*/
|
||||
private fun walkVertical(up: Boolean, absAxisVal: Float) {
|
||||
readonly_totalY = veloY +
|
||||
actorValue.getAsFloat(AVKey.ACCEL)!! *
|
||||
actorValue.getAsFloat(AVKey.ACCELMULT)!! *
|
||||
FastMath.sqrt(scale) *
|
||||
applyAccelRealism(walkPowerCounter) *
|
||||
(if (up) -1 else 1).toFloat() *
|
||||
absAxisVal
|
||||
|
||||
veloY = readonly_totalY
|
||||
|
||||
if (walkPowerCounter < WALK_FRAMES_TO_MAX_ACCEL) {
|
||||
walkPowerCounter += 1
|
||||
}
|
||||
|
||||
// Clamp veloX
|
||||
veloY = absClamp(veloY, actorValue.getAsFloat(AVKey.SPEED)!!
|
||||
* actorValue.getAsFloat(AVKey.SPEEDMULT)!!
|
||||
* FastMath.sqrt(scale))
|
||||
}
|
||||
|
||||
/**
|
||||
* For realistic accelerating while walking.
|
||||
|
||||
* Naïve 'veloX += 3' is actually like:
|
||||
|
||||
* a
|
||||
* | ------------
|
||||
* |
|
||||
* |
|
||||
* 0+------············ t
|
||||
|
||||
* which is unrealistic, so this method tries to introduce some realism by doing:
|
||||
|
||||
* a
|
||||
* | ------------
|
||||
* | ---
|
||||
* | -
|
||||
* | ---
|
||||
* 0+----··················· t
|
||||
|
||||
|
||||
* @param x
|
||||
*/
|
||||
private fun applyAccelRealism(x: Int): Float {
|
||||
return 0.5f + 0.5f * -FastMath.cos(10 * x / (WALK_FRAMES_TO_MAX_ACCEL * FastMath.PI))
|
||||
}
|
||||
|
||||
private fun walkHStop() {
|
||||
if (veloX > 0) {
|
||||
veloX -= actorValue.getAsFloat(AVKey.ACCEL)!! *
|
||||
actorValue.getAsFloat(AVKey.ACCELMULT)!! *
|
||||
FastMath.sqrt(scale)
|
||||
|
||||
// compensate overshoot
|
||||
if (veloX < 0) veloX = 0f
|
||||
} else if (veloX < 0) {
|
||||
veloX += actorValue.getAsFloat(AVKey.ACCEL)!! *
|
||||
actorValue.getAsFloat(AVKey.ACCELMULT)!! *
|
||||
FastMath.sqrt(scale)
|
||||
|
||||
// compensate overshoot
|
||||
if (veloX > 0) veloX = 0f
|
||||
} else {
|
||||
veloX = 0f
|
||||
}
|
||||
|
||||
walkPowerCounter = 0
|
||||
}
|
||||
|
||||
private fun walkVStop() {
|
||||
if (veloY > 0) {
|
||||
veloY -= WALK_STOP_ACCEL *
|
||||
actorValue.getAsFloat(AVKey.ACCELMULT)!! *
|
||||
FastMath.sqrt(scale)
|
||||
|
||||
// compensate overshoot
|
||||
if (veloY < 0)
|
||||
veloY = 0f
|
||||
} else if (veloY < 0) {
|
||||
veloY += WALK_STOP_ACCEL *
|
||||
actorValue.getAsFloat(AVKey.ACCELMULT)!! *
|
||||
FastMath.sqrt(scale)
|
||||
|
||||
// compensate overshoot
|
||||
if (veloY > 0) veloY = 0f
|
||||
} else {
|
||||
veloY = 0f
|
||||
}
|
||||
|
||||
walkPowerCounter = 0
|
||||
}
|
||||
|
||||
private fun updateMovementControl() {
|
||||
if (!noClip) {
|
||||
if (grounded) {
|
||||
actorValue.set(AVKey.ACCELMULT, 1f)
|
||||
} else {
|
||||
actorValue.set(AVKey.ACCELMULT, ACCEL_MULT_IN_FLIGHT)
|
||||
}
|
||||
} else {
|
||||
actorValue.set(AVKey.ACCELMULT, 1f)
|
||||
}
|
||||
}
|
||||
|
||||
override fun processInput(input: Input) {
|
||||
var gamepad: Controller? = null
|
||||
var axisX = 0f
|
||||
var axisY = 0f
|
||||
var axisRX = 0f
|
||||
var axisRY = 0f
|
||||
if (Terrarum.hasController) {
|
||||
gamepad = Controllers.getController(0)
|
||||
axisX = gamepad!!.getAxisValue(0)
|
||||
axisY = gamepad.getAxisValue(1)
|
||||
axisRX = gamepad.getAxisValue(2)
|
||||
axisRY = gamepad.getAxisValue(3)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* L-R stop
|
||||
*/
|
||||
if (Terrarum.hasController) {
|
||||
if (axisX == 0f) {
|
||||
walkHStop()
|
||||
}
|
||||
} else {
|
||||
// ↑F, ↑S
|
||||
if (!isFuncDown(input, EnumKeyFunc.MOVE_LEFT) && !isFuncDown(input, EnumKeyFunc.MOVE_RIGHT)) {
|
||||
walkHStop()
|
||||
prevHMoveKey = KEY_NULL
|
||||
}
|
||||
}
|
||||
/**
|
||||
* U-D stop
|
||||
*/
|
||||
if (Terrarum.hasController) {
|
||||
if (axisY == 0f) {
|
||||
walkVStop()
|
||||
}
|
||||
} else {
|
||||
// ↑E
|
||||
// ↑D
|
||||
if (isNoClip()
|
||||
&& !isFuncDown(input, EnumKeyFunc.MOVE_UP)
|
||||
&& !isFuncDown(input, EnumKeyFunc.MOVE_DOWN)) {
|
||||
walkVStop()
|
||||
prevVMoveKey = KEY_NULL
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Left/Right movement
|
||||
*/
|
||||
|
||||
if (Terrarum.hasController) {
|
||||
if (axisX != 0f) {
|
||||
walkHorizontal(axisX < 0, AXIS_POSMAX)
|
||||
}
|
||||
} else {
|
||||
// ↑F, ↓S
|
||||
if (isFuncDown(input, EnumKeyFunc.MOVE_RIGHT) && !isFuncDown(input, EnumKeyFunc.MOVE_LEFT)) {
|
||||
walkHorizontal(false, AXIS_POSMAX)
|
||||
prevHMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_RIGHT)
|
||||
} else if (isFuncDown(input, EnumKeyFunc.MOVE_LEFT) && !isFuncDown(input, EnumKeyFunc.MOVE_RIGHT)) {
|
||||
walkHorizontal(true, AXIS_POSMAX)
|
||||
prevHMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_LEFT)
|
||||
} else if (isFuncDown(input, EnumKeyFunc.MOVE_LEFT) && isFuncDown(input, EnumKeyFunc.MOVE_RIGHT)) {
|
||||
if (prevHMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_LEFT)) {
|
||||
walkHorizontal(false, AXIS_POSMAX)
|
||||
prevHMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_RIGHT)
|
||||
} else if (prevHMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_RIGHT)) {
|
||||
walkHorizontal(true, AXIS_POSMAX)
|
||||
prevHMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_LEFT)
|
||||
}
|
||||
}// ↓F, ↓S
|
||||
// ↓F, ↑S
|
||||
}
|
||||
|
||||
/**
|
||||
* Up/Down movement
|
||||
*/
|
||||
if (noClip) {
|
||||
if (Terrarum.hasController) {
|
||||
if (axisY != 0f) {
|
||||
walkVertical(axisY > 0, AXIS_POSMAX)
|
||||
}
|
||||
} else {
|
||||
// ↑E
|
||||
// ↓D
|
||||
if (isFuncDown(input, EnumKeyFunc.MOVE_DOWN) && !isFuncDown(input, EnumKeyFunc.MOVE_UP)) {
|
||||
walkVertical(false, AXIS_POSMAX)
|
||||
prevVMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_DOWN)
|
||||
} else if (isFuncDown(input, EnumKeyFunc.MOVE_UP) && !isFuncDown(input, EnumKeyFunc.MOVE_DOWN)) {
|
||||
walkVertical(true, AXIS_POSMAX)
|
||||
prevVMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_UP)
|
||||
} else if (isFuncDown(input, EnumKeyFunc.MOVE_UP) && isFuncDown(input, EnumKeyFunc.MOVE_DOWN)) {
|
||||
if (prevVMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_UP)) {
|
||||
walkVertical(false, AXIS_POSMAX)
|
||||
prevVMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_DOWN)
|
||||
} else if (prevVMoveKey == KeyMap.getKeyCode(EnumKeyFunc.MOVE_DOWN)) {
|
||||
walkVertical(true, AXIS_POSMAX)
|
||||
prevVMoveKey = KeyMap.getKeyCode(EnumKeyFunc.MOVE_UP)
|
||||
}
|
||||
}// ↓E
|
||||
// ↓D
|
||||
// ↓E
|
||||
// ↑D
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Jump control
|
||||
*/
|
||||
if (isFuncDown(input, EnumKeyFunc.JUMP) || Terrarum.hasController && gamepad!!.isButtonPressed(GAMEPAD_JUMP)) {
|
||||
if (!noClip) {
|
||||
if (grounded) {
|
||||
jumping = true
|
||||
}
|
||||
jump()
|
||||
} else {
|
||||
walkVertical(true, AXIS_POSMAX)
|
||||
}
|
||||
} else {
|
||||
jumping = false
|
||||
jumpCounter = 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun keyPressed(key: Int, c: Char) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See ./work_files/Jump\ power\ by\ pressing\ time.gcx
|
||||
*/
|
||||
private fun jump() {
|
||||
if (jumping) {
|
||||
val len = MAX_JUMP_LENGTH.toFloat()
|
||||
val pwr = actorValue.getAsFloat(AVKey.JUMPPOWER)!! * (actorValue.getAsFloat(AVKey.JUMPPOWERMULT) ?: 1f)
|
||||
|
||||
// increment jump counter
|
||||
if (jumpCounter < len) jumpCounter += 1
|
||||
|
||||
// linear time mode
|
||||
val init = (len + 1) / 2f
|
||||
var timedJumpCharge = init - init / len * jumpCounter
|
||||
if (timedJumpCharge < 0) timedJumpCharge = 0f
|
||||
|
||||
val jumpAcc = pwr * timedJumpCharge * JUMP_ACCELERATION_MOD * FastMath.sqrt(scale)
|
||||
|
||||
veloY -= jumpAcc
|
||||
|
||||
// try concave mode?
|
||||
}
|
||||
|
||||
// for mob ai:
|
||||
//super.setVeloY(veloY
|
||||
// -
|
||||
// pwr * FastMath.sqrt(scale)
|
||||
//);
|
||||
}
|
||||
|
||||
private fun jumpFuncLin(pwr: Float, len: Float): Float {
|
||||
return -(pwr / len) * jumpCounter
|
||||
}
|
||||
|
||||
private fun jumpFuncSqu(pwr: Float, len: Float): Float {
|
||||
return pwr / (len * len) * (jumpCounter - len * jumpCounter - len) - pwr
|
||||
}
|
||||
|
||||
private fun jumpFuncExp(pwr: Float, len: Float): Float {
|
||||
val a = FastMath.pow(pwr + 1, 1 / len)
|
||||
return -FastMath.pow(a, len) + 1
|
||||
}
|
||||
|
||||
private fun isFuncDown(input: Input, fn: EnumKeyFunc): Boolean {
|
||||
return input.isKeyDown(KeyMap.getKeyCode(fn))
|
||||
}
|
||||
|
||||
private fun absClamp(i: Float, ceil: Float): Float {
|
||||
if (i > 0)
|
||||
return if (i > ceil) ceil else i
|
||||
else if (i < 0)
|
||||
return if (-i > ceil) -ceil else i
|
||||
else
|
||||
return 0f
|
||||
}
|
||||
|
||||
private fun updateSprite(delta_t: Int) {
|
||||
sprite!!.update(delta_t)
|
||||
if (spriteGlow != null) {
|
||||
spriteGlow!!.update(delta_t)
|
||||
}
|
||||
|
||||
if (grounded) {
|
||||
if (walkHeading == LEFT) {
|
||||
sprite!!.flip(true, false)
|
||||
if (spriteGlow != null) {
|
||||
spriteGlow!!.flip(true, false)
|
||||
}
|
||||
} else {
|
||||
sprite!!.flip(false, false)
|
||||
if (spriteGlow != null) {
|
||||
spriteGlow!!.flip(false, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isNoClip(): Boolean {
|
||||
return noClip
|
||||
}
|
||||
|
||||
fun setNoClip(b: Boolean) {
|
||||
noClip = b
|
||||
}
|
||||
|
||||
override fun addHouseTile(x: Int, y: Int) {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun removeHouseTile(x: Int, y: Int) {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
override fun clearHouseDesignation() {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
|
||||
}
|
||||
24
src/net/torvald/terrarum/gameactors/PlayerBuilder.kt
Normal file
24
src/net/torvald/terrarum/gameactors/PlayerBuilder.kt
Normal file
@@ -0,0 +1,24 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import org.newdawn.slick.SlickException
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-15.
|
||||
*/
|
||||
object PlayerBuilder {
|
||||
private val JSONPATH = "./res/raw/"
|
||||
private val jsonString = String()
|
||||
|
||||
@Throws(IOException::class, SlickException::class)
|
||||
fun create(): Player {
|
||||
val p: Player = Player()
|
||||
CreatureRawInjector.inject(p.actorValue, "CreatureHuman.json")
|
||||
|
||||
// attach sprite
|
||||
|
||||
// do etc.
|
||||
|
||||
return p
|
||||
}
|
||||
}
|
||||
10
src/net/torvald/terrarum/gameactors/Pocketed.kt
Normal file
10
src/net/torvald/terrarum/gameactors/Pocketed.kt
Normal file
@@ -0,0 +1,10 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface Pocketed {
|
||||
|
||||
var inventory: ActorInventory
|
||||
|
||||
}
|
||||
13
src/net/torvald/terrarum/gameactors/Visible.kt
Normal file
13
src/net/torvald/terrarum/gameactors/Visible.kt
Normal file
@@ -0,0 +1,13 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import org.newdawn.slick.GameContainer
|
||||
import org.newdawn.slick.Graphics
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface Visible {
|
||||
fun drawBody(gc: GameContainer, g: Graphics)
|
||||
|
||||
fun updateBodySprite(gc: GameContainer, delta: Int)
|
||||
}
|
||||
7
src/net/torvald/terrarum/gameactors/ai/ActorAI.kt
Normal file
7
src/net/torvald/terrarum/gameactors/ai/ActorAI.kt
Normal file
@@ -0,0 +1,7 @@
|
||||
package net.torvald.terrarum.gameactors.ai
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-03-14.
|
||||
*/
|
||||
interface ActorAI {
|
||||
}
|
||||
62
src/net/torvald/terrarum/gameactors/faction/Faction.kt
Normal file
62
src/net/torvald/terrarum/gameactors/faction/Faction.kt
Normal file
@@ -0,0 +1,62 @@
|
||||
package net.torvald.terrarum.gameactors.faction
|
||||
|
||||
import net.torvald.random.HQRNG
|
||||
import java.util.HashSet
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-02-15.
|
||||
*/
|
||||
class Faction(factionName: String) {
|
||||
|
||||
lateinit var factionName: String
|
||||
lateinit var factionAmicable: HashSet<String>
|
||||
lateinit var factionNeutral: HashSet<String>
|
||||
lateinit var factionHostile: HashSet<String>
|
||||
lateinit var factionFearful: HashSet<String>
|
||||
var factionID: Long = HQRNG().nextLong()
|
||||
|
||||
init {
|
||||
this.factionName = factionName
|
||||
factionAmicable = HashSet<String>()
|
||||
factionNeutral = HashSet<String>()
|
||||
factionHostile = HashSet<String>()
|
||||
factionFearful = HashSet<String>()
|
||||
}
|
||||
|
||||
fun renewFactionName(factionName: String) {
|
||||
this.factionName = factionName
|
||||
}
|
||||
|
||||
fun addFactionAmicable(faction: String) {
|
||||
factionAmicable.add(faction)
|
||||
}
|
||||
|
||||
fun addFactionNeutral(faction: String) {
|
||||
factionNeutral.add(faction)
|
||||
}
|
||||
|
||||
fun addFactionHostile(faction: String) {
|
||||
factionHostile.add(faction)
|
||||
}
|
||||
|
||||
fun addFactionFearful(faction: String) {
|
||||
factionFearful.add(faction)
|
||||
}
|
||||
|
||||
fun removeFactionAmicable(faction: String) {
|
||||
factionAmicable.remove(faction)
|
||||
}
|
||||
|
||||
fun removeFactionNeutral(faction: String) {
|
||||
factionNeutral.remove(faction)
|
||||
}
|
||||
|
||||
fun removeFactionHostile(faction: String) {
|
||||
factionHostile.remove(faction)
|
||||
}
|
||||
|
||||
fun removeFactionFearful(faction: String) {
|
||||
factionFearful.remove(faction)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package net.torvald.terrarum.gameactors.faction
|
||||
|
||||
import net.torvald.JsonFetcher
|
||||
import com.google.gson.JsonObject
|
||||
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-02-15.
|
||||
*/
|
||||
object FactionFactory {
|
||||
|
||||
const val JSONPATH = "./res/raw/factions/"
|
||||
|
||||
/**
|
||||
* @param filename with extension
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun create(filename: String): Faction {
|
||||
val jsonObj = JsonFetcher.readJson(JSONPATH + filename)
|
||||
val factionObj = Faction(jsonObj.get("factionname").asString)
|
||||
|
||||
|
||||
jsonObj.get("factionamicable").asJsonArray.forEach { s -> factionObj.addFactionAmicable(s.asString) }
|
||||
jsonObj.get("factionneutral").asJsonArray.forEach { s -> factionObj.addFactionNeutral(s.asString) }
|
||||
jsonObj.get("factionhostile").asJsonArray.forEach { s -> factionObj.addFactionHostile(s.asString) }
|
||||
jsonObj.get("factionfearful").asJsonArray.forEach { s -> factionObj.addFactionFearful(s.asString) }
|
||||
|
||||
return factionObj
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package net.torvald.terrarum.gameactors.scheduler
|
||||
|
||||
/**
|
||||
* Ultima-like NPC scheduler
|
||||
* Created by minjaesong on 16-03-26.
|
||||
*/
|
||||
interface NPCSchedule {
|
||||
}
|
||||
Reference in New Issue
Block a user