mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-17 14:04:05 +09:00
actor AI from Lua script
Former-commit-id: 184160efc59c4f846f1cc154fe3e60d21b301ee3 Former-commit-id: 4e228542975ea52945a597b7ca1bc06b407c3be7
This commit is contained in:
@@ -22,7 +22,7 @@ import java.util.*
|
||||
* Created by minjaesong on 16-10-24.
|
||||
*/
|
||||
open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
|
||||
: HistoricalFigure(birth, death), Controllable, Pocketed, Factionable, Luminous, LandHolder {
|
||||
: HistoricalFigure(birth, death), Controllable, Pocketed, Factionable, Luminous, LandHolder {
|
||||
|
||||
/** Must be set by PlayerFactory */
|
||||
override var inventory: ActorInventory = ActorInventory()
|
||||
@@ -197,6 +197,22 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
|
||||
isDownDown = isFuncDown(input, EnumKeyFunc.MOVE_DOWN)
|
||||
isRightDown = isFuncDown(input, EnumKeyFunc.MOVE_RIGHT)
|
||||
isJumpDown = isFuncDown(input, EnumKeyFunc.JUMP)
|
||||
|
||||
if (Terrarum.hasController) {
|
||||
gamepad = Controllers.getController(0)
|
||||
axisX = gamepad!!.getAxisValue(0)
|
||||
axisY = gamepad!!.getAxisValue(1)
|
||||
axisRX = gamepad!!.getAxisValue(2)
|
||||
axisRY = gamepad!!.getAxisValue(3)
|
||||
|
||||
// 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
|
||||
|
||||
gamepad!!.isButtonPressed(GAMEPAD_JUMP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,29 +220,17 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
|
||||
if (!noClip) {
|
||||
if (grounded) {
|
||||
actorValue[AVKey.ACCELMULT] = 1.0
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
actorValue[AVKey.ACCELMULT] = ACCEL_MULT_IN_FLIGHT
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
actorValue[AVKey.ACCELMULT] = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
override fun processInput(gc: GameContainer, delta: Int, input: Input) {
|
||||
if (isGamer && Terrarum.hasController) {
|
||||
gamepad = Controllers.getController(0)
|
||||
axisX = gamepad!!.getAxisValue(0)
|
||||
axisY = gamepad!!.getAxisValue(1)
|
||||
axisRX = gamepad!!.getAxisValue(2)
|
||||
axisRY = gamepad!!.getAxisValue(3)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// MOUSE CONTROL //
|
||||
///////////////////
|
||||
@@ -333,16 +337,18 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
|
||||
/**
|
||||
* Jump control
|
||||
*/
|
||||
if (isJumpDown || isGamer && Terrarum.hasController && gamepad!!.isButtonPressed(GAMEPAD_JUMP)) {
|
||||
if (isJumpDown) {
|
||||
if (!noClip) {
|
||||
if (grounded) {
|
||||
jumping = true
|
||||
}
|
||||
jump()
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
walkVertical(true, AXIS_POSMAX)
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
jumping = false
|
||||
jumpCounter = 0
|
||||
jumpAcc = 0.0
|
||||
@@ -376,7 +382,7 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
|
||||
private fun walkHorizontal(left: Boolean, absAxisVal: Float) {
|
||||
if ((!walledLeft && left) || (!walledRight && !left)) {
|
||||
readonly_totalX =
|
||||
absMax( // keyboard
|
||||
absMax(// keyboard
|
||||
actorValue.getAsDouble(AVKey.ACCEL)!! *
|
||||
actorValue.getAsDouble(AVKey.ACCELMULT)!! *
|
||||
Math.sqrt(scale) *
|
||||
@@ -414,7 +420,7 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
|
||||
*/
|
||||
private fun walkVertical(up: Boolean, absAxisVal: Float) {
|
||||
readonly_totalY =
|
||||
absMax( // keyboard
|
||||
absMax(// keyboard
|
||||
actorValue.getAsDouble(AVKey.ACCEL)!! *
|
||||
actorValue.getAsDouble(AVKey.ACCELMULT)!! *
|
||||
Math.sqrt(scale) *
|
||||
@@ -465,7 +471,6 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
|
||||
* TODO linear function (play Super Mario Bros. and you'll get what I'm talking about)
|
||||
*/
|
||||
private fun jump() {
|
||||
|
||||
val len = MAX_JUMP_LENGTH.toFloat()
|
||||
val pwr = actorValue.getAsDouble(AVKey.JUMPPOWER)!! * (actorValue.getAsDouble(AVKey.JUMPPOWERMULT) ?: 1.0)
|
||||
val jumpLinearThre = 0.08
|
||||
@@ -537,7 +542,8 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
|
||||
if (spriteGlow != null) {
|
||||
spriteGlow!!.flip(true, false)
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
sprite!!.flip(false, false)
|
||||
if (spriteGlow != null) {
|
||||
spriteGlow!!.flip(false, false)
|
||||
|
||||
@@ -907,7 +907,7 @@ open class ActorWithBody : Actor() {
|
||||
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
|
||||
(scale).toFloat()
|
||||
)
|
||||
// Q&D fix for Roundworld anormaly
|
||||
// Q&D fix for Roundworld anomaly
|
||||
spriteGlow!!.render(g,
|
||||
(hitbox.posX - hitboxTranslateX * scale).toFloat() + world.width * TILE_SIZE,
|
||||
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
|
||||
@@ -925,7 +925,7 @@ open class ActorWithBody : Actor() {
|
||||
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
|
||||
(scale).toFloat()
|
||||
)
|
||||
// Q&D fix for Roundworld anormaly
|
||||
// Q&D fix for Roundworld anomaly
|
||||
spriteGlow!!.render(g,
|
||||
(hitbox.posX - scale).toFloat() + world.width * TILE_SIZE,
|
||||
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
|
||||
@@ -956,7 +956,7 @@ open class ActorWithBody : Actor() {
|
||||
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
|
||||
(scale).toFloat()
|
||||
)
|
||||
// Q&D fix for Roundworld anormaly
|
||||
// Q&D fix for Roundworld anomaly
|
||||
sprite!!.render(g,
|
||||
(hitbox.posX - hitboxTranslateX * scale).toFloat() + world.width * TILE_SIZE,
|
||||
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
|
||||
@@ -974,7 +974,7 @@ open class ActorWithBody : Actor() {
|
||||
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
|
||||
(scale).toFloat()
|
||||
)
|
||||
// Q&D fix for Roundworld anormaly
|
||||
// Q&D fix for Roundworld anomaly
|
||||
sprite!!.render(g,
|
||||
(hitbox.posX - scale).toFloat() + world.width * TILE_SIZE,
|
||||
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.torvald.terrarum.gameactors
|
||||
|
||||
import net.torvald.terrarum.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.gameactors.ai.AILuaAPI
|
||||
import net.torvald.terrarum.gameitem.EquipPosition
|
||||
import net.torvald.terrarum.gameitem.InventoryItem
|
||||
import org.luaj.vm2.Globals
|
||||
@@ -11,25 +12,23 @@ import org.luaj.vm2.compiler.LuaC
|
||||
import org.luaj.vm2.lib.*
|
||||
import org.luaj.vm2.lib.jse.JseBaseLib
|
||||
import org.luaj.vm2.lib.jse.JseMathLib
|
||||
import org.luaj.vm2.lib.jse.JsePlatform
|
||||
import org.newdawn.slick.GameContainer
|
||||
import org.newdawn.slick.Input
|
||||
import java.io.InputStreamReader
|
||||
import java.io.Reader
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-01-31.
|
||||
*/
|
||||
open class HumanoidNPC(luaScript: String, born: GameDate) : ActorHumanoid(born), AIControlled, CanBeAnItem {
|
||||
open class HumanoidNPC(val luaScript: String, born: GameDate) : ActorHumanoid(born), AIControlled, CanBeAnItem {
|
||||
|
||||
override val scriptPath: String = ""
|
||||
|
||||
companion object {
|
||||
protected val luag = Globals()
|
||||
protected val luag: Globals = JsePlatform.standardGlobals()
|
||||
|
||||
init {
|
||||
luag.load(JseBaseLib())
|
||||
LoadState.install(luag)
|
||||
LuaC.install(luag)
|
||||
}
|
||||
init {
|
||||
AILuaAPI(luag, this)
|
||||
}
|
||||
|
||||
// we're having InventoryItem data so that this class could be somewhat universal
|
||||
@@ -72,13 +71,15 @@ open class HumanoidNPC(luaScript: String, born: GameDate) : ActorHumanoid(born),
|
||||
init {
|
||||
//val inputStream = javaClass.getResourceAsStream(scriptPath)
|
||||
//runCommand(InputStreamReader(inputStream), scriptPath)
|
||||
runCommand(luaScript)
|
||||
}
|
||||
|
||||
|
||||
override fun update(gc: GameContainer, delta: Int) {
|
||||
super.update(gc, delta)
|
||||
//runCommand(luaScript)
|
||||
luag.load(luaScript).call()
|
||||
|
||||
//moveRight()
|
||||
}
|
||||
|
||||
override fun moveLeft() { // hit the buttons on the controller box
|
||||
@@ -126,7 +127,7 @@ open class HumanoidNPC(luaScript: String, born: GameDate) : ActorHumanoid(born),
|
||||
|
||||
fun runCommand(script: String) {
|
||||
if (!threadRun && !flagDespawn) {
|
||||
currentExecutionThread = Thread(ThreadRunCommand(luag, script, "="))
|
||||
currentExecutionThread = Thread(ThreadRunCommand(luag, script, ""))
|
||||
currentExecutionThread.start()
|
||||
threadRun = true
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import java.security.SecureRandom
|
||||
*/
|
||||
object InjectCreatureRaw {
|
||||
|
||||
// FIXME strength not injected properly?
|
||||
|
||||
const val JSONPATH = "./assets/raw/creatures/"
|
||||
private const val MULTIPLIER_RAW_ELEM_SUFFIX = AVKey.MULT
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ object PlayerBuilderCynthia {
|
||||
InjectCreatureRaw(p.actorValue, "CreatureHuman.json")
|
||||
|
||||
p.actorValue[AVKey.__PLAYER_QUICKBARSEL] = 0
|
||||
p.actorValue[AVKey.NAME] = "Cynthia"
|
||||
|
||||
|
||||
p.makeNewSprite(26, 42)
|
||||
|
||||
@@ -16,12 +16,17 @@ import org.luaj.vm2.lib.ZeroArgFunction
|
||||
internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
|
||||
|
||||
init {
|
||||
if (actor !is AIControlled) throw IllegalArgumentException("The actor is not AIControlled! $actor")
|
||||
if (actor !is AIControlled)
|
||||
throw IllegalArgumentException("The actor is not AIControlled! $actor")
|
||||
|
||||
// load things. WARNING: THIS IS MANUAL!
|
||||
g["ai"] = LuaValue.tableOf()
|
||||
|
||||
g["ai"]["getSelfActorInfo"] = GetSelfActorInfo(actor)
|
||||
|
||||
g["ai"]["getNearestActor"] = GetNearestActor()
|
||||
g["ai"]["getNearestPlayer"] = GetNearestPlayer()
|
||||
|
||||
g["ai"]["getX"] = GetX(actor)
|
||||
g["ai"]["getY"] = GetY(actor)
|
||||
g["ai"]["moveUp"] = MoveUp(actor)
|
||||
@@ -29,10 +34,14 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
|
||||
g["ai"]["moveLeft"] = MoveLeft(actor)
|
||||
g["ai"]["moveRight"] = MoveRight(actor)
|
||||
g["ai"]["moveTo"] = MoveTo(actor)
|
||||
g["ai"]["jump"] = Jump(actor)
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Reads arbitrary ActorWithBody and returns its information as Lua table
|
||||
*/
|
||||
fun composeActorObject(actor: ActorWithBody): LuaTable {
|
||||
val t = LuaValue.tableOf()
|
||||
|
||||
@@ -48,7 +57,7 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
|
||||
|
||||
t["mass"] = actor.mass
|
||||
|
||||
t["collision_type"] = actor.collisionType
|
||||
t["collisionType"] = actor.collisionType
|
||||
|
||||
t["strength"] = actor.actorValue.getAsInt(AVKey.STRENGTH) ?: 0
|
||||
|
||||
@@ -56,7 +65,7 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
|
||||
val MUL_2 = LightmapRenderer.MUL_2
|
||||
val MUL = LightmapRenderer.MUL
|
||||
val CHMAX = LightmapRenderer.CHANNEL_MAX
|
||||
t["luminosity_rgb"] = lumrgb
|
||||
t["luminosityRGB"] = lumrgb
|
||||
t["luminosity"] = (lumrgb.div(MUL_2).and(CHMAX).times(3) +
|
||||
lumrgb.div(MUL).and(CHMAX).times(4) +
|
||||
lumrgb.and(1023)) / 8 // quick luminosity calculation
|
||||
@@ -65,6 +74,12 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
|
||||
}
|
||||
}
|
||||
|
||||
class GetSelfActorInfo(val actor: ActorWithBody) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return composeActorObject(actor)
|
||||
}
|
||||
}
|
||||
|
||||
/** ai.getNearestActor(nullable any criterion, nullable number range) */
|
||||
class GetNearestActor() : LuaFunction() {
|
||||
override fun call(): LuaValue {
|
||||
@@ -147,4 +162,11 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
class Jump(val actor: AIControlled) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
actor.moveJump()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
package net.torvald.terrarum.gameactors.ai.scripts
|
||||
|
||||
/**
|
||||
* Randomly roams around.
|
||||
*
|
||||
* Created by SKYHi14 on 2016-12-23.
|
||||
*/
|
||||
object PokemonNPCAI {
|
||||
operator fun invoke(): String = """
|
||||
ai.jump()
|
||||
ai.moveRight()
|
||||
|
||||
thisActorInfo = ai.getSelfActorInfo()
|
||||
print(thisActorInfo.strength)
|
||||
"""
|
||||
}
|
||||
Reference in New Issue
Block a user