mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-11 06:11:50 +09:00
gdx 1.10/lwjgl3 migration; removing old Lua stuffs
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
module terrarum {
|
||||
module terrarum.terrarum {
|
||||
// java
|
||||
requires java.desktop;
|
||||
requires java.logging;
|
||||
@@ -6,11 +6,14 @@ module terrarum {
|
||||
|
||||
// kotlin
|
||||
requires kotlin.stdlib;
|
||||
requires kotlin.test;
|
||||
|
||||
// gdx
|
||||
requires gdx;
|
||||
requires gdx.backend.lwjgl;
|
||||
requires gdx.controllers;
|
||||
requires gdx.platform;
|
||||
requires gdx.backend.lwjgl3;
|
||||
requires gdx.controllers.core;
|
||||
requires gdx.controllers.desktop;
|
||||
|
||||
// terrarum
|
||||
requires TerrarumSansBitmap;
|
||||
@@ -19,8 +22,8 @@ module terrarum {
|
||||
|
||||
// etc
|
||||
requires GetCpuName;
|
||||
requires jxinput;
|
||||
requires gson;
|
||||
requires commons.codec;
|
||||
requires com.google.gson;
|
||||
requires org.apache.commons.codec;
|
||||
requires commons.csv;
|
||||
requires jxinput;
|
||||
}
|
||||
@@ -238,7 +238,7 @@ data class CIEXYZ(var X: Float = 0f, var Y: Float = 0f, var Z: Float = 0f, var a
|
||||
data class CIEYXY(val yy: Float = 0f, var x: Float = 0f, var y: Float = 0f, var alpha: Float = 1f) {
|
||||
init {
|
||||
if (yy < 0f || x < 0f || y < 0f)
|
||||
throw IllegalArgumentException("Value range error - parametres of YXY cannot be negative: ($yy, $x, $y)")
|
||||
throw IllegalArgumentException("Value range error - parameters of YXY cannot be negative: ($yy, $x, $y)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ package net.torvald.parametricsky
|
||||
import com.badlogic.gdx.Game
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Screen
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
@@ -284,10 +284,8 @@ class Application : Game() {
|
||||
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val config = LwjglApplicationConfiguration()
|
||||
config.width = WIDTH
|
||||
config.height = HEIGHT
|
||||
config.foregroundFPS = 0
|
||||
val config = Lwjgl3ApplicationConfiguration()
|
||||
config.setWindowedMode(WIDTH, HEIGHT)
|
||||
|
||||
LwjglApplication(Application(), config)
|
||||
Lwjgl3Application(Application(), config)
|
||||
}
|
||||
@@ -2,8 +2,8 @@ package net.torvald.spriteassembler
|
||||
|
||||
import com.badlogic.gdx.Game
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
@@ -309,15 +309,14 @@ class SpriteAssemblerPreview: Game() {
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val appConfig = LwjglApplicationConfiguration()
|
||||
appConfig.resizable = false
|
||||
appConfig.width = 512
|
||||
appConfig.height = 1024
|
||||
appConfig.foregroundFPS = 5
|
||||
appConfig.backgroundFPS = 5
|
||||
val appConfig = Lwjgl3ApplicationConfiguration()
|
||||
appConfig.setWindowedMode(512, 1024)
|
||||
appConfig.setIdleFPS(5)
|
||||
appConfig.setForegroundFPS(5)
|
||||
appConfig.setResizable(false)
|
||||
|
||||
val gdxWindow = SpriteAssemblerPreview()
|
||||
|
||||
LwjglApplication(gdxWindow, appConfig)
|
||||
Lwjgl3Application(gdxWindow, appConfig)
|
||||
SpriteAssemblerApp(gdxWindow)
|
||||
}
|
||||
@@ -2,8 +2,8 @@ package net.torvald.terrarum;
|
||||
|
||||
import com.badlogic.gdx.*;
|
||||
import com.badlogic.gdx.audio.AudioDevice;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
||||
import com.badlogic.gdx.controllers.Controllers;
|
||||
import com.badlogic.gdx.graphics.*;
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||
@@ -40,6 +40,7 @@ import net.torvald.util.ArrayListMap;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
@@ -94,7 +95,7 @@ public class AppLoader implements ApplicationListener {
|
||||
* @param appConfig LWJGL(2) Application Configuration
|
||||
* @param injectScreen GDX Screen you want to run
|
||||
*/
|
||||
public AppLoader(LwjglApplicationConfiguration appConfig, Screen injectScreen) {
|
||||
public AppLoader(Lwjgl3ApplicationConfiguration appConfig, Screen injectScreen) {
|
||||
AppLoader.injectScreen = injectScreen;
|
||||
AppLoader.appConfig = appConfig;
|
||||
}
|
||||
@@ -102,9 +103,9 @@ public class AppLoader implements ApplicationListener {
|
||||
/**
|
||||
* Initialise the application with default game screen
|
||||
*
|
||||
* @param appConfig LWJGL(2) Application Configuration
|
||||
* @param appConfig LWJGL3 Application Configuration
|
||||
*/
|
||||
public AppLoader(LwjglApplicationConfiguration appConfig) {
|
||||
public AppLoader(Lwjgl3ApplicationConfiguration appConfig) {
|
||||
AppLoader.appConfig = appConfig;
|
||||
}
|
||||
|
||||
@@ -148,14 +149,6 @@ public class AppLoader implements ApplicationListener {
|
||||
|
||||
public static final int GLOBAL_FRAMERATE_LIMIT = 300;
|
||||
|
||||
public static final float TV_SAFE_GRAPHICS = 0.05f; // as per EBU recommendation (https://tech.ebu.ch/docs/r/r095.pdf)
|
||||
public static final float TV_SAFE_ACTION = 0.035f; // as per EBU recommendation (https://tech.ebu.ch/docs/r/r095.pdf)
|
||||
|
||||
public static int getTvSafeGraphicsWidth() { return Math.round(screenW * TV_SAFE_GRAPHICS); }
|
||||
public static int getTvSafeGraphicsHeight() { return Math.round(screenH * TV_SAFE_GRAPHICS); }
|
||||
public static int getTvSafeActionWidth() { return Math.round(screenW * TV_SAFE_ACTION); }
|
||||
public static int getTvSafeActionHeight() { return Math.round(screenH * TV_SAFE_ACTION); }
|
||||
|
||||
/**
|
||||
* These languages won't distinguish regional differences (e.g. enUS and enUK, frFR and frCA)
|
||||
*/
|
||||
@@ -192,7 +185,8 @@ public class AppLoader implements ApplicationListener {
|
||||
private static boolean resizeRequested = false;
|
||||
private static Point2i resizeReqSize;
|
||||
|
||||
public static LwjglApplicationConfiguration appConfig;
|
||||
public static Lwjgl3ApplicationConfiguration appConfig;
|
||||
public static TerrarumScreenSize screenSize;
|
||||
public static GameFontBase fontGame;
|
||||
public static TinyAlphNum fontSmallNumbers;
|
||||
|
||||
@@ -209,10 +203,6 @@ public class AppLoader implements ApplicationListener {
|
||||
|
||||
public static ArrayListMap debugTimers = new ArrayListMap<String, Long>();
|
||||
|
||||
public static final int defaultW = 1280;
|
||||
public static final int defaultH = 720;
|
||||
public static final int minimumW = 1080;
|
||||
public static final int minimumH = 720;
|
||||
|
||||
public static final String FONT_DIR = "assets/graphics/fonts/terrarum-sans-bitmap";
|
||||
|
||||
@@ -238,15 +228,6 @@ public class AppLoader implements ApplicationListener {
|
||||
|
||||
private static Screen currenScreen;
|
||||
private static LoadScreenBase currentSetLoadScreen;
|
||||
public static int screenW = 0;
|
||||
public static int screenH = 0;
|
||||
public static float screenWf = 0f;
|
||||
public static float screenHf = 0f;
|
||||
public static int halfScreenW = 0;
|
||||
public static int halfScreenH = 0;
|
||||
public static float halfScreenWf = 0f;
|
||||
public static float halfScreenHf = 0f;
|
||||
public static float aspectRatio = 0f;
|
||||
|
||||
public static Texture textureWhiteSquare;
|
||||
public static Texture textureWhiteCircle;
|
||||
@@ -315,35 +296,37 @@ public class AppLoader implements ApplicationListener {
|
||||
|
||||
ShaderProgram.pedantic = false;
|
||||
|
||||
LwjglApplicationConfiguration appConfig = new LwjglApplicationConfiguration();
|
||||
appConfig.useGL30 = false; // https://stackoverflow.com/questions/46753218/libgdx-should-i-use-gl30
|
||||
appConfig.vSyncEnabled = getConfigBoolean("usevsync");
|
||||
appConfig.resizable = false;//true;
|
||||
appConfig.width = getConfigInt("screenwidth");
|
||||
if (appConfig.width % 2 == 1) appConfig.width -= 1;
|
||||
if (appConfig.width < minimumW) appConfig.width = minimumW;
|
||||
appConfig.height = getConfigInt("screenheight");
|
||||
if (appConfig.height % 2 == 1) appConfig.height -= 1;
|
||||
if (appConfig.height < minimumH) appConfig.height = minimumH;
|
||||
appConfig.backgroundFPS = Math.min(GLOBAL_FRAMERATE_LIMIT, getConfigInt("displayfps"));
|
||||
appConfig.foregroundFPS = Math.min(GLOBAL_FRAMERATE_LIMIT, getConfigInt("displayfps"));
|
||||
appConfig.title = GAME_NAME;
|
||||
appConfig.forceExit = true; // it seems KDE 5 likes this one better...
|
||||
// (Plasma freezes upon app exit. with forceExit = true, it's only frozen for a minute; with forceExit = false, it's indefinite)
|
||||
appConfig.samples = 4; // force the AA on, if the graphics driver didn't do already
|
||||
screenSize = new TerrarumScreenSize(getConfigInt("screenwidth"), getConfigInt("screenheight"));
|
||||
int width = screenSize.getScreenW();
|
||||
int height = screenSize.getScreenH();
|
||||
|
||||
if (appConfig.backgroundFPS <= 0) appConfig.backgroundFPS = GLOBAL_FRAMERATE_LIMIT;
|
||||
if (appConfig.foregroundFPS <= 0) appConfig.foregroundFPS = GLOBAL_FRAMERATE_LIMIT;
|
||||
Lwjgl3ApplicationConfiguration appConfig = new Lwjgl3ApplicationConfiguration();
|
||||
//appConfig.useGL30 = false; // https://stackoverflow.com/questions/46753218/libgdx-should-i-use-gl30
|
||||
appConfig.useVsync(getConfigBoolean("usevsync"));
|
||||
appConfig.setResizable(false);
|
||||
appConfig.setWindowedMode(width, height);
|
||||
int fps = Math.min(GLOBAL_FRAMERATE_LIMIT, getConfigInt("displayfps"));
|
||||
if (fps <= 0) fps = GLOBAL_FRAMERATE_LIMIT;
|
||||
appConfig.setIdleFPS(fps);
|
||||
appConfig.setForegroundFPS(fps);
|
||||
appConfig.setTitle(GAME_NAME);
|
||||
//appConfig.forceExit = true; // it seems KDE 5 likes this one better...
|
||||
// (Plasma freezes upon app exit. with forceExit = true, it's only frozen for a minute; with forceExit = false, it's indefinite)
|
||||
//appConfig.samples = 4; // force the AA on, if the graphics driver didn't do already
|
||||
|
||||
// load app icon
|
||||
int[] appIconSizes = new int[]{256,128,64,32,16};
|
||||
ArrayList<String> appIconPaths = new ArrayList<>();
|
||||
for (int size : appIconSizes) {
|
||||
String name = "assets/appicon" + size + ".png";
|
||||
if (new File("./" + name).exists()) {
|
||||
appConfig.addIcon(name, Files.FileType.Internal);
|
||||
appIconPaths.add("./" + name);
|
||||
}
|
||||
}
|
||||
|
||||
Object[] iconPathsTemp = appIconPaths.toArray();
|
||||
appConfig.setWindowIcon(Arrays.copyOf(iconPathsTemp, iconPathsTemp.length, String[].class));
|
||||
|
||||
//if (args.length == 1 && args[0].equals("isdev=true")) {
|
||||
IS_DEVELOPMENT_BUILD = true;
|
||||
// safe area box
|
||||
@@ -356,7 +339,7 @@ public class AppLoader implements ApplicationListener {
|
||||
// set some more configuration vars
|
||||
MULTITHREAD = THREAD_COUNT >= 3 && getConfigBoolean("multithread");
|
||||
|
||||
new LwjglApplication(new AppLoader(appConfig), appConfig);
|
||||
new Lwjgl3Application(new AppLoader(appConfig), appConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -390,12 +373,12 @@ public class AppLoader implements ApplicationListener {
|
||||
|
||||
// set basis of draw
|
||||
logoBatch = new SpriteBatch();
|
||||
camera = new OrthographicCamera(((float) appConfig.width), ((float) appConfig.height));
|
||||
camera = new OrthographicCamera((screenSize.getScreenWf()), (screenSize.getScreenHf()));
|
||||
|
||||
batch = new SpriteBatch();
|
||||
shapeRender = new ShapeRenderer();
|
||||
|
||||
initViewPort(appConfig.width, appConfig.height);
|
||||
initViewPort(screenSize.getScreenW(), screenSize.getScreenH());
|
||||
|
||||
// logo here :p
|
||||
logo = new TextureRegion(new Texture(Gdx.files.internal("assets/graphics/logo_placeholder.tga")));
|
||||
@@ -417,7 +400,7 @@ public class AppLoader implements ApplicationListener {
|
||||
VertexAttribute.ColorUnpacked(),
|
||||
VertexAttribute.TexCoords(0)
|
||||
);
|
||||
updateFullscreenQuad(appConfig.width, appConfig.height);
|
||||
updateFullscreenQuad(screenSize.getScreenW(), screenSize.getScreenH());
|
||||
|
||||
|
||||
// set up renderer info variables
|
||||
@@ -562,7 +545,7 @@ public class AppLoader implements ApplicationListener {
|
||||
screenshotRequested = false;
|
||||
|
||||
try {
|
||||
Pixmap p = ScreenUtils.getFrameBufferPixmap(0, 0, appConfig.width, appConfig.height);
|
||||
Pixmap p = ScreenUtils.getFrameBufferPixmap(0, 0, screenSize.getScreenW(), screenSize.getScreenH());
|
||||
PixmapIO2.writeTGA(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".tga"), p, true);
|
||||
p.dispose();
|
||||
|
||||
@@ -592,8 +575,8 @@ public class AppLoader implements ApplicationListener {
|
||||
setCameraPosition(0f, 0f);
|
||||
|
||||
int safetyTextLen = fontGame.getWidth(Lang.INSTANCE.get("APP_WARNING_HEALTH_AND_SAFETY"));
|
||||
int logoPosX = (appConfig.width - logo.getRegionWidth() - safetyTextLen) >>> 1;
|
||||
int logoPosY = Math.round(appConfig.height / 15f);
|
||||
int logoPosX = (screenSize.getScreenW() - logo.getRegionWidth() - safetyTextLen) >>> 1;
|
||||
int logoPosY = Math.round(screenSize.getScreenH() / 15f);
|
||||
int textY = logoPosY + logo.getRegionHeight() - 16;
|
||||
|
||||
// draw logo reflection
|
||||
@@ -605,8 +588,8 @@ public class AppLoader implements ApplicationListener {
|
||||
logoBatch.draw(logo, logoPosX, logoPosY + logo.getRegionHeight());
|
||||
}
|
||||
else {
|
||||
logoBatch.draw(logo, (appConfig.width - logo.getRegionWidth()) / 2f,
|
||||
(appConfig.height - logo.getRegionHeight() * 2) / 2f + logo.getRegionHeight()
|
||||
logoBatch.draw(logo, (screenSize.getScreenW() - logo.getRegionWidth()) / 2f,
|
||||
(screenSize.getScreenH() - logo.getRegionHeight() * 2) / 2f + logo.getRegionHeight()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -631,8 +614,8 @@ public class AppLoader implements ApplicationListener {
|
||||
String s = Lang.INSTANCE.get("APP_CHINESE_HEALTHY_GAME_MSG_" + i);
|
||||
|
||||
fontGame.draw(logoBatch, s,
|
||||
(appConfig.width - fontGame.getWidth(s)) >>> 1,
|
||||
Math.round(appConfig.height * 12f / 15f + fontGame.getLineHeight() * (i - 1))
|
||||
(screenSize.getScreenW() - fontGame.getWidth(s)) >>> 1,
|
||||
Math.round(screenSize.getScreenH() * 12f / 15f + fontGame.getLineHeight() * (i - 1))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -640,15 +623,15 @@ public class AppLoader implements ApplicationListener {
|
||||
logoBatch.setColor(new Color(0x282828ff));
|
||||
Texture tex1 = CommonResourcePool.INSTANCE.getAsTexture("title_health1");
|
||||
Texture tex2 = CommonResourcePool.INSTANCE.getAsTexture("title_health2");
|
||||
int virtualHeight = appConfig.height - logoPosY - logo.getRegionHeight() / 4;
|
||||
int virtualHeightOffset = appConfig.height - virtualHeight;
|
||||
logoBatch.draw(tex1, (appConfig.width - tex1.getWidth()) >>> 1, virtualHeightOffset + (virtualHeight >>> 1) - 16, tex1.getWidth(), -tex1.getHeight());
|
||||
logoBatch.draw(tex2, (appConfig.width - tex2.getWidth()) >>> 1, virtualHeightOffset + (virtualHeight >>> 1) + 16 + tex2.getHeight(), tex2.getWidth(), -tex2.getHeight());
|
||||
int virtualHeight = screenSize.getScreenH() - logoPosY - logo.getRegionHeight() / 4;
|
||||
int virtualHeightOffset = screenSize.getScreenH() - virtualHeight;
|
||||
logoBatch.draw(tex1, (screenSize.getScreenW() - tex1.getWidth()) >>> 1, virtualHeightOffset + (virtualHeight >>> 1) - 16, tex1.getWidth(), -tex1.getHeight());
|
||||
logoBatch.draw(tex2, (screenSize.getScreenW() - tex2.getWidth()) >>> 1, virtualHeightOffset + (virtualHeight >>> 1) + 16 + tex2.getHeight(), tex2.getWidth(), -tex2.getHeight());
|
||||
|
||||
}
|
||||
else {
|
||||
logoBatch.draw(logo, (appConfig.width - logo.getRegionWidth()) / 2f,
|
||||
(appConfig.height - logo.getRegionHeight() * 2) / 2f
|
||||
logoBatch.draw(logo, (screenSize.getScreenW() - logo.getRegionWidth()) / 2f,
|
||||
(screenSize.getScreenH() - logo.getRegionHeight() * 2) / 2f
|
||||
);
|
||||
}
|
||||
|
||||
@@ -662,45 +645,30 @@ public class AppLoader implements ApplicationListener {
|
||||
|
||||
//initViewPort(width, height);
|
||||
|
||||
screenW = width;
|
||||
screenH = height;
|
||||
screenSize.setDimension(width, height);
|
||||
|
||||
if (currenScreen != null) currenScreen.resize(screenW, screenH);
|
||||
if (currenScreen != null) currenScreen.resize(screenSize.getScreenW(), screenSize.getScreenH());
|
||||
updateFullscreenQuad(screenSize.getScreenW(), screenSize.getScreenH());
|
||||
|
||||
|
||||
if (renderFBO == null ||
|
||||
(renderFBO.getWidth() != screenW ||
|
||||
renderFBO.getHeight() != screenH)
|
||||
(renderFBO.getWidth() != screenSize.getScreenW() ||
|
||||
renderFBO.getHeight() != screenSize.getScreenH())
|
||||
) {
|
||||
renderFBO = new FrameBuffer(
|
||||
Pixmap.Format.RGBA8888,
|
||||
screenW,
|
||||
screenH,
|
||||
screenSize.getScreenW(),
|
||||
screenSize.getScreenH(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
appConfig.width = screenW;
|
||||
appConfig.height = screenH;
|
||||
|
||||
halfScreenW = screenW / 2;
|
||||
halfScreenH = screenH / 2;
|
||||
|
||||
screenWf = (float) screenW;
|
||||
screenHf = (float) screenH;
|
||||
halfScreenWf = (float) halfScreenW;
|
||||
halfScreenHf = (float) halfScreenH;
|
||||
|
||||
aspectRatio = screenWf / screenHf;
|
||||
|
||||
updateFullscreenQuad(screenW, screenH);
|
||||
|
||||
printdbg(this, "Resize end");
|
||||
}
|
||||
|
||||
public static void resizeScreen(int width, int height) {
|
||||
resizeRequested = true;
|
||||
resizeReqSize = new Point2i(Math.max(width, minimumW), Math.max(height, minimumH));
|
||||
resizeReqSize = new Point2i(width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -798,7 +766,7 @@ public class AppLoader implements ApplicationListener {
|
||||
currenScreen = screen;
|
||||
|
||||
currenScreen.show();
|
||||
currenScreen.resize(appConfig.width, appConfig.height);
|
||||
currenScreen.resize(screenSize.getScreenW(), screenSize.getScreenH());
|
||||
|
||||
|
||||
System.gc();
|
||||
@@ -847,7 +815,7 @@ public class AppLoader implements ApplicationListener {
|
||||
|
||||
|
||||
private void setCameraPosition(float newX, float newY) {
|
||||
camera.position.set((-newX + appConfig.width / 2), (-newY + appConfig.height / 2), 0f); // deliberate integer division
|
||||
camera.position.set((-newX + screenSize.getScreenW() / 2), (-newY + screenSize.getScreenH() / 2), 0f); // deliberate integer division
|
||||
camera.update();
|
||||
logoBatch.setProjectionMatrix(camera.combined);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.ApplicationAdapter
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.GL20
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
@@ -18,14 +18,11 @@ import net.torvald.terrarumsansbitmap.gdx.GameFontBase
|
||||
*/
|
||||
|
||||
fun main(args: Array<String>) { // LWJGL 3 won't work? java.lang.VerifyError
|
||||
val config = LwjglApplicationConfiguration()
|
||||
//config.useGL30 = true
|
||||
config.vSyncEnabled = false
|
||||
config.resizable = false
|
||||
config.width = 1072
|
||||
config.height = 742
|
||||
config.foregroundFPS = 9999
|
||||
LwjglApplication(ColorLimiterTest, config)
|
||||
val config = Lwjgl3ApplicationConfiguration()
|
||||
config.useVsync(false)
|
||||
config.setResizable(false)
|
||||
config.setWindowedMode(1072, 742)
|
||||
Lwjgl3Application(ColorLimiterTest, config)
|
||||
}
|
||||
|
||||
object ColorLimiterTest : ApplicationAdapter() {
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.badlogic.gdx.Input
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
|
||||
/**
|
||||
* Keys must be all lowercase
|
||||
@@ -17,8 +16,8 @@ object DefaultConfig {
|
||||
|
||||
jsonObject.addProperty("displayfps", 0) // 0: no limit, non-zero: limit
|
||||
jsonObject.addProperty("usevsync", false)
|
||||
jsonObject.addProperty("screenwidth", AppLoader.defaultW)
|
||||
jsonObject.addProperty("screenheight", AppLoader.defaultH)
|
||||
jsonObject.addProperty("screenwidth", TerrarumScreenSize.defaultW)
|
||||
jsonObject.addProperty("screenheight", TerrarumScreenSize.defaultH)
|
||||
|
||||
|
||||
//jsonObject.addProperty("imtooyoungtodie", false) // no perma-death
|
||||
|
||||
@@ -2,8 +2,8 @@ package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.ApplicationAdapter
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
@@ -15,14 +15,11 @@ import net.torvald.terrarumsansbitmap.gdx.GameFontBase
|
||||
* Created by minjaesong on 2017-08-25.
|
||||
*/
|
||||
fun main(args: Array<String>) { // LWJGL 3 won't work? java.lang.VerifyError
|
||||
val config = LwjglApplicationConfiguration()
|
||||
//config.useGL30 = true
|
||||
config.vSyncEnabled = false
|
||||
config.resizable = false
|
||||
config.width = 1072
|
||||
config.height = 742
|
||||
config.foregroundFPS = 9999
|
||||
LwjglApplication(GlslTilingTest, config)
|
||||
val config = Lwjgl3ApplicationConfiguration()
|
||||
config.useVsync(false)
|
||||
config.setResizable(false)
|
||||
config.setWindowedMode(1072, 742)
|
||||
Lwjgl3Application(GlslTilingTest, config)
|
||||
}
|
||||
|
||||
object GlslTilingTest : ApplicationAdapter() {
|
||||
|
||||
@@ -21,7 +21,7 @@ open class LoadScreenBase : ScreenAdapter(), Disposable {
|
||||
internal var errorTrapped = false
|
||||
internal var doContextChange = false
|
||||
|
||||
var camera = OrthographicCamera(AppLoader.screenWf, AppLoader.screenHf)
|
||||
var camera = OrthographicCamera(AppLoader.screenSize.screenWf, AppLoader.screenSize.screenHf)
|
||||
|
||||
override fun show() {
|
||||
messages.clear()
|
||||
@@ -49,7 +49,7 @@ open class LoadScreenBase : ScreenAdapter(), Disposable {
|
||||
}
|
||||
|
||||
|
||||
initViewPort(AppLoader.screenW, AppLoader.screenH)
|
||||
initViewPort(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH)
|
||||
}
|
||||
|
||||
fun initViewPort(width: Int, height: Int) {
|
||||
@@ -77,6 +77,6 @@ open class LoadScreenBase : ScreenAdapter(), Disposable {
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
initViewPort(AppLoader.screenW, AppLoader.screenH)
|
||||
initViewPort(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH)
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@ class ModOptionsHost : UICanvas() {
|
||||
private val moduleAreaHMargin = 48
|
||||
private val moduleAreaBorder = 8
|
||||
|
||||
override var width = AppLoader.screenW - UIRemoCon.remoConWidth - moduleAreaHMargin
|
||||
override var height = AppLoader.screenH - moduleAreaHMargin * 2
|
||||
override var width = AppLoader.screenSize.screenW - UIRemoCon.remoConWidth - moduleAreaHMargin
|
||||
override var height = AppLoader.screenSize.screenH - moduleAreaHMargin * 2
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package net.torvald.terrarum;
|
||||
|
||||
import com.badlogic.gdx.ApplicationAdapter;
|
||||
import com.badlogic.gdx.Files;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import net.torvald.terrarumsansbitmap.gdx.GameFontBase;
|
||||
|
||||
@@ -14,37 +14,22 @@ import java.io.File;
|
||||
*/
|
||||
public class MusicComposerApp extends ApplicationAdapter {
|
||||
|
||||
public static LwjglApplicationConfiguration appConfig;
|
||||
public static Lwjgl3ApplicationConfiguration appConfig;
|
||||
public static GameFontBase fontGame;
|
||||
|
||||
public MusicComposerApp(LwjglApplicationConfiguration appConfig) {
|
||||
public MusicComposerApp(Lwjgl3ApplicationConfiguration appConfig) {
|
||||
this.appConfig = appConfig;
|
||||
}
|
||||
|
||||
public void main(String[] args) {
|
||||
|
||||
LwjglApplicationConfiguration appConfig = new LwjglApplicationConfiguration();
|
||||
appConfig.useGL30 = true; // utilising some GL trickeries, need this to be TRUE
|
||||
appConfig.resizable = false;//true;
|
||||
//appConfig.width = 1110; // photographic ratio (1.5:1)
|
||||
//appConfig.height = 740; // photographic ratio (1.5:1)
|
||||
appConfig.width = 1000;;;
|
||||
appConfig.height = 666;
|
||||
appConfig.backgroundFPS = 9999;
|
||||
appConfig.foregroundFPS = 9999;
|
||||
appConfig.title = "Speelklok";
|
||||
appConfig.forceExit = false;
|
||||
Lwjgl3ApplicationConfiguration appConfig = new Lwjgl3ApplicationConfiguration();
|
||||
|
||||
// load app icon
|
||||
int[] appIconSizes = new int[]{256,128,64,32,16};
|
||||
for (int size : appIconSizes) {
|
||||
String name = "assets/appicon" + size + ".png";
|
||||
if (new File("./" + name).exists()) {
|
||||
appConfig.addIcon(name, Files.FileType.Internal);
|
||||
}
|
||||
}
|
||||
appConfig.setResizable(false);
|
||||
appConfig.setWindowedMode(1280, 720);
|
||||
appConfig.setTitle("Speelklok");
|
||||
|
||||
new LwjglApplication(new MusicComposerApp(appConfig), appConfig);
|
||||
new Lwjgl3Application(new MusicComposerApp(appConfig), appConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.ApplicationAdapter
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.glester.jopus.JOpusBufferFile
|
||||
|
||||
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
|
||||
|
||||
val config = LwjglApplicationConfiguration()
|
||||
LwjglApplication(OpusDecodeTest, config)
|
||||
val config = Lwjgl3ApplicationConfiguration()
|
||||
config.useVsync(false)
|
||||
config.setResizable(false)
|
||||
config.setWindowedMode(1072, 742)
|
||||
Lwjgl3Application(OpusDecodeTest, config)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -21,8 +21,6 @@ fun main(args: Array<String>) {
|
||||
object OpusDecodeTest : ApplicationAdapter() {
|
||||
|
||||
|
||||
private lateinit var opusFile: JOpusBufferFile
|
||||
|
||||
override fun create() {
|
||||
|
||||
}
|
||||
|
||||
@@ -65,13 +65,13 @@ object PostProcessor : Disposable {
|
||||
debugUI.setPosition(0, 0)
|
||||
|
||||
batch = SpriteBatch()
|
||||
camera = OrthographicCamera(AppLoader.screenWf, AppLoader.screenHf)
|
||||
camera = OrthographicCamera(AppLoader.screenSize.screenWf, AppLoader.screenSize.screenHf)
|
||||
camera.setToOrtho(true)
|
||||
|
||||
batch.projectionMatrix = camera.combined
|
||||
|
||||
shapeRenderer = ShapeRenderer()
|
||||
Gdx.gl20.glViewport(0, 0, AppLoader.appConfig.width, AppLoader.appConfig.height)
|
||||
Gdx.gl20.glViewport(0, 0, AppLoader.screenSize.screenW, AppLoader.screenSize.screenH)
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ object PostProcessor : Disposable {
|
||||
batch.color = Color.WHITE
|
||||
batch.inUse {
|
||||
it.draw(functionRowHelper,
|
||||
(AppLoader.screenW - functionRowHelper.width) / 2f,
|
||||
(AppLoader.screenSize.screenW - functionRowHelper.width) / 2f,
|
||||
functionRowHelper.height.toFloat(),
|
||||
functionRowHelper.width.toFloat(),
|
||||
functionRowHelper.height * -1f
|
||||
@@ -120,7 +120,7 @@ object PostProcessor : Disposable {
|
||||
if (AppLoader.IS_DEVELOPMENT_BUILD && Terrarum.ingame != null) {
|
||||
batch.inUse {
|
||||
batch.color = safeAreaCol
|
||||
AppLoader.fontGame.draw(it, thisIsDebugStr, 5f, AppLoader.screenH - 24f)
|
||||
AppLoader.fontGame.draw(it, thisIsDebugStr, 5f, AppLoader.screenSize.screenH - 24f)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,37 +147,37 @@ object PostProcessor : Disposable {
|
||||
}
|
||||
|
||||
private fun drawSafeArea() {
|
||||
val tvSafeAreaW = AppLoader.getTvSafeGraphicsWidth().toFloat()
|
||||
val tvSafeAreaH = AppLoader.getTvSafeGraphicsHeight().toFloat()
|
||||
val tvSafeArea2W = AppLoader.getTvSafeActionWidth().toFloat()
|
||||
val tvSafeArea2H = AppLoader.getTvSafeActionHeight().toFloat()
|
||||
val tvSafeAreaW = AppLoader.screenSize.tvSafeGraphicsWidth.toFloat()
|
||||
val tvSafeAreaH = AppLoader.screenSize.tvSafeGraphicsHeight.toFloat()
|
||||
val tvSafeArea2W = AppLoader.screenSize.tvSafeActionWidth.toFloat()
|
||||
val tvSafeArea2H = AppLoader.screenSize.tvSafeActionHeight.toFloat()
|
||||
|
||||
shapeRenderer.inUse(ShapeRenderer.ShapeType.Line) {
|
||||
|
||||
// centre ind
|
||||
shapeRenderer.color = safeAreaCol2
|
||||
shapeRenderer.line(0f, 0f, AppLoader.screenWf, AppLoader.screenHf)
|
||||
shapeRenderer.line(0f, AppLoader.screenHf, AppLoader.screenWf, 0f)
|
||||
shapeRenderer.line(0f, 0f, AppLoader.screenSize.screenWf, AppLoader.screenSize.screenHf)
|
||||
shapeRenderer.line(0f, AppLoader.screenSize.screenHf, AppLoader.screenSize.screenWf, 0f)
|
||||
|
||||
// safe action area
|
||||
shapeRenderer.color = safeAreaCol2
|
||||
shapeRenderer.rect(
|
||||
tvSafeArea2W, tvSafeArea2H, AppLoader.screenW - 2 * tvSafeArea2W, AppLoader.screenH - 2 * tvSafeArea2H
|
||||
tvSafeArea2W, tvSafeArea2H, AppLoader.screenSize.screenW - 2 * tvSafeArea2W, AppLoader.screenSize.screenH - 2 * tvSafeArea2H
|
||||
)
|
||||
|
||||
// safe graphics area
|
||||
shapeRenderer.color = safeAreaCol
|
||||
shapeRenderer.rect(
|
||||
tvSafeAreaW, tvSafeAreaH, AppLoader.screenW - 2 * tvSafeAreaW, AppLoader.screenH - 2 * tvSafeAreaH
|
||||
tvSafeAreaW, tvSafeAreaH, AppLoader.screenSize.screenW - 2 * tvSafeAreaW, AppLoader.screenSize.screenH - 2 * tvSafeAreaH
|
||||
)
|
||||
|
||||
// default res ind
|
||||
shapeRenderer.color = defaultResCol
|
||||
shapeRenderer.rect(
|
||||
(AppLoader.screenW - AppLoader.minimumW).div(2).toFloat(),
|
||||
(AppLoader.screenH - AppLoader.minimumH).div(2).toFloat(),
|
||||
AppLoader.minimumW.toFloat(),
|
||||
AppLoader.minimumH.toFloat()
|
||||
(AppLoader.screenSize.screenW - TerrarumScreenSize.minimumW).div(2).toFloat(),
|
||||
(AppLoader.screenSize.screenH - TerrarumScreenSize.minimumH).div(2).toFloat(),
|
||||
TerrarumScreenSize.minimumW.toFloat(),
|
||||
TerrarumScreenSize.minimumH.toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -192,14 +192,14 @@ object PostProcessor : Disposable {
|
||||
batch.color = defaultResCol
|
||||
AppLoader.fontSmallNumbers.draw(
|
||||
batch, defaultResStr,
|
||||
(AppLoader.screenW - AppLoader.minimumW).div(2).toFloat(),
|
||||
(AppLoader.screenH - AppLoader.minimumH).div(2).toFloat()
|
||||
(AppLoader.screenSize.screenW - TerrarumScreenSize.minimumW).div(2).toFloat(),
|
||||
(AppLoader.screenSize.screenH - TerrarumScreenSize.minimumH).div(2).toFloat()
|
||||
)
|
||||
|
||||
batch.color = currentResCol
|
||||
AppLoader.fontSmallNumbers.draw(
|
||||
batch, currentResStr,
|
||||
AppLoader.screenW - 80f,
|
||||
AppLoader.screenSize.screenW - 80f,
|
||||
0f
|
||||
)
|
||||
}
|
||||
@@ -213,8 +213,8 @@ object PostProcessor : Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private val defaultResStr = "${AppLoader.minimumW}x${AppLoader.minimumH}"
|
||||
private val currentResStr = "${AppLoader.screenW}x${AppLoader.screenH}"
|
||||
private val defaultResStr = "${TerrarumScreenSize.minimumW}x${TerrarumScreenSize.minimumH}"
|
||||
private val currentResStr = "${AppLoader.screenSize.screenW}x${AppLoader.screenSize.screenH}"
|
||||
private val safeAreaStr = "TV Safe Area"
|
||||
private val versionStr = "Version ${AppLoader.getVERSION_STRING()}"
|
||||
private val thisIsDebugStr = "${AppLoader.GAME_NAME} Develoment Build $versionStr"
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.ScreenAdapter
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.util.CircularArray
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-07-13.
|
||||
@@ -24,7 +21,7 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
private var arrowObjPos = 0f // 0 means at starting position, regardless of screen position
|
||||
private var arrowObjGlideOffsetX = 0f
|
||||
private var arrowObjGlideSize = 0f
|
||||
private val arrowGlideSpeed: Float; get() = AppLoader.screenW * 2f // pixels per sec
|
||||
private val arrowGlideSpeed: Float; get() = AppLoader.screenSize.screenW * 2f // pixels per sec
|
||||
private lateinit var arrowObjTex: Texture
|
||||
private var glideTimer = 0f
|
||||
private var glideDispY = 0f
|
||||
@@ -63,7 +60,7 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
}
|
||||
|
||||
|
||||
val textX: Float; get() = (AppLoader.screenW * 0.72f).floor()
|
||||
val textX: Float; get() = (AppLoader.screenSize.screenW * 0.72f).floor()
|
||||
|
||||
private var genuineSonic = false // the "NOW LOADING..." won't appear unless the arrow first run passes it (it's totally not a GenuineIntel tho)
|
||||
|
||||
@@ -75,8 +72,8 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
|
||||
val delta = Gdx.graphics.rawDeltaTime
|
||||
|
||||
glideDispY = AppLoader.screenH - 100f - AppLoader.fontGame.lineHeight
|
||||
arrowObjGlideSize = arrowObjTex.width + 2f * AppLoader.screenW
|
||||
glideDispY = AppLoader.screenSize.screenH - 100f - AppLoader.fontGame.lineHeight
|
||||
arrowObjGlideSize = arrowObjTex.width + 2f * AppLoader.screenSize.screenW
|
||||
|
||||
|
||||
|
||||
@@ -137,14 +134,14 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
|
||||
|
||||
AppLoader.batch.inUse {
|
||||
initViewPort(AppLoader.screenW, AppLoader.screenH) // dunno, no render without this
|
||||
initViewPort(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH) // dunno, no render without this
|
||||
it.projectionMatrix = camera.combined
|
||||
blendNormal(AppLoader.batch)
|
||||
|
||||
|
||||
// almost black background
|
||||
it.color = Color(0x181818ff)
|
||||
it.fillRect(0f, 0f, AppLoader.screenWf, AppLoader.screenHf)
|
||||
it.fillRect(0f, 0f, AppLoader.screenSize.screenWf, AppLoader.screenSize.screenHf)
|
||||
|
||||
|
||||
it.color = Color.WHITE
|
||||
@@ -187,14 +184,14 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
|
||||
// message backgrounds
|
||||
it.color = messageBackgroundColour
|
||||
it.fillRect(0f, 60f, AppLoader.screenWf, 40f + (messages.size) * AppLoader.fontGame.lineHeight)
|
||||
it.fillRect(0f, 60f, AppLoader.screenSize.screenWf, 40f + (messages.size) * AppLoader.fontGame.lineHeight)
|
||||
|
||||
// log messages
|
||||
it.color = messageForegroundColour
|
||||
messages.forEachIndexed { i, s ->
|
||||
AppLoader.fontGame.draw(it,
|
||||
s,
|
||||
AppLoader.getTvSafeGraphicsWidth() + 16f,
|
||||
AppLoader.screenSize.tvSafeGraphicsWidth + 16f,
|
||||
80f + (messages.size - i - 1) * AppLoader.fontGame.lineHeight
|
||||
)
|
||||
}
|
||||
@@ -204,7 +201,7 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
AppLoader.batch.inUse {
|
||||
// recycling part of the draw code //
|
||||
|
||||
initViewPort(AppLoader.screenW, AppLoader.screenH) // dunno, no render without this
|
||||
initViewPort(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH) // dunno, no render without this
|
||||
it.projectionMatrix = camera.combined
|
||||
blendNormal(AppLoader.batch)
|
||||
|
||||
@@ -212,14 +209,14 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
|
||||
// message backgrounds
|
||||
it.color = messageBackgroundColour
|
||||
it.fillRect(0f, 60f, AppLoader.screenWf, 40f + (messages.size) * AppLoader.fontGame.lineHeight)
|
||||
it.fillRect(0f, 60f, AppLoader.screenSize.screenWf, 40f + (messages.size) * AppLoader.fontGame.lineHeight)
|
||||
|
||||
// log messages
|
||||
it.color = messageForegroundColour
|
||||
messages.forEachIndexed { i, s ->
|
||||
AppLoader.fontGame.draw(it,
|
||||
s,
|
||||
AppLoader.getTvSafeGraphicsWidth() + 16f,
|
||||
AppLoader.screenSize.tvSafeGraphicsWidth + 16f,
|
||||
80f + (messages.size - i - 1) * AppLoader.fontGame.lineHeight
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.ApplicationAdapter
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||
@@ -14,14 +14,11 @@ import net.torvald.terrarumsansbitmap.gdx.GameFontBase
|
||||
* Created by minjaesong on 2017-08-11.
|
||||
*/
|
||||
fun main(args: Array<String>) { // LWJGL 3 won't work? java.lang.VerifyError
|
||||
val config = LwjglApplicationConfiguration()
|
||||
//config.useGL30 = true
|
||||
config.vSyncEnabled = false
|
||||
config.resizable = false
|
||||
config.width = 1072
|
||||
config.height = 742
|
||||
config.foregroundFPS = 9999
|
||||
LwjglApplication(ShitOnGlsl, config)
|
||||
val config = Lwjgl3ApplicationConfiguration()
|
||||
config.useVsync(false)
|
||||
config.setResizable(false)
|
||||
config.setWindowedMode(1072, 742)
|
||||
Lwjgl3Application(ShitOnGlsl, config)
|
||||
}
|
||||
|
||||
object ShitOnGlsl : ApplicationAdapter() {
|
||||
|
||||
@@ -335,7 +335,7 @@ inline fun FrameBuffer.inAction(camera: OrthographicCamera?, batch: SpriteBatch?
|
||||
//this.end()
|
||||
FrameBufferManager.end()
|
||||
|
||||
camera?.setToOrtho(true, AppLoader.screenWf, AppLoader.screenHf)
|
||||
camera?.setToOrtho(true, AppLoader.screenSize.screenWf, AppLoader.screenSize.screenHf)
|
||||
camera?.update()
|
||||
batch?.projectionMatrix = camera?.combined
|
||||
}
|
||||
|
||||
48
src/net/torvald/terrarum/TerrarumScreenSize.kt
Normal file
48
src/net/torvald/terrarum/TerrarumScreenSize.kt
Normal file
@@ -0,0 +1,48 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
|
||||
|
||||
companion object {
|
||||
const val minimumW = 1080
|
||||
const val minimumH = 720
|
||||
const val defaultW = 1280
|
||||
const val defaultH = 720
|
||||
|
||||
const val TV_SAFE_GRAPHICS = 0.05f // as per EBU recommendation (https://tech.ebu.ch/docs/r/r095.pdf)
|
||||
const val TV_SAFE_ACTION = 0.035f // as per EBU recommendation (https://tech.ebu.ch/docs/r/r095.pdf)
|
||||
}
|
||||
|
||||
var screenW: Int = 0; private set
|
||||
var screenH: Int = 0; private set
|
||||
var screenWf: Float = 0f; private set
|
||||
var screenHf: Float = 0f; private set
|
||||
var halfScreenW: Int = 0; private set
|
||||
var halfScreenH: Int = 0; private set
|
||||
var halfScreenWf: Float = 0f; private set
|
||||
var halfScreenHf: Float = 0f; private set
|
||||
var aspectRatio: Float = 0f; private set
|
||||
|
||||
|
||||
|
||||
val tvSafeGraphicsWidth: Int; get() = Math.round(screenW * TV_SAFE_GRAPHICS)
|
||||
val tvSafeGraphicsHeight: Int; get() = Math.round(screenH * TV_SAFE_GRAPHICS)
|
||||
val tvSafeActionWidth: Int; get() = Math.round(screenW * TV_SAFE_ACTION)
|
||||
val tvSafeActionHeight: Int; get() = Math.round(screenH * TV_SAFE_ACTION)
|
||||
|
||||
init {
|
||||
setDimension(maxOf(minimumW, scrw), maxOf(minimumH, scrh))
|
||||
}
|
||||
|
||||
fun setDimension(scrw: Int, scrh: Int) {
|
||||
screenW = scrw and 0x7FFFFFFE
|
||||
screenH = scrh and 0x7FFFFFFE
|
||||
screenWf = scrw.toFloat()
|
||||
screenHf = scrh.toFloat()
|
||||
halfScreenW = screenW / 2
|
||||
halfScreenH = screenH / 2
|
||||
halfScreenWf = screenWf / 2f
|
||||
halfScreenHf = screenHf / 2f
|
||||
aspectRatio = screenWf / screenHf
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,8 +3,8 @@ package net.torvald.terrarum
|
||||
import com.badlogic.gdx.ApplicationAdapter
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Screen
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.*
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
@@ -45,7 +45,7 @@ class TestTestTest(val batch: SpriteBatch) : Screen {
|
||||
|
||||
fun enter() {
|
||||
// init view port
|
||||
camera = OrthographicCamera(AppLoader.screenWf, AppLoader.screenHf)
|
||||
camera = OrthographicCamera(AppLoader.screenSize.screenWf, AppLoader.screenSize.screenHf)
|
||||
|
||||
|
||||
img = Texture("assets/test_texture.tga")
|
||||
@@ -57,14 +57,14 @@ class TestTestTest(val batch: SpriteBatch) : Screen {
|
||||
blurFboA = FrameBuffer(Pixmap.Format.RGBA8888, img.width, img.height, false)
|
||||
blurFboB = FrameBuffer(Pixmap.Format.RGBA8888, img.width, img.height, false)
|
||||
|
||||
worldFbo = FrameBuffer(Pixmap.Format.RGBA8888, AppLoader.screenW, AppLoader.screenH, false)
|
||||
worldFbo = FrameBuffer(Pixmap.Format.RGBA8888, AppLoader.screenSize.screenW, AppLoader.screenSize.screenH, false)
|
||||
|
||||
//blurShader.begin()
|
||||
//blurShader.setUniformf("iResolution", img.width.toFloat(), img.height.toFloat(), 0f)
|
||||
//blurShader.end()
|
||||
|
||||
|
||||
initViewPort(AppLoader.screenW, AppLoader.screenH)
|
||||
initViewPort(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH)
|
||||
}
|
||||
|
||||
override fun render(delta: Float) {
|
||||
@@ -135,7 +135,7 @@ class TestTestTest(val batch: SpriteBatch) : Screen {
|
||||
batch.inUse {
|
||||
batch.shader = null
|
||||
|
||||
camera.position.set(AppLoader.screenW / 2f - 50f, AppLoader.screenH / 2f - 50f, 0f)
|
||||
camera.position.set(AppLoader.screenSize.screenW / 2f - 50f, AppLoader.screenSize.screenH / 2f - 50f, 0f)
|
||||
camera.update()
|
||||
batch.projectionMatrix = camera.combined
|
||||
|
||||
@@ -147,11 +147,11 @@ class TestTestTest(val batch: SpriteBatch) : Screen {
|
||||
}
|
||||
|
||||
|
||||
camera.setToOrtho(true, AppLoader.screenWf, AppLoader.screenHf)
|
||||
camera.setToOrtho(true, AppLoader.screenSize.screenWf, AppLoader.screenSize.screenHf)
|
||||
batch.projectionMatrix = camera.combined
|
||||
batch.inUse {
|
||||
|
||||
camera.position.set(AppLoader.screenW / 2f, AppLoader.screenH / 2f, 0f)
|
||||
camera.position.set(AppLoader.screenSize.screenW / 2f, AppLoader.screenSize.screenH / 2f, 0f)
|
||||
camera.update()
|
||||
batch.projectionMatrix = camera.combined
|
||||
|
||||
@@ -168,7 +168,7 @@ class TestTestTest(val batch: SpriteBatch) : Screen {
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
initViewPort(AppLoader.screenW, AppLoader.screenH)
|
||||
initViewPort(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH)
|
||||
}
|
||||
|
||||
override fun pause() {
|
||||
@@ -216,12 +216,9 @@ object TestTestMain : ApplicationAdapter() {
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) { // LWJGL 3 won't work? java.lang.VerifyError
|
||||
val config = LwjglApplicationConfiguration()
|
||||
//config.useGL30 = true
|
||||
config.vSyncEnabled = false
|
||||
config.resizable = false
|
||||
config.width = 1072
|
||||
config.height = 742
|
||||
config.foregroundFPS = 9999
|
||||
LwjglApplication(TestTestMain, config)
|
||||
val config = Lwjgl3ApplicationConfiguration()
|
||||
config.useVsync(false)
|
||||
config.setResizable(false)
|
||||
config.setWindowedMode(1072, 742)
|
||||
Lwjgl3Application(TestTestMain, config)
|
||||
}
|
||||
@@ -2,8 +2,8 @@ package net.torvald.terrarum
|
||||
|
||||
import com.badlogic.gdx.ApplicationAdapter
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
|
||||
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration
|
||||
import com.badlogic.gdx.graphics.GL20
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
@@ -19,14 +19,11 @@ import java.util.zip.GZIPInputStream
|
||||
*/
|
||||
|
||||
fun main(args: Array<String>) { // LWJGL 3 won't work? java.lang.VerifyError
|
||||
val config = LwjglApplicationConfiguration()
|
||||
//config.useGL30 = true
|
||||
config.vSyncEnabled = false
|
||||
config.resizable = false
|
||||
config.width = 1072
|
||||
config.height = 742
|
||||
config.foregroundFPS = 9999
|
||||
LwjglApplication(TexRegionTilingTest, config)
|
||||
val config = Lwjgl3ApplicationConfiguration()
|
||||
config.useVsync(false)
|
||||
config.setResizable(false)
|
||||
config.setWindowedMode(1072, 742)
|
||||
Lwjgl3Application(TexRegionTilingTest, config)
|
||||
}
|
||||
|
||||
object TexRegionTilingTest : ApplicationAdapter() {
|
||||
|
||||
@@ -5,9 +5,7 @@ import com.badlogic.gdx.InputAdapter
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.random.HQRNG
|
||||
@@ -38,7 +36,7 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
// todo register titlescreen as the ingame, similar in a way that the buildingmaker did
|
||||
|
||||
var camera = OrthographicCamera(AppLoader.screenWf, AppLoader.screenHf)
|
||||
var camera = OrthographicCamera(AppLoader.screenSize.screenWf, AppLoader.screenSize.screenHf)
|
||||
|
||||
|
||||
// invert Y
|
||||
@@ -170,13 +168,13 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
override fun show() {
|
||||
printdbg(this, "show() called")
|
||||
|
||||
initViewPort(AppLoader.screenW, AppLoader.screenH)
|
||||
initViewPort(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH)
|
||||
|
||||
|
||||
Gdx.input.inputProcessor = TitleScreenController(this)
|
||||
|
||||
|
||||
worldFBO = FrameBuffer(Pixmap.Format.RGBA8888, AppLoader.screenW, AppLoader.screenH, false)
|
||||
worldFBO = FrameBuffer(Pixmap.Format.RGBA8888, AppLoader.screenSize.screenW, AppLoader.screenSize.screenH, false)
|
||||
|
||||
loadThingsWhileIntroIsVisible()
|
||||
|
||||
@@ -235,7 +233,7 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
Gdx.graphics.setTitle(TerrarumIngame.getCanonicalTitle())
|
||||
|
||||
|
||||
//camera.setToOrtho(true, AppLoader.screenWf, AppLoader.screenHf)
|
||||
//camera.setToOrtho(true, AppLoader.terrarumAppConfig.screenWf, AppLoader.terrarumAppConfig.screenHf)
|
||||
|
||||
// render world
|
||||
gdxClearAndSetBlend(.64f, .754f, .84f, 1f)
|
||||
@@ -272,14 +270,14 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
COPYTING.forEachIndexed { index, s ->
|
||||
val textWidth = AppLoader.fontGame.getWidth(s)
|
||||
AppLoader.fontGame.draw(batch, s,
|
||||
(AppLoader.screenW - textWidth - 1f).toInt().toFloat(),
|
||||
(AppLoader.screenH - AppLoader.fontGame.lineHeight * (COPYTING.size - index) - 1f).toInt().toFloat()
|
||||
(AppLoader.screenSize.screenW - textWidth - 1f).toInt().toFloat(),
|
||||
(AppLoader.screenSize.screenH - AppLoader.fontGame.lineHeight * (COPYTING.size - index) - 1f).toInt().toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
AppLoader.fontGame.draw(batch, "${AppLoader.GAME_NAME} ${AppLoader.getVERSION_STRING()}",
|
||||
1f.toInt().toFloat(),
|
||||
(AppLoader.screenH - AppLoader.fontGame.lineHeight - 1f).toInt().toFloat()
|
||||
(AppLoader.screenSize.screenH - AppLoader.fontGame.lineHeight - 1f).toInt().toFloat()
|
||||
)
|
||||
|
||||
}
|
||||
@@ -296,11 +294,11 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
printStackTrace(this)
|
||||
|
||||
// Set up viewport when window is resized
|
||||
initViewPort(AppLoader.screenW, AppLoader.screenH)
|
||||
initViewPort(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH)
|
||||
|
||||
|
||||
// resize UI by re-creating it (!!)
|
||||
uiMenu.resize(AppLoader.screenW, AppLoader.screenH)
|
||||
uiMenu.resize(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH)
|
||||
// TODO I forgot what the fuck kind of hack I was talking about
|
||||
//uiMenu.setPosition(0, UITitleRemoConRoot.menubarOffY)
|
||||
uiMenu.setPosition(0, 0) // shitty hack. Could be:
|
||||
@@ -308,7 +306,7 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
// 2: The UI is coded shit
|
||||
|
||||
|
||||
IngameRenderer.resize(AppLoader.screenW, AppLoader.screenH)
|
||||
IngameRenderer.resize(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH)
|
||||
|
||||
printdbg(this, "resize() exit")
|
||||
}
|
||||
@@ -342,8 +340,8 @@ class TitleScreen(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
screen.uiContainer.forEach { it?.scrolled(amount) }
|
||||
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||
screen.uiContainer.forEach { it?.scrolled(amountX, amountY) }
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameitem.ItemID
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.worlddrawer.BlocksDrawer
|
||||
import net.torvald.terrarum.worlddrawer.CreateTileAtlas
|
||||
@@ -31,8 +30,8 @@ object BlockStats {
|
||||
val player = (Terrarum.ingame!! as TerrarumIngame).actorNowPlaying
|
||||
if (player == null) return
|
||||
|
||||
val renderWidth = FastMath.ceil(AppLoader.screenWf)
|
||||
val renderHeight = FastMath.ceil(AppLoader.screenHf)
|
||||
val renderWidth = FastMath.ceil(AppLoader.screenSize.screenWf)
|
||||
val renderHeight = FastMath.ceil(AppLoader.screenSize.screenHf)
|
||||
|
||||
val noZoomCameraX = Math.round(FastMath.clamp(
|
||||
player.hitbox.centeredX.toFloat() - renderWidth / 2, TSIZE.toFloat(), map.width * TSIZE - renderWidth - TSIZE.toFloat()))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.torvald.terrarum.console
|
||||
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.TerrarumScreenSize
|
||||
|
||||
object ResizeScreen: ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
@@ -11,7 +12,7 @@ object ResizeScreen: ConsoleCommand {
|
||||
when (args[1]) {
|
||||
"720p" -> AppLoader.resizeScreen(1280,720)
|
||||
"1080p" -> AppLoader.resizeScreen(1920,1080)
|
||||
"default" -> AppLoader.resizeScreen(AppLoader.defaultW, AppLoader.defaultH)
|
||||
"default" -> AppLoader.resizeScreen(TerrarumScreenSize.defaultW, TerrarumScreenSize.defaultH)
|
||||
else -> { printUsage(); return }
|
||||
}
|
||||
}
|
||||
@@ -19,11 +20,11 @@ object ResizeScreen: ConsoleCommand {
|
||||
printUsage(); return
|
||||
}
|
||||
|
||||
Echo("Screen resized to ${AppLoader.screenW}x${AppLoader.screenH}")
|
||||
Echo("Screen resized to ${AppLoader.screenSize.screenW}x${AppLoader.screenSize.screenH}")
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("Usage: resize [width] [height]. Minimum size is ${AppLoader.minimumW}x${AppLoader.minimumH}")
|
||||
Echo("Usage: resize [width] [height]. Minimum size is ${TerrarumScreenSize.minimumW}x${TerrarumScreenSize.minimumH}")
|
||||
Echo("Reserved keywords: 720p, 1080p, default")
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.torvald.terrarum.controller
|
||||
|
||||
import com.badlogic.gdx.controllers.Controller
|
||||
import com.badlogic.gdx.controllers.PovDirection
|
||||
import net.torvald.terrarum.toInt
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2019-02-09.
|
||||
@@ -16,18 +16,11 @@ class GdxControllerAdapter(val c: Controller): TerrarumController {
|
||||
return c.getAxis(index)
|
||||
}
|
||||
|
||||
override fun getPov(): Int {
|
||||
return when(c.getPov(0)) {
|
||||
PovDirection.north -> TerrarumController.POV_N
|
||||
PovDirection.northEast -> TerrarumController.POV_NE
|
||||
PovDirection.northWest -> TerrarumController.POV_NW
|
||||
PovDirection.east -> TerrarumController.POV_E
|
||||
PovDirection.west -> TerrarumController.POV_W
|
||||
PovDirection.south -> TerrarumController.POV_S
|
||||
PovDirection.southEast -> TerrarumController.POV_SE
|
||||
PovDirection.southWest -> TerrarumController.POV_SW
|
||||
else -> 0
|
||||
}
|
||||
override fun getDpad(): Int {
|
||||
return (c.getButton(c.mapping.buttonDpadLeft).toInt()) or
|
||||
(c.getButton(c.mapping.buttonDpadDown).toInt() shl 1) or
|
||||
(c.getButton(c.mapping.buttonDpadRight).toInt() shl 2) or
|
||||
(c.getButton(c.mapping.buttonDpadUp).toInt() shl 3)
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
|
||||
@@ -70,7 +70,7 @@ interface TerrarumController {
|
||||
* 6 2 3
|
||||
* ```
|
||||
*/
|
||||
fun getPov(): Int
|
||||
fun getDpad(): Int
|
||||
fun getName(): String
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,7 +53,7 @@ class XinputControllerAdapter(val c: XInputDevice): TerrarumController {
|
||||
return -1f
|
||||
}
|
||||
|
||||
override fun getPov(): Int {
|
||||
override fun getDpad(): Int {
|
||||
if (c.poll()) {
|
||||
val axes = c.components.axes
|
||||
|
||||
|
||||
@@ -1,398 +0,0 @@
|
||||
package net.torvald.terrarum.gameactors.ai
|
||||
|
||||
import org.luaj.vm2.LuaTable
|
||||
import org.luaj.vm2.LuaValue
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-10-24.
|
||||
*/
|
||||
/*internal class AILuaAPI(g: Globals, actor: ActorWBMovable) {
|
||||
|
||||
// FIXME when actor jumps, the actor releases left/right stick
|
||||
|
||||
init {
|
||||
if (actor !is AIControlled)
|
||||
throw IllegalArgumentException("The actor is not AIControlled! $actor")
|
||||
|
||||
// load functions and set up constants
|
||||
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)
|
||||
g["ai"]["moveDown"] = MoveDown(actor)
|
||||
g["ai"]["moveLeft"] = MoveLeft(actor)
|
||||
g["ai"]["moveRight"] = MoveRight(actor)
|
||||
g["ai"]["moveTo"] = MoveTo(actor)
|
||||
g["ai"]["jump"] = Jump(actor)
|
||||
|
||||
g["ai"]["getNearbyTiles"] = GetNearbyTiles(actor)
|
||||
g["ai"]["getFloorsHeight"] = GetFloorsHeight(actor)
|
||||
g["ai"]["getCeilingsHeight"] = GetCeilingsHeight(actor)
|
||||
g["ai"]["getLedgesHeight"] = GetLedgesHeight(actor)
|
||||
|
||||
g["game"] = LuaValue.tableOf()
|
||||
g["game"]["version"] = GameVersion()
|
||||
g["game"]["versionRaw"] = GameVersionRaw()
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Reads arbitrary ActorWBMovable and returns its information as Lua table
|
||||
*/
|
||||
fun composeActorObject(actor: ActorWBMovable): LuaTable {
|
||||
val t: LuaTable = LuaTable()
|
||||
val moveDelta = actor.externalV + actor.controllerV
|
||||
|
||||
t["name"] = actor.actorValue.getAsString(AVKey.NAME).toLua()
|
||||
t["startX"] = actor.hitbox.centeredX.toLua()
|
||||
t["startY"] = actor.hitbox.centeredY.toLua()
|
||||
|
||||
t["veloX"] = moveDelta.x.toLua()
|
||||
t["veloY"] = moveDelta.y.toLua()
|
||||
|
||||
t["width"] = actor.hitbox.width.toLua()
|
||||
t["height"] = actor.hitbox.height.toLua()
|
||||
|
||||
t["mass"] = actor.mass.toLua()
|
||||
|
||||
t["collisionType"] = actor.collisionType.toLua()
|
||||
|
||||
t["strength"] = actor.avStrength.toLua()
|
||||
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
operator fun LuaTable.set(index: Int, value: Int) { this[index] = value.toLua() }
|
||||
}
|
||||
|
||||
class GetSelfActorInfo(val actor: ActorWBMovable) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return composeActorObject(actor)
|
||||
}
|
||||
}
|
||||
|
||||
/** ai.getNearestActor(nullable any criterion, nullable number range) */
|
||||
class GetNearestActor() : LuaFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
override fun call(crit: LuaValue): LuaValue {
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
override fun call(crit: LuaValue, range: LuaValue): LuaValue {
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/** ai.getNearestPlayer(nullable any criterion, nullable number range) */
|
||||
class GetNearestPlayer() : LuaFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
override fun call(crit: LuaValue): LuaValue {
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
override fun call(crit: LuaValue, range: LuaValue): LuaValue {
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class GetX(val actor: ActorWBMovable) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(actor.hitbox.centeredX)
|
||||
}
|
||||
}
|
||||
|
||||
class GetY(val actor: ActorWBMovable) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(actor.hitbox.centeredY)
|
||||
}
|
||||
}
|
||||
|
||||
class MoveLeft(val actor: AIControlled) : LuaFunction() {
|
||||
override fun call(): LuaValue { // hard key press
|
||||
actor.moveLeft()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
/** @param amount [0.0 - 1.0] */
|
||||
override fun call(amount: LuaValue): LuaValue { // stick tilt
|
||||
actor.moveLeft(amount.checkdouble().toFloat())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class MoveRight(val actor: AIControlled) : LuaFunction() {
|
||||
override fun call(): LuaValue { // hard key press
|
||||
actor.moveRight()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
/** @param amount [0.0 - 1.0] */
|
||||
override fun call(amount: LuaValue): LuaValue { // stick tilt
|
||||
actor.moveRight(amount.checkdouble().toFloat())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class MoveUp(val actor: AIControlled) : LuaFunction() {
|
||||
override fun call(): LuaValue { // hard key press
|
||||
actor.moveUp()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
/** @param amount [0.0 - 1.0] */
|
||||
override fun call(amount: LuaValue): LuaValue { // stick tilt
|
||||
actor.moveUp(amount.checkdouble().toFloat())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class MoveDown(val actor: AIControlled) : LuaFunction() {
|
||||
override fun call(): LuaValue { // hard key press
|
||||
actor.moveDown()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
/** @param amount [0.0 - 1.0] */
|
||||
override fun call(amount: LuaValue): LuaValue { // stick tilt
|
||||
actor.moveDown(amount.checkdouble().toFloat())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class MoveTo(val actor: AIControlled) : LuaFunction() {
|
||||
override fun call(bearing: LuaValue): LuaValue {
|
||||
actor.moveTo(bearing.checkdouble())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
override fun call(toX: LuaValue, toY: LuaValue): LuaValue {
|
||||
actor.moveTo(toX.checkdouble(), toY.checkdouble())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class Jump(val actor: AIControlled) : LuaFunction() {
|
||||
override fun call(): LuaValue {
|
||||
actor.moveJump()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
/** @param amount [0.0 - 1.0] */
|
||||
override fun call(amount: LuaValue): LuaValue { // stick tilt
|
||||
actor.moveJump(amount.checkdouble().toFloat())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class GetNearbyTiles(val actor: ActorWBMovable) : OneArgFunction() {
|
||||
/** @param radius
|
||||
*
|
||||
* 3 will return 7x7 array, 0 will return 1x1, 1 will return 3x3
|
||||
*
|
||||
* Index: [-3: y][-3: x] ... [0: y][0: x] ... [3: y][3: x] for radius 3
|
||||
* Return value: bitset (int 0-7)
|
||||
* 1 -- solidity
|
||||
* 2 -- liquidity
|
||||
* 3 -- gravity
|
||||
*/
|
||||
override fun call(arg: LuaValue): LuaValue {
|
||||
val radius = arg.checkint()
|
||||
|
||||
if (radius < 0) {
|
||||
return LuaValue.NONE
|
||||
}
|
||||
else if (radius > 8) {
|
||||
throw IllegalArgumentException("Radius too large -- must be 8 or less")
|
||||
}
|
||||
else {
|
||||
val luatable = LuaTable()
|
||||
val feetTilePos = actor.feetPosTile
|
||||
for (y in feetTilePos[1] - radius..feetTilePos[1] + radius) {
|
||||
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 solidity = tile.isSolid.toInt()
|
||||
val liquidity = tile.isFluid.toInt()
|
||||
val gravity = tile.maxSupport.toInt()
|
||||
val tileFlag: Int = gravity.shl(2) + liquidity.shl(1) + solidity
|
||||
|
||||
luatable[y - feetTilePos[1]][x - feetTilePos[0]] = tileFlag.toLua()
|
||||
}
|
||||
}
|
||||
|
||||
return luatable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GetFloorsHeight(val actor: ActorWBMovable) : OneArgFunction() {
|
||||
/** @param radius
|
||||
*
|
||||
* 3 will return len:7 array, 0 will return len:1, 1 will return len:3
|
||||
*
|
||||
* Index: [-3] .. [0] .. [3] for radius
|
||||
* Return value: floor height
|
||||
* 0: body tile (legs area)
|
||||
* 1: tile you can stand on
|
||||
* 2+: tiles down there
|
||||
*/
|
||||
override fun call(arg: LuaValue): LuaValue {
|
||||
val radius = arg.checkint()
|
||||
|
||||
val searchDownLimit = 12
|
||||
|
||||
if (radius < 0) {
|
||||
return LuaValue.NONE
|
||||
}
|
||||
else if (radius > 8) {
|
||||
throw IllegalArgumentException("Radius too large -- must be 8 or less")
|
||||
}
|
||||
else {
|
||||
val luatable = LuaTable()
|
||||
val feetTilePos = actor.feetPosTile
|
||||
for (x in feetTilePos[0] - radius..feetTilePos[0] + radius) {
|
||||
// search down
|
||||
var searchDownCounter = 0
|
||||
while (true) {
|
||||
val tile = (Terrarum.ingame!!.world).getTileFromTerrain(x, feetTilePos[1] + searchDownCounter) ?: Block.STONE
|
||||
if (BlockCodex[tile].isSolid || searchDownCounter >= searchDownLimit) {
|
||||
luatable[x - feetTilePos[0]] = searchDownCounter
|
||||
break
|
||||
}
|
||||
searchDownCounter++
|
||||
}
|
||||
}
|
||||
|
||||
return luatable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GetCeilingsHeight(val actor: ActorWBMovable) : OneArgFunction() {
|
||||
/** @param arg radius
|
||||
*
|
||||
* 3 will return 7x7 array, 0 will return 1x1, 1 will return 3x3
|
||||
*
|
||||
* Index: [-3] .. [0] .. [3] for radius
|
||||
* Return value: floor height
|
||||
* 0: body tile (legs area)
|
||||
* 1: body tile (may be vary depend on the size of the actor)
|
||||
* 2+: tiles up there
|
||||
*/
|
||||
override fun call(arg: LuaValue): LuaValue {
|
||||
val radius = arg.checkint()
|
||||
|
||||
val searchUpLimit = 12
|
||||
|
||||
if (radius < 0) {
|
||||
return LuaValue.NONE
|
||||
}
|
||||
else if (radius > 8) {
|
||||
throw IllegalArgumentException("Radius too large -- must be 8 or less")
|
||||
}
|
||||
else {
|
||||
val luatable = LuaTable()
|
||||
val feetTilePos = actor.feetPosTile
|
||||
for (x in feetTilePos[0] - radius..feetTilePos[0] + radius) {
|
||||
// search up
|
||||
var searchUpCounter = 0
|
||||
while (true) {
|
||||
val tile = (Terrarum.ingame!!.world).getTileFromTerrain(x, feetTilePos[1] - searchUpCounter) ?: Block.STONE
|
||||
if (BlockCodex[tile].isSolid || searchUpCounter >= searchUpLimit) {
|
||||
luatable[x - feetTilePos[0]] = searchUpCounter
|
||||
break
|
||||
}
|
||||
searchUpCounter++
|
||||
}
|
||||
}
|
||||
|
||||
return luatable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GetLedgesHeight(val actor: ActorWBMovable) : OneArgFunction() {
|
||||
/** @param arg radius
|
||||
* ==
|
||||
* <- (non-solid found)
|
||||
* ==
|
||||
* ==
|
||||
* ==
|
||||
* == @ -> ledge height: 4
|
||||
* =================
|
||||
*/
|
||||
override fun call(arg: LuaValue): LuaValue {
|
||||
val radius = arg.checkint()
|
||||
|
||||
val searchUpLimit = 12
|
||||
|
||||
if (radius < 0) {
|
||||
return LuaValue.NONE
|
||||
}
|
||||
else if (radius > 8) {
|
||||
throw IllegalArgumentException("Radius too large -- must be 8 or less")
|
||||
}
|
||||
else {
|
||||
val luatable = LuaTable()
|
||||
val feetTilePos = actor.feetPosTile
|
||||
for (x in feetTilePos[0] - radius..feetTilePos[0] + radius) {
|
||||
// search up
|
||||
var searchUpCounter = 0
|
||||
while (true) {
|
||||
val tile = (Terrarum.ingame!!.world).getTileFromTerrain(x, feetTilePos[1] - searchUpCounter) ?: Block.STONE
|
||||
if (!BlockCodex[tile].isSolid || searchUpCounter >= searchUpLimit) {
|
||||
luatable[x - feetTilePos[0]] = searchUpCounter
|
||||
break
|
||||
}
|
||||
searchUpCounter++
|
||||
}
|
||||
}
|
||||
|
||||
return luatable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class GameVersion : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return AppLoader.getVERSION_STRING().toLua()
|
||||
}
|
||||
}
|
||||
|
||||
class GameVersionRaw : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return AppLoader.VERSION_RAW.toLua()
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
fun Double.toLua() = LuaValue.valueOf(this)
|
||||
fun Int.toLua() = LuaValue.valueOf(this)
|
||||
fun String.toLua() = LuaValue.valueOf(this)
|
||||
fun Boolean.toLua() = LuaValue.valueOf(this)
|
||||
fun Double?.toLua() = if (this == null) LuaValue.NIL else this.toLua()
|
||||
fun Int?.toLua() = if (this == null) LuaValue.NIL else this.toLua()
|
||||
fun String?.toLua() = if (this == null) LuaValue.NIL else this.toLua()
|
||||
fun Boolean?.toLua() = if (this == null) LuaValue.NIL else this.toLua()
|
||||
fun luaTableOf(vararg luaValues: LuaValue): LuaTable {
|
||||
val t = LuaTable.tableOf()
|
||||
luaValues.forEachIndexed { index, luaValue -> t[index + 1] = luaValue }
|
||||
return t
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package net.torvald.terrarum.gameactors.ai
|
||||
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LuaError
|
||||
import org.luaj.vm2.LuaInteger
|
||||
import org.luaj.vm2.LuaValue
|
||||
import org.luaj.vm2.lib.jse.JsePlatform
|
||||
import java.io.InputStreamReader
|
||||
import java.io.Reader
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-02-04.
|
||||
*/
|
||||
/*class LuaAIWrapper(private val scriptPath: String) : ActorAI {
|
||||
|
||||
protected val luag: Globals = JsePlatform.standardGlobals()
|
||||
|
||||
/**
|
||||
* Initialised in init block.
|
||||
* Use lua function "update(delta)" to step the AI.
|
||||
*/
|
||||
protected lateinit var luaInstance: LuaValue
|
||||
|
||||
private lateinit var aiLuaAPI: AILuaAPI
|
||||
|
||||
private lateinit var targetActor: Actor
|
||||
|
||||
/**
|
||||
* The initialiser
|
||||
*
|
||||
* Use ```(p.ai as LuaAIWrapper).attachActor(p)```
|
||||
*/
|
||||
fun attachActor(actor: Actor) {
|
||||
targetActor = actor
|
||||
|
||||
luag["io"] = LuaValue.NIL
|
||||
luag["os"] = LuaValue.NIL
|
||||
luag["luajava"] = LuaValue.NIL
|
||||
aiLuaAPI = AILuaAPI(luag, targetActor)
|
||||
// load the script and execute it (initialises target script)
|
||||
val inputStream = javaClass.getResourceAsStream(scriptPath)
|
||||
luaInstance = luag.load(InputStreamReader(inputStream), scriptPath.split(Regex("[\\/]")).last())
|
||||
luaInstance.call()
|
||||
}
|
||||
|
||||
override fun update(actor: Actor, delta: Float) {
|
||||
// run "update()" function in the script
|
||||
luag.get("update").call(delta.toLua())
|
||||
}
|
||||
|
||||
lateinit var currentExecutionThread: Thread
|
||||
var threadRun = false
|
||||
|
||||
fun runCommand(reader: Reader, filename: String) {
|
||||
if (!threadRun && !targetActor.flagDespawn) {
|
||||
currentExecutionThread = Thread(ThreadRunCommand(luag, reader, filename))
|
||||
currentExecutionThread.start()
|
||||
threadRun = true
|
||||
}
|
||||
}
|
||||
|
||||
fun runCommand(script: String) {
|
||||
if (!threadRun && !targetActor.flagDespawn) {
|
||||
currentExecutionThread = Thread(ThreadRunCommand(luag, script, ""))
|
||||
currentExecutionThread.start()
|
||||
threadRun = true
|
||||
}
|
||||
}
|
||||
|
||||
class ThreadRunCommand : Runnable {
|
||||
|
||||
val mode: Int
|
||||
val arg1: Any
|
||||
val arg2: String
|
||||
val lua: Globals
|
||||
|
||||
constructor(luaInstance: Globals, line: String, env: String) {
|
||||
mode = 0
|
||||
arg1 = line
|
||||
arg2 = env
|
||||
lua = luaInstance
|
||||
}
|
||||
|
||||
constructor(luaInstance: Globals, reader: Reader, filename: String) {
|
||||
mode = 1
|
||||
arg1 = reader
|
||||
arg2 = filename
|
||||
lua = luaInstance
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
try {
|
||||
val chunk: LuaValue
|
||||
if (mode == 0)
|
||||
chunk = lua.load(arg1 as String, arg2)
|
||||
else if (mode == 1)
|
||||
chunk = lua.load(arg1 as Reader, arg2)
|
||||
else
|
||||
throw IllegalArgumentException("Unsupported mode: $mode")
|
||||
|
||||
|
||||
chunk.call()
|
||||
}
|
||||
catch (e: LuaError) {
|
||||
e.printStackTrace(System.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Float.toLua(): LuaValue = LuaInteger.valueOf(this.toDouble())
|
||||
}*/
|
||||
@@ -1,83 +0,0 @@
|
||||
--
|
||||
-- Created by minjaesong on 2017-01-06.
|
||||
--
|
||||
timeCounter = 0
|
||||
countMax = 0
|
||||
moveMode = math.random() >= 0.5 and "left" or "right"
|
||||
currentMode = "move"
|
||||
jumpheight = 6 -- lol
|
||||
|
||||
function generateCountMax()
|
||||
local function generateTurn()
|
||||
return 4600 + 1250 * math.random()
|
||||
end
|
||||
|
||||
local function generateWalk()
|
||||
return 1645 + 402 * math.random()
|
||||
end
|
||||
|
||||
return (currentMode == "move") and generateWalk() or generateTurn()
|
||||
end
|
||||
|
||||
function moveToDirection(delta)
|
||||
local pits = ai.getFloorsHeight(2)
|
||||
local ledges = ai.getLedgesHeight(1)
|
||||
|
||||
if moveMode == "left" then
|
||||
if pits[-1] == 1 then
|
||||
ai.moveLeft(0.8)
|
||||
if ledges[-1] <= jumpheight then -- no futile jumps
|
||||
ai.jump()
|
||||
end
|
||||
else
|
||||
ai.moveLeft(0.5)
|
||||
end
|
||||
elseif moveMode == "right" then
|
||||
if pits[1] == 1 then
|
||||
ai.moveRight(0.8)
|
||||
if ledges[1] <= jumpheight then -- no futile jumps
|
||||
ai.jump()
|
||||
end
|
||||
else
|
||||
ai.moveRight(0.5)
|
||||
end
|
||||
end
|
||||
|
||||
timeCounter = timeCounter + delta
|
||||
end
|
||||
|
||||
function toggleCurrentMode()
|
||||
currentMode = (currentMode == "move") and "turn" or "move"
|
||||
end
|
||||
|
||||
function toggleMoveMode()
|
||||
moveMode = (moveMode == "left") and "right" or "left"
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
countMax = generateCountMax()
|
||||
|
||||
function toggleCondition()
|
||||
local floorsheight = ai.getFloorsHeight(1)
|
||||
return timeCounter >= countMax or
|
||||
-- avoid great falls
|
||||
(timeCounter > 150 and (floorsheight[-1] > jumpheight or floorsheight[1] > jumpheight))
|
||||
end
|
||||
|
||||
function update(delta)
|
||||
if currentMode == "move" then
|
||||
moveToDirection(delta)
|
||||
else
|
||||
timeCounter = timeCounter + delta -- no countup when jumping
|
||||
end
|
||||
|
||||
if toggleCondition() then
|
||||
timeCounter = 0
|
||||
toggleCurrentMode()
|
||||
countMax = generateCountMax()
|
||||
if currentMode == "turn" then
|
||||
toggleMoveMode()
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -4,8 +4,10 @@ import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.InputAdapter
|
||||
import com.badlogic.gdx.controllers.Controllers
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.AppLoader.printdbgerr
|
||||
import net.torvald.terrarum.controller.TerrarumController
|
||||
import net.torvald.terrarum.floorInt
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
@@ -44,8 +46,14 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
||||
get() = (mouseY / CreateTileAtlas.TILE_SIZE).floorInt()
|
||||
|
||||
init {
|
||||
if (Controllers.getControllers().size == 0) {
|
||||
printdbg(this, "Controller not found")
|
||||
try {
|
||||
if (Controllers.getControllers().size == 0) {
|
||||
printdbg(this, "Controller not found")
|
||||
}
|
||||
}
|
||||
catch (e: GdxRuntimeException) {
|
||||
printdbg(this, e.message)
|
||||
e.stackTrace.forEach { printdbgerr(this, "\t$it") }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,18 +199,18 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||
if (!terrarumIngame.paused) {
|
||||
// quickslot by wheel
|
||||
if (terrarumIngame.actorNowPlaying != null) {
|
||||
terrarumIngame.actorNowPlaying!!.actorValue.set(
|
||||
AVKey.__PLAYER_QUICKSLOTSEL,
|
||||
(terrarumIngame.actorNowPlaying!!.actorValue.getAsInt(AVKey.__PLAYER_QUICKSLOTSEL)!! - amount) fmod terrarumIngame.actorNowPlaying!!.inventory.quickSlot.size
|
||||
(terrarumIngame.actorNowPlaying!!.actorValue.getAsInt(AVKey.__PLAYER_QUICKSLOTSEL)!! - amountY.toInt()) fmod terrarumIngame.actorNowPlaying!!.inventory.quickSlot.size
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
terrarumIngame.uiContainer.forEach { it?.scrolled(amount) }
|
||||
terrarumIngame.uiContainer.forEach { it?.scrolled(amountX, amountY) }
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package net.torvald.terrarum.itemproperties
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.gameactors.ai.toLua
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LuaTable
|
||||
import org.luaj.vm2.LuaValue
|
||||
import org.luaj.vm2.lib.ThreeArgFunction
|
||||
import org.luaj.vm2.lib.ZeroArgFunction
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-04-16.
|
||||
*/
|
||||
class ItemEffectsLuaAPI(g: Globals) {
|
||||
|
||||
init {
|
||||
g["getMouseTile"] = GetMouseTile()
|
||||
g["getMousePos"] = GetMousePos()
|
||||
|
||||
|
||||
|
||||
g["world"] = LuaTable()
|
||||
|
||||
g["world"]["strikeEarth"] = StrikeEarth()
|
||||
g["world"]["strikeWall"] = StrikeWall()
|
||||
|
||||
|
||||
|
||||
g["actor"] = LuaTable()
|
||||
}
|
||||
|
||||
|
||||
class GetMouseTile : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.tableOf(arrayOf(Terrarum.mouseTileX.toLua(), Terrarum.mouseTileY.toLua()))
|
||||
}
|
||||
}
|
||||
class GetMousePos : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.tableOf(arrayOf(Terrarum.mouseX.toLua(), Terrarum.mouseY.toLua()))
|
||||
}
|
||||
}
|
||||
|
||||
class StrikeEarth : ThreeArgFunction() {
|
||||
override fun call(x: LuaValue, y: LuaValue, power: LuaValue): LuaValue {
|
||||
(Terrarum.ingame!!.world).inflictTerrainDamage(x.checkint(), y.checkint(), power.checkdouble())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
class StrikeWall : ThreeArgFunction() {
|
||||
override fun call(x: LuaValue, y: LuaValue, power: LuaValue): LuaValue {
|
||||
(Terrarum.ingame!!.world).inflictWallDamage(x.checkint(), y.checkint(), power.checkdouble())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.blockproperties.BlockPropUtil
|
||||
import net.torvald.terrarum.gameactors.*
|
||||
import net.torvald.terrarum.gameitem.ItemID
|
||||
@@ -20,18 +19,8 @@ import net.torvald.terrarum.modulebasegame.ui.UIBuildingMakerBlockChooser
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIBuildingMakerPenMenu
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIPaletteSelector
|
||||
import net.torvald.terrarum.modulebasegame.weather.WeatherMixer
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.serialise.WriteLayerDataZip.FILE_FOOTER
|
||||
import net.torvald.terrarum.serialise.WriteLayerDataZip.PAYLOAD_FOOTER
|
||||
import net.torvald.terrarum.serialise.WriteLayerDataZip.PAYLOAD_HEADER
|
||||
import net.torvald.terrarum.serialise.toLittle
|
||||
import net.torvald.terrarum.serialise.toLittleShort
|
||||
import net.torvald.terrarum.serialise.toULittle48
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.ui.UINSMenu
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2018-07-06.
|
||||
@@ -295,11 +284,11 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
uiToolbox.isVisible = true
|
||||
uiToolbox.invocationArgument = arrayOf(this)
|
||||
|
||||
uiPaletteSelector.setPosition(AppLoader.screenW - uiPaletteSelector.width, 0)
|
||||
uiPaletteSelector.setPosition(AppLoader.screenSize.screenW - uiPaletteSelector.width, 0)
|
||||
uiPaletteSelector.isVisible = true
|
||||
|
||||
notifier.setPosition(
|
||||
(AppLoader.screenW - notifier.width) / 2, AppLoader.screenH - notifier.height)
|
||||
(AppLoader.screenSize.screenW - notifier.width) / 2, AppLoader.screenSize.screenH - notifier.height)
|
||||
|
||||
|
||||
actorNowPlaying?.setPosition(512 * 16.0, 149 * 16.0)
|
||||
@@ -379,8 +368,8 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
// position the menu to where the cursor is
|
||||
uiPenMenu.posX = Terrarum.mouseScreenX - uiPenMenu.width / 2
|
||||
uiPenMenu.posY = Terrarum.mouseScreenY - uiPenMenu.height / 2
|
||||
uiPenMenu.posX = uiPenMenu.posX.coerceIn(0, AppLoader.screenW - uiPenMenu.width)
|
||||
uiPenMenu.posY = uiPenMenu.posY.coerceIn(0, AppLoader.screenH - uiPenMenu.height)
|
||||
uiPenMenu.posX = uiPenMenu.posX.coerceIn(0, AppLoader.screenSize.screenW - uiPenMenu.width)
|
||||
uiPenMenu.posY = uiPenMenu.posY.coerceIn(0, AppLoader.screenSize.screenH - uiPenMenu.height)
|
||||
|
||||
// actually open
|
||||
uiPenMenu.setAsOpen()
|
||||
@@ -398,10 +387,10 @@ class BuildingMaker(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
IngameRenderer.resize(AppLoader.screenW, AppLoader.screenH)
|
||||
IngameRenderer.resize(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH)
|
||||
uiToolbox.setPosition(0, 0)
|
||||
notifier.setPosition(
|
||||
(AppLoader.screenW - notifier.width) / 2, AppLoader.screenH - notifier.height)
|
||||
(AppLoader.screenSize.screenW - notifier.width) / 2, AppLoader.screenSize.screenH - notifier.height)
|
||||
|
||||
println("[BuildingMaker] Resize event")
|
||||
}
|
||||
@@ -518,8 +507,8 @@ class BuildingMakerController(val screen: BuildingMaker) : InputAdapter() {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
screen.uiContainer.forEach { it?.scrolled(amount) }
|
||||
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||
screen.uiContainer.forEach { it?.scrolled(amountX, amountY) }
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -563,12 +552,12 @@ class MovableWorldCamera(val parent: BuildingMaker) : ActorHumanoid(0, physProp
|
||||
|
||||
// TODO resize-aware
|
||||
private var coerceInStart = Point2d(
|
||||
(AppLoader.screenW - hitbox.width) / 2.0,
|
||||
(AppLoader.screenH - hitbox.height) / 2.0
|
||||
(AppLoader.screenSize.screenW - hitbox.width) / 2.0,
|
||||
(AppLoader.screenSize.screenH - hitbox.height) / 2.0
|
||||
)
|
||||
private var coerceInEnd = Point2d(
|
||||
parent.world.width * TILE_SIZE - (AppLoader.screenW - hitbox.width) / 2.0,
|
||||
parent.world.height * TILE_SIZE - (AppLoader.screenH - hitbox.height) / 2.0
|
||||
parent.world.width * TILE_SIZE - (AppLoader.screenSize.screenW - hitbox.width) / 2.0,
|
||||
parent.world.height * TILE_SIZE - (AppLoader.screenSize.screenH - hitbox.height) / 2.0
|
||||
)
|
||||
|
||||
override fun update(delta: Float) {
|
||||
|
||||
@@ -56,8 +56,8 @@ object IngameRenderer : Disposable {
|
||||
val shaderAtoGrey: ShaderProgram
|
||||
val shaderPassthru = SpriteBatch.createDefaultShader()
|
||||
|
||||
private val WIDTH = AppLoader.screenW
|
||||
private val HEIGHT = AppLoader.screenH
|
||||
private val WIDTH = AppLoader.screenSize.screenW
|
||||
private val HEIGHT = AppLoader.screenSize.screenH
|
||||
private val WIDTHF = WIDTH.toFloat()
|
||||
private val HEIGHTF = HEIGHT.toFloat()
|
||||
|
||||
@@ -608,7 +608,7 @@ object IngameRenderer : Disposable {
|
||||
* Camera will be moved so that (newX, newY) would be sit on the top-left edge.
|
||||
*/
|
||||
private fun setCameraPosition(newX: Float, newY: Float) {
|
||||
camera.position.set((-newX + AppLoader.halfScreenW).round(), (-newY + AppLoader.halfScreenH).round(), 0f)
|
||||
camera.position.set((-newX + AppLoader.screenSize.halfScreenW).round(), (-newY + AppLoader.screenSize.halfScreenH).round(), 0f)
|
||||
camera.update()
|
||||
batch.projectionMatrix = camera.combined
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import net.torvald.EMDASH
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
@@ -83,7 +82,7 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
companion object {
|
||||
/** Sets camera position so that (0,0) would be top-left of the screen, (width, height) be bottom-right. */
|
||||
fun setCameraPosition(batch: SpriteBatch, camera: Camera, newX: Float, newY: Float) {
|
||||
camera.position.set((-newX + AppLoader.halfScreenW).round(), (-newY + AppLoader.halfScreenH).round(), 0f)
|
||||
camera.position.set((-newX + AppLoader.screenSize.halfScreenW).round(), (-newY + AppLoader.screenSize.halfScreenH).round(), 0f)
|
||||
camera.update()
|
||||
batch.projectionMatrix = camera.combined
|
||||
}
|
||||
@@ -184,7 +183,7 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
//initViewPort(AppLoader.screenW, AppLoader.screenH)
|
||||
//initViewPort(AppLoader.terrarumAppConfig.screenW, AppLoader.terrarumAppConfig.screenH)
|
||||
|
||||
// gameLoadMode and gameLoadInfoPayload must be set beforehand!!
|
||||
|
||||
@@ -289,8 +288,8 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
/** Load rest of the game with GL context */
|
||||
fun postInit() {
|
||||
//setTheRealGamerFirstTime(PlayerBuilderSigrid())
|
||||
//setTheRealGamerFirstTime(PlayerBuilderTestSubject1())
|
||||
setTheRealGamerFirstTime(PlayerBuilderWerebeastTest())
|
||||
setTheRealGamerFirstTime(PlayerBuilderTestSubject1())
|
||||
//setTheRealGamerFirstTime(PlayerBuilderWerebeastTest())
|
||||
|
||||
|
||||
|
||||
@@ -314,8 +313,8 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
// init notifier
|
||||
notifier = Notification()
|
||||
notifier.setPosition(
|
||||
(AppLoader.screenW - notifier.width) / 2,
|
||||
AppLoader.screenH - notifier.height - AppLoader.getTvSafeGraphicsHeight()
|
||||
(AppLoader.screenSize.screenW - notifier.width) / 2,
|
||||
AppLoader.screenSize.screenH - notifier.height - AppLoader.screenSize.tvSafeGraphicsHeight
|
||||
)
|
||||
|
||||
|
||||
@@ -332,11 +331,11 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
// quick bar
|
||||
uiQuickBar = UIQuickslotBar()
|
||||
uiQuickBar.isVisible = true
|
||||
uiQuickBar.setPosition((AppLoader.screenW - uiQuickBar.width) / 2, AppLoader.getTvSafeGraphicsHeight())
|
||||
uiQuickBar.setPosition((AppLoader.screenSize.screenW - uiQuickBar.width) / 2, AppLoader.screenSize.tvSafeGraphicsHeight)
|
||||
|
||||
// pie menu
|
||||
uiPieMenu = UIQuickslotPie()
|
||||
uiPieMenu.setPosition(AppLoader.halfScreenW, AppLoader.halfScreenH)
|
||||
uiPieMenu.setPosition(AppLoader.screenSize.halfScreenW, AppLoader.screenSize.halfScreenH)
|
||||
|
||||
// vital metre
|
||||
// fill in getter functions by
|
||||
@@ -351,14 +350,14 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
uiWatchTierOne = UITierOneWatch(actorNowPlaying)
|
||||
uiWatchTierOne.setAsAlwaysVisible()
|
||||
uiWatchTierOne.setPosition(
|
||||
((AppLoader.screenW - AppLoader.getTvSafeActionWidth()) - (uiQuickBar.posX + uiQuickBar.width) - uiWatchTierOne.width) / 2 + (uiQuickBar.posX + uiQuickBar.width),
|
||||
AppLoader.getTvSafeGraphicsHeight() + 8
|
||||
((AppLoader.screenSize.screenW - AppLoader.screenSize.tvSafeActionWidth) - (uiQuickBar.posX + uiQuickBar.width) - uiWatchTierOne.width) / 2 + (uiQuickBar.posX + uiQuickBar.width),
|
||||
AppLoader.screenSize.tvSafeGraphicsHeight + 8
|
||||
)
|
||||
|
||||
// basic watch-style notification bar (temperature, new mail)
|
||||
uiBasicInfo = UIBasicInfo(actorNowPlaying)
|
||||
uiBasicInfo.setAsAlwaysVisible()
|
||||
uiBasicInfo.setPosition((uiQuickBar.posX - uiBasicInfo.width - AppLoader.getTvSafeActionWidth()) / 2 + AppLoader.getTvSafeActionWidth(), uiWatchTierOne.posY)
|
||||
uiBasicInfo.setPosition((uiQuickBar.posX - uiBasicInfo.width - AppLoader.screenSize.tvSafeActionWidth) / 2 + AppLoader.screenSize.tvSafeActionWidth, uiWatchTierOne.posY)
|
||||
|
||||
|
||||
uiTooltip = UITooltip()
|
||||
@@ -1009,8 +1008,8 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
|
||||
/**
|
||||
* @param width same as AppLoader.screenW
|
||||
* @param height same as AppLoader.screenH
|
||||
* @param width same as AppLoader.terrarumAppConfig.screenW
|
||||
* @param height same as AppLoader.terrarumAppConfig.screenH
|
||||
* @see net.torvald.terrarum.Terrarum
|
||||
*/
|
||||
override fun resize(width: Int, height: Int) {
|
||||
@@ -1019,7 +1018,7 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
//MegaRainGovernor.resize()
|
||||
|
||||
|
||||
IngameRenderer.resize(AppLoader.screenW, AppLoader.screenH)
|
||||
IngameRenderer.resize(AppLoader.screenSize.screenW, AppLoader.screenSize.screenH)
|
||||
|
||||
|
||||
if (gameInitialised) {
|
||||
@@ -1031,23 +1030,23 @@ open class TerrarumIngame(batch: SpriteBatch) : IngameInstance(batch) {
|
||||
// resize UIs
|
||||
|
||||
notifier.setPosition(
|
||||
(AppLoader.screenW - notifier.width) / 2, AppLoader.screenH - notifier.height)
|
||||
uiQuickBar.setPosition((AppLoader.screenW - uiQuickBar.width) / 2, AppLoader.getTvSafeGraphicsHeight())
|
||||
(AppLoader.screenSize.screenW - notifier.width) / 2, AppLoader.screenSize.screenH - notifier.height)
|
||||
uiQuickBar.setPosition((AppLoader.screenSize.screenW - uiQuickBar.width) / 2, AppLoader.screenSize.tvSafeGraphicsHeight)
|
||||
|
||||
// inventory
|
||||
/*uiInventoryPlayer =
|
||||
UIInventory(player,
|
||||
width = 840,
|
||||
height = AppLoader.screenH - 160,
|
||||
height = AppLoader.terrarumAppConfig.screenH - 160,
|
||||
categoryWidth = 210
|
||||
)*/
|
||||
|
||||
|
||||
// basic watch-style notification bar (temperature, new mail)
|
||||
uiBasicInfo.setPosition(AppLoader.screenW - uiBasicInfo.width, 0)
|
||||
uiBasicInfo.setPosition(AppLoader.screenSize.screenW - uiBasicInfo.width, 0)
|
||||
uiWatchTierOne.setPosition(
|
||||
((AppLoader.screenW - AppLoader.getTvSafeGraphicsWidth()) - (uiQuickBar.posX + uiQuickBar.width) - uiWatchTierOne.width) / 2 + (uiQuickBar.posX + uiQuickBar.width),
|
||||
AppLoader.getTvSafeGraphicsHeight() + 8
|
||||
((AppLoader.screenSize.screenW - AppLoader.screenSize.tvSafeGraphicsWidth) - (uiQuickBar.posX + uiQuickBar.width) - uiWatchTierOne.width) / 2 + (uiQuickBar.posX + uiQuickBar.width),
|
||||
AppLoader.screenSize.tvSafeGraphicsHeight + 8
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
package net.torvald.terrarum.modulebasegame
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.ScreenAdapter
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.Pixmap
|
||||
import com.badlogic.gdx.graphics.Texture
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.blockproperties.BlockCodex
|
||||
import net.torvald.terrarum.blockproperties.BlockProp
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.util.CircularArray
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
@@ -39,8 +34,8 @@ class WorldgenLoadScreen(screenToBeLoaded: IngameInstance, private val worldwidt
|
||||
private val COL_AIR = Color.BLACK
|
||||
}
|
||||
|
||||
private val previewWidth = (AppLoader.screenW * WIDTH_RATIO).roundToInt()
|
||||
private val previewHeight = (AppLoader.screenW * WIDTH_RATIO * worldheight / worldwidth).roundToInt()
|
||||
private val previewWidth = (AppLoader.screenSize.screenW * WIDTH_RATIO).roundToInt()
|
||||
private val previewHeight = (AppLoader.screenSize.screenW * WIDTH_RATIO * worldheight / worldwidth).roundToInt()
|
||||
|
||||
private lateinit var previewPixmap: Pixmap
|
||||
private lateinit var previewTexture: Texture
|
||||
@@ -73,15 +68,15 @@ class WorldgenLoadScreen(screenToBeLoaded: IngameInstance, private val worldwidt
|
||||
|
||||
AppLoader.batch.inUse {
|
||||
it.color = Color.WHITE
|
||||
val previewY = (AppLoader.screenH - previewHeight.times(1.5f)).div(2f).round()
|
||||
val previewY = (AppLoader.screenSize.screenH - previewHeight.times(1.5f)).div(2f).round()
|
||||
it.draw(previewTexture,
|
||||
(AppLoader.screenW - previewWidth).div(2f).round(),
|
||||
(AppLoader.screenSize.screenW - previewWidth).div(2f).round(),
|
||||
previewY
|
||||
)
|
||||
val text = messages.getHeadElem() ?: ""
|
||||
AppLoader.fontGame.draw(it,
|
||||
text,
|
||||
(AppLoader.screenW - AppLoader.fontGame.getWidth(text)).div(2f).round(),
|
||||
(AppLoader.screenSize.screenW - AppLoader.fontGame.getWidth(text)).div(2f).round(),
|
||||
previewY + previewHeight + 98 - AppLoader.fontGame.lineHeight
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.AppLoader.printdbg
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.gameitem.GameItem
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
@@ -13,7 +12,6 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory.Companion.CAPACITY_MODE_COUNT
|
||||
import net.torvald.terrarum.modulebasegame.ui.*
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryCells.Companion.weightBarWidth
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELLS_HOR
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELLS_VRT
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_OFFSET_X
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.INVENTORY_CELLS_OFFSET_Y
|
||||
@@ -61,8 +59,8 @@ internal class UIStorageChest : UICanvas(), HasInventory {
|
||||
lateinit var chestInventory: FixtureInventory
|
||||
lateinit var chestNameFun: () -> String
|
||||
|
||||
override var width = AppLoader.screenW
|
||||
override var height = AppLoader.screenH
|
||||
override var width = AppLoader.screenSize.screenW
|
||||
override var height = AppLoader.screenSize.screenH
|
||||
override var openCloseTime: Second = 0.0f
|
||||
|
||||
private val shapeRenderer = ShapeRenderer()
|
||||
@@ -124,8 +122,8 @@ internal class UIStorageChest : UICanvas(), HasInventory {
|
||||
|
||||
catBar = UIItemInventoryCatBar(
|
||||
this,
|
||||
(AppLoader.screenW - catBarWidth) / 2,
|
||||
42 + (AppLoader.screenH - internalHeight) / 2,
|
||||
(AppLoader.screenSize.screenW - catBarWidth) / 2,
|
||||
42 + (AppLoader.screenSize.screenH - internalHeight) / 2,
|
||||
internalWidth,
|
||||
catBarWidth,
|
||||
false
|
||||
@@ -192,17 +190,17 @@ internal class UIStorageChest : UICanvas(), HasInventory {
|
||||
gdxSetBlendNormal()
|
||||
|
||||
|
||||
val gradTopStart = (AppLoader.screenH - internalHeight).div(2).toFloat()
|
||||
val gradBottomEnd = AppLoader.screenH - gradTopStart
|
||||
val gradTopStart = (AppLoader.screenSize.screenH - internalHeight).div(2).toFloat()
|
||||
val gradBottomEnd = AppLoader.screenSize.screenH - gradTopStart
|
||||
|
||||
shapeRenderer.inUse {
|
||||
shapeRenderer.rect(0f, gradTopStart, AppLoader.screenWf, gradHeight, gradStartCol, gradStartCol, gradEndCol, gradEndCol)
|
||||
shapeRenderer.rect(0f, gradBottomEnd, AppLoader.screenWf, -gradHeight, gradStartCol, gradStartCol, gradEndCol, gradEndCol)
|
||||
shapeRenderer.rect(0f, gradTopStart, AppLoader.screenSize.screenWf, gradHeight, gradStartCol, gradStartCol, gradEndCol, gradEndCol)
|
||||
shapeRenderer.rect(0f, gradBottomEnd, AppLoader.screenSize.screenWf, -gradHeight, gradStartCol, gradStartCol, gradEndCol, gradEndCol)
|
||||
|
||||
shapeRenderer.rect(0f, gradTopStart + gradHeight, AppLoader.screenWf, internalHeight - (2 * gradHeight), gradEndCol, gradEndCol, gradEndCol, gradEndCol)
|
||||
shapeRenderer.rect(0f, gradTopStart + gradHeight, AppLoader.screenSize.screenWf, internalHeight - (2 * gradHeight), gradEndCol, gradEndCol, gradEndCol, gradEndCol)
|
||||
|
||||
shapeRenderer.rect(0f, 0f, AppLoader.screenWf, gradTopStart, gradStartCol, gradStartCol, gradStartCol, gradStartCol)
|
||||
shapeRenderer.rect(0f, AppLoader.screenHf, AppLoader.screenWf, -(AppLoader.screenHf - gradBottomEnd), gradStartCol, gradStartCol, gradStartCol, gradStartCol)
|
||||
shapeRenderer.rect(0f, 0f, AppLoader.screenSize.screenWf, gradTopStart, gradStartCol, gradStartCol, gradStartCol, gradStartCol)
|
||||
shapeRenderer.rect(0f, AppLoader.screenSize.screenHf, AppLoader.screenSize.screenWf, -(AppLoader.screenSize.screenHf - gradBottomEnd), gradStartCol, gradStartCol, gradStartCol, gradStartCol)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ object MegaRainGovernor {
|
||||
val h = body.height
|
||||
|
||||
bodies = Array(1024) {
|
||||
//val pixmap = Pixmap(AppLoader.screenW * 2, AppLoader.screenH / 4, Pixmap.Format.RGBA8888)
|
||||
//val pixmap = Pixmap(AppLoader.terrarumAppConfig.screenW * 2, AppLoader.terrarumAppConfig.screenH / 4, Pixmap.Format.RGBA8888)
|
||||
val pixmap = Pixmap(64, 64, Pixmap.Format.RGBA8888)
|
||||
|
||||
val rng = HQRNG()
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.blendNormal
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
|
||||
@@ -62,7 +61,7 @@ class Notification : UICanvas() {
|
||||
val displayedTextWidth = maxOf(240, realTextWidth)
|
||||
|
||||
// force the UI to the centre of the screen
|
||||
this.posX = (AppLoader.screenW - displayedTextWidth) / 2
|
||||
this.posX = (AppLoader.screenSize.screenW - displayedTextWidth) / 2
|
||||
|
||||
val textHeight = message.size * AppLoader.fontGame.lineHeight
|
||||
|
||||
|
||||
@@ -70,8 +70,8 @@ class UIBuildingMakerPenMenu(val parent: BuildingMaker): UICanvas() {
|
||||
{
|
||||
parent.uiPalette.isVisible = true
|
||||
parent.uiPalette.setPosition(Gdx.input.x - parent.uiPalette.width / 2, Gdx.input.y - parent.uiPalette.height / 2)
|
||||
parent.uiPalette.posX = parent.uiPalette.posX.coerceIn(0, AppLoader.screenW - parent.uiPalette.width)
|
||||
parent.uiPalette.posY = parent.uiPalette.posY.coerceIn(0, AppLoader.screenH - parent.uiPalette.height)
|
||||
parent.uiPalette.posX = parent.uiPalette.posX.coerceIn(0, AppLoader.screenSize.screenW - parent.uiPalette.width)
|
||||
parent.uiPalette.posY = parent.uiPalette.posY.coerceIn(0, AppLoader.screenSize.screenH - parent.uiPalette.height)
|
||||
},
|
||||
{
|
||||
parent.currentPenMode = BuildingMaker.PENMODE_PENCIL_ERASE
|
||||
|
||||
@@ -52,40 +52,4 @@ class UIBuildingMakerToolbox : UICanvas() {
|
||||
override fun dispose() {
|
||||
toolsTexture.dispose()
|
||||
}
|
||||
|
||||
override fun mouseMoved(screenX: Int, screenY: Int): Boolean {
|
||||
return super.mouseMoved(screenX, screenY)
|
||||
}
|
||||
|
||||
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
|
||||
return super.touchDragged(screenX, screenY, pointer)
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
return super.touchDown(screenX, screenY, pointer, button)
|
||||
}
|
||||
|
||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
return super.touchUp(screenX, screenY, pointer, button)
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
return super.scrolled(amount)
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
return super.keyDown(keycode)
|
||||
}
|
||||
|
||||
override fun keyUp(keycode: Int): Boolean {
|
||||
return super.keyUp(keycode)
|
||||
}
|
||||
|
||||
override fun keyTyped(character: Char): Boolean {
|
||||
return super.keyTyped(character)
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
super.resize(width, height)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@ import net.torvald.terrarum.ui.UICanvas
|
||||
class UICheatDetected : UICanvas() {
|
||||
|
||||
override var width: Int
|
||||
get() = AppLoader.screenW
|
||||
get() = AppLoader.screenSize.screenW
|
||||
set(value) { throw UnsupportedOperationException() }
|
||||
|
||||
override var height: Int
|
||||
get() = AppLoader.screenH
|
||||
get() = AppLoader.screenSize.screenH
|
||||
set(value) { throw UnsupportedOperationException() }
|
||||
|
||||
override var openCloseTime: Second = 0f
|
||||
|
||||
@@ -6,7 +6,6 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorInventory
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELLS_HOR
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIInventoryFull.Companion.CELLS_VRT
|
||||
@@ -23,8 +22,8 @@ internal class UIInventoryCells(
|
||||
val full: UIInventoryFull
|
||||
) : UICanvas() {
|
||||
|
||||
override var width: Int = AppLoader.screenW
|
||||
override var height: Int = AppLoader.screenH
|
||||
override var width: Int = AppLoader.screenSize.screenW
|
||||
override var height: Int = AppLoader.screenSize.screenH
|
||||
override var openCloseTime: Second = 0.0f
|
||||
|
||||
companion object {
|
||||
@@ -56,7 +55,7 @@ internal class UIInventoryCells(
|
||||
full,
|
||||
full.actor.inventory,
|
||||
full.actor as ActorWithBody,
|
||||
internalWidth - UIItemInventoryEquippedView.WIDTH + (AppLoader.screenW - internalWidth) / 2,
|
||||
internalWidth - UIItemInventoryEquippedView.WIDTH + (AppLoader.screenSize.screenW - internalWidth) / 2,
|
||||
INVENTORY_CELLS_OFFSET_Y,
|
||||
{ rebuildList() }
|
||||
)
|
||||
|
||||
@@ -15,8 +15,8 @@ import net.torvald.terrarum.ui.UIItemTextButtonList.Companion.DEFAULT_LINE_HEIGH
|
||||
|
||||
class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
||||
|
||||
override var width: Int = AppLoader.screenW
|
||||
override var height: Int = AppLoader.screenH
|
||||
override var width: Int = AppLoader.screenSize.screenW
|
||||
override var height: Int = AppLoader.screenSize.screenH
|
||||
override var openCloseTime = 0.0f
|
||||
|
||||
private val gameMenu = arrayOf("MENU_LABEL_MAINMENU", "MENU_LABEL_DESKTOP", "MENU_OPTIONS_CONTROLS", "MENU_OPTIONS_SOUND", "MENU_LABEL_GRAPHICS")
|
||||
@@ -24,7 +24,7 @@ class UIInventoryEscMenu(val full: UIInventoryFull) : UICanvas() {
|
||||
private val gameMenuListWidth = 400
|
||||
private val gameMenuButtons = UIItemTextButtonList(
|
||||
this, gameMenu,
|
||||
(AppLoader.screenW - gameMenuListWidth) / 2,
|
||||
(AppLoader.screenSize.screenW - gameMenuListWidth) / 2,
|
||||
INVENTORY_CELLS_OFFSET_Y + (INVENTORY_CELLS_UI_HEIGHT - gameMenuListHeight) / 2,
|
||||
gameMenuListWidth, gameMenuListHeight,
|
||||
readFromLang = true,
|
||||
|
||||
@@ -25,8 +25,8 @@ class UIInventoryFull(
|
||||
doNotWarnConstant: Boolean = false
|
||||
) : UICanvas(toggleKeyLiteral, toggleButtonLiteral, customPositioning, doNotWarnConstant) {
|
||||
|
||||
override var width: Int = AppLoader.screenW
|
||||
override var height: Int = AppLoader.screenH
|
||||
override var width: Int = AppLoader.screenSize.screenW
|
||||
override var height: Int = AppLoader.screenSize.screenH
|
||||
override var openCloseTime: Second = 0.0f
|
||||
|
||||
companion object {
|
||||
@@ -34,7 +34,7 @@ class UIInventoryFull(
|
||||
|
||||
const val REQUIRED_MARGIN: Int = 138 // hard-coded value. Don't know the details. Range: [91-146]. I chose MAX-8 because cell gap is 8
|
||||
const val CELLS_HOR = 10
|
||||
val CELLS_VRT: Int; get() = (AppLoader.screenH - REQUIRED_MARGIN - 134 + UIItemInventoryItemGrid.listGap) / // 134 is another magic number
|
||||
val CELLS_VRT: Int; get() = (AppLoader.screenSize.screenH - REQUIRED_MARGIN - 134 + UIItemInventoryItemGrid.listGap) / // 134 is another magic number
|
||||
(UIItemInventoryElemSimple.height + UIItemInventoryItemGrid.listGap)
|
||||
|
||||
const val itemListToEquipViewGap = UIItemInventoryItemGrid.listGap // used to be 24; figured out that the extra gap does nothig
|
||||
@@ -45,8 +45,8 @@ class UIInventoryFull(
|
||||
val itemListHeight: Int = CELLS_VRT * UIItemInventoryElemSimple.height + (CELLS_VRT - 1) * net.torvald.terrarum.modulebasegame.ui.UIItemInventoryItemGrid.Companion.listGap
|
||||
|
||||
val INVENTORY_CELLS_UI_HEIGHT: Int = CELLS_VRT * UIItemInventoryElemSimple.height + (CELLS_VRT - 1) * UIItemInventoryItemGrid.listGap
|
||||
val INVENTORY_CELLS_OFFSET_X = 0 + (AppLoader.screenW - internalWidth) / 2
|
||||
val INVENTORY_CELLS_OFFSET_Y: Int = 107 + (AppLoader.screenH - internalHeight) / 2
|
||||
val INVENTORY_CELLS_OFFSET_X = 0 + (AppLoader.screenSize.screenW - internalWidth) / 2
|
||||
val INVENTORY_CELLS_OFFSET_Y: Int = 107 + (AppLoader.screenSize.screenH - internalHeight) / 2
|
||||
|
||||
val catBarWidth = 330
|
||||
|
||||
@@ -60,7 +60,7 @@ class UIInventoryFull(
|
||||
//val REQUIRED_MARGIN: Int = 138 // hard-coded value. Don't know the details. Range: [91-146]. I chose MAX-8 because cell gap is 8
|
||||
|
||||
//val CELLS_HOR = 10
|
||||
//val CELLS_VRT: Int; get() = (AppLoader.screenH - REQUIRED_MARGIN - 134 + UIItemInventoryItemGrid.listGap) / // 134 is another magic number
|
||||
//val CELLS_VRT: Int; get() = (AppLoader.terrarumAppConfig.screenH - REQUIRED_MARGIN - 134 + UIItemInventoryItemGrid.listGap) / // 134 is another magic number
|
||||
// (UIItemInventoryElemSimple.height + UIItemInventoryItemGrid.listGap)
|
||||
|
||||
//private val itemListToEquipViewGap = UIItemInventoryItemGrid.listGap // used to be 24; figured out that the extra gap does nothig
|
||||
@@ -71,8 +71,8 @@ class UIInventoryFull(
|
||||
//val itemListHeight: Int = CELLS_VRT * UIItemInventoryElemSimple.height + (CELLS_VRT - 1) * net.torvald.terrarum.modulebasegame.ui.UIItemInventoryItemGrid.Companion.listGap
|
||||
|
||||
//val INVENTORY_CELLS_UI_HEIGHT: Int = CELLS_VRT * UIItemInventoryElemSimple.height + (CELLS_VRT - 1) * UIItemInventoryItemGrid.listGap
|
||||
//val INVENTORY_CELLS_OFFSET_X = 0 + (AppLoader.screenW - internalWidth) / 2
|
||||
//val INVENTORY_CELLS_OFFSET_Y: Int = 107 + (AppLoader.screenH - internalHeight) / 2
|
||||
//val INVENTORY_CELLS_OFFSET_X = 0 + (AppLoader.terrarumAppConfig.screenW - internalWidth) / 2
|
||||
//val INVENTORY_CELLS_OFFSET_Y: Int = 107 + (AppLoader.terrarumAppConfig.screenH - internalHeight) / 2
|
||||
|
||||
init {
|
||||
handler.allowESCtoClose = true
|
||||
@@ -113,8 +113,8 @@ class UIInventoryFull(
|
||||
|
||||
val catBar = UIItemInventoryCatBar(
|
||||
this,
|
||||
(AppLoader.screenW - catBarWidth) / 2,
|
||||
42 + (AppLoader.screenH - internalHeight) / 2,
|
||||
(AppLoader.screenSize.screenW - catBarWidth) / 2,
|
||||
42 + (AppLoader.screenSize.screenH - internalHeight) / 2,
|
||||
internalWidth,
|
||||
catBarWidth,
|
||||
true,
|
||||
@@ -127,10 +127,10 @@ class UIInventoryFull(
|
||||
private val transitionalEscMenu = UIInventoryEscMenu(this)
|
||||
private val transitionPanel = UIItemHorizontalFadeSlide(
|
||||
this,
|
||||
(AppLoader.screenW - internalWidth) / 2,
|
||||
(AppLoader.screenSize.screenW - internalWidth) / 2,
|
||||
INVENTORY_CELLS_OFFSET_Y,
|
||||
AppLoader.screenW,
|
||||
AppLoader.screenH,
|
||||
AppLoader.screenSize.screenW,
|
||||
AppLoader.screenSize.screenH,
|
||||
1f,
|
||||
transitionalMinimap, transitionalItemCells, transitionalEscMenu
|
||||
)
|
||||
@@ -151,9 +151,9 @@ class UIInventoryFull(
|
||||
|
||||
}
|
||||
|
||||
internal var offsetX = ((AppLoader.screenW - internalWidth) / 2).toFloat()
|
||||
internal var offsetX = ((AppLoader.screenSize.screenW - internalWidth) / 2).toFloat()
|
||||
private set
|
||||
internal var offsetY = ((AppLoader.screenH - internalHeight) / 2).toFloat()
|
||||
internal var offsetY = ((AppLoader.screenSize.screenH - internalHeight) / 2).toFloat()
|
||||
private set
|
||||
|
||||
fun requestTransition(target: Int) = transitionPanel.requestTransition(target)
|
||||
@@ -172,9 +172,9 @@ class UIInventoryFull(
|
||||
//private val gradHeight = 48f
|
||||
private val shapeRenderer = ShapeRenderer()
|
||||
|
||||
internal var xEnd = (AppLoader.screenW + internalWidth).div(2).toFloat()
|
||||
internal var xEnd = (AppLoader.screenSize.screenW + internalWidth).div(2).toFloat()
|
||||
private set
|
||||
internal var yEnd = (AppLoader.screenH + internalHeight).div(2).toFloat()
|
||||
internal var yEnd = (AppLoader.screenSize.screenH + internalHeight).div(2).toFloat()
|
||||
private set
|
||||
|
||||
override fun renderUI(batch: SpriteBatch, camera: Camera) {
|
||||
@@ -185,17 +185,17 @@ class UIInventoryFull(
|
||||
gdxSetBlendNormal()
|
||||
|
||||
|
||||
val gradTopStart = (AppLoader.screenH - internalHeight).div(2).toFloat()
|
||||
val gradBottomEnd = AppLoader.screenH - gradTopStart
|
||||
val gradTopStart = (AppLoader.screenSize.screenH - internalHeight).div(2).toFloat()
|
||||
val gradBottomEnd = AppLoader.screenSize.screenH - gradTopStart
|
||||
|
||||
shapeRenderer.inUse {
|
||||
shapeRenderer.rect(0f, gradTopStart, AppLoader.screenWf, gradHeight, gradStartCol, gradStartCol, gradEndCol, gradEndCol)
|
||||
shapeRenderer.rect(0f, gradBottomEnd, AppLoader.screenWf, -gradHeight, gradStartCol, gradStartCol, gradEndCol, gradEndCol)
|
||||
shapeRenderer.rect(0f, gradTopStart, AppLoader.screenSize.screenWf, gradHeight, gradStartCol, gradStartCol, gradEndCol, gradEndCol)
|
||||
shapeRenderer.rect(0f, gradBottomEnd, AppLoader.screenSize.screenWf, -gradHeight, gradStartCol, gradStartCol, gradEndCol, gradEndCol)
|
||||
|
||||
shapeRenderer.rect(0f, gradTopStart + gradHeight, AppLoader.screenWf, internalHeight - (2 * gradHeight), gradEndCol, gradEndCol, gradEndCol, gradEndCol)
|
||||
shapeRenderer.rect(0f, gradTopStart + gradHeight, AppLoader.screenSize.screenWf, internalHeight - (2 * gradHeight), gradEndCol, gradEndCol, gradEndCol, gradEndCol)
|
||||
|
||||
shapeRenderer.rect(0f, 0f, AppLoader.screenWf, gradTopStart, gradStartCol, gradStartCol, gradStartCol, gradStartCol)
|
||||
shapeRenderer.rect(0f, AppLoader.screenHf, AppLoader.screenWf, -(AppLoader.screenHf - gradBottomEnd), gradStartCol, gradStartCol, gradStartCol, gradStartCol)
|
||||
shapeRenderer.rect(0f, 0f, AppLoader.screenSize.screenWf, gradTopStart, gradStartCol, gradStartCol, gradStartCol, gradStartCol)
|
||||
shapeRenderer.rect(0f, AppLoader.screenSize.screenHf, AppLoader.screenSize.screenWf, -(AppLoader.screenSize.screenHf - gradBottomEnd), gradStartCol, gradStartCol, gradStartCol, gradStartCol)
|
||||
}
|
||||
|
||||
|
||||
@@ -255,11 +255,11 @@ class UIInventoryFull(
|
||||
override fun resize(width: Int, height: Int) {
|
||||
super.resize(width, height)
|
||||
|
||||
offsetX = ((AppLoader.screenW - internalWidth) / 2).toFloat()
|
||||
offsetY = ((AppLoader.screenH - internalHeight) / 2).toFloat()
|
||||
offsetX = ((AppLoader.screenSize.screenW - internalWidth) / 2).toFloat()
|
||||
offsetY = ((AppLoader.screenSize.screenH - internalHeight) / 2).toFloat()
|
||||
|
||||
xEnd = (AppLoader.screenW + internalWidth).div(2).toFloat()
|
||||
yEnd = (AppLoader.screenH + internalHeight).div(2).toFloat()
|
||||
xEnd = (AppLoader.screenSize.screenW + internalWidth).div(2).toFloat()
|
||||
yEnd = (AppLoader.screenSize.screenH + internalHeight).div(2).toFloat()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() {
|
||||
|
||||
private val debugvals = true
|
||||
|
||||
override var width: Int = AppLoader.screenW
|
||||
override var height: Int = AppLoader.screenH
|
||||
override var width: Int = AppLoader.screenSize.screenW
|
||||
override var height: Int = AppLoader.screenSize.screenH
|
||||
override var openCloseTime = 0.0f
|
||||
|
||||
private val MINIMAP_WIDTH = 800f
|
||||
@@ -115,23 +115,23 @@ class UIInventoryMinimap(val full: UIInventoryFull) : UICanvas() {
|
||||
batch.begin()
|
||||
|
||||
if (debugvals) {
|
||||
AppLoader.fontSmallNumbers.draw(batch, "$minimapPanX, $minimapPanY; x$minimapZoom", (AppLoader.screenW - MINIMAP_WIDTH) / 2, -10f + INVENTORY_CELLS_OFFSET_Y)
|
||||
AppLoader.fontSmallNumbers.draw(batch, "$minimapPanX, $minimapPanY; x$minimapZoom", (AppLoader.screenSize.screenW - MINIMAP_WIDTH) / 2, -10f + INVENTORY_CELLS_OFFSET_Y)
|
||||
}
|
||||
|
||||
batch.projectionMatrix = camera.combined
|
||||
// 1px stroke
|
||||
batch.color = Color.WHITE
|
||||
batch.fillRect((AppLoader.screenW - MINIMAP_WIDTH) / 2, -1 + INVENTORY_CELLS_OFFSET_Y.toFloat(), MINIMAP_WIDTH, 1f)
|
||||
batch.fillRect((AppLoader.screenW - MINIMAP_WIDTH) / 2, INVENTORY_CELLS_OFFSET_Y + MINIMAP_HEIGHT, MINIMAP_WIDTH, 1f)
|
||||
batch.fillRect(-1 + (AppLoader.screenW - MINIMAP_WIDTH) / 2, INVENTORY_CELLS_OFFSET_Y.toFloat(), 1f, MINIMAP_HEIGHT)
|
||||
batch.fillRect((AppLoader.screenW - MINIMAP_WIDTH) / 2 + MINIMAP_WIDTH, INVENTORY_CELLS_OFFSET_Y.toFloat(), 1f, MINIMAP_HEIGHT)
|
||||
batch.fillRect((AppLoader.screenSize.screenW - MINIMAP_WIDTH) / 2, -1 + INVENTORY_CELLS_OFFSET_Y.toFloat(), MINIMAP_WIDTH, 1f)
|
||||
batch.fillRect((AppLoader.screenSize.screenW - MINIMAP_WIDTH) / 2, INVENTORY_CELLS_OFFSET_Y + MINIMAP_HEIGHT, MINIMAP_WIDTH, 1f)
|
||||
batch.fillRect(-1 + (AppLoader.screenSize.screenW - MINIMAP_WIDTH) / 2, INVENTORY_CELLS_OFFSET_Y.toFloat(), 1f, MINIMAP_HEIGHT)
|
||||
batch.fillRect((AppLoader.screenSize.screenW - MINIMAP_WIDTH) / 2 + MINIMAP_WIDTH, INVENTORY_CELLS_OFFSET_Y.toFloat(), 1f, MINIMAP_HEIGHT)
|
||||
|
||||
// control hints
|
||||
batch.color = Color.WHITE
|
||||
AppLoader.fontGame.draw(batch, full.minimapControlHelp, full.offsetX, full.yEnd - 20)
|
||||
|
||||
// the minimap
|
||||
batch.draw(minimapFBO.colorBufferTexture, (AppLoader.screenW - MINIMAP_WIDTH) / 2, INVENTORY_CELLS_OFFSET_Y.toFloat())
|
||||
batch.draw(minimapFBO.colorBufferTexture, (AppLoader.screenSize.screenW - MINIMAP_WIDTH) / 2, INVENTORY_CELLS_OFFSET_Y.toFloat())
|
||||
}
|
||||
|
||||
override fun doOpening(delta: Float) {}
|
||||
|
||||
@@ -523,12 +523,12 @@ class UIItemInventoryItemGrid(
|
||||
return true
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
super.scrolled(amount)
|
||||
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||
super.scrolled(amountX, amountY)
|
||||
|
||||
// scroll the item list (for now)
|
||||
if (mouseUp) {
|
||||
scrollItemPage(amount)
|
||||
scrollItemPage(amountX.toInt())
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
@@ -46,40 +46,4 @@ class UIProxyNewBuildingMaker : UICanvas() {
|
||||
override fun dispose() {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
override fun mouseMoved(screenX: Int, screenY: Int): Boolean {
|
||||
return super.mouseMoved(screenX, screenY)
|
||||
}
|
||||
|
||||
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
|
||||
return super.touchDragged(screenX, screenY, pointer)
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
return super.touchDown(screenX, screenY, pointer, button)
|
||||
}
|
||||
|
||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
return super.touchUp(screenX, screenY, pointer, button)
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
return super.scrolled(amount)
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
return super.keyDown(keycode)
|
||||
}
|
||||
|
||||
override fun keyUp(keycode: Int): Boolean {
|
||||
return super.keyUp(keycode)
|
||||
}
|
||||
|
||||
override fun keyTyped(character: Char): Boolean {
|
||||
return super.keyTyped(character)
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
super.resize(width, height)
|
||||
}
|
||||
}
|
||||
@@ -62,40 +62,4 @@ class UIProxyNewRandomGame : UICanvas() {
|
||||
override fun dispose() {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
override fun mouseMoved(screenX: Int, screenY: Int): Boolean {
|
||||
return super.mouseMoved(screenX, screenY)
|
||||
}
|
||||
|
||||
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
|
||||
return super.touchDragged(screenX, screenY, pointer)
|
||||
}
|
||||
|
||||
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
return super.touchDown(screenX, screenY, pointer, button)
|
||||
}
|
||||
|
||||
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
||||
return super.touchUp(screenX, screenY, pointer, button)
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
return super.scrolled(amount)
|
||||
}
|
||||
|
||||
override fun keyDown(keycode: Int): Boolean {
|
||||
return super.keyDown(keycode)
|
||||
}
|
||||
|
||||
override fun keyUp(keycode: Int): Boolean {
|
||||
return super.keyUp(keycode)
|
||||
}
|
||||
|
||||
override fun keyTyped(character: Char): Boolean {
|
||||
return super.keyTyped(character)
|
||||
}
|
||||
|
||||
override fun resize(width: Int, height: Int) {
|
||||
super.resize(width, height)
|
||||
}
|
||||
}
|
||||
@@ -83,10 +83,10 @@ class UIQuickslotBar : UICanvas() {
|
||||
handler.opacity = 0f
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||
// super.scrolled(amount) // no UIItems here
|
||||
|
||||
selection = selection.plus(if (amount > 1) 1 else if (amount < -1) -1 else 0).fmod(SLOT_COUNT)
|
||||
selection = selection.plus(if (amountX > 1) 1 else if (amountX < -1) -1 else 0).fmod(SLOT_COUNT)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class UIQuickslotPie : UICanvas() {
|
||||
// update controls
|
||||
if (handler.isOpened || handler.isOpening) {
|
||||
val cursorPos = Vector2(Terrarum.mouseScreenX.toDouble(), Terrarum.mouseScreenY.toDouble())
|
||||
val centre = Vector2(AppLoader.halfScreenW.toDouble(), AppLoader.halfScreenH.toDouble())
|
||||
val centre = Vector2(AppLoader.screenSize.halfScreenW.toDouble(), AppLoader.screenSize.halfScreenH.toDouble())
|
||||
val deg = -(centre - cursorPos).direction.toFloat()
|
||||
|
||||
selection = Math.round(deg * slotCount / FastMath.TWO_PI)
|
||||
|
||||
@@ -8,7 +8,6 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.AppLoader.printdbgerr
|
||||
import net.torvald.terrarum.QNDTreeNode
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.Yaml
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.ui.UIItemTextButton
|
||||
@@ -221,9 +220,9 @@ open class UIRemoCon(treeRepresentation: QNDTreeNode<String>) : UICanvas() {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun scrolled(amount: Int): Boolean {
|
||||
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
||||
screens.forEach {
|
||||
it.second.scrolled(amount) // again, underlying handler will block unnecessary renders
|
||||
it.second.scrolled(amountX, amountY) // again, underlying handler will block unnecessary renders
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -300,6 +299,6 @@ open class UIRemoCon(treeRepresentation: QNDTreeNode<String>) : UICanvas() {
|
||||
val remoConWidth = 304
|
||||
fun getRemoConHeight(menu: ArrayList<String>) = DEFAULT_LINE_HEIGHT * menu.size.plus(1)
|
||||
fun getRemoConHeight(menu: Array<String>) = DEFAULT_LINE_HEIGHT * menu.size.plus(1)
|
||||
val menubarOffY: Int; get() = AppLoader.screenH / 2 - (AppLoader.fontGame.lineHeight * 1.5).toInt()
|
||||
val menubarOffY: Int; get() = AppLoader.screenSize.screenH / 2 - (AppLoader.fontGame.lineHeight * 1.5).toInt()
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.EMDASH
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.TerrarumScreenSize
|
||||
import net.torvald.terrarum.keyToIcon
|
||||
import net.torvald.terrarum.ui.Movement
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
@@ -39,8 +40,8 @@ class UIScreenZoom : UICanvas(
|
||||
|
||||
AppLoader.fontGame.draw(
|
||||
batch, zoomText,
|
||||
(AppLoader.screenW * AppLoader.TV_SAFE_GRAPHICS + 1).toInt().toFloat(),
|
||||
(AppLoader.screenH - height - AppLoader.getTvSafeGraphicsHeight()).toFloat()
|
||||
(AppLoader.screenSize.screenW * TerrarumScreenSize.TV_SAFE_GRAPHICS + 1).toInt().toFloat(),
|
||||
(AppLoader.screenSize.screenH - height - AppLoader.screenSize.tvSafeGraphicsHeight).toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ class UITitleCharactersList : UICanvas() {
|
||||
private val moduleAreaHMargin = 48
|
||||
private val moduleAreaBorder = 8
|
||||
|
||||
override var width = AppLoader.screenW - UIRemoCon.remoConWidth - moduleAreaHMargin
|
||||
override var height = AppLoader.screenH - moduleAreaHMargin * 2
|
||||
override var width = AppLoader.screenSize.screenW - UIRemoCon.remoConWidth - moduleAreaHMargin
|
||||
override var height = AppLoader.screenSize.screenH - moduleAreaHMargin * 2
|
||||
|
||||
private val moduleInfoCells = ArrayList<UIItemSavegameInfoCell>()
|
||||
// build characters list
|
||||
|
||||
@@ -3,7 +3,6 @@ package net.torvald.terrarum.modulebasegame.ui
|
||||
import com.badlogic.gdx.graphics.Camera
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
@@ -21,13 +20,13 @@ class UITitleLanguage : UICanvas() {
|
||||
|
||||
|
||||
private val textAreaHMargin = 48
|
||||
override var width = (AppLoader.screenW * 0.75).toInt()
|
||||
override var height = AppLoader.screenH - textAreaHMargin * 2
|
||||
override var width = (AppLoader.screenSize.screenW * 0.75).toInt()
|
||||
override var height = AppLoader.screenSize.screenH - textAreaHMargin * 2
|
||||
|
||||
private val localeList = Lang.languageList.toList().sorted()
|
||||
private val textArea = UIItemTextButtonList(this,
|
||||
localeList.map { Lang.langpack["MENU_LANGUAGE_THIS_$it"] ?: "!ERR: $it" }.toTypedArray(),
|
||||
AppLoader.screenW - width, textAreaHMargin,
|
||||
AppLoader.screenSize.screenW - width, textAreaHMargin,
|
||||
width, height,
|
||||
textAreaWidth = width,
|
||||
readFromLang = false,
|
||||
|
||||
@@ -21,8 +21,8 @@ class UITitleModules : UICanvas() {
|
||||
private val moduleAreaHMargin = 48
|
||||
private val moduleAreaBorder = 8
|
||||
|
||||
override var width = AppLoader.screenW - UIRemoCon.remoConWidth - moduleAreaHMargin
|
||||
override var height = AppLoader.screenH - moduleAreaHMargin * 2
|
||||
override var width = AppLoader.screenSize.screenW - UIRemoCon.remoConWidth - moduleAreaHMargin
|
||||
override var height = AppLoader.screenSize.screenH - moduleAreaHMargin * 2
|
||||
|
||||
|
||||
private val moduleInfoCells = ArrayList<UIItemModuleInfoCell>()
|
||||
|
||||
@@ -6,7 +6,7 @@ package net.torvald.terrarum.modulebasegame.ui
|
||||
val remoConWidth = 240
|
||||
fun getRemoConHeight(menu: ArrayList<String>) = 36 * menu.size.plus(1)
|
||||
fun getRemoConHeight(menu: Array<String>) = 36 * menu.size.plus(1)
|
||||
val menubarOffY: Int; get() = AppLoader.screenH / 2 - (AppLoader.fontGame.lineHeight * 1.5).toInt()
|
||||
val menubarOffY: Int; get() = AppLoader.terrarumAppConfig.screenH / 2 - (AppLoader.fontGame.lineHeight * 1.5).toInt()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ open class UITitleWallOfText(private val text: List<String>) : UICanvas() {
|
||||
|
||||
|
||||
private val textAreaHMargin = 48
|
||||
override var width = AppLoader.screenW - UIRemoCon.remoConWidth - textAreaHMargin
|
||||
override var height = AppLoader.screenH - textAreaHMargin * 2
|
||||
override var width = AppLoader.screenSize.screenW - UIRemoCon.remoConWidth - textAreaHMargin
|
||||
override var height = AppLoader.screenSize.screenH - textAreaHMargin * 2
|
||||
private val textArea = UIItemTextArea(this,
|
||||
UIRemoCon.remoConWidth, textAreaHMargin,
|
||||
width, height
|
||||
|
||||
@@ -50,8 +50,8 @@ class UIVitalMetre(
|
||||
|
||||
override fun updateUI(delta: Float) {
|
||||
handler.setPosition(
|
||||
AppLoader.halfScreenW,
|
||||
AppLoader.halfScreenH
|
||||
AppLoader.screenSize.halfScreenW,
|
||||
AppLoader.screenSize.halfScreenH
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -99,8 +99,8 @@ internal object WeatherMixer : RNGConsumer {
|
||||
val playerPosY = player.hitbox.centeredY
|
||||
kotlin.repeat(7) {
|
||||
val rainParticle = ParticleMegaRain(
|
||||
playerPosX + HQRNG().nextInt(AppLoader.screenW) - AppLoader.halfScreenW,
|
||||
playerPosY - AppLoader.screenH
|
||||
playerPosX + HQRNG().nextInt(AppLoader.screenSize.screenW) - AppLoader.screenSize.halfScreenW,
|
||||
playerPosY - AppLoader.screenSize.screenH
|
||||
)
|
||||
(Terrarum.ingame!! as TerrarumIngame).addParticle(rainParticle)
|
||||
}
|
||||
@@ -187,7 +187,7 @@ internal object WeatherMixer : RNGConsumer {
|
||||
batch.shader = null
|
||||
}
|
||||
batch.inUse {
|
||||
it.draw(skyboxTexture, 0f, -AppLoader.halfScreenHf, AppLoader.screenWf, AppLoader.screenHf * 2f) // because of how the linear filter works, we extend the image by two
|
||||
it.draw(skyboxTexture, 0f, -AppLoader.screenSize.halfScreenHf, AppLoader.screenSize.screenWf, AppLoader.screenSize.screenHf * 2f) // because of how the linear filter works, we extend the image by two
|
||||
}
|
||||
|
||||
// don't use shader to just fill the whole screen... frag shader will be called a million times and it's best to not burden it
|
||||
|
||||
@@ -53,7 +53,7 @@ abstract class Gen(val world: GameWorld, val seed: Long, val params: Any) {
|
||||
|
||||
data class WorldgenParams(
|
||||
val seed: Long,
|
||||
// optional parametres
|
||||
// optional parameters
|
||||
val terragenParams: TerragenParams = TerragenParams(),
|
||||
val biomegenParams: BiomegenParams = BiomegenParams()
|
||||
)
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
_G.parsecmd = function(str)
|
||||
local parsetable = {}
|
||||
local quotemode = false
|
||||
local wordbuffer = ""
|
||||
|
||||
for c = 1, #str do
|
||||
local char = str:byte(c)
|
||||
if not quotemode and char == 32 then -- quotestack is empty and char is a space
|
||||
table.insert(parsetable, wordbuffer)
|
||||
wordbuffer = ""
|
||||
elseif char == 34 then -- "
|
||||
quotemode = not quotemode
|
||||
else
|
||||
wordbuffer = wordbuffer..string.char(char)
|
||||
end
|
||||
end
|
||||
|
||||
if #wordbuffer ~= 0 then
|
||||
table.insert(parsetable, wordbuffer)
|
||||
end
|
||||
|
||||
return parsetable
|
||||
end
|
||||
|
||||
_G.TODO = function(str)
|
||||
error("Not implemented: "..str or "TODO", 2)
|
||||
end
|
||||
@@ -1,6 +0,0 @@
|
||||
local args = {...}
|
||||
if (#args ~= 2) then
|
||||
print([[usage: cp source_file target_file
|
||||
cp source_file target_directory]])
|
||||
return end
|
||||
fs.cp(os.expandPath(args[1]), os.expandPath(args[2]))
|
||||
@@ -1,257 +0,0 @@
|
||||
local args = {...}
|
||||
|
||||
os.dshenv = {}
|
||||
|
||||
--[[
|
||||
DUMBSHELL: semi sh-compatible language interpreter
|
||||
|
||||
SYNOPSIS
|
||||
dsh [option] [file]
|
||||
sh [option] [file]
|
||||
|
||||
OPTIONS
|
||||
-c string If the -c option is present, then commands are read from
|
||||
string. If there are arguments after the string, they are
|
||||
assigned to the positional parameters, starting with $0.
|
||||
|
||||
|
||||
]]
|
||||
|
||||
-- returns full path. if p starts with "/", only the p is returned
|
||||
local function expandPath(p)
|
||||
return (p:byte(1) == 47) and p or os.expandPath(p)
|
||||
end
|
||||
|
||||
local function startsFromRoot(p)
|
||||
return p:byte(1) == 47
|
||||
end
|
||||
|
||||
local function endsWithSlash(p)
|
||||
return p:byte(#p) == 47
|
||||
end
|
||||
|
||||
--__DSHDEBUG__ = 0x51621D
|
||||
|
||||
local function debug(msg)
|
||||
if __DSHDEBUG__ then print("DEBUG", msg) end
|
||||
end
|
||||
|
||||
local function printErr(msg)
|
||||
print(DLE..msg)
|
||||
end
|
||||
|
||||
local function shallowCopy(t)
|
||||
return {table.unpack(t)}
|
||||
end
|
||||
|
||||
-- BUILTINS -------------------------------------------------------------------
|
||||
|
||||
local function cd(tArgs)
|
||||
local dir = tArgs[1]
|
||||
|
||||
if (dir == nil or #dir < 1) then return end
|
||||
|
||||
local oldWorkingDir = shallowCopy(os.workingDir)
|
||||
|
||||
-- parse dir by delimeter '/'
|
||||
if (dir:byte(1) == 47) then -- if dir begins with '/'
|
||||
os.setWorkingDir(dir)
|
||||
else
|
||||
for word in string.gmatch(dir, "[^/]+") do
|
||||
|
||||
machine.println("CD word: "..word)
|
||||
|
||||
-- 'execute' directory
|
||||
-- Rules: '..' pops os.workingDir
|
||||
-- if dir begins with '/', re-build os.workingDir
|
||||
-- otherwise, push the 'word' to os.workingDir
|
||||
if (word == "..") then
|
||||
os.popWorkingDir()
|
||||
elseif (word == ".") then
|
||||
-- pass
|
||||
else
|
||||
os.pushWorkingDir(word)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- check if the directory exists
|
||||
if not fs.isDir(os.fullWorkPath()) then
|
||||
os.errorNoSuchFileOrDir("cd: "..dir)
|
||||
os.workingDir = shallowCopy(oldWorkingDir)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local function exit(tArgs)
|
||||
exitshell = true
|
||||
end
|
||||
|
||||
local function exec(tArgs)
|
||||
debug("EXECARGS\t"..table.concat(tArgs, ", "))
|
||||
|
||||
if (tArgs[1] == nil or #tArgs[1] < 1) then return end
|
||||
|
||||
local filePath = tArgs[1]
|
||||
local fullFilePath = expandPath(tArgs[1])
|
||||
local execArgs = {}
|
||||
for i, v in ipairs(tArgs) do
|
||||
if (i >= 2) then table.insert(execArgs, v) end
|
||||
end
|
||||
local execByPathFileExists = false
|
||||
local execByPathArg = ""
|
||||
|
||||
-- do some sophisticated file-matching
|
||||
-- step 1: exact file
|
||||
if fs.isFile(fullFilePath) then
|
||||
shell.run(fullFilePath, execArgs)
|
||||
-- step 2: try appending ".lua"
|
||||
elseif fs.isFile(fullFilePath..".lua") then
|
||||
shell.run(fullFilePath..".lua", execArgs)
|
||||
-- step 3: parse os.path (just like $PATH)
|
||||
-- step 3.1: exact file; step 3.2: append ".lua"
|
||||
elseif not startsFromRoot(filePath) then
|
||||
for path in string.gmatch(os.path, "[^;]+") do
|
||||
-- check if 'path' ends with '/'
|
||||
if not endsWithSlash(path) then path = path.."/" end
|
||||
|
||||
debug(path..filePath)
|
||||
|
||||
if fs.isFile(path..filePath) then
|
||||
execByPathArg = path..filePath
|
||||
execByPathFileExists = true
|
||||
break
|
||||
elseif fs.isFile(path..filePath..".lua") then
|
||||
execByPathArg = path..filePath..".lua"
|
||||
execByPathFileExists = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- step else: file not found
|
||||
if execByPathFileExists then
|
||||
shell.run(execByPathArg, execArgs)
|
||||
return EXIT_SUCCESS
|
||||
else
|
||||
if filePath:byte(1) == 46 or filePath:byte(1) == 47 then
|
||||
os.errorNoSuchFile(filePath)
|
||||
else
|
||||
os.errorCmdNotFound(filePath)
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- SYNTAX PARSER --------------------------------------------------------------
|
||||
|
||||
-- tables with functions
|
||||
local builtins = {
|
||||
cd = cd,
|
||||
exit = exit,
|
||||
exec = exec,
|
||||
clear = term.clear
|
||||
}
|
||||
|
||||
local function runcommand(str, recurse)
|
||||
if #str < 1 then return end
|
||||
|
||||
local cmdFound = false
|
||||
|
||||
-- simple cmd parse: WORD ARG1 ARG2 ARG3 ...
|
||||
local args = {}
|
||||
local command = ""
|
||||
for word in string.gmatch(str, "[^ ]+") do
|
||||
if #command < 1 then command = word -- first word will be a name of command
|
||||
else table.insert(args, word) end
|
||||
end
|
||||
|
||||
if builtins[command] then -- try for builtins table
|
||||
builtins[command](args)
|
||||
cmdFound = true
|
||||
return true
|
||||
else
|
||||
|
||||
-- FIXME: 'exec programname args' works, but not 'programname args'
|
||||
|
||||
-- try for os.dshenv.aliases
|
||||
if os.dshenv.aliases[command] then
|
||||
--builtins[os.dshenv.aliases[command]](args)
|
||||
if not recurse then
|
||||
cmdFound = runcommand(os.dshenv.aliases[command], true)
|
||||
end
|
||||
else
|
||||
-- try to launch as program
|
||||
if not recurse then
|
||||
cmdFound = runcommand("exec "..str, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- command not found (really)
|
||||
if not cmdFound then
|
||||
os.errorCmdNotFound(command)
|
||||
end
|
||||
end
|
||||
|
||||
-- END OF SYNTAX PARSER -------------------------------------------------------
|
||||
-- INIT SHELL -----------------------------------------------------------------
|
||||
|
||||
exitshell = false
|
||||
|
||||
-- load up aliases
|
||||
if fs.isFile("/etc/.dshrc") then
|
||||
fs.dofile("/etc/.dshrc")
|
||||
machine.println("[dummix/dsh.lua] Dsh aliases successfully loaded.")
|
||||
end
|
||||
|
||||
|
||||
-- END OF INIT SHELL ----------------------------------------------------------
|
||||
|
||||
-- run interpreter and quit
|
||||
if (args[1]) then
|
||||
local f = fs.open(args[1], "r")
|
||||
local line = ""
|
||||
local s = ""
|
||||
|
||||
-- treat interpreter key (#!) properly
|
||||
-- I'm assuming I was called because I'm the right one
|
||||
-- I have a full trust on "shell.run()" that it rightfully redirected to me
|
||||
--
|
||||
-- NOTE: shell redirection should only apply in interactive mode AND the input
|
||||
-- was like "./filename", or else I'm the right one. Period.
|
||||
-- (and that's how BASH works)
|
||||
repeat
|
||||
line = f.readLine()
|
||||
if line == nil then break end
|
||||
if line:sub(1,2) ~= "#!" then -- ignore line that contains hashbang
|
||||
s = s.." "..line
|
||||
end
|
||||
until line == nil
|
||||
|
||||
f.close()
|
||||
|
||||
runcommand(s)
|
||||
|
||||
exitshell = true
|
||||
end
|
||||
|
||||
|
||||
function getPromptText()
|
||||
--return DC4..os.workingDir[#os.workingDir]..DC3.."# "..DC4 -- we're root! omgwtf
|
||||
return DC4..os.fullWorkPath()..DC3.."# "..DC4 -- we're root! omgwtf
|
||||
end
|
||||
|
||||
-- interactive mode
|
||||
local time = os.date()
|
||||
print(time)
|
||||
|
||||
repeat
|
||||
term.setCursorBlink(true)
|
||||
io.write(getPromptText())
|
||||
local s = input.readLine()
|
||||
runcommand(s)
|
||||
until exitshell
|
||||
|
||||
collectgarbage()
|
||||
return EXIT_SUCCESS
|
||||
@@ -1,170 +0,0 @@
|
||||
--[[
|
||||
LESS IS MORE
|
||||
|
||||
SYNOPSIS:
|
||||
lessismore [filename]
|
||||
less [filename]
|
||||
more [filename]
|
||||
]]
|
||||
local args = {...}
|
||||
|
||||
displayLineNo = true
|
||||
|
||||
local prompt = function()
|
||||
term.setForeCol(3)
|
||||
|
||||
term.emitString(" scroll ", 3, term.height())
|
||||
term.emitString(" quit", 14, term.height())
|
||||
|
||||
term.setForeCol(1)
|
||||
term.emit(18, 1, term.height())
|
||||
term.emit(29, 2, term.height())
|
||||
term.emit(81, 13, term.height())
|
||||
|
||||
term.setForeCol(3)
|
||||
term.setBackCol(0)
|
||||
end
|
||||
|
||||
local function printUsage()
|
||||
print("More: no file specified.")
|
||||
print("Usage: more [filename]")
|
||||
end
|
||||
|
||||
if args[1] == nil or #args[1] <= 0 then printUsage() return end
|
||||
filepath = os.expandPath(args[1])
|
||||
if not fs.isFile(filepath) then os.errorNoSuchFile(filepath) return end
|
||||
|
||||
function log10(n)
|
||||
if n < 1 then return 0
|
||||
elseif n < 10 then return 1
|
||||
elseif n < 100 then return 2
|
||||
elseif n < 1000 then return 3
|
||||
elseif n < 10000 then return 4
|
||||
elseif n < 100000 then return 5
|
||||
elseif n < 1000000 then return 6
|
||||
elseif n < 10000000 then return 7
|
||||
elseif n < 100000000 then return 8
|
||||
elseif n < 1000000000 then return 9
|
||||
else return 10
|
||||
end
|
||||
end
|
||||
|
||||
----------------
|
||||
-- fetch text --
|
||||
----------------
|
||||
lines = {}
|
||||
displayHeight = term.height() - 1 -- bottom one line for prompt
|
||||
|
||||
local file = fs.open(filepath, "r")
|
||||
local line = ""
|
||||
repeat
|
||||
line = file.readLine()
|
||||
table.insert(lines, line)
|
||||
until line == nil
|
||||
|
||||
lineNoLen = log10(#lines)
|
||||
|
||||
-----------
|
||||
-- input --
|
||||
-----------
|
||||
local function scrollDownAction(n)
|
||||
term.clearLine() -- prevent prompt to be scrolled
|
||||
curY = curY + n
|
||||
|
||||
-- prevent overscroll
|
||||
if (curY > #lines - displayHeight) then
|
||||
curY = #lines - displayHeight
|
||||
end
|
||||
|
||||
term.scroll(n)
|
||||
for i = 0, n - 1 do
|
||||
drawString(curY + displayHeight - i, displayHeight - i) -- redraw newline
|
||||
end
|
||||
end
|
||||
|
||||
local function scrollUpAction(n)
|
||||
curY = curY - n
|
||||
|
||||
-- prevent overscroll
|
||||
if (curY < 1) then
|
||||
curY = 1
|
||||
end
|
||||
|
||||
term.scroll(-n)
|
||||
for i = 0, n - 1 do
|
||||
drawString(curY + i, i + 1) -- redraw prev line
|
||||
end
|
||||
term.setCursor(n, term.height())
|
||||
end
|
||||
|
||||
local function processInput()
|
||||
if input.isKeyDown(keys.q) then quit = true end
|
||||
if input.isKeyDown(keys.down) and curY < #lines - displayHeight then
|
||||
scrollDownAction(1)
|
||||
prompt()
|
||||
elseif input.isKeyDown(keys.pageDown) and curY < #lines - displayHeight then
|
||||
scrollDownAction(8)
|
||||
prompt()
|
||||
elseif input.isKeyDown(keys.up) and curY > 1 then
|
||||
scrollUpAction(1)
|
||||
term.clearLine() -- make space for prompt
|
||||
prompt()
|
||||
elseif input.isKeyDown(keys.pageUp) and curY > 1 then
|
||||
scrollUpAction(8)
|
||||
term.clearLine() -- make space for prompt
|
||||
prompt()
|
||||
end
|
||||
|
||||
machine.sleep(50)
|
||||
end
|
||||
|
||||
-------------
|
||||
-- display --
|
||||
-------------
|
||||
displayWidth = term.width() - 1 - (displayLineNo and lineNoLen or 0)
|
||||
|
||||
function drawString(lineNo, y)
|
||||
local string = (lineNo > #lines) and ""
|
||||
or lines[lineNo]:sub(curX, curX + displayWidth)
|
||||
|
||||
if (displayLineNo) then
|
||||
local lineNoStr = DC3..string.format("%"..lineNoLen.."d", curY + y - 1)..DC4
|
||||
string = lineNoStr..string
|
||||
end
|
||||
|
||||
local strDrawX = curX
|
||||
term.emitString(string, strDrawX, y)
|
||||
end
|
||||
|
||||
function redrawText()
|
||||
for i = curY, #lines do
|
||||
if (i >= displayHeight + curY) then break end
|
||||
drawString(i, i - curY + 1)
|
||||
end
|
||||
end
|
||||
|
||||
curY = 1
|
||||
curX = 1
|
||||
quit = false
|
||||
|
||||
if term.isTeletype() then
|
||||
for _, l in ipairs(line) do
|
||||
term.print(l)
|
||||
end
|
||||
quit = true
|
||||
end
|
||||
|
||||
|
||||
term.clear()
|
||||
term.setCursorBlink(false)
|
||||
redrawText()
|
||||
|
||||
repeat
|
||||
prompt()
|
||||
|
||||
term.setCursor(1, term.height())
|
||||
processInput()
|
||||
until quit
|
||||
|
||||
term.clearLine()
|
||||
return
|
||||
@@ -1,10 +0,0 @@
|
||||
local args = {...}
|
||||
|
||||
local dir = os.fullWorkPath()--(#args < 1) and os.fullWorkPath() or args[1]
|
||||
|
||||
local list = fs.list("/"..dir)
|
||||
table.sort(list)
|
||||
|
||||
for _, v in ipairs(list) do
|
||||
print(v)
|
||||
end
|
||||
@@ -1,76 +0,0 @@
|
||||
local args = {...}
|
||||
local _APPVERSION = 0.3
|
||||
--[[
|
||||
MOONSHELL: basically just lua.lua
|
||||
|
||||
SYNOPSIS
|
||||
msh [file]
|
||||
|
||||
msh: Runs shell in interactive mode
|
||||
msh [file]: Try to execute file as Lua script
|
||||
|
||||
]]
|
||||
|
||||
-- run interpreter and quit
|
||||
if (args[1]) then
|
||||
local f = fs.open(args[1], "r")
|
||||
local line = ""
|
||||
local s = ""
|
||||
|
||||
-- treat interpreter key (#!) properly
|
||||
-- I'm assuming I was called because I'm the right one
|
||||
-- I have a full trust on "shell.run()" that it rightfully redirected to me
|
||||
repeat
|
||||
line = f.readLine()
|
||||
if line == nil then break end
|
||||
if line:sub(1,2) ~= "#!" then -- ignore line that contains hashbang
|
||||
s = s.." "..line
|
||||
end
|
||||
until line == nil
|
||||
|
||||
f.close()
|
||||
|
||||
xpcall(
|
||||
function() _G.runscript(s, "="..args[1]) end,
|
||||
function(err) print(DLE..err) end
|
||||
)
|
||||
|
||||
goto terminate
|
||||
end
|
||||
|
||||
-- interactive mode. This is a copy of BOOT.lua
|
||||
run = shell.run
|
||||
|
||||
print("Moonshell "..DC2.._APPVERSION..DC4..", running "..DC2.._VERSION..DC4)
|
||||
print("Lua is copyrighted (C) 1994-2013 Lua.org, PUC-Rio")
|
||||
print("Run run(path) to execute program on 'path'.")
|
||||
print("Run exit() to quit.")
|
||||
|
||||
while not machine.isHalted() do
|
||||
term.setCursorBlink(true)
|
||||
|
||||
io.write(DC3.."lua"..computer.prompt)
|
||||
|
||||
local s = input.readLine()
|
||||
|
||||
if s == "exit()" then break end
|
||||
|
||||
xpcall(
|
||||
function()
|
||||
if s:byte(1) == 61 then -- print out value
|
||||
s1 = string.sub(s, 2)
|
||||
_G.runscript("print(tostring("..s1.."))\n", "=stdin")
|
||||
else
|
||||
_G.runscript(s, "=stdin")
|
||||
end
|
||||
end,
|
||||
function(err) print(DLE..err) end -- it catches logical errors
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
::terminate::
|
||||
collectgarbage()
|
||||
return EXIT_SUCCESS
|
||||
@@ -1,6 +0,0 @@
|
||||
local args = {...}
|
||||
if (#args ~= 2) then
|
||||
print([[usage: mv source target
|
||||
mv source ... directory]])
|
||||
return end
|
||||
fs.mv(os.expandPath(args[1]), os.expandPath(args[2]))
|
||||
@@ -1 +0,0 @@
|
||||
fs.dofile("/etc/_boot.lua")
|
||||
@@ -1,8 +0,0 @@
|
||||
-- dsh aliases
|
||||
os.dshenv.aliases = {
|
||||
lua = "msh",
|
||||
sh = "dsh",
|
||||
shutdown = "exit", -- should be a separate program that actually halts the system
|
||||
less = "lessismore",
|
||||
more = "lessismore"
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
--[[
|
||||
Bootloader for Operation System
|
||||
|
||||
Created by minjaesong on 2016-09-21
|
||||
]]
|
||||
|
||||
-- check directories
|
||||
dirlist = {
|
||||
"/boot",
|
||||
"/bin", -- crucial binaries (e.g. cat, ls, sh(ell), cp, rm, mkdir), it's loosely an UNIX system
|
||||
"/usr",
|
||||
"/usr/bin", -- more utilities and binaries (e.g. less/more, nano)
|
||||
"/home", -- home directory for user
|
||||
"/home/bin", -- user-installed apps
|
||||
"/media" -- auto mounts (e.g. "/media/fd1", "/media/hdb", "/media/sda")
|
||||
}
|
||||
-- just make them if they don't exist
|
||||
for _, dir in ipairs(dirlist) do
|
||||
fs.mkdir(dir)
|
||||
end
|
||||
|
||||
|
||||
if not _G.os then _G.os = {} end
|
||||
os.version = "0.0"
|
||||
os.EXIT_SUCCESS = 0
|
||||
os.workingDir = {"home"}
|
||||
os.path = "home/bin/;/usr/bin/;/bin/" -- infamous $path
|
||||
os.fullWorkPath = function()
|
||||
local ret = table.concat(os.workingDir, "/") -- there's nothing wrong with this.
|
||||
|
||||
if computer.verbose then
|
||||
machine.println("workingDir size: "..#os.workingDir)
|
||||
machine.println("fullWorkPath: "..ret)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
os.setWorkingDir = function(s)
|
||||
if s:byte(#s) == 47 then
|
||||
s = string.sub(s, 1, #s - 1)
|
||||
end
|
||||
if s:byte(1) == 47 then
|
||||
s = string.sub(s, 2, #s)
|
||||
end
|
||||
|
||||
if computer.verbose then
|
||||
machine.println("renew working dir; '"..s.."'")
|
||||
end
|
||||
|
||||
local oldWorkingDir = {table.unpack(os.workingDir)}
|
||||
|
||||
-- renew working directory, EVEN IF s STARTS WITH '/'
|
||||
local t = {}
|
||||
for word in string.gmatch(s, "[^/]+") do
|
||||
table.insert(t, word)
|
||||
end
|
||||
|
||||
os.workingDir = t
|
||||
|
||||
-- check if the directory exists
|
||||
if not fs.isDir(s) then
|
||||
os.errorNoSuchFileOrDir("cd: "..s)
|
||||
os.workingDir = oldWorkingDir
|
||||
return
|
||||
end
|
||||
end
|
||||
os.pushWorkingDir = function(s)
|
||||
if (s == "..") then
|
||||
error("cannot push '..' to working directory.")
|
||||
else
|
||||
table.insert(os.workingDir, s)
|
||||
|
||||
if computer.verbose then
|
||||
machine.println("pushing '"..s.."' to working directory.")
|
||||
end
|
||||
end
|
||||
end
|
||||
os.popWorkingDir = function()
|
||||
if (#os.workingDir > 1) then
|
||||
table.remove(os.workingDir)
|
||||
end
|
||||
end
|
||||
-- @param "path/of/arbitrary"
|
||||
-- @return /working/dir/path/of/arbitrary
|
||||
-- input path's trailing '/' is PRESERVED.
|
||||
os.expandPath = function(p)
|
||||
-- not applicable if the path starts with /
|
||||
if p:byte(1) == 47 or p:byte(1) == 92 then
|
||||
return p
|
||||
end
|
||||
|
||||
return os.fullWorkPath().."/"..p
|
||||
end
|
||||
os.defaultshell = "/bin/dsh.lua"
|
||||
os.clock = function() return machine.milliTime() / 1000 end -- uptime of the computer, in seconds
|
||||
|
||||
|
||||
function os.errorCmdNotFound(cmd)
|
||||
print(cmd..": command not found")
|
||||
end
|
||||
|
||||
function os.errorNoSuchFile(cmd)
|
||||
print(cmd..": No such file")
|
||||
end
|
||||
|
||||
function os.errorNoSuchFileOrDir(cmd)
|
||||
print(cmd..": No such file or directory")
|
||||
end
|
||||
function os.errorIsDir(cmd)
|
||||
print(cmd.." is a directory")
|
||||
end
|
||||
|
||||
|
||||
-- run default shell
|
||||
fs.dofile(os.defaultshell)
|
||||
|
||||
-- quit properly
|
||||
shell.status = shell.halt
|
||||
@@ -1,12 +0,0 @@
|
||||
NAME
|
||||
msh - the Moonshell
|
||||
|
||||
SYNOPSIS
|
||||
msh [file]
|
||||
|
||||
COPYRIGHT
|
||||
See copyright information for the game you are actually playing.
|
||||
|
||||
DESCRIPTION
|
||||
Msh is a Lua prompt that reads lua script from the user, or execute
|
||||
a file user had put as an argument.
|
||||
@@ -1,58 +0,0 @@
|
||||
print("")
|
||||
print("Starting Lunados...")
|
||||
|
||||
------------------
|
||||
--- INITIALISE ---
|
||||
------------------
|
||||
|
||||
require "common"
|
||||
|
||||
local prompt = "> "
|
||||
|
||||
_G.dos = {}
|
||||
_G.dos.version = "0.1"
|
||||
_G.dos.copyright = "Copyright (C) 2019 CuriousTorvald. Distributed under GNU GPL 3."
|
||||
_G.dos.currentpath = {}
|
||||
|
||||
--- appends the directory into the current path
|
||||
_G.dos.currentpath.push = function(name)
|
||||
table.insert(dos.path, name)
|
||||
end
|
||||
|
||||
--- removes the current directory from the current path and returns what has been removed
|
||||
_G.dos.currentpath.pop = function()
|
||||
return table.remove(dos.path)
|
||||
end
|
||||
|
||||
_G.dos.envpath = "C:\\lunados\\bin;" -- must be a sting and not a table
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
--- LET THE SHOW BEGIN ---
|
||||
--------------------------
|
||||
|
||||
print("Lunados Version "..dos.version)
|
||||
print(dos.copyright)
|
||||
|
||||
--- PARSE AND RUN COMMANDS ---
|
||||
|
||||
local exit = false
|
||||
|
||||
while not exit do
|
||||
io.write(table.concat(dos.path, '\\'))
|
||||
io.write(prompt)
|
||||
local cmd = io.read()
|
||||
local commands = parsecmd(cmd)
|
||||
|
||||
TODO()
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,47 +0,0 @@
|
||||
--[[
|
||||
From https://github.com/prapin/LuaBrainFuck/blob/master/brainfuck.lua
|
||||
|
||||
LuaBrainFuck License
|
||||
--------------------
|
||||
|
||||
LuaBrainFuck is placed under the same license as Lua itself,
|
||||
so licensed under terms of the MIT license reproduced below.
|
||||
This means that the library is free software and can be used for both academic
|
||||
and commercial purposes at absolutely no cost.
|
||||
|
||||
===============================================================================
|
||||
|
||||
Copyright (C) 2012 Patrick Rapin, CH-1543 Grandcour
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
===============================================================================
|
||||
|
||||
(end of COPYRIGHT)
|
||||
|
||||
Example usage: require "brainfuck" "+++>>> your BF code here <<<---"
|
||||
]]
|
||||
return function(s)
|
||||
local subst = {["+"]="v=v+1 ", ["-"]="v=v-1 ", [">"]="i=i+1 ", ["<"]="i=i-1 ",
|
||||
["."] = "w(v)", [","]="v=r()", ["["]="while v~=0 do ", ["]"]="end "}
|
||||
local env = setmetatable({ i=0, t=setmetatable({},{__index=function() return 0 end}),
|
||||
r=function() return io.read(1):byte() end, w=function(c) io.write(string.char(c)) end },
|
||||
{__index=function(t,k) return t.t[t.i] end, __newindex=function(t,k,v) t.t[t.i]=v end })
|
||||
load(s:gsub("[^%+%-<>%.,%[%]]+",""):gsub(".", subst), "brainfuck", "t", env)()
|
||||
end
|
||||
@@ -1,159 +0,0 @@
|
||||
--[[
|
||||
-- ComputerCraft API compatibility layer
|
||||
Usage: require("CCAPI")
|
||||
|
||||
Created by minjaesong on 2016-09-16.
|
||||
--]]
|
||||
|
||||
--------------
|
||||
-- PREAMBLE --
|
||||
--------------
|
||||
|
||||
if term.isTeletype() then error("This is a teletype; cannot use CCAPI layer") end
|
||||
|
||||
|
||||
table.insert(computer.loadedCLayer, "CCAPI")
|
||||
|
||||
|
||||
local function intLog2(i)
|
||||
if i == 0 then return 0 end
|
||||
local log = 0
|
||||
if bit32.band(i, 0xffff0000) ~= 0 then i = bit32.rshift(i, 16) log = 16 end
|
||||
if i >= 256 then i = bit32.rshift(i, 8) log = log + 8 end
|
||||
if i >= 16 then i = bit32.rshift(i, 8) log = log + 4 end
|
||||
if i >= 4 then i = bit32.rshift(i, 8) log = log + 2 end
|
||||
return log + bit32.rshift(i, 1)
|
||||
end
|
||||
|
||||
|
||||
-----------------------
|
||||
-- BIT API Extension --
|
||||
-----------------------
|
||||
|
||||
bit.blshift = bit32.lshift(n, bits)
|
||||
bit.brshift = bit32.arshift(n, bits)
|
||||
bit.blogic_rshift = bit32.rshift(n, bits)
|
||||
|
||||
|
||||
----------------
|
||||
-- COLORS API --
|
||||
----------------
|
||||
|
||||
_G.colors = {}
|
||||
|
||||
colors.white = 0x1
|
||||
colors.orange = 0x2
|
||||
colors.magenta = 0x4
|
||||
colors.lightBlue = 0x8
|
||||
colors.yellow = 0x10
|
||||
colors.lime = 0x20
|
||||
colors.pink = 0x40
|
||||
colors.gray = 0x80
|
||||
colors.grey = 0x80
|
||||
colors.lightGray = 0x100
|
||||
colors.lightGrey = 0x100
|
||||
colors.cyan = 0x200
|
||||
colors.purple = 0x400
|
||||
colors.blue = 0x800
|
||||
colors.brown = 0x1000
|
||||
colors.green = 0x2000
|
||||
colors.red = 0x4000
|
||||
colors.black = 0x8000
|
||||
|
||||
local function normaliseCCcol(cccol)
|
||||
if cccol >= 0x1 and cccol <= 0xFFFF then
|
||||
return intLog2(cccol)
|
||||
else
|
||||
error("invalid CC Colors: "..cccol)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
_G.colours = _G.colors
|
||||
|
||||
|
||||
--------------
|
||||
-- TERM API --
|
||||
--------------
|
||||
|
||||
-- paint_index -> Terminal colour index
|
||||
local ccToGameCol = {--pink
|
||||
1, 5, 7, 10, 4, 11, 15, 2, 3, 10, 8, 9, 14, 12, 6, 0
|
||||
}
|
||||
|
||||
-- "a" -> 10, "3" -> 3
|
||||
local function cHexToInt(c)
|
||||
if type(c) == "number" then -- char
|
||||
if c >= 48 and c <= 57 then
|
||||
return c - 48
|
||||
elseif c >= 65 and c <= 70 then
|
||||
return c - 65 + 10
|
||||
elseif c >= 97 and c <= 102 then
|
||||
return c - 97 + 10
|
||||
else
|
||||
return 0
|
||||
end
|
||||
elseif type(c) == "string" then -- single-letter string
|
||||
if c:byte(1) >= 48 and c:byte(1) <= 57 then
|
||||
return c:byte(1) - 48
|
||||
elseif c:byte(1) >= 65 and c:byte(1) <= 70 then
|
||||
return c:byte(1) - 65 + 10
|
||||
elseif c:byte(1) >= 97 and c:byte(1) <= 102 then
|
||||
return c:byte(1) - 97 + 10
|
||||
else
|
||||
--error("unrepresentable: " .. c)
|
||||
-- return black, as defined in http://www.computercraft.info/wiki/Term.blit
|
||||
return 0
|
||||
end
|
||||
else
|
||||
error("bad argument (string or number expected, got "..type(c)..")")
|
||||
end
|
||||
end
|
||||
|
||||
-- str, str, str
|
||||
term.blit = function(text, foreCol, backCol)
|
||||
assert(
|
||||
type(text) == "string" and type(backCol) == "string" and type(foreCol) == "string",
|
||||
"bad argument: (string, string, string expected, got "..type(text)..", "..type(foreCol)..", "..type(backCol)..")"
|
||||
)
|
||||
if #text ~= #foreCol or #text ~= #backCol or #foreCol ~= #backCol then
|
||||
error("arguments must be the same length")
|
||||
end
|
||||
|
||||
for i = 1, #text do
|
||||
term.setForeCol(ccToGameCol[1 + cHexToInt(foreCol:byte(i))])
|
||||
term.setBackCol(ccToGameCol[1 + cHexToInt(backCol:byte(i))])
|
||||
term.emit(text:byte(i))
|
||||
term.moveCursor(term.getX() + 1, term.getY())
|
||||
end
|
||||
end
|
||||
|
||||
term.getCursorPos = term.getCursor
|
||||
term.setCursorPos = term.moveCursor
|
||||
term.setCursorBlink = term.blink
|
||||
term.isColor = term.isCol
|
||||
term.getSize = term.size
|
||||
term.setTextColor = function(cccol) term.setForeCol(ccToGameCol[normaliseCCcol(cccol)]) end
|
||||
term.getTextColor = term.getForeCol
|
||||
term.setBackgroundColor = function(cccol) term.setBackCol(ccToGameCol[normaliseCCcol(cccol)]) end
|
||||
term.getBackgroundColor = term.getBackCol
|
||||
|
||||
|
||||
--------------------
|
||||
-- FILESYSTEM API --
|
||||
--------------------
|
||||
|
||||
fs.makeDir = fs.mkdir
|
||||
fs.move = fs.mv
|
||||
fs.copy = fs.cp
|
||||
fs.delete = fs.rm
|
||||
fs.combine = fs.concat
|
||||
fs.getDir = fs.parent
|
||||
fs.run = fs.dofile
|
||||
|
||||
|
||||
------------------
|
||||
-- DOWN AND OUT --
|
||||
------------------
|
||||
|
||||
if computer.verbose then print("ComputerCraft compatibility layer successfully loaded.") end
|
||||
@@ -1,434 +0,0 @@
|
||||
--[[
|
||||
Created by minjaesong on 2016-09-15.
|
||||
--]]
|
||||
|
||||
-------------
|
||||
-- ALIASES --
|
||||
-------------
|
||||
|
||||
--_G.io = {} -- we make our own sandbox'd system
|
||||
|
||||
--[[fs.dofile = function(p, ...)
|
||||
local f = fs.open(p, "r")
|
||||
local s = f.readAll()
|
||||
_G.runscript(s, "="..p, ...)
|
||||
end]] -- implementation moved to BOOT.lua
|
||||
|
||||
_G.loadstring = _G.load
|
||||
|
||||
--_G.dofile = function(f) fs.dofile(f) end
|
||||
|
||||
|
||||
fs.fetchText = function(p)
|
||||
local file = fs.open(p, "r")
|
||||
local text = file.readAll()
|
||||
file.close()
|
||||
return text
|
||||
end
|
||||
|
||||
-----------------------------------------
|
||||
-- INPUTSTREAM AND SCANNER (java-like) --
|
||||
-----------------------------------------
|
||||
--[[
|
||||
In whatever code that actually runs everything (computer),
|
||||
there must be:
|
||||
|
||||
override fun keyPressed(key: Int, c: Char) {
|
||||
super.keyPressed(key, c)
|
||||
vt.keyPressed(key, c)
|
||||
|
||||
if (key == Key.RETURN) {
|
||||
val input = vt.closeInputString()
|
||||
}
|
||||
}
|
||||
|
||||
...it basically says to close the input if RETURN is hit,
|
||||
and THIS exact part will close the input for this function.
|
||||
]]
|
||||
_G.__scanforline__ = function(echo) -- pass '1' to not echo; pass nothing to echo
|
||||
machine.closeInputString()
|
||||
machine.openInput(echo or 0)
|
||||
_G.__scanMode__ = "line"
|
||||
local s
|
||||
repeat -- we can do this ONLY IF lua execution process is SEPARATE THREAD
|
||||
s = machine.__readFromStdin()
|
||||
until s
|
||||
-- input is closed when RETURN is hit. See above comments.
|
||||
return s
|
||||
end
|
||||
|
||||
-- use Keys API to identify the keycode
|
||||
--[[_G.__scanforkey__ = function(echo) -- pass '1' to not echo; pass nothing to echo
|
||||
machine.closeInputString()
|
||||
machine.openInput(echo or 0)
|
||||
_G.__scanMode__ = "a_key"
|
||||
local key
|
||||
repeat -- we can do this ONLY IF lua execution process is SEPARATE THREAD
|
||||
key = machine.getLastKeyPress()
|
||||
until key
|
||||
-- input is closed when any key is hit. See above comments.
|
||||
return key
|
||||
end]] -- DELETED: use _G.input.isKeyDown(keycode)
|
||||
|
||||
--- ---
|
||||
-- IO IMPLEMENTATION --
|
||||
--- ---
|
||||
|
||||
|
||||
io.__openfile__ = "stdin"
|
||||
io.stdin = "stdin"
|
||||
io.stdout = "stdout"
|
||||
io.stderr = "stderr"
|
||||
|
||||
io.open = fs.open
|
||||
|
||||
io.input = function(luafile)
|
||||
io.__openfile__ = luafile
|
||||
end
|
||||
|
||||
io.read = function(option)
|
||||
if io.__openfile__ == "stdin" then
|
||||
local input = {}
|
||||
|
||||
-- RETURN not hit
|
||||
while true do
|
||||
local inkey = machine.__readFromStdin()
|
||||
if inkey == 13 or inkey == 10 then
|
||||
break
|
||||
elseif inkey == 8 or inkey == 127 then
|
||||
io.write(string.char(inkey))
|
||||
table.remove(input)
|
||||
elseif inkey > 0 then
|
||||
io.write(string.char(inkey))
|
||||
table.insert(input, string.char(inkey))
|
||||
end
|
||||
end
|
||||
-- RETURN finally hit
|
||||
io.write("\n")
|
||||
|
||||
return table.concat(input)
|
||||
end
|
||||
|
||||
function _readAll()
|
||||
return io.open(io.__openfile__).readAll()
|
||||
end
|
||||
|
||||
function _readLine()
|
||||
return io.open(io.__openfile__).readLine()
|
||||
end
|
||||
|
||||
options = {}
|
||||
options["*n"] = function() error("Read number is not supported, yet!") end--_readNumber
|
||||
options["*a"] = _readAll
|
||||
options["*l"] = _readLine
|
||||
end
|
||||
|
||||
-----------------
|
||||
-- PRINTSTREAM --
|
||||
-----------------
|
||||
|
||||
-- only useful when IO is "opening" stdin
|
||||
--[[io.write = function(...)
|
||||
local args = {...}
|
||||
for _, v in ipairs(args) do
|
||||
local s
|
||||
if v == nil then
|
||||
s = "nil"
|
||||
else
|
||||
s = tostring(v)
|
||||
end
|
||||
term.write(s)
|
||||
end
|
||||
end]]
|
||||
-- for some reason, inputstream above kills 'print' function.
|
||||
-- So we rewrite it.
|
||||
--[[_G.print = function(...) -- dependent on above io.write reimpl
|
||||
local args = {...}
|
||||
|
||||
io.write(args[1])
|
||||
|
||||
if (#args > 1) then
|
||||
for i = 2, #args do
|
||||
io.write("\t")
|
||||
io.write(args[i])
|
||||
end
|
||||
end
|
||||
|
||||
io.write("\n")
|
||||
end]]
|
||||
|
||||
|
||||
---------------
|
||||
-- SHELL API --
|
||||
---------------
|
||||
|
||||
_G.shell = {}
|
||||
shell.status = shell.ok
|
||||
|
||||
-- run a script with path (string) and argstable (table)
|
||||
shell.run = function(path, argstable)
|
||||
-- check for interpreter key "#!"
|
||||
local f = fs.open(path, "r")
|
||||
local s = f.readAll()
|
||||
f.close()
|
||||
|
||||
if s:sub(1,2) == "#!" then
|
||||
local interpreter = s:sub(3)
|
||||
if not argstable then
|
||||
xpcall(function() fs.dofile(interpreter..".lua", path) end, function(err) print(DLE..err) end)
|
||||
else
|
||||
xpcall(function() fs.dofile(interpreter..".lua", path, table.unpack(argstable)) end, function(err) print(DLE..err) end)
|
||||
end
|
||||
else
|
||||
if not argstable then
|
||||
xpcall(function() fs.dofile(path) end, function(err) print(DLE..err) end)
|
||||
else
|
||||
xpcall(function() fs.dofile(path, table.unpack(argstable)) end, function(err) print(DLE..err) end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
shell.ok = 0
|
||||
shell.halt = 127
|
||||
|
||||
|
||||
--------------
|
||||
-- HEXUTILS --
|
||||
--------------
|
||||
|
||||
_G.hexutils = {}
|
||||
|
||||
_G.hexutils.toHexString = function(byteString)
|
||||
assert(type(byteString) == "string", error("Expected string."))
|
||||
|
||||
-- speedup
|
||||
local function iToHex(i)
|
||||
if i == 0 then return "0"
|
||||
elseif i == 1 then return "1"
|
||||
elseif i == 2 then return "2"
|
||||
elseif i == 3 then return "3"
|
||||
elseif i == 4 then return "4"
|
||||
elseif i == 5 then return "5"
|
||||
elseif i == 6 then return "6"
|
||||
elseif i == 7 then return "7"
|
||||
elseif i == 8 then return "8"
|
||||
elseif i == 9 then return "9"
|
||||
elseif i == 10 then return "a"
|
||||
elseif i == 11 then return "b"
|
||||
elseif i == 12 then return "c"
|
||||
elseif i == 13 then return "d"
|
||||
elseif i == 14 then return "e"
|
||||
elseif i == 15 then return "f"
|
||||
else error("unrepresentable: " .. i)
|
||||
end
|
||||
end
|
||||
|
||||
local ret = ""
|
||||
|
||||
for i = 1, #byteString do
|
||||
local c = byteString:byte(i)
|
||||
local msb = iToHex(bit32.rshift(c, 4) % 16)
|
||||
local lsb = iToHex(c % 16)
|
||||
|
||||
ret = ret .. (msb .. lsb)
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
|
||||
--------------
|
||||
-- KEYS API --
|
||||
--------------
|
||||
-- ComputerCraft compliant
|
||||
local keycodeNumToName = {
|
||||
["30"] = "a",
|
||||
["48"] = "b",
|
||||
["46"] = "c",
|
||||
["32"] = "d",
|
||||
["18"] = "e",
|
||||
["33"] = "f",
|
||||
["34"] = "g",
|
||||
["35"] = "h",
|
||||
["23"] = "i",
|
||||
["36"] = "j",
|
||||
["37"] = "k",
|
||||
["38"] = "l",
|
||||
["50"] = "m",
|
||||
["49"] = "n",
|
||||
["24"] = "o",
|
||||
["25"] = "p",
|
||||
["16"] = "q",
|
||||
["19"] = "r",
|
||||
["31"] = "s",
|
||||
["20"] = "t",
|
||||
["22"] = "u",
|
||||
["47"] = "v",
|
||||
["17"] = "w",
|
||||
["45"] = "x",
|
||||
["21"] = "y",
|
||||
["44"] = "z",
|
||||
["2"] = "one",
|
||||
["3"] = "two",
|
||||
["4"] = "three",
|
||||
["5"] = "four",
|
||||
["6"] = "five",
|
||||
["7"] = "six",
|
||||
["8"] = "seven",
|
||||
["9"] = "eight",
|
||||
["10"] = "nine",
|
||||
["11"] = "zero",
|
||||
["12"] = "minus",
|
||||
["13"] = "equals",
|
||||
["14"] = "backspace",
|
||||
["15"] = "tab",
|
||||
["26"] = "leftBracket",
|
||||
["27"] = "rightBracket",
|
||||
["28"] = "enter",
|
||||
["29"] = "leftCtrl",
|
||||
["39"] = "semiColon",
|
||||
["40"] = "apostrophe",
|
||||
["41"] = "grave",
|
||||
["42"] = "leftShift",
|
||||
["43"] = "backslash",
|
||||
["51"] = "comma",
|
||||
["52"] = "period",
|
||||
["53"] = "slash",
|
||||
["54"] = "rightShift",
|
||||
["55"] = "multiply",
|
||||
["56"] = "leftAlt",
|
||||
["57"] = "space",
|
||||
["58"] = "capsLock",
|
||||
["59"] = "f1",
|
||||
["60"] = "f2",
|
||||
["61"] = "f3",
|
||||
["62"] = "f4",
|
||||
["63"] = "f5",
|
||||
["64"] = "f6",
|
||||
["65"] = "f7",
|
||||
["66"] = "f8",
|
||||
["67"] = "f9",
|
||||
["68"] = "f10",
|
||||
["69"] = "numLock",
|
||||
["70"] = "scollLock",
|
||||
["87"] = "f11",
|
||||
["88"] = "f12",
|
||||
["89"] = "f13",
|
||||
["90"] = "f14",
|
||||
["91"] = "f15",
|
||||
["144"] = "cimcumflex",
|
||||
["145"] = "at",
|
||||
["146"] = "colon",
|
||||
["147"] = "underscore",
|
||||
["157"] = "rightCtrl",
|
||||
["184"] = "rightAlt",
|
||||
["197"] = "pause",
|
||||
["199"] = "home",
|
||||
["200"] = "up",
|
||||
["201"] = "pageUp",
|
||||
["203"] = "left",
|
||||
["205"] = "right",
|
||||
["207"] = "end",
|
||||
["208"] = "down",
|
||||
["209"] = "pageDown",
|
||||
["210"] = "insert",
|
||||
["211"] = "delete",
|
||||
["219"] = "leftCommand"
|
||||
}
|
||||
|
||||
_G.keys = {
|
||||
["a"] = 30,
|
||||
["b"] = 48,
|
||||
["c"] = 46,
|
||||
["d"] = 32,
|
||||
["e"] = 18,
|
||||
["f"] = 33,
|
||||
["g"] = 34,
|
||||
["h"] = 35,
|
||||
["i"] = 23,
|
||||
["j"] = 36,
|
||||
["k"] = 37,
|
||||
["l"] = 38,
|
||||
["m"] = 50,
|
||||
["n"] = 49,
|
||||
["o"] = 24,
|
||||
["p"] = 25,
|
||||
["q"] = 16,
|
||||
["r"] = 19,
|
||||
["s"] = 31,
|
||||
["t"] = 20,
|
||||
["u"] = 22,
|
||||
["v"] = 47,
|
||||
["w"] = 17,
|
||||
["x"] = 45,
|
||||
["y"] = 21,
|
||||
["z"] = 44,
|
||||
["one"] = 2,
|
||||
["two"] = 3,
|
||||
["three"] = 4,
|
||||
["four"] = 5,
|
||||
["five"] = 6,
|
||||
["six"] = 7,
|
||||
["seven"] = 8,
|
||||
["eight"] = 9,
|
||||
["nine"] = 10,
|
||||
["zero"] = 11,
|
||||
["minus"] = 12,
|
||||
["equals"] = 13,
|
||||
["backspace"] = 14,
|
||||
["tab"] = 15,
|
||||
["leftBracket"] = 26,
|
||||
["rightBracket"] = 27,
|
||||
["enter"] = 28,
|
||||
["leftCtrl"] = 29,
|
||||
["semiColon"] = 39,
|
||||
["apostrophe"] = 40,
|
||||
["grave"] = 41,
|
||||
["leftShift"] = 42,
|
||||
["backslash"] = 43,
|
||||
["comma"] = 51,
|
||||
["period"] = 52,
|
||||
["slash"] = 53,
|
||||
["rightShift"] = 54,
|
||||
["multiply"] = 55,
|
||||
["leftAlt"] = 56,
|
||||
["space"] = 57,
|
||||
["capsLock"] = 58,
|
||||
["f1"] = 59,
|
||||
["f2"] = 60,
|
||||
["f3"] = 61,
|
||||
["f4"] = 62,
|
||||
["f5"] = 63,
|
||||
["f6"] = 64,
|
||||
["f7"] = 65,
|
||||
["f8"] = 66,
|
||||
["f9"] = 67,
|
||||
["f10"] = 68,
|
||||
["numLock"] = 69,
|
||||
["scollLock"] = 70,
|
||||
["f11"] = 87,
|
||||
["f12"] = 88,
|
||||
["f13"] = 89,
|
||||
["f14"] = 90,
|
||||
["f15"] = 91,
|
||||
["cimcumflex"] = 144,
|
||||
["at"] = 145,
|
||||
["colon"] = 146,
|
||||
["underscore"] = 147,
|
||||
["rightCtrl"] = 157,
|
||||
["rightAlt"] = 184,
|
||||
["pause"] = 197,
|
||||
["home"] = 199,
|
||||
["up"] = 200,
|
||||
["pageUp"] = 201,
|
||||
["left"] = 203,
|
||||
["right"] = 205,
|
||||
["end"] = 207,
|
||||
["down"] = 208,
|
||||
["pageDown"] = 209,
|
||||
["insert"] = 210,
|
||||
["delete"] = 211,
|
||||
["leftCommand"] = 219
|
||||
}
|
||||
_G.keys.getName = function(code) return keycodeNumToName[tostring(code)] end
|
||||
@@ -1,497 +0,0 @@
|
||||
--[[
|
||||
TBASIC: Simple BASIC language based on the Commodore BASIC Version 2.
|
||||
|
||||
(C64 rulz? Nope.)
|
||||
|
||||
|
||||
How to use in your program:
|
||||
|
||||
1. load the script by:
|
||||
if you're using ComputerCraft, use:
|
||||
os.loadAPI "TBASEXEC.lua"
|
||||
else, use:
|
||||
require "TBASEXEC"
|
||||
|
||||
2. run:
|
||||
_TBASIC.EXEC(string of whole command)
|
||||
]]
|
||||
|
||||
if os and os.loadAPI then -- ComputerCraft
|
||||
os.loadAPI "TBASINCL.lua"
|
||||
else
|
||||
require "TBASINCL"
|
||||
end
|
||||
|
||||
table.concat = function(t, delimeter)
|
||||
if #t == 0 then return "" end
|
||||
local outstr = t[1]
|
||||
for i = 2, #t do
|
||||
outstr = outstr..delimeter..tostring(t[i])
|
||||
end
|
||||
|
||||
return outstr
|
||||
end
|
||||
|
||||
-- Copy from TBASINCL; looks like OpenComputers has a bug...
|
||||
function string_hash(str)
|
||||
local hash = 2166136261
|
||||
for i = 1, #str do
|
||||
hash = hash * 16777619
|
||||
hash = bit.bxor(hash, str:byte(i))
|
||||
end
|
||||
return hash
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-- INTERPRETER STATUS ---------------------------------------------------------
|
||||
|
||||
local programlist = {}
|
||||
|
||||
-- LEXER ----------------------------------------------------------------------
|
||||
|
||||
local function appendcommand(lineno, statement)
|
||||
if lineno > _TBASIC._INTPRTR.MAXLINES then
|
||||
_TBASIC._ERROR.LINETOOBIG()
|
||||
elseif lineno < 0 then
|
||||
_TBASIC._ERROR.NOLINENUM()
|
||||
else
|
||||
programlist[lineno] = statement
|
||||
end
|
||||
end
|
||||
|
||||
do -- Avoid heap allocs for performance
|
||||
local tokens = {" ", "\t", ",", "(", ")"} -- initial obvious tokens
|
||||
local longest_token_len = 0
|
||||
-- build 'tokens' table from list of operators from the language
|
||||
for _, v in ipairs(_TBASIC._OPERATR) do
|
||||
if not v:match("[A-Za-z]") then -- we want non-alphabetic operators as a token
|
||||
table.insert(tokens, v)
|
||||
-- get longest_token_len, will be used for 'lookahead'
|
||||
local tokenlen = #v
|
||||
if longest_token_len < #v then
|
||||
longest_token_len = #v
|
||||
end
|
||||
end
|
||||
end
|
||||
-- sort them out using ther hash for binary search
|
||||
table.sort(tokens, function(a, b) return string_hash(a) < string_hash(b) end)
|
||||
|
||||
|
||||
function parsewords(line)
|
||||
if line == nil then return end
|
||||
|
||||
-----------------------
|
||||
-- check line sanity --
|
||||
-----------------------
|
||||
|
||||
-- filter for IF statement
|
||||
if line:sub(1, 2):upper() == "IF" then
|
||||
-- no matching THEN
|
||||
if not line:match("[Tt][Hh][Ee][Nn]") then
|
||||
_TBASIC._ERROR.NOMATCHING("IF", "THEN")
|
||||
-- assignment on IF clause
|
||||
elseif line:match("[Ii][Ff][^\n]+[Tt][Hh][Ee][Nn]"):match("[^=+%-*/%%<>!]=[^=<>]") or
|
||||
line:match("[Ii][Ff][^\n]+[Tt][Hh][Ee][Nn]"):match(":=") then
|
||||
_TBASIC._ERROR.ASGONIF()
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------------------------------
|
||||
-- automatically infer and insert some commands --
|
||||
--------------------------------------------------
|
||||
-- (This is starting to get dirty...)
|
||||
|
||||
-- unary minus
|
||||
for matchobj in line:gmatch("%-[0-9]+") do
|
||||
local newline = line:gsub(matchobj, "MINUS "..matchobj:sub(2, #matchobj))
|
||||
line = newline
|
||||
end
|
||||
-- conditional for IF
|
||||
-- if IF statement has no appended paren
|
||||
if line:sub(1, 2):upper() == "IF" and not line:match("[Ii][Ff][ ]*%(") then
|
||||
local newline = line:gsub("[Ii][Ff]", "IF ( ", 1):gsub("[Tt][Hh][Ee][Nn]", " ) THEN", 1)
|
||||
line = newline
|
||||
end
|
||||
-- special treatment for FOR
|
||||
if line:sub(1, 3):upper() == "FOR" then
|
||||
if line:match("[0-9]?%.[0-9]") then -- real number used (e.g. "3.14", ".5")
|
||||
_TBASIC._ERROR.ILLEGALARG()
|
||||
else
|
||||
local varnameintm = line:match(" [^\n]+[ =]")
|
||||
|
||||
if varnameintm then
|
||||
local varname = varnameintm:match("[^= ]+")
|
||||
if varname then
|
||||
local newline = line:gsub(" "..varname.."[ =]", " $"..varname.." "..varname.." = ")
|
||||
line = newline:gsub("= =", "=")
|
||||
else
|
||||
_TBASIC._ERROR.SYNTAX()
|
||||
end
|
||||
end
|
||||
-- basically, "FOR x x = 1 TO 10", which converts to "x x 1 10 TO = FOR",
|
||||
-- which is executed (in RPN) in steps of:
|
||||
-- "x x 1 10 TO = FOR"
|
||||
-- "x x (arr) = FOR"
|
||||
-- "x FOR" -- see this part? we need extra 'x' to feed for the FOR statement to function
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
printdbg("parsing line", line)
|
||||
|
||||
|
||||
|
||||
lextable = {}
|
||||
isquote = false
|
||||
quotemode = false
|
||||
wordbuffer = ""
|
||||
local function flush()
|
||||
if (#wordbuffer > 0) then
|
||||
table.insert(lextable, wordbuffer)
|
||||
wordbuffer = ""
|
||||
end
|
||||
end
|
||||
local function append(char)
|
||||
wordbuffer = wordbuffer..char
|
||||
end
|
||||
local function append_no_whitespace(char)
|
||||
if char ~= " " and char ~= "\t" then
|
||||
wordbuffer = wordbuffer..char
|
||||
end
|
||||
end
|
||||
|
||||
-- return: lookless_count on success, nil on failure
|
||||
local function isdelimeter(string)
|
||||
local cmpval = function(table_elem) return string_hash(table_elem) end
|
||||
local lookless_count = #string
|
||||
local ret = nil
|
||||
repeat
|
||||
ret = table.binsearch(tokens, string:sub(1, lookless_count), cmpval)
|
||||
lookless_count = lookless_count - 1
|
||||
until ret or lookless_count < 1
|
||||
return ret and lookless_count + 1 or false
|
||||
end
|
||||
|
||||
local i = 1 -- Lua Protip: variable in 'for' is immutable, and is different from general variable table, even if they have same name
|
||||
while i <= #line do
|
||||
local c = string.char(line:byte(i))
|
||||
|
||||
local lookahead = line:sub(i, i+longest_token_len)
|
||||
|
||||
if isquote then
|
||||
if c == [["]] then
|
||||
flush()
|
||||
isquote = false
|
||||
else
|
||||
append(c)
|
||||
end
|
||||
else
|
||||
if c == [["]] then
|
||||
isquote = true
|
||||
append_no_whitespace("~")
|
||||
else
|
||||
local delimsize = isdelimeter(lookahead) -- returns nil if no matching delimeter found
|
||||
if delimsize then
|
||||
flush() -- flush buffer
|
||||
append_no_whitespace(lookahead:sub(1, delimsize))
|
||||
flush() -- flush this delimeter
|
||||
i = i + delimsize - 1
|
||||
else
|
||||
append_no_whitespace(c)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
flush() -- don't forget this!
|
||||
|
||||
|
||||
return lextable
|
||||
end
|
||||
end
|
||||
|
||||
local function readprogram(program)
|
||||
for line in program:gmatch("[^\n]+") do
|
||||
lineno = line:match("[0-9]+ ", 1)
|
||||
|
||||
if not lineno then
|
||||
_TBASIC._ERROR.NOLINENUM()
|
||||
end
|
||||
|
||||
statement = line:sub(#lineno + 1)
|
||||
|
||||
appendcommand(tonumber(lineno), statement)
|
||||
end
|
||||
end
|
||||
|
||||
do -- Avoid heap allocs for performance
|
||||
local function stackpush(t, v)
|
||||
t[#t + 1] = v
|
||||
end
|
||||
|
||||
local function stackpop(t)
|
||||
local v = t[#t]
|
||||
t[#t] = nil
|
||||
return v
|
||||
end
|
||||
|
||||
local function stackpeek(t)
|
||||
local v = t[#t]
|
||||
return v
|
||||
end
|
||||
|
||||
local function unmark(word)
|
||||
if type(word) == "table" then return word end
|
||||
return word:sub(2, #word)
|
||||
end
|
||||
|
||||
local function isoperator(word)
|
||||
if word == nil then return false end
|
||||
return word:byte(1) == 35
|
||||
end
|
||||
|
||||
local isvariable = _TBASIC.isvariable
|
||||
local isnumber = _TBASIC.isnumber
|
||||
local isstring = _TBASIC.isstring
|
||||
|
||||
local function isuserfunc(word)
|
||||
if type(word) == "table" then return false end
|
||||
if word == nil then return false end
|
||||
return word:byte(1) == 64
|
||||
end
|
||||
|
||||
local function isbuiltin(word)
|
||||
if type(word) == "table" then return false end
|
||||
if word == nil then return false end
|
||||
return word:byte(1) == 38
|
||||
end
|
||||
|
||||
local function iskeyword(word)
|
||||
if word == nil then return false end
|
||||
return isoperator(word) or isuserfunc(word) or isbuiltin(word)
|
||||
end
|
||||
|
||||
local function isassign(word)
|
||||
if word == nil then return false end
|
||||
return word ~= "==" and word ~= ">=" and word ~= "<=" and word:byte(#word) == 61
|
||||
end
|
||||
|
||||
-- returns truthy value "terminate_loop" upon termination of loop; nil otherwise.
|
||||
local function execword(word, args)
|
||||
if not _TBASIC.__appexit then
|
||||
printdbg("--> execword", word)
|
||||
printdbg("--> execword_args", table.unpack(args))
|
||||
|
||||
if word == "IF" then
|
||||
printdbg("--> branch statement 'IF'")
|
||||
if not _TBASIC.__readvar(args[1]) then -- if condition 'false'
|
||||
printdbg("--> if condition 'false'", table.unpack(args))
|
||||
return "terminate_loop" -- evaluated as 'true' to Lua
|
||||
else
|
||||
printdbg("--> if condition 'true'", table.unpack(args))
|
||||
end
|
||||
end
|
||||
|
||||
printdbg("--> execword_outarg", table.unpack(args))
|
||||
result = _TBASIC.LUAFN[word][1](table.unpack(args))
|
||||
|
||||
printdbg("--> result", result)
|
||||
stackpush(execstack, result)
|
||||
end
|
||||
end
|
||||
|
||||
function printdbg(...)
|
||||
local debug = false
|
||||
if debug then print("DBG", ...) end
|
||||
end
|
||||
|
||||
|
||||
function interpretline(line)
|
||||
if not _TBASIC.__appexit then
|
||||
--[[
|
||||
impl
|
||||
|
||||
1. (normalise expr using parsewords)
|
||||
2. use _TBASIC.RPNPARSR to convert to RPN
|
||||
3. execute RPN op set like FORTH
|
||||
|
||||
* "&" - internal functions
|
||||
* "@" - user-defined functions
|
||||
* "$" - variables (builtin constants and user-defined) -- familiar, eh?
|
||||
* "#" - operators
|
||||
* "~" - strings
|
||||
* none prepended - data (number or string)
|
||||
]]
|
||||
|
||||
lextable = parsewords(line)
|
||||
local vararg = -13 -- magic
|
||||
|
||||
|
||||
if lextable and lextable[1] ~= nil then
|
||||
if lextable[1]:upper() == "REM" then return nil end
|
||||
|
||||
printdbg("lextable", table.concat(lextable, "|"))
|
||||
|
||||
-- execute expression
|
||||
exprlist = _TBASIC.TORPN(lextable) -- 2 2 #+ &PRINT for "PRINT 2+2"
|
||||
|
||||
printdbg("trying to exec", table.concat(exprlist, " "), "\n--------")
|
||||
|
||||
execstack = {}
|
||||
|
||||
for _, word in ipairs(exprlist) do
|
||||
printdbg("stack before", table.concat(execstack, " "))
|
||||
printdbg("word", word)
|
||||
|
||||
if iskeyword(word) then
|
||||
printdbg("is keyword")
|
||||
|
||||
funcname = unmark(word)
|
||||
args = {}
|
||||
argsize = _TBASIC._GETARGS(funcname)
|
||||
|
||||
printdbg("argsize", argsize)
|
||||
|
||||
if not argsize then
|
||||
_TBASIC._ERROR.DEV_UNIMPL(funcname)
|
||||
else
|
||||
if argsize ~= vararg then
|
||||
-- consume 'argsize' elements from the stack
|
||||
for argcnt = argsize, 1, -1 do
|
||||
if #execstack == 0 then
|
||||
_TBASIC._ERROR.ARGMISSING(funcname)
|
||||
end
|
||||
args[argcnt] = stackpop(execstack)
|
||||
end
|
||||
else
|
||||
-- consume entire stack
|
||||
local reversedargs = {}
|
||||
|
||||
while #execstack > 0 and
|
||||
(isvariable(stackpeek(execstack)) or isnumber(stackpeek(execstack)) or
|
||||
isstring(stackpeek(execstack)))
|
||||
do
|
||||
stackpush(reversedargs, stackpop(execstack))
|
||||
end
|
||||
-- reverse 'args'
|
||||
while #reversedargs > 0 do
|
||||
stackpush(args, stackpop(reversedargs))
|
||||
end
|
||||
end
|
||||
|
||||
local terminate_loop = execword(funcname, args)
|
||||
|
||||
if terminate_loop then
|
||||
printdbg("--> termination of loop")
|
||||
printdbg("--------")
|
||||
break
|
||||
end
|
||||
end
|
||||
elseif isvariable(word) then
|
||||
printdbg("is variable")
|
||||
stackpush(execstack, word) -- push raw variable ($ sign retained)
|
||||
else
|
||||
printdbg("is data")
|
||||
stackpush(execstack, word) -- push number or string
|
||||
end
|
||||
|
||||
printdbg("stack after", table.concat(execstack, " "))
|
||||
printdbg("--------")
|
||||
end
|
||||
|
||||
-- if execstack is not empty, something is wrong
|
||||
if #execstack > 0 then
|
||||
_TBASIC._ERROR.SYNTAX() -- cannot reliably pinpoint which statement has error; use generic error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function termination_condition()
|
||||
return terminated or
|
||||
_TBASIC.__appexit or
|
||||
#_TBASIC._INTPRTR.CALLSTCK > _TBASIC._INTPRTR.STACKMAX
|
||||
end
|
||||
|
||||
local function fetchnextcmd()
|
||||
cmd = nil
|
||||
repeat
|
||||
_TBASIC._INTPRTR.PROGCNTR = _TBASIC._INTPRTR.PROGCNTR + 1
|
||||
cmd = programlist[_TBASIC._INTPRTR.PROGCNTR]
|
||||
|
||||
if _TBASIC._INTPRTR.PROGCNTR > _TBASIC._INTPRTR.MAXLINES then
|
||||
terminated = true
|
||||
break
|
||||
end
|
||||
until cmd ~= nil
|
||||
|
||||
if cmd ~= nil then
|
||||
if _TBASIC._INTPRTR.TRACE then
|
||||
print("PC", _TBASIC._INTPRTR.PROGCNTR)
|
||||
end
|
||||
|
||||
return cmd
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function interpretall()
|
||||
|
||||
terminated = false
|
||||
|
||||
repeat
|
||||
interpretline(fetchnextcmd())
|
||||
until termination_condition()
|
||||
end
|
||||
|
||||
-- END OF LEXER ---------------------------------------------------------------
|
||||
|
||||
-- _TBASIC.SHOWLUAERROR = false -- commented; let the shell handle it
|
||||
|
||||
local testprogram = nil
|
||||
|
||||
_G._TBASIC.EXEC = function(cmdstring) -- you can access this interpreter with this global function
|
||||
_TBASIC._INTPRTR.RESET()
|
||||
programlist = {} -- wipe out previous commands from interpreter (do not delete)
|
||||
readprogram(cmdstring)
|
||||
interpretall()
|
||||
end
|
||||
|
||||
|
||||
if testprogram then
|
||||
_TBASIC._INTPRTR.RESET()
|
||||
programlist = {} -- wipe out previous commands from interpreter (do not delete)
|
||||
readprogram(testprogram)
|
||||
interpretall()
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Terran BASIC (TBASIC)
|
||||
Copyright (c) 2016 Torvald (minjaesong) and the contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the Software), to deal in the
|
||||
Software without restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
@@ -1,34 +0,0 @@
|
||||
-- TBASIC extension
|
||||
|
||||
-- these are utilities. Do not touch these lines
|
||||
local __assert = _TBASIC.__assert
|
||||
local __assertlhand = _TBASIC.__assertlhand
|
||||
local __assertrhand = _TBASIC.__assertrhand
|
||||
local __checknumber = _TBASIC.__checknumber
|
||||
local __checkstring = _TBASIC.__checkstring
|
||||
local __readvar = _TBASIC.__readvar
|
||||
local __resolvevararg = _TBASIC.__resolvevarar
|
||||
local vararg = -13 -- magic
|
||||
-- end of utilities
|
||||
|
||||
|
||||
-- these are the sample code for defining your own words
|
||||
--[[
|
||||
-- actual function that does the job
|
||||
local function _fnupgoer(n)
|
||||
print("Up-goer "..__checknumber(n).." goes up!")
|
||||
end
|
||||
|
||||
-- add the word UPGOER to word list
|
||||
table.insert(_TBASIC._FNCTION, "UPGOER")
|
||||
-- add the actual function '_fnupgoer' and its number of arguments (1) to
|
||||
-- '_TBASIC.LUAFN'. 'UPGOER' part should match with the word you just
|
||||
-- inserted to _TBASIC._FNCTION.
|
||||
_TBASIC.LUAFN.UPGOER = {_fnupgoer, 1}
|
||||
]]
|
||||
|
||||
|
||||
-- little debugger's blessing
|
||||
local function _fnenableluatrace() _TBASIC.SHOWLUAERROR = true end
|
||||
table.insert(_TBASIC._FNCTION, "LUATRACEON")
|
||||
_TBASIC.LUAFN.LUATRACEON = {_fnenableluatrace, 0}
|
||||
@@ -1,292 +0,0 @@
|
||||
--[[
|
||||
TBASIC shell
|
||||
|
||||
Synopsis: TBASIC (filename)
|
||||
If no file is specified, interactive mode will be started
|
||||
|
||||
|
||||
To debug EXEC and/or INCL, there's line ```local debug = false``` on each file; change it to ```true``` manually
|
||||
and you are all set.
|
||||
]]
|
||||
|
||||
|
||||
if os and os.loadAPI then -- ComputerCraft
|
||||
os.loadAPI "TBASINCL.lua"
|
||||
os.loadAPI "TBASEXEC.lua"
|
||||
else
|
||||
require "TBASINCL"
|
||||
require "TBASEXEC"
|
||||
end
|
||||
|
||||
args = {...}
|
||||
|
||||
print(_G._TBASIC._HEADER)
|
||||
_TBASIC.PROMPT()
|
||||
_TBASIC.SHOWLUAERROR = false
|
||||
|
||||
|
||||
local function concat_lines(lines, startindex, endindex)
|
||||
local out = ""
|
||||
for i = startindex or 1, endindex or _TBASIC._INTPRTR.MAXLINES do
|
||||
if lines[i] ~= nil then
|
||||
out = out.."\n"..tostring(i).." "..lines[i]
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
|
||||
if args[1] then
|
||||
local prog = nil
|
||||
if fs and fs.open then -- ComputerCraft
|
||||
local inp = assert(fs.open(args[1], "r"))
|
||||
prog = inp:readAll()
|
||||
inp:close()
|
||||
else
|
||||
local inp = assert(io.open(args[1], "r"))
|
||||
prog = inp:read("*all")
|
||||
inp:close()
|
||||
end
|
||||
|
||||
_TBASIC.EXEC(prog)
|
||||
else
|
||||
local terminate_app = false
|
||||
|
||||
local ptn_nums = "[0-9]+"
|
||||
local renum_targets = {"GOTO[ ]+"..ptn_nums, "GOSUB[ ]+"..ptn_nums }
|
||||
|
||||
local lines = {}
|
||||
|
||||
local linenum_match = "[0-9]+ "
|
||||
|
||||
local get_linenum = function(line) return line:sub(1,6):match(linenum_match, 1) end -- line:sub(1,6) limits max linumber to be 99999
|
||||
local split_num_and_statements = function(line)
|
||||
local linenum = get_linenum(line)
|
||||
local statements = line:sub(#linenum + 1)
|
||||
return tonumber(linenum), statements
|
||||
end
|
||||
|
||||
while not terminate_app do
|
||||
local __read = false
|
||||
local line = io.read()
|
||||
|
||||
-- tokenise line by " "
|
||||
local args = {} -- shadows system args
|
||||
for word in line:gmatch("[^ ]+") do
|
||||
table.insert(args, word:upper())
|
||||
end
|
||||
|
||||
|
||||
-- TODO more elegant code than IF-ELSEIF-ELSE
|
||||
|
||||
-- massive if-else for running command, cos implementing proper command executor is too expensive here
|
||||
if line:sub(1,6):match(linenum_match) then -- enter new command
|
||||
local linenum, statements = split_num_and_statements(line)
|
||||
lines[tonumber(linenum)] = statements
|
||||
__read = true
|
||||
elseif args[1] == "NEW" then
|
||||
lines = {}
|
||||
elseif args[1] == "RUN" then
|
||||
_TBASIC.EXEC(concat_lines(lines))
|
||||
elseif args[1] == "LIST" then -- LIST, LIST 42, LIST 10-80
|
||||
if not args[2] then
|
||||
print(concat_lines(lines))
|
||||
else
|
||||
if args[2]:match("-") then -- ranged
|
||||
local range = {}
|
||||
for n in args[2]:gmatch("[^-]+") do
|
||||
table.insert(range, n)
|
||||
end
|
||||
local rangestart = tonumber(range[1])
|
||||
local rangeend = tonumber(range[2])
|
||||
|
||||
if not rangestart or not rangeend then
|
||||
_TBASIC._ERROR.ILLEGALARG()
|
||||
else
|
||||
print(concat_lines(lines, rangestart, rangeend))
|
||||
end
|
||||
else
|
||||
local linenum = tonumber(args[2])
|
||||
if not linenum then
|
||||
_TBASIC._ERROR.ILLEGALARG()
|
||||
else
|
||||
print(concat_lines(lines, linenum, linenum))
|
||||
end
|
||||
end
|
||||
end
|
||||
_TBASIC.PROMPT()
|
||||
__read = true
|
||||
elseif args[1] == "DELETE" then -- DELETE 30, DELETE 454-650
|
||||
if not args[2] then
|
||||
_TBASIC._ERROR.ILLEGALARG()
|
||||
else
|
||||
if args[2]:match("-") then -- ranged
|
||||
local range = {}
|
||||
for n in args[2]:gmatch("[^-]+") do
|
||||
table.insert(range, n)
|
||||
end
|
||||
local rangestart = tonumber(range[1])
|
||||
local rangeend = tonumber(range[2])
|
||||
|
||||
if not rangestart or not rangeend then
|
||||
_TBASIC._ERROR.ILLEGALARG()
|
||||
else
|
||||
for i = rangestart, rangeend do
|
||||
lines[i] = nil
|
||||
end
|
||||
end
|
||||
else
|
||||
local linenum = tonumber(args[2])
|
||||
if not linenum then
|
||||
_TBASIC._ERROR.ILLEGALARG()
|
||||
else
|
||||
lines[linenum] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif args[1] == "EXIT" then
|
||||
terminate_app = true
|
||||
break
|
||||
elseif args[1] == "SAVE" then
|
||||
local status, err = pcall(function()
|
||||
if fs and fs.open then -- computercraft
|
||||
local file = fs.open(args[2], "w")
|
||||
file.write(concat_lines(lines))
|
||||
file.close()
|
||||
else
|
||||
local file = assert(io.open(args[2], "w"))
|
||||
file:write(concat_lines(lines))
|
||||
file:close()
|
||||
end
|
||||
end
|
||||
)
|
||||
if err then
|
||||
if _TBASIC.SHOWLUAERROR then
|
||||
print(err)
|
||||
end
|
||||
_TBASIC._ERROR.IOERR()
|
||||
else
|
||||
print("FILE SAVED")
|
||||
end
|
||||
elseif args[1] == "LOAD" then
|
||||
local status, err = pcall(function()
|
||||
lines = {}
|
||||
if fs and fs.open then -- computercraft
|
||||
local file = fs.open(args[2], "r")
|
||||
local data = file.readAll("*all")
|
||||
for dataline in data:gmatch("[^\n]+") do
|
||||
if #dataline > 0 then
|
||||
local linenum, statements = split_num_and_statements(dataline)
|
||||
lines[linenum] = statements
|
||||
end
|
||||
end
|
||||
file.close()
|
||||
else
|
||||
local file = assert(io.open(args[2], "r"))
|
||||
local data = file:read("*all")
|
||||
for dataline in data:gmatch("[^\n]+") do
|
||||
if #dataline > 0 then
|
||||
local linenum, statements = split_num_and_statements(dataline)
|
||||
lines[linenum] = statements
|
||||
end
|
||||
end
|
||||
file:close()
|
||||
end
|
||||
end
|
||||
)
|
||||
if err then
|
||||
if _TBASIC.SHOWLUAERROR then
|
||||
error(err)
|
||||
end
|
||||
_TBASIC._ERROR.IOERR()
|
||||
else
|
||||
print("FILE LOADED")
|
||||
end
|
||||
elseif args[1] == "RENUM" then
|
||||
local statement_table = {}
|
||||
local renumbering_table = {}
|
||||
local new_linenum_counter = 10
|
||||
-- first, get the list of commands, without line number indexing
|
||||
for i = 1, _TBASIC._INTPRTR.MAXLINES do
|
||||
if lines[i] ~= nil then
|
||||
--table.insert(statement_table, lines[i])
|
||||
statement_table[new_linenum_counter] = lines[i]
|
||||
renumbering_table[i] = new_linenum_counter
|
||||
|
||||
-- test
|
||||
--print("old line", i, "new line", new_linenum_counter)
|
||||
|
||||
new_linenum_counter = new_linenum_counter + 10
|
||||
end
|
||||
end
|
||||
-- copy statement_table into lines table
|
||||
lines = statement_table
|
||||
|
||||
-- re-number GOTO and GOSUB line numbers
|
||||
local line_counter = 0 -- loop counter
|
||||
for line_pc = 0, _TBASIC._INTPRTR.MAXLINES do
|
||||
local line = lines[line_pc]
|
||||
if line then
|
||||
line_counter = line_counter + 1
|
||||
|
||||
-- replace
|
||||
-- extract a <- "GOTO 320"
|
||||
-- extract n_from from a (320), make n_to from it
|
||||
-- make new string b <- "GOTO "..n_to
|
||||
for _, match_string in ipairs(renum_targets) do
|
||||
local match = line:match(match_string)
|
||||
if match then
|
||||
local matching_statement = match:gsub("[ ]+"..ptn_nums, "")
|
||||
local target_line_old = tonumber(match:match(ptn_nums))
|
||||
local target_line_new = renumbering_table[target_line_old]
|
||||
|
||||
local gsub_from = match
|
||||
local gsub_to = matching_statement.." "..target_line_new
|
||||
|
||||
-- test
|
||||
--print("matching_statement", matching_statement, "target_line_old", target_line_old, "target_line_new", target_line_new)
|
||||
--print("gsub_from", gsub_from, "gsub_to", gsub_to)
|
||||
|
||||
-- substitute
|
||||
lines[line_pc] = line:gsub(gsub_from, gsub_to)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif #line == 0 and line:byte(1) ~= 10 and line:byte(1) ~= 13 then
|
||||
__read = true
|
||||
else
|
||||
_TBASIC.EXEC("1 "..line) -- execute command right away
|
||||
end
|
||||
|
||||
-- reset
|
||||
if not __read then
|
||||
_TBASIC.PROMPT()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Terran BASIC (TBASIC)
|
||||
Copyright (c) 2016 Torvald (minjaesong) and the contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the Software), to deal in the
|
||||
Software without restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
// TODO Fill in from work_files/romapidoc/romapidoc.tex
|
||||
@@ -1,87 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.computer
|
||||
|
||||
import net.torvald.UnsafeHelper
|
||||
import net.torvald.UnsafePtr
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.CommonResourcePool
|
||||
|
||||
/**
|
||||
* Blit is a display adapter that operates in pixel-space, with resolution of 224x320 with bit depth of one.
|
||||
*
|
||||
* This Blit is inspired by the real-world Blit terminal from 1982 by Bell Labs.
|
||||
*
|
||||
* @link https://en.wikipedia.org/wiki/Blit_(computer_terminal)
|
||||
*
|
||||
* Created by minjaesong on 2019-07-22.
|
||||
*/
|
||||
class BLIT {
|
||||
|
||||
private val framebuffer = UnsafeHelper.allocate(W.toLong() * H)
|
||||
|
||||
var scrollOffsetX = 0
|
||||
var scrollOffsetY = 0
|
||||
var textCursorPos = 0
|
||||
|
||||
// each pixel is a byte. I know, 7 bits wasted, but whatever.
|
||||
|
||||
// any conversion to texture/GDX pixmap/etc must be done by other system.
|
||||
// at least you can memcpy() them using UnsafeHelper
|
||||
// TODO test memcpy() over pixmap and native memory
|
||||
|
||||
private fun toAddr(x: Int, y: Int) = (W * y + x) % framebuffer.size
|
||||
|
||||
fun drawPict(x: Int, y: Int, bytes: ByteArray, width: Int) {
|
||||
for (yy in 0L until bytes.size / width) {
|
||||
val writeAddr = toAddr(x, y)
|
||||
|
||||
UnsafeHelper.memcpyRaw(
|
||||
bytes, UnsafeHelper.getArrayOffset(bytes) + yy * width,
|
||||
null, framebuffer.ptr + writeAddr,
|
||||
width.toLong()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun drawLetter(px: Int, py: Int, char: Int) {
|
||||
for (yy in 0L until 13L) {
|
||||
UnsafeHelper.memcpy(
|
||||
fontRom.ptr + (FONTROMW * (char / FONTROMCOLS) * FONTH * yy) + (char % FONTROMCOLS) * FONTW,
|
||||
toAddr(px, py),
|
||||
FONTW.toLong()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notes:
|
||||
*
|
||||
* - The font ROM will not be redefine-able. Just draw your shape on the pixel space.
|
||||
*/
|
||||
companion object {
|
||||
const val W = 240
|
||||
const val H = 320
|
||||
|
||||
const val FONTW = 6
|
||||
const val FONTH = 10
|
||||
|
||||
const val FONTROMW = 192
|
||||
const val FONTROMH = 80
|
||||
|
||||
const val FONTROMCOLS = FONTROMW / FONTW
|
||||
const val FONTROMROWS = FONTROMH / FONTH
|
||||
|
||||
const val TEXT_OFFSET_X = 0 // hand-calculated value
|
||||
const val TEXT_OFFSET_Y = 4 // hand-calculated value
|
||||
// so, y=0..3 and y=317..320 won't be touched by the text drawing
|
||||
|
||||
init {
|
||||
// load common font rom
|
||||
CommonResourcePool.addToLoadingList("dwarventech.computers.blit.fontrom") {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
private val fontRom = CommonResourcePool.getAs<UnsafePtr>("dwarventech.computers.blit.fontrom")
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.computer
|
||||
|
||||
import java.io.RandomAccessFile
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2019-07-13.
|
||||
*/
|
||||
class TEVDFile(path: String, mode: String) : RandomAccessFile(path, mode) {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.computer
|
||||
|
||||
import net.torvald.terrarum.gameactors.ai.luaTableOf
|
||||
import net.torvald.terrarum.gameactors.ai.toLua
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LuaError
|
||||
import org.luaj.vm2.LuaValue
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2019-07-10.
|
||||
*/
|
||||
object LoadTerrarumTermLib {
|
||||
|
||||
operator fun invoke(globals: Globals, terminal: MDA) {
|
||||
globals.addZeroArgFun("term.getCursor") {
|
||||
luaTableOf(
|
||||
(terminal.cursor % terminal.width).toLua(),
|
||||
(terminal.cursor / terminal.height).toLua()
|
||||
)
|
||||
}
|
||||
globals.addTwoArgFun("term.setCursor") { p0, p1 ->
|
||||
terminal.setCursor(p0.checkint(), p1.checkint())
|
||||
LuaValue.NIL
|
||||
}
|
||||
globals.addZeroArgFun("term.getCursorBlink") {
|
||||
terminal.blink.toLua()
|
||||
}
|
||||
globals.addOneArgFun("term.setCursorBlink") { p0 ->
|
||||
terminal.blink = p0.checkboolean()
|
||||
LuaValue.NIL
|
||||
}
|
||||
globals.addZeroArgFun("term.getTextColor") {
|
||||
terminal.foreground.toLua()
|
||||
}
|
||||
globals.addZeroArgFun("term.getBackgroundColor") {
|
||||
terminal.background.toLua()
|
||||
}
|
||||
globals.addOneArgFun("term.setTextColor") { p0 ->
|
||||
terminal.foreground = p0.checkint()
|
||||
LuaValue.NIL
|
||||
}
|
||||
globals.addOneArgFun("term.setBackgroundColor") { p0 ->
|
||||
terminal.background = p0.checkint()
|
||||
LuaValue.NIL
|
||||
}
|
||||
globals.addZeroArgFun("term.getSize") {
|
||||
luaTableOf(
|
||||
(terminal.width).toLua(),
|
||||
(terminal.height).toLua()
|
||||
)
|
||||
}
|
||||
globals.addZeroArgFun("term.clear") {
|
||||
terminal.clear()
|
||||
LuaValue.NIL
|
||||
}
|
||||
globals.addZeroArgFun("term.clearLine") {
|
||||
terminal.clearCurrentLine()
|
||||
LuaValue.NIL
|
||||
}
|
||||
globals.addOneArgFun("term.scroll") { p0 ->
|
||||
if (p0.checkint() < 0)
|
||||
throw LuaError("Scroll amount must be a positive number")
|
||||
terminal.scroll(p0.toint())
|
||||
LuaValue.NIL
|
||||
}
|
||||
globals.addOneArgFun("term.write") { p0 ->
|
||||
terminal.print(p0.checkjstring())
|
||||
LuaValue.NIL
|
||||
}
|
||||
globals.addThreeArgFun("term.setText") { p0, p1, p2 ->
|
||||
terminal.setOneText(p0.checkint(), p1.checkint(), p2.checkint().toByte())
|
||||
LuaValue.NIL
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,697 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.computer
|
||||
|
||||
import net.torvald.terrarum.KVHashMap
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.ceilInt
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LoadState
|
||||
import org.luaj.vm2.LuaError
|
||||
import org.luaj.vm2.LuaValue
|
||||
import org.luaj.vm2.compiler.LuaC
|
||||
import org.luaj.vm2.lib.*
|
||||
import org.luaj.vm2.lib.jse.*
|
||||
import org.lwjgl.BufferUtils
|
||||
import org.lwjgl.openal.AL10
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.io.PrintStream
|
||||
import java.io.Reader
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* A part that makes "computer fixture" actually work
|
||||
*
|
||||
* @param avFixtureComputer : actor values for FixtureComputerBase
|
||||
*
|
||||
* @param term : terminal that is connected to the computer fixtures, null if not connected any.
|
||||
* Created by minjaesong on 2016-09-10.
|
||||
*/
|
||||
class LuaComputerVM(val display: MDA) {
|
||||
|
||||
val DEBUG = true
|
||||
|
||||
lateinit private var luaJ_globals: Globals
|
||||
|
||||
var stdout: PrintStream? = null
|
||||
private set
|
||||
var stderr: PrintStream? = null
|
||||
private set
|
||||
var stdin: InputStream? = null
|
||||
private set
|
||||
|
||||
|
||||
val UUID = java.util.UUID.randomUUID().toString()
|
||||
|
||||
val computerValue = KVHashMap()
|
||||
|
||||
var isHalted = false
|
||||
|
||||
var stdinInput: Int = -1
|
||||
private set
|
||||
|
||||
|
||||
// os-related functions. These are called "machine" library-wise.
|
||||
private val startupTimestamp: Long = System.currentTimeMillis()
|
||||
/** Time elapsed since the power is on. */
|
||||
val milliTime: Int
|
||||
get() = (System.currentTimeMillis() - startupTimestamp).toInt()
|
||||
|
||||
|
||||
init {
|
||||
initSandbox()
|
||||
}
|
||||
|
||||
fun initSandbox() {
|
||||
val luaJ_globals = Globals()
|
||||
luaJ_globals.load(JseBaseLib())
|
||||
luaJ_globals.load(PackageLib())
|
||||
luaJ_globals.load(Bit32Lib())
|
||||
luaJ_globals.load(TableLib())
|
||||
luaJ_globals.load(JseStringLib())
|
||||
luaJ_globals.load(CoroutineLib())
|
||||
luaJ_globals.load(JseMathLib())
|
||||
luaJ_globals.load(JseIoLib())
|
||||
luaJ_globals.load(JseOsLib())
|
||||
luaJ_globals.load(LuajavaLib())
|
||||
LoadState.install(luaJ_globals)
|
||||
LuaC.install(luaJ_globals)
|
||||
|
||||
stdout = TerminalPrintStream(this)
|
||||
stderr = TerminalPrintStream(this)
|
||||
stdin = TerminalInputStream(this)
|
||||
|
||||
luaJ_globals.STDOUT = stdout
|
||||
luaJ_globals.STDERR = stderr
|
||||
luaJ_globals.STDIN = stdin
|
||||
|
||||
luaJ_globals["bit"] = luaJ_globals["bit32"]
|
||||
|
||||
// load libraries
|
||||
LoadTerrarumTermLib(luaJ_globals, display)
|
||||
|
||||
// secure the sandbox
|
||||
//luaJ_globals["io"] = LuaValue.NIL
|
||||
// dubug should be sandboxed in BOOT.lua (use OpenComputers code)
|
||||
//val sethook = luaJ_globals["debug"]["sethook"]
|
||||
//luaJ_globals["debug"] = LuaValue.NIL
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun update(delta: Float) {
|
||||
|
||||
if (currentExecutionThread.state == Thread.State.TERMINATED) {
|
||||
threadRun = false
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (!isHalted) {
|
||||
runBeepQueueManager(delta)
|
||||
}
|
||||
}
|
||||
|
||||
fun keyPressed(c: Int) {
|
||||
stdinInput = c
|
||||
|
||||
// wake thread
|
||||
runnableRunCommand.resume()
|
||||
|
||||
synchronized(stdin!!) {
|
||||
(stdin as java.lang.Object).notifyAll()
|
||||
}
|
||||
}
|
||||
|
||||
fun openStdin() {
|
||||
stdinInput = -1
|
||||
// sleep the thread
|
||||
runnableRunCommand.pause()
|
||||
}
|
||||
|
||||
lateinit var currentExecutionThread: Thread
|
||||
private set
|
||||
lateinit var runnableRunCommand: ThreadRunCommand
|
||||
private set
|
||||
private var threadRun = false
|
||||
|
||||
fun runCommand(line: String, env: String) {
|
||||
if (!threadRun) {
|
||||
runnableRunCommand = ThreadRunCommand(luaJ_globals, line, env)
|
||||
currentExecutionThread = Thread(null, runnableRunCommand, "LuaJ Separated")
|
||||
currentExecutionThread.start()
|
||||
threadRun = true
|
||||
}
|
||||
}
|
||||
|
||||
fun runCommand(reader: Reader, filename: String) {
|
||||
if (!threadRun) {
|
||||
runnableRunCommand = ThreadRunCommand(luaJ_globals, reader, filename)
|
||||
currentExecutionThread = Thread(null, runnableRunCommand, "LuaJ Separated")
|
||||
currentExecutionThread.start()
|
||||
threadRun = true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @link https://stackoverflow.com/questions/16758346/how-pause-and-then-resume-a-thread#16758373
|
||||
*/
|
||||
class ThreadRunCommand : Runnable {
|
||||
|
||||
private val mode: Int
|
||||
private val arg1: Any
|
||||
private val arg2: String
|
||||
private val lua: Globals
|
||||
|
||||
@Volatile private var running = true
|
||||
@Volatile private var paused = false
|
||||
private val pauseLock = java.lang.Object()
|
||||
|
||||
constructor(luaInstance: Globals, line: String, env: String) {
|
||||
mode = 0
|
||||
arg1 = line
|
||||
arg2 = env
|
||||
lua = luaInstance
|
||||
}
|
||||
|
||||
constructor(luaInstance: Globals, reader: Reader, filename: String) {
|
||||
mode = 1
|
||||
arg1 = reader
|
||||
arg2 = filename
|
||||
lua = luaInstance
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
synchronized(pauseLock) {
|
||||
if (!running) { // may have changed while waiting to
|
||||
// synchronize on pauseLock
|
||||
return
|
||||
}
|
||||
if (paused) {
|
||||
try {
|
||||
pauseLock.wait() // will cause this Thread to block until
|
||||
// another thread calls pauseLock.notifyAll()
|
||||
// Note that calling wait() will
|
||||
// relinquish the synchronized lock that this
|
||||
// thread holds on pauseLock so another thread
|
||||
// can acquire the lock to call notifyAll()
|
||||
// (link with explanation below this code)
|
||||
}
|
||||
catch (ex: InterruptedException) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!running) { // running might have changed since we paused
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
val chunk: LuaValue
|
||||
if (mode == 0)
|
||||
chunk = lua.load(arg1 as String, arg2)
|
||||
else if (mode == 1)
|
||||
chunk = lua.load(arg1 as Reader, arg2)
|
||||
else
|
||||
throw IllegalArgumentException("Unsupported mode: $mode")
|
||||
|
||||
|
||||
chunk.call()
|
||||
}
|
||||
catch (e: LuaError) {
|
||||
e.printStackTrace(System.err)
|
||||
//lua.STDERR.println("${SimpleTextTerminal.ASCII_DLE}${e.message}${SimpleTextTerminal.ASCII_DC4}")
|
||||
}
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
running = false
|
||||
// you might also want to do this:
|
||||
//interrupt()
|
||||
}
|
||||
|
||||
fun pause() {
|
||||
// you may want to throw an IllegalStateException if !running
|
||||
paused = true
|
||||
}
|
||||
|
||||
fun resume() {
|
||||
synchronized(pauseLock) {
|
||||
paused = false
|
||||
pauseLock.notifyAll() // Unblocks thread
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ComputerEmitTone(val computer: LuaComputerVM) : TwoArgFunction() {
|
||||
override fun call(millisec: LuaValue, freq: LuaValue): LuaValue {
|
||||
computer.playTone(millisec.checkdouble().toFloat(), freq.checkdouble())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// BEEPER DRIVER //
|
||||
///////////////////
|
||||
|
||||
private val beepMaxLen = 10f
|
||||
// let's regard it as a tracker...
|
||||
private val beepQueue = ArrayList<Pair<Second, Double>>()
|
||||
private var beepCursor = -1
|
||||
private var beepQueueLineExecTimer: Second = 0f
|
||||
private var beepQueueFired = false
|
||||
|
||||
private fun runBeepQueueManager(delta: Float) {
|
||||
// start emitTone queue
|
||||
if (beepQueue.size > 0 && beepCursor == -1) {
|
||||
beepCursor = 0
|
||||
}
|
||||
|
||||
// advance emitTone queue
|
||||
if (beepCursor >= 0 && beepQueueLineExecTimer >= beepQueueGetLenOfPtn(beepCursor)) {
|
||||
beepQueueLineExecTimer -= beepQueueGetLenOfPtn(beepCursor)
|
||||
beepCursor += 1
|
||||
beepQueueFired = false
|
||||
}
|
||||
|
||||
// complete emitTone queue
|
||||
if (beepCursor >= beepQueue.size) {
|
||||
clearBeepQueue()
|
||||
}
|
||||
|
||||
// actually play queue
|
||||
if (beepCursor >= 0 && beepQueue.size > 0 && !beepQueueFired) {
|
||||
playTone(beepQueue[beepCursor].first, beepQueue[beepCursor].second)
|
||||
beepQueueFired = true
|
||||
|
||||
// delete sources that is finished. AL is limited to 256 sources. If you exceed it,
|
||||
// we won't get any more sounds played.
|
||||
AL10.alSourcei(oldBeepSource, AL10.AL_BUFFER, 0)
|
||||
AL10.alDeleteSources(oldBeepSource)
|
||||
AL10.alDeleteBuffers(oldBeepBuffer)
|
||||
}
|
||||
|
||||
if (beepQueueFired) beepQueueLineExecTimer += delta
|
||||
}
|
||||
|
||||
fun clearBeepQueue() {
|
||||
beepQueue.clear()
|
||||
beepCursor = -1
|
||||
beepQueueLineExecTimer = 0f
|
||||
|
||||
//AL.destroy()
|
||||
|
||||
if (DEBUG) println("[TerrarumComputerOld] !! Beep queue clear")
|
||||
}
|
||||
|
||||
fun enqueueBeep(duration: Double, freq: Double) {
|
||||
beepQueue.add(Pair(Math.min(duration.toFloat(), beepMaxLen), freq))
|
||||
}
|
||||
|
||||
fun beepQueueGetLenOfPtn(ptnIndex: Int) = beepQueue[ptnIndex].first
|
||||
|
||||
|
||||
////////////////////
|
||||
// TONE GENERATOR //
|
||||
////////////////////
|
||||
|
||||
private val sampleRate = 44100
|
||||
private var beepSource: Int = -1
|
||||
private var beepBuffer: Int = -1
|
||||
private var oldBeepSource: Int = -1
|
||||
private var oldBeepBuffer: Int = -1
|
||||
var audioData: ByteBuffer? = null
|
||||
|
||||
/**
|
||||
* @param duration : milliseconds
|
||||
* @param rampUp
|
||||
* @param rampDown
|
||||
*
|
||||
* ,---. (true, true) ,---- (true, false) ----. (false, true) ----- (false, false)
|
||||
*/
|
||||
private fun makeAudioData(duration: Second, freq: Double,
|
||||
rampUp: Boolean = true, rampDown: Boolean = true): ByteBuffer {
|
||||
|
||||
TODO("with duration as Seconds")
|
||||
|
||||
val audioDataSize = duration.times(sampleRate).ceilInt()
|
||||
val audioData = BufferUtils.createByteBuffer(audioDataSize)
|
||||
|
||||
/*val realDuration = duration * sampleRate / 1000
|
||||
val chopSize = freq / sampleRate
|
||||
|
||||
val amp = Math.max(4600.0 / freq, 1.0)
|
||||
val nHarmonics = if (freq >= 22050.0) 1
|
||||
else if (freq >= 11025.0) 2
|
||||
else if (freq >= 5512.5) 3
|
||||
else if (freq >= 2756.25) 4
|
||||
else if (freq >= 1378.125) 5
|
||||
else if (freq >= 689.0625) 6
|
||||
else 7
|
||||
|
||||
val transitionThre = 974.47218
|
||||
|
||||
// TODO volume ramping?
|
||||
if (freq == 0.0) {
|
||||
for (_ in 0..audioDataSize - 1) {
|
||||
audioData.put(0x00.toByte())
|
||||
}
|
||||
}
|
||||
else if (freq < transitionThre) { // chopper generator (for low freq)
|
||||
for (tsart in 0..audioDataSize - 1) {
|
||||
var sine: Double = amp * Math.cos(Math.PI * 2 * () * chopSize)
|
||||
if (sine > 0.79) sine = 0.79
|
||||
else if (sine < -0.79) sine = -0.79
|
||||
audioData.put(
|
||||
(0.5 + 0.5 * sine).times(0xFF).roundToInt().toByte()
|
||||
)
|
||||
}
|
||||
}
|
||||
else { // harmonics generator (for high freq)
|
||||
for (x in 0..realDuration - 1) {
|
||||
var sine: Double = 0.0
|
||||
for (k in 1..nHarmonics) { // mix only odd harmonics in order to make a squarewave
|
||||
sine += Math.sin(Math.PI * 2 * (2*k - 1) * chopSize * x) / (2*k - 1)
|
||||
}
|
||||
audioData.put(
|
||||
(0.5 + 0.5 * sine).times(0xFF).roundToInt().toByte()
|
||||
)
|
||||
}
|
||||
}*/
|
||||
|
||||
audioData.rewind()
|
||||
|
||||
return audioData
|
||||
}
|
||||
|
||||
private fun playTone(length: Second, freq: Double) {
|
||||
/*audioData = makeAudioData(leninmilli, freq)
|
||||
|
||||
|
||||
if (!AL.isCreated()) AL.create()
|
||||
|
||||
|
||||
// Clear error stack.
|
||||
AL10.alGetError()
|
||||
|
||||
oldBeepBuffer = beepBuffer
|
||||
beepBuffer = AL10.alGenBuffers()
|
||||
checkALError()
|
||||
|
||||
try {
|
||||
AL10.alBufferData(beepBuffer, AL10.AL_FORMAT_MONO8, audioData, sampleRate)
|
||||
checkALError()
|
||||
|
||||
oldBeepSource = beepSource
|
||||
beepSource = AL10.alGenSources()
|
||||
checkALError()
|
||||
|
||||
try {
|
||||
AL10.alSourceQueueBuffers(beepSource, beepBuffer)
|
||||
checkALError()
|
||||
|
||||
AL10.alSource3f(beepSource, AL10.AL_POSITION, 0f, 0f, 1f)
|
||||
AL10.alSourcef(beepSource, AL10.AL_REFERENCE_DISTANCE, 1f)
|
||||
AL10.alSourcef(beepSource, AL10.AL_MAX_DISTANCE, 1f)
|
||||
AL10.alSourcef(beepSource, AL10.AL_GAIN, 0.3f)
|
||||
checkALError()
|
||||
|
||||
AL10.alSourcePlay(beepSource)
|
||||
checkALError()
|
||||
}
|
||||
catch (e: ALException) {
|
||||
AL10.alDeleteSources(beepSource)
|
||||
}
|
||||
}
|
||||
catch (e: ALException) {
|
||||
AL10.alDeleteSources(beepSource)
|
||||
}*/
|
||||
}
|
||||
|
||||
// Custom implementation of Util.checkALError() that uses our custom exception.
|
||||
private fun checkALError() {
|
||||
val errorCode = AL10.alGetError()
|
||||
if (errorCode != AL10.AL_NO_ERROR) {
|
||||
throw ALException(errorCode)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TerminalPrintStream(val host: LuaComputerVM) : PrintStream(TerminalOutputStream(host))
|
||||
|
||||
class TerminalOutputStream(val host: LuaComputerVM) : OutputStream() {
|
||||
override fun write(b: Int) = host.display.write(b.and(0xFF).toByte())
|
||||
}
|
||||
|
||||
class TerminalInputStream(val host: LuaComputerVM) : InputStream() {
|
||||
|
||||
override fun read(): Int {
|
||||
//System.err.println(Thread.currentThread().name)
|
||||
// would display "LuaJ Separated", which means this InputStream will not block main thread
|
||||
|
||||
/*host.openStdin()
|
||||
synchronized(this) {
|
||||
(this as java.lang.Object).wait()
|
||||
}*/
|
||||
|
||||
return 65//host.stdinInput
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ALException(errorCode: Int) : Exception("ALerror: $errorCode") {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Install a function into the lua.
|
||||
* @param identifier How you might call this lua function. E.g. "term.println"
|
||||
*/
|
||||
fun Globals.addOneArgFun(identifier: String, function: (p0: LuaValue) -> LuaValue) {
|
||||
val theActualFun = object : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
return function(p0)
|
||||
}
|
||||
}
|
||||
|
||||
val tableNames = identifier.split('.')
|
||||
|
||||
if (tableNames.isEmpty()) throw IllegalArgumentException("Identifier is empty")
|
||||
|
||||
//println(tableNames)
|
||||
|
||||
if (this[tableNames[0]].isnil()) {
|
||||
this[tableNames[0]] = LuaValue.tableOf()
|
||||
}
|
||||
else if (!this[tableNames[0]].istable()) {
|
||||
throw IllegalStateException("Redefinition: '${tableNames[0]}' (${this[tableNames[0]]})")
|
||||
}
|
||||
|
||||
var currentTable = this[tableNames[0]]
|
||||
|
||||
// turn nils into tables
|
||||
if (tableNames.size > 1) {
|
||||
tableNames.slice(1..tableNames.lastIndex).forEachIndexed { index, it ->
|
||||
if (currentTable[it].isnil()) {
|
||||
currentTable[it] = LuaValue.tableOf()
|
||||
}
|
||||
else if (!currentTable[it].istable()) {
|
||||
throw IllegalStateException("Redefinition: '${tableNames.slice(0..(index + 1)).joinToString(".")}' (${currentTable[it]})")
|
||||
}
|
||||
|
||||
currentTable = currentTable[it]
|
||||
}
|
||||
|
||||
// actually put the function onto the target
|
||||
// for some reason, memoisation doesn't work here so we use recursion to reach the target table as generated above
|
||||
tailrec fun putIntoTheTableRec(luaTable: LuaValue, recursionCount: Int) {
|
||||
if (recursionCount == tableNames.lastIndex - 1) {
|
||||
luaTable[tableNames[tableNames.lastIndex]] = theActualFun
|
||||
}
|
||||
else {
|
||||
putIntoTheTableRec(luaTable[tableNames[recursionCount + 1]], recursionCount + 1)
|
||||
}
|
||||
}
|
||||
|
||||
putIntoTheTableRec(this[tableNames[0]], 0)
|
||||
}
|
||||
else {
|
||||
this[tableNames[0]] = theActualFun
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a function into the lua.
|
||||
* @param identifier How you might call this lua function. E.g. "term.println"
|
||||
*/
|
||||
fun Globals.addZeroArgFun(identifier: String, function: () -> LuaValue) {
|
||||
val theActualFun = object : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return function()
|
||||
}
|
||||
}
|
||||
|
||||
val tableNames = identifier.split('.')
|
||||
|
||||
if (tableNames.isEmpty()) throw IllegalArgumentException("Identifier is empty")
|
||||
|
||||
//println(tableNames)
|
||||
|
||||
if (this[tableNames[0]].isnil()) {
|
||||
this[tableNames[0]] = LuaValue.tableOf()
|
||||
}
|
||||
else if (!this[tableNames[0]].istable()) {
|
||||
throw IllegalStateException("Redefinition: '${tableNames[0]}' (${this[tableNames[0]]})")
|
||||
}
|
||||
|
||||
var currentTable = this[tableNames[0]]
|
||||
|
||||
// turn nils into tables
|
||||
if (tableNames.size > 1) {
|
||||
tableNames.slice(1..tableNames.lastIndex).forEachIndexed { index, it ->
|
||||
if (currentTable[it].isnil()) {
|
||||
currentTable[it] = LuaValue.tableOf()
|
||||
}
|
||||
else if (!currentTable[it].istable()) {
|
||||
throw IllegalStateException("Redefinition: '${tableNames.slice(0..(index + 1)).joinToString(".")}' (${currentTable[it]})")
|
||||
}
|
||||
|
||||
currentTable = currentTable[it]
|
||||
}
|
||||
|
||||
// actually put the function onto the target
|
||||
// for some reason, memoisation doesn't work here so we use recursion to reach the target table as generated above
|
||||
tailrec fun putIntoTheTableRec(luaTable: LuaValue, recursionCount: Int) {
|
||||
if (recursionCount == tableNames.lastIndex - 1) {
|
||||
luaTable[tableNames[tableNames.lastIndex]] = theActualFun
|
||||
}
|
||||
else {
|
||||
putIntoTheTableRec(luaTable[tableNames[recursionCount + 1]], recursionCount + 1)
|
||||
}
|
||||
}
|
||||
|
||||
putIntoTheTableRec(this[tableNames[0]], 0)
|
||||
}
|
||||
else {
|
||||
this[tableNames[0]] = theActualFun
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a function into the lua.
|
||||
* @param identifier How you might call this lua function. E.g. "term.println"
|
||||
*/
|
||||
fun Globals.addTwoArgFun(identifier: String, function: (p0: LuaValue, p1: LuaValue) -> LuaValue) {
|
||||
val theActualFun = object : TwoArgFunction() {
|
||||
override fun call(p0: LuaValue, p1: LuaValue): LuaValue {
|
||||
return function(p0, p1)
|
||||
}
|
||||
}
|
||||
|
||||
val tableNames = identifier.split('.')
|
||||
|
||||
if (tableNames.isEmpty()) throw IllegalArgumentException("Identifier is empty")
|
||||
|
||||
//println(tableNames)
|
||||
|
||||
if (this[tableNames[0]].isnil()) {
|
||||
this[tableNames[0]] = LuaValue.tableOf()
|
||||
}
|
||||
else if (!this[tableNames[0]].istable()) {
|
||||
throw IllegalStateException("Redefinition: '${tableNames[0]}' (${this[tableNames[0]]})")
|
||||
}
|
||||
|
||||
var currentTable = this[tableNames[0]]
|
||||
|
||||
// turn nils into tables
|
||||
if (tableNames.size > 1) {
|
||||
tableNames.slice(1..tableNames.lastIndex).forEachIndexed { index, it ->
|
||||
if (currentTable[it].isnil()) {
|
||||
currentTable[it] = LuaValue.tableOf()
|
||||
}
|
||||
else if (!currentTable[it].istable()) {
|
||||
throw IllegalStateException("Redefinition: '${tableNames.slice(0..(index + 1)).joinToString(".")}' (${currentTable[it]})")
|
||||
}
|
||||
|
||||
currentTable = currentTable[it]
|
||||
}
|
||||
|
||||
// actually put the function onto the target
|
||||
// for some reason, memoisation doesn't work here so we use recursion to reach the target table as generated above
|
||||
tailrec fun putIntoTheTableRec(luaTable: LuaValue, recursionCount: Int) {
|
||||
if (recursionCount == tableNames.lastIndex - 1) {
|
||||
luaTable[tableNames[tableNames.lastIndex]] = theActualFun
|
||||
}
|
||||
else {
|
||||
putIntoTheTableRec(luaTable[tableNames[recursionCount + 1]], recursionCount + 1)
|
||||
}
|
||||
}
|
||||
|
||||
putIntoTheTableRec(this[tableNames[0]], 0)
|
||||
}
|
||||
else {
|
||||
this[tableNames[0]] = theActualFun
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a function into the lua.
|
||||
* @param identifier How you might call this lua function. E.g. "term.println"
|
||||
*/
|
||||
fun Globals.addThreeArgFun(identifier: String, function: (p0: LuaValue, p1: LuaValue, p2: LuaValue) -> LuaValue) {
|
||||
val theActualFun = object : ThreeArgFunction() {
|
||||
override fun call(p0: LuaValue, p1: LuaValue, p2: LuaValue): LuaValue {
|
||||
return function(p0, p1, p2)
|
||||
}
|
||||
}
|
||||
|
||||
val tableNames = identifier.split('.')
|
||||
|
||||
if (tableNames.isEmpty()) throw IllegalArgumentException("Identifier is empty")
|
||||
|
||||
//println(tableNames)
|
||||
|
||||
if (this[tableNames[0]].isnil()) {
|
||||
this[tableNames[0]] = LuaValue.tableOf()
|
||||
}
|
||||
else if (!this[tableNames[0]].istable()) {
|
||||
throw IllegalStateException("Redefinition: '${tableNames[0]}' (${this[tableNames[0]]})")
|
||||
}
|
||||
|
||||
var currentTable = this[tableNames[0]]
|
||||
|
||||
// turn nils into tables
|
||||
if (tableNames.size > 1) {
|
||||
tableNames.slice(1..tableNames.lastIndex).forEachIndexed { index, it ->
|
||||
if (currentTable[it].isnil()) {
|
||||
currentTable[it] = LuaValue.tableOf()
|
||||
}
|
||||
else if (!currentTable[it].istable()) {
|
||||
throw IllegalStateException("Redefinition: '${tableNames.slice(0..(index + 1)).joinToString(".")}' (${currentTable[it]})")
|
||||
}
|
||||
|
||||
currentTable = currentTable[it]
|
||||
}
|
||||
|
||||
// actually put the function onto the target
|
||||
// for some reason, memoisation doesn't work here so we use recursion to reach the target table as generated above
|
||||
tailrec fun putIntoTheTableRec(luaTable: LuaValue, recursionCount: Int) {
|
||||
if (recursionCount == tableNames.lastIndex - 1) {
|
||||
luaTable[tableNames[tableNames.lastIndex]] = theActualFun
|
||||
}
|
||||
else {
|
||||
putIntoTheTableRec(luaTable[tableNames[recursionCount + 1]], recursionCount + 1)
|
||||
}
|
||||
}
|
||||
|
||||
putIntoTheTableRec(this[tableNames[0]], 0)
|
||||
}
|
||||
else {
|
||||
this[tableNames[0]] = theActualFun
|
||||
}
|
||||
}
|
||||
@@ -1,246 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.computer
|
||||
|
||||
import net.torvald.UnsafeHelper
|
||||
import net.torvald.terrarum.AppLoader
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
import java.io.OutputStream
|
||||
import java.io.PrintStream
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/**
|
||||
* Only one kind of display adapter should exist in the game: they add nothing to the game and the game
|
||||
* shouldn't put much emphasis on computers anyway.
|
||||
*
|
||||
* The actual draw code must not exist in this class!
|
||||
*
|
||||
* Created by minjaesong on 2019-07-09.
|
||||
*/
|
||||
class MDA(val width: Int, val height: Int) {
|
||||
|
||||
companion object {
|
||||
val charset: Charset = Charset.forName("cp437")
|
||||
}
|
||||
|
||||
init {
|
||||
if (width % 2 == 1) throw IllegalArgumentException("Display width must be an even number (width = $width)")
|
||||
}
|
||||
|
||||
private val arrayElemOffset = 8L * if (AppLoader.is32BitJVM) 1 else 2 // 8 for 32-bit, 16 for 64-bit
|
||||
|
||||
private val glyphs = UnsafeHelper.allocate(width.toLong() * height + 1) // extra one byte is absolutely needed
|
||||
private val attributes = UnsafeHelper.allocate(width.toLong() * height + 1)
|
||||
|
||||
var cursor = 0
|
||||
private set
|
||||
var background = 0
|
||||
var foreground = 1
|
||||
var blink = true
|
||||
|
||||
init {
|
||||
glyphs.fillWith(0)
|
||||
attributes.fillWith(1)
|
||||
}
|
||||
|
||||
/*
|
||||
Attibutes memory map:
|
||||
|
||||
for every byte:
|
||||
|
||||
(msb) 00bb 00ff (lsb)
|
||||
|
||||
where:
|
||||
|
||||
bb: background colour
|
||||
ff: foreground colour
|
||||
|
||||
Colours:
|
||||
|
||||
0: black
|
||||
1: light grey
|
||||
2: dark grey
|
||||
3: white
|
||||
|
||||
*/
|
||||
|
||||
fun toAttribute(back: Int, fore: Int) = (back.shl(4) or fore).toByte()
|
||||
|
||||
private fun wrapAround(x: Int, y: Int) = (x fmod width) to (y fmod height)
|
||||
private fun toAddress(x: Int, y: Int) = (y * width + x).toLong()
|
||||
inline private fun Pair<Int, Int>.toAddress() = toAddress(this.first, this.second)
|
||||
|
||||
fun rawGet(offset: Int) = glyphs[offset.toLong()] to attributes[offset.toLong()]
|
||||
|
||||
fun get(x: Int, y: Int): Pair<Byte, Byte> {
|
||||
val a = wrapAround(x, y).toAddress()
|
||||
return glyphs[a] to attributes[a]
|
||||
}
|
||||
|
||||
fun set(x: Int, y: Int, glyph: Byte, attribute: Byte) {
|
||||
val a = wrapAround(x, y).toAddress()
|
||||
glyphs[a] = glyph
|
||||
attributes[a] = attribute
|
||||
}
|
||||
|
||||
private fun set(offset: Int, glyph: Byte, attribute: Byte) {
|
||||
glyphs[offset.toLong()] = glyph
|
||||
attributes[offset.toLong()] = attribute
|
||||
}
|
||||
|
||||
fun setCursor(x: Int, y: Int) {
|
||||
cursor = wrapAround(x, y).toAddress().toInt()
|
||||
}
|
||||
|
||||
// SETTEXT methods should not deal with the scrolling, it must be handled by the PRINT methods.
|
||||
|
||||
/** Bulk write method. Any control characers will be represented as a glyph, rather than an actual control sequence.
|
||||
* E.g. '\n' will print a symbol. */
|
||||
fun setText(x: Int, y: Int, text: ByteArray, attribute: ByteArray) {
|
||||
UnsafeHelper.memcpyRaw(text, arrayElemOffset, null, glyphs.ptr + wrapAround(x, y).toAddress(), text.size.toLong())
|
||||
UnsafeHelper.memcpyRaw(attribute, arrayElemOffset, null, attributes.ptr + wrapAround(x, y).toAddress(), text.size.toLong())
|
||||
}
|
||||
|
||||
private fun setText(offset: Int, text: ByteArray, attribute: ByteArray) {
|
||||
UnsafeHelper.memcpyRaw(text, arrayElemOffset, null, glyphs.ptr + offset, text.size.toLong())
|
||||
UnsafeHelper.memcpyRaw(attribute, arrayElemOffset, null, attributes.ptr + offset, text.size.toLong())
|
||||
}
|
||||
|
||||
/** Bulk write method. Any control characers will be represented as a glyph, rather than an actual control sequence.
|
||||
* E.g. '\n' will print a symbol. */
|
||||
fun setText(x: Int, y: Int, text: ByteArray, attribute: Byte) {
|
||||
setText(x, y, text, ByteArray(text.size) { attribute })
|
||||
}
|
||||
|
||||
private fun setText(offset: Int, text: ByteArray, attribute: Byte = toAttribute(background, foreground)) {
|
||||
setText(offset, text, ByteArray(text.size) { attribute })
|
||||
}
|
||||
|
||||
/** Bulk write method. Any control characers will be represented as a glyph, rather than an actual control sequence.
|
||||
* E.g. '\n' will print a symbol. */
|
||||
inline fun setText(x: Int, y: Int, text: ByteArray) {
|
||||
setText(x, y, text, toAttribute(background, foreground))
|
||||
}
|
||||
|
||||
fun setOneText(x: Int, y: Int, text: Byte, attribute: Byte = toAttribute(background, foreground)) {
|
||||
val o = wrapAround(x, y).toAddress()
|
||||
glyphs[o] = text
|
||||
attributes[o] = attribute
|
||||
}
|
||||
|
||||
private fun setOneText(offset: Int, text: Byte, attribute: Byte = toAttribute(background, foreground)) {
|
||||
glyphs[offset.toLong()] = text
|
||||
attributes[offset.toLong()] = attribute
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun println(text: String) {
|
||||
print(text)
|
||||
write(0x0A)
|
||||
}
|
||||
inline fun print(text: String) {
|
||||
print(text.toByteArray(charset))
|
||||
}
|
||||
|
||||
fun println(text: ByteArray) {
|
||||
print(text)
|
||||
write(0x0A)
|
||||
}
|
||||
fun print(text: ByteArray) {
|
||||
text.forEach { write(it) }
|
||||
}
|
||||
|
||||
fun write(text: Byte) {
|
||||
when (text) {
|
||||
// LF
|
||||
0x0A.toByte() -> newline()
|
||||
// all others (e.g. CR)
|
||||
in 0x00.toByte()..0x0D.toByte() -> { /* do nothing */ }
|
||||
|
||||
else -> {
|
||||
setOneText(cursor, text)
|
||||
cursor += 1
|
||||
|
||||
if (cursor > width * height) {
|
||||
scroll(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
glyphs.fillWith(0)
|
||||
attributes.fillWith(toAttribute(background, foreground))
|
||||
cursor = 0
|
||||
}
|
||||
|
||||
fun clearCurrentLine() {
|
||||
clearLine(cursor / width)
|
||||
}
|
||||
|
||||
fun clearLine(line: Int) {
|
||||
val lineOffset = line * width
|
||||
for (i in 0L until width) {
|
||||
glyphs[lineOffset + i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
fun clearLineAfterCursor() {
|
||||
val lineOffset = (cursor / width) * width
|
||||
for (i in (cursor % width).toLong() until width) {
|
||||
glyphs[lineOffset + i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* moves text and the current cursor position
|
||||
*/
|
||||
fun scroll(amount: Int) {
|
||||
val offset = (width * amount).toLong()
|
||||
if (amount < 0) throw IllegalArgumentException("amount = $amount")
|
||||
|
||||
UnsafeHelper.memcpy(glyphs, offset, glyphs, 0L, glyphs.size - offset)
|
||||
UnsafeHelper.memcpy(attributes, offset, attributes, 0L, attributes.size - offset)
|
||||
|
||||
cursor -= offset.toInt()
|
||||
if (cursor < 0) cursor = 0
|
||||
|
||||
clearLineAfterCursor()
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance one line, scroll the screen if necessary
|
||||
*/
|
||||
fun newline() {
|
||||
cursor += width
|
||||
|
||||
if (cursor >= width * height) {
|
||||
scroll(1)
|
||||
}
|
||||
|
||||
cursor = (cursor / width) * width // set cursorX to 0
|
||||
clearLineAfterCursor()
|
||||
}
|
||||
|
||||
fun dispose() {
|
||||
glyphs.destroy()
|
||||
attributes.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
private class MDAOutputStream(val mda: MDA) : OutputStream() {
|
||||
override fun write(b: Int) {
|
||||
mda.write(b.toByte())
|
||||
}
|
||||
}
|
||||
|
||||
class MDAPrintStream(val mda: MDA) : PrintStream(MDAOutputStream(mda)) {
|
||||
override fun print(s: String?) {
|
||||
mda.print((s ?: "").toByteArray(MDA.charset))
|
||||
}
|
||||
|
||||
override fun println(s: String?) {
|
||||
print(s)
|
||||
mda.newline()
|
||||
}
|
||||
}
|
||||
@@ -1,585 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.computer
|
||||
|
||||
import net.torvald.terrarum.KVHashMap
|
||||
import net.torvald.terrarum.Second
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.ceilInt
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.VDUtil
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.VirtualDisk
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.worldobject.ComputerPartsCodex
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LuaError
|
||||
import org.luaj.vm2.LuaTable
|
||||
import org.luaj.vm2.LuaValue
|
||||
import org.luaj.vm2.lib.TwoArgFunction
|
||||
import org.luaj.vm2.lib.ZeroArgFunction
|
||||
import org.luaj.vm2.lib.jse.JsePlatform
|
||||
import org.lwjgl.BufferUtils
|
||||
import org.lwjgl.openal.AL10
|
||||
import java.io.*
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.*
|
||||
import java.util.logging.Level
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
/**
|
||||
* A part that makes "computer fixture" actually work
|
||||
*
|
||||
* @param avFixtureComputer : actor values for FixtureComputerBase
|
||||
*
|
||||
* @param term : terminal that is connected to the computer fixtures, null if not connected any.
|
||||
* Created by minjaesong on 2016-09-10.
|
||||
*/
|
||||
class TerrarumComputerOldOld(peripheralSlots: Int) {
|
||||
|
||||
val DEBUG_UNLIMITED_MEM = false
|
||||
val DEBUG = true
|
||||
|
||||
|
||||
val maxPeripherals: Int = if (DEBUG) 32 else peripheralSlots
|
||||
|
||||
|
||||
lateinit var luaJ_globals: Globals
|
||||
private set
|
||||
|
||||
var stdout: PrintStream? = null
|
||||
private set
|
||||
var stderr: PrintStream? = null
|
||||
private set
|
||||
var stdin: InputStream? = null
|
||||
private set
|
||||
|
||||
val processorCycle: Int // number of Lua statement to process per tick (1/100 s)
|
||||
get() = ComputerPartsCodex.getProcessorCycles(computerValue.getAsInt("processor") ?: 0)
|
||||
val memSize: Int // in bytes; max: 8 GB
|
||||
get() {
|
||||
if (DEBUG_UNLIMITED_MEM) return 16.shl(20)// 16 MB
|
||||
|
||||
var size = 0
|
||||
for (i in 0..3)
|
||||
size += ComputerPartsCodex.getRamSize(computerValue.getAsInt("memSlot$i")!!)
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
val UUID = java.util.UUID.randomUUID().toString()
|
||||
|
||||
val computerValue = KVHashMap()
|
||||
|
||||
var isHalted = false
|
||||
|
||||
lateinit var term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype
|
||||
private set
|
||||
|
||||
val peripheralTable = Array<net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral.Peripheral?>(peripheralSlots, { null }) // index == slot number
|
||||
|
||||
var stdinInput: Int = -1
|
||||
private set
|
||||
|
||||
|
||||
// os-related functions. These are called "machine" library-wise.
|
||||
private val startupTimestamp: Long = System.currentTimeMillis()
|
||||
/** Time elapsed since the power is on. */
|
||||
val milliTime: Int
|
||||
get() = (System.currentTimeMillis() - startupTimestamp).toInt()
|
||||
|
||||
/** String:
|
||||
* if it's UUID, formatted UUID as string, always 36 chars
|
||||
* if not (test purpose only!), just String
|
||||
*/
|
||||
val diskRack = HashMap<String, VirtualDisk>()
|
||||
|
||||
fun attachDisk(slot: String, filename: String) {
|
||||
computerValue[slot] = filename
|
||||
|
||||
// put disk in diskRack
|
||||
if (filename.isNotEmpty() && filename.isNotBlank()) {
|
||||
diskRack[slot] = VDUtil.readDiskArchive(
|
||||
File(Terrarum.currentSaveDir.path + "/computers/$filename").absoluteFile,
|
||||
Level.WARNING,
|
||||
{ },
|
||||
net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi.Filesystem.sysCharset
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
computerValue["memslot0"] = 4864 // -1 indicates mem slot is empty
|
||||
computerValue["memslot1"] = -1 // put index of item here
|
||||
computerValue["memslot2"] = -1 // ditto.
|
||||
computerValue["memslot3"] = -1 // do.
|
||||
|
||||
computerValue["processor"] = -1 // do.
|
||||
|
||||
// as in "dev/hda"; refers hard disk drive (and no partitioning)
|
||||
attachDisk("hda", "uuid_testhda")
|
||||
attachDisk("hdb", "")
|
||||
attachDisk("hdc", "")
|
||||
attachDisk("hdd", "")
|
||||
// as in "dev/fd1"; refers floppy disk drive
|
||||
attachDisk("fd1", "")
|
||||
attachDisk("fd2", "")
|
||||
attachDisk("fd3", "")
|
||||
attachDisk("fd4", "")
|
||||
// SCSI connected optical drive
|
||||
attachDisk("sda", "")
|
||||
|
||||
// boot device
|
||||
computerValue["boot"] = "hda"
|
||||
}
|
||||
|
||||
fun getPeripheral(tableName: String): net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral.Peripheral? {
|
||||
peripheralTable.forEach {
|
||||
if (it?.tableName == tableName)
|
||||
return it
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun getPeripheralSlot(tableName: String): Int? {
|
||||
peripheralTable.forEachIndexed { index, peri ->
|
||||
if (peri?.tableName == tableName)
|
||||
return index
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/** @return installed slot */
|
||||
fun attachPeripheral(peri: net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral.Peripheral): Int {
|
||||
(0..maxPeripherals - 1).forEach {
|
||||
try {
|
||||
attachPeripheralTo(peri, it)
|
||||
return it
|
||||
}
|
||||
catch (tryNext: RuntimeException) { }
|
||||
}
|
||||
|
||||
throw RuntimeException("No vacant peripheral slot")
|
||||
}
|
||||
|
||||
fun attachPeripheralTo(peri: net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral.Peripheral, slot: Int) {
|
||||
if (peripheralTable[slot] == null) {
|
||||
peripheralTable[slot] = peri
|
||||
peri.loadLib(luaJ_globals)
|
||||
println("[TerrarumComputerOld] loading peripheral $peri")
|
||||
}
|
||||
else {
|
||||
throw RuntimeException("Peripheral slot is already taken by: ${peripheralTable[slot]?.tableName}")
|
||||
}
|
||||
}
|
||||
|
||||
fun detachPeripheral(peri: net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral.Peripheral) {
|
||||
// search for the peripheral
|
||||
var found = -1
|
||||
for (i in 0..maxPeripherals - 1) {
|
||||
if (peripheralTable[i] == peri) {
|
||||
found = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if (found >= 0) {
|
||||
peripheralTable[found] = null
|
||||
println("[TerrarumComputerOld] unloading peripheral $peri")
|
||||
}
|
||||
else {
|
||||
throw IllegalArgumentException("Peripheral not exists: $peri")
|
||||
}
|
||||
}
|
||||
|
||||
fun attachTerminal(term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype) {
|
||||
this.term = term
|
||||
initSandbox(term)
|
||||
}
|
||||
|
||||
fun initSandbox(term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype) {
|
||||
luaJ_globals = JsePlatform.debugGlobals()
|
||||
|
||||
stdout = net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.TerminalPrintStream(this)
|
||||
stderr = net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.TerminalPrintStream(this)
|
||||
stdin = net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.TerminalInputStream(this)
|
||||
|
||||
luaJ_globals.STDOUT = stdout
|
||||
luaJ_globals.STDERR = stderr
|
||||
luaJ_globals.STDIN = stdin
|
||||
|
||||
luaJ_globals["bit"] = luaJ_globals["bit32"]
|
||||
|
||||
// load libraries
|
||||
net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi.Term(luaJ_globals, term)
|
||||
net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi.Security(luaJ_globals)
|
||||
net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi.Filesystem(luaJ_globals, this)
|
||||
net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi.HostAccessProvider(luaJ_globals, this)
|
||||
net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi.Input(luaJ_globals, this)
|
||||
net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi.PcSpeakerDriver(luaJ_globals, this)
|
||||
net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi.WorldInformationProvider(luaJ_globals)
|
||||
|
||||
// secure the sandbox
|
||||
//luaJ_globals["io"] = LuaValue.NIL
|
||||
// dubug should be sandboxed in BOOT.lua (use OpenComputers code)
|
||||
//val sethook = luaJ_globals["debug"]["sethook"]
|
||||
//luaJ_globals["debug"] = LuaValue.NIL
|
||||
|
||||
// ROM BASIC
|
||||
val inputStream = javaClass.getResourceAsStream("/net/torvald/terrarum/modulecomputers/virtualcomputer/virtualcomputer/assets/lua/BOOT.lua")
|
||||
runCommand(InputStreamReader(inputStream), "=boot")
|
||||
|
||||
// computer-related global functions
|
||||
luaJ_globals["totalMemory"] = LuaFunGetTotalMem(this)
|
||||
|
||||
luaJ_globals["computer"] = LuaTable()
|
||||
// rest of the "computer" APIs should be implemented in BOOT.lua
|
||||
|
||||
|
||||
|
||||
// load every peripheral if we're in DEBUG
|
||||
if (DEBUG) {
|
||||
attachPeripheral(net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral.PeripheralInternet(this))
|
||||
attachPeripheral(net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral.PeripheralPSG(this))
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
fun update(delta: Float) {
|
||||
|
||||
if (currentExecutionThread.state == Thread.State.TERMINATED) {
|
||||
threadRun = false
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (!isHalted) {
|
||||
runBeepQueueManager(delta)
|
||||
}
|
||||
}
|
||||
|
||||
fun keyPressed(key: Int, c: Char) {
|
||||
stdinInput = c.toInt()
|
||||
|
||||
// wake thread
|
||||
runnableRunCommand.resume()
|
||||
|
||||
synchronized(stdin!!) {
|
||||
(stdin as java.lang.Object).notifyAll()
|
||||
}
|
||||
}
|
||||
|
||||
fun openStdin() {
|
||||
stdinInput = -1
|
||||
// sleep the thread
|
||||
runnableRunCommand.pause()
|
||||
}
|
||||
|
||||
lateinit var currentExecutionThread: Thread
|
||||
private set
|
||||
lateinit var runnableRunCommand: ThreadRunCommand
|
||||
private set
|
||||
private var threadRun = false
|
||||
|
||||
fun runCommand(line: String, env: String) {
|
||||
if (!threadRun) {
|
||||
runnableRunCommand = ThreadRunCommand(luaJ_globals, line, env)
|
||||
currentExecutionThread = Thread(null, runnableRunCommand, "LuaJ Separated")
|
||||
currentExecutionThread.start()
|
||||
threadRun = true
|
||||
}
|
||||
}
|
||||
|
||||
fun runCommand(reader: Reader, filename: String) {
|
||||
if (!threadRun) {
|
||||
runnableRunCommand = ThreadRunCommand(luaJ_globals, reader, filename)
|
||||
currentExecutionThread = Thread(null, runnableRunCommand, "LuaJ Separated")
|
||||
currentExecutionThread.start()
|
||||
threadRun = true
|
||||
}
|
||||
}
|
||||
|
||||
class ThreadRunCommand : Runnable {
|
||||
|
||||
private val mode: Int
|
||||
private val arg1: Any
|
||||
private val arg2: String
|
||||
private val lua: Globals
|
||||
|
||||
@Volatile private var running = true
|
||||
@Volatile private var paused = false
|
||||
private val pauseLock = java.lang.Object()
|
||||
|
||||
constructor(luaInstance: Globals, line: String, env: String) {
|
||||
mode = 0
|
||||
arg1 = line
|
||||
arg2 = env
|
||||
lua = luaInstance
|
||||
}
|
||||
|
||||
constructor(luaInstance: Globals, reader: Reader, filename: String) {
|
||||
mode = 1
|
||||
arg1 = reader
|
||||
arg2 = filename
|
||||
lua = luaInstance
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
synchronized(pauseLock) {
|
||||
if (!running) { // may have changed while waiting to
|
||||
// synchronize on pauseLock
|
||||
return
|
||||
}
|
||||
if (paused) {
|
||||
try {
|
||||
pauseLock.wait() // will cause this Thread to block until
|
||||
// another thread calls pauseLock.notifyAll()
|
||||
// Note that calling wait() will
|
||||
// relinquish the synchronized lock that this
|
||||
// thread holds on pauseLock so another thread
|
||||
// can acquire the lock to call notifyAll()
|
||||
// (link with explanation below this code)
|
||||
}
|
||||
catch (ex: InterruptedException) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!running) { // running might have changed since we paused
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
val chunk: LuaValue
|
||||
if (mode == 0)
|
||||
chunk = lua.load(arg1 as String, arg2)
|
||||
else if (mode == 1)
|
||||
chunk = lua.load(arg1 as Reader, arg2)
|
||||
else
|
||||
throw IllegalArgumentException("Unsupported mode: $mode")
|
||||
|
||||
|
||||
chunk.call()
|
||||
}
|
||||
catch (e: LuaError) {
|
||||
e.printStackTrace(System.err)
|
||||
//lua.STDERR.println("${SimpleTextTerminal.ASCII_DLE}${e.message}${SimpleTextTerminal.ASCII_DC4}")
|
||||
}
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
running = false
|
||||
// you might also want to do this:
|
||||
//interrupt()
|
||||
}
|
||||
|
||||
fun pause() {
|
||||
// you may want to throw an IllegalStateException if !running
|
||||
paused = true
|
||||
}
|
||||
|
||||
fun resume() {
|
||||
synchronized(pauseLock) {
|
||||
paused = false
|
||||
pauseLock.notifyAll() // Unblocks thread
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LuaFunGetTotalMem(val computer: TerrarumComputerOldOld) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(computer.memSize)
|
||||
}
|
||||
}
|
||||
|
||||
class ComputerEmitTone(val computer: TerrarumComputerOldOld) : TwoArgFunction() {
|
||||
override fun call(millisec: LuaValue, freq: LuaValue): LuaValue {
|
||||
computer.playTone(millisec.checkdouble().toFloat(), freq.checkdouble())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// BEEPER DRIVER //
|
||||
///////////////////
|
||||
|
||||
private val beepMaxLen = 10f
|
||||
// let's regard it as a tracker...
|
||||
private val beepQueue = ArrayList<Pair<Second, Double>>()
|
||||
private var beepCursor = -1
|
||||
private var beepQueueLineExecTimer: Second = 0f
|
||||
private var beepQueueFired = false
|
||||
|
||||
private fun runBeepQueueManager(delta: Float) {
|
||||
// start emitTone queue
|
||||
if (beepQueue.size > 0 && beepCursor == -1) {
|
||||
beepCursor = 0
|
||||
}
|
||||
|
||||
// advance emitTone queue
|
||||
if (beepCursor >= 0 && beepQueueLineExecTimer >= beepQueueGetLenOfPtn(beepCursor)) {
|
||||
beepQueueLineExecTimer -= beepQueueGetLenOfPtn(beepCursor)
|
||||
beepCursor += 1
|
||||
beepQueueFired = false
|
||||
}
|
||||
|
||||
// complete emitTone queue
|
||||
if (beepCursor >= beepQueue.size) {
|
||||
clearBeepQueue()
|
||||
}
|
||||
|
||||
// actually play queue
|
||||
if (beepCursor >= 0 && beepQueue.size > 0 && !beepQueueFired) {
|
||||
playTone(beepQueue[beepCursor].first, beepQueue[beepCursor].second)
|
||||
beepQueueFired = true
|
||||
|
||||
// delete sources that is finished. AL is limited to 256 sources. If you exceed it,
|
||||
// we won't get any more sounds played.
|
||||
AL10.alSourcei(oldBeepSource, AL10.AL_BUFFER, 0)
|
||||
AL10.alDeleteSources(oldBeepSource)
|
||||
AL10.alDeleteBuffers(oldBeepBuffer)
|
||||
}
|
||||
|
||||
if (beepQueueFired) beepQueueLineExecTimer += delta
|
||||
}
|
||||
|
||||
fun clearBeepQueue() {
|
||||
beepQueue.clear()
|
||||
beepCursor = -1
|
||||
beepQueueLineExecTimer = 0f
|
||||
|
||||
//AL.destroy()
|
||||
|
||||
if (DEBUG) println("[TerrarumComputerOld] !! Beep queue clear")
|
||||
}
|
||||
|
||||
fun enqueueBeep(duration: Double, freq: Double) {
|
||||
beepQueue.add(Pair(Math.min(duration.toFloat(), beepMaxLen), freq))
|
||||
}
|
||||
|
||||
fun beepQueueGetLenOfPtn(ptnIndex: Int) = beepQueue[ptnIndex].first
|
||||
|
||||
|
||||
////////////////////
|
||||
// TONE GENERATOR //
|
||||
////////////////////
|
||||
|
||||
private val sampleRate = 44100
|
||||
private var beepSource: Int = -1
|
||||
private var beepBuffer: Int = -1
|
||||
private var oldBeepSource: Int = -1
|
||||
private var oldBeepBuffer: Int = -1
|
||||
var audioData: ByteBuffer? = null
|
||||
|
||||
/**
|
||||
* @param duration : milliseconds
|
||||
* @param rampUp
|
||||
* @param rampDown
|
||||
*
|
||||
* ,---. (true, true) ,---- (true, false) ----. (false, true) ----- (false, false)
|
||||
*/
|
||||
private fun makeAudioData(duration: Second, freq: Double,
|
||||
rampUp: Boolean = true, rampDown: Boolean = true): ByteBuffer {
|
||||
|
||||
TODO("with duration as Seconds")
|
||||
|
||||
val audioDataSize = duration.times(sampleRate).ceilInt()
|
||||
val audioData = BufferUtils.createByteBuffer(audioDataSize)
|
||||
|
||||
/*val realDuration = duration * sampleRate / 1000
|
||||
val chopSize = freq / sampleRate
|
||||
|
||||
val amp = Math.max(4600.0 / freq, 1.0)
|
||||
val nHarmonics = if (freq >= 22050.0) 1
|
||||
else if (freq >= 11025.0) 2
|
||||
else if (freq >= 5512.5) 3
|
||||
else if (freq >= 2756.25) 4
|
||||
else if (freq >= 1378.125) 5
|
||||
else if (freq >= 689.0625) 6
|
||||
else 7
|
||||
|
||||
val transitionThre = 974.47218
|
||||
|
||||
// TODO volume ramping?
|
||||
if (freq == 0.0) {
|
||||
for (_ in 0..audioDataSize - 1) {
|
||||
audioData.put(0x00.toByte())
|
||||
}
|
||||
}
|
||||
else if (freq < transitionThre) { // chopper generator (for low freq)
|
||||
for (tsart in 0..audioDataSize - 1) {
|
||||
var sine: Double = amp * Math.cos(Math.PI * 2 * () * chopSize)
|
||||
if (sine > 0.79) sine = 0.79
|
||||
else if (sine < -0.79) sine = -0.79
|
||||
audioData.put(
|
||||
(0.5 + 0.5 * sine).times(0xFF).roundToInt().toByte()
|
||||
)
|
||||
}
|
||||
}
|
||||
else { // harmonics generator (for high freq)
|
||||
for (x in 0..realDuration - 1) {
|
||||
var sine: Double = 0.0
|
||||
for (k in 1..nHarmonics) { // mix only odd harmonics in order to make a squarewave
|
||||
sine += Math.sin(Math.PI * 2 * (2*k - 1) * chopSize * x) / (2*k - 1)
|
||||
}
|
||||
audioData.put(
|
||||
(0.5 + 0.5 * sine).times(0xFF).roundToInt().toByte()
|
||||
)
|
||||
}
|
||||
}*/
|
||||
|
||||
audioData.rewind()
|
||||
|
||||
return audioData
|
||||
}
|
||||
|
||||
private fun playTone(length: Second, freq: Double) {
|
||||
/*audioData = makeAudioData(leninmilli, freq)
|
||||
|
||||
|
||||
if (!AL.isCreated()) AL.create()
|
||||
|
||||
|
||||
// Clear error stack.
|
||||
AL10.alGetError()
|
||||
|
||||
oldBeepBuffer = beepBuffer
|
||||
beepBuffer = AL10.alGenBuffers()
|
||||
checkALError()
|
||||
|
||||
try {
|
||||
AL10.alBufferData(beepBuffer, AL10.AL_FORMAT_MONO8, audioData, sampleRate)
|
||||
checkALError()
|
||||
|
||||
oldBeepSource = beepSource
|
||||
beepSource = AL10.alGenSources()
|
||||
checkALError()
|
||||
|
||||
try {
|
||||
AL10.alSourceQueueBuffers(beepSource, beepBuffer)
|
||||
checkALError()
|
||||
|
||||
AL10.alSource3f(beepSource, AL10.AL_POSITION, 0f, 0f, 1f)
|
||||
AL10.alSourcef(beepSource, AL10.AL_REFERENCE_DISTANCE, 1f)
|
||||
AL10.alSourcef(beepSource, AL10.AL_MAX_DISTANCE, 1f)
|
||||
AL10.alSourcef(beepSource, AL10.AL_GAIN, 0.3f)
|
||||
checkALError()
|
||||
|
||||
AL10.alSourcePlay(beepSource)
|
||||
checkALError()
|
||||
}
|
||||
catch (e: ALException) {
|
||||
AL10.alDeleteSources(beepSource)
|
||||
}
|
||||
}
|
||||
catch (e: ALException) {
|
||||
AL10.alDeleteSources(beepSource)
|
||||
}*/
|
||||
}
|
||||
|
||||
// Custom implementation of Util.checkALError() that uses our custom exception.
|
||||
private fun checkALError() {
|
||||
val errorCode = AL10.alGetError()
|
||||
if (errorCode != AL10.AL_NO_ERROR) {
|
||||
throw net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.ALException(errorCode)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,521 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi
|
||||
|
||||
import org.luaj.vm2.*
|
||||
import org.luaj.vm2.lib.OneArgFunction
|
||||
import org.luaj.vm2.lib.TwoArgFunction
|
||||
import org.luaj.vm2.lib.ZeroArgFunction
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi.Term.Companion.checkIBM437
|
||||
import java.io.*
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.NoSuchFileException
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* computer directory:
|
||||
* .../computers/
|
||||
* media/hda/ -> .../computers/<uuid for the hda>/
|
||||
*
|
||||
* Created by minjaesong on 2016-09-17.
|
||||
*
|
||||
*
|
||||
* NOTES:
|
||||
* Don't convert '\' to '/'! Rev-slash is used for escape character in sh, and we're sh-compatible!
|
||||
* Use .absoluteFile whenever possible; there's fuckin oddity! (http://bugs.java.com/bugdatabase/view_bug.do;:YfiG?bug_id=4483097)
|
||||
*/
|
||||
@Deprecated("Fuck permission and shit, we go virtual. Use FilesystemTar")
|
||||
internal class FilesystemDir(globals: Globals, computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) {
|
||||
|
||||
init {
|
||||
// load things. WARNING: THIS IS MANUAL!
|
||||
globals["fs"] = LuaValue.tableOf()
|
||||
globals["fs"]["list"] = ListFiles(computer) // CC compliant
|
||||
globals["fs"]["exists"] = FileExists(computer) // CC/OC compliant
|
||||
globals["fs"]["isDir"] = IsDirectory(computer) // CC compliant
|
||||
globals["fs"]["isFile"] = IsFile(computer)
|
||||
globals["fs"]["isReadOnly"] = IsReadOnly(computer) // CC compliant
|
||||
globals["fs"]["getSize"] = GetSize(computer) // CC compliant
|
||||
globals["fs"]["mkdir"] = Mkdir(computer)
|
||||
globals["fs"]["mv"] = Mv(computer)
|
||||
globals["fs"]["cp"] = Cp(computer)
|
||||
globals["fs"]["rm"] = Rm(computer)
|
||||
globals["fs"]["concat"] = ConcatPath(computer) // OC compliant
|
||||
globals["fs"]["open"] = OpenFile(computer) //CC compliant
|
||||
globals["fs"]["parent"] = GetParentDir(computer)
|
||||
// fs.dofile defined in BOOT
|
||||
// fs.fetchText defined in ROMLIB
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun ensurePathSanity(path: LuaValue) {
|
||||
if (path.checkIBM437().contains(Regex("""\.\.""")))
|
||||
throw LuaError("'..' on path is not supported.")
|
||||
if (!isValidFilename(path.checkIBM437()))
|
||||
throw IOException("path contains invalid characters")
|
||||
}
|
||||
|
||||
var isCaseInsensitive: Boolean
|
||||
|
||||
init {
|
||||
try {
|
||||
val uuid = UUID.randomUUID().toString()
|
||||
val lowerCase = File(Terrarum.currentSaveDir, uuid + "oc_rox")
|
||||
val upperCase = File(Terrarum.currentSaveDir, uuid + "OC_ROX")
|
||||
// This should NEVER happen but could also lead to VERY weird bugs, so we
|
||||
// make sure the files don't exist.
|
||||
if (lowerCase.exists()) lowerCase.delete()
|
||||
if (upperCase.exists()) upperCase.delete()
|
||||
|
||||
lowerCase.createNewFile()
|
||||
|
||||
val insensitive = upperCase.exists()
|
||||
lowerCase.delete()
|
||||
|
||||
isCaseInsensitive = insensitive
|
||||
|
||||
println("[Filesystem] Case insensitivity: $isCaseInsensitive")
|
||||
}
|
||||
catch (e: IOException) {
|
||||
System.err.println("[Filesystem] Couldn't determine if the file system is case sensitive, falling back to insensitive.")
|
||||
e.printStackTrace(System.out)
|
||||
isCaseInsensitive = true
|
||||
}
|
||||
}
|
||||
|
||||
// Worst-case: we're on Windows or using a FAT32 partition mounted in *nix.
|
||||
// Note: we allow / as the path separator and expect all \s to be converted
|
||||
// accordingly before the path is passed to the file system.
|
||||
private val invalidChars = Regex("""[<>:"|?*\u0000-\u001F]""") // original OC uses Set(); we use regex
|
||||
|
||||
fun isValidFilename(name: String) = !name.contains(invalidChars)
|
||||
|
||||
fun String.validatePath() : String {
|
||||
if (!isValidFilename(this)) {
|
||||
throw IOException("path contains invalid characters")
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/** actual directory: <appdata>/Saves/<savename>/computers/<drivename>/
|
||||
* directs media/ directory to /<uuid> directory
|
||||
*/
|
||||
fun net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld.getRealPath(luapath: LuaValue) : String {
|
||||
// direct mounted paths to real path
|
||||
val computerDir = Terrarum.currentSaveDir.absolutePath + "/computers/"
|
||||
/* if not begins with "(/?)media/", direct to boot
|
||||
* else, to corresponding drives
|
||||
*
|
||||
* List of device names (these are auto-mounted. why? primitivism :p):
|
||||
* = hda - hdd: hard disks
|
||||
* = fd1 - fd4: floppy drives
|
||||
* = sda: whatever external drives, usually a CD
|
||||
* = boot: current boot device
|
||||
*/
|
||||
|
||||
// remove first '/' in path
|
||||
var path = luapath.checkIBM437().validatePath()
|
||||
if (path.startsWith('/')) path = path.substring(1)
|
||||
|
||||
val finalPath: String
|
||||
|
||||
if (path.startsWith("media/")) {
|
||||
val device = path.substring(6, 9)
|
||||
val subPath = path.substring(9)
|
||||
finalPath = computerDir + this.computerValue.getAsString("device") + subPath
|
||||
}
|
||||
else {
|
||||
finalPath = computerDir + this.computerValue.getAsString("boot") + "/" + path
|
||||
}
|
||||
|
||||
// remove trailing slash
|
||||
return if (finalPath.endsWith("\\") || finalPath.endsWith("/"))
|
||||
finalPath.substring(0, finalPath.length - 1)
|
||||
else
|
||||
finalPath
|
||||
}
|
||||
|
||||
fun combinePath(base: String, local: String) : String {
|
||||
return "$base$local".replace("//", "/")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cname == UUID of the drive
|
||||
*
|
||||
* actual directory: <appdata>/Saves/<savename>/computers/<drivename>/
|
||||
*/
|
||||
class ListFiles(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(path)
|
||||
|
||||
println("ListFiles: got path ${path.checkIBM437()}")
|
||||
|
||||
val table = LuaTable()
|
||||
val file = File(computer.getRealPath(path)).absoluteFile
|
||||
try {
|
||||
file.list().forEachIndexed { i, s -> table.insert(i, LuaValue.valueOf(s)) }
|
||||
}
|
||||
catch (e: NullPointerException) {}
|
||||
return table
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't use this. Use isFile */
|
||||
class FileExists(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(Files.exists(Paths.get(computer.getRealPath(path)).toAbsolutePath()))
|
||||
}
|
||||
}
|
||||
|
||||
class IsDirectory(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(path)
|
||||
|
||||
val isDir = Files.isDirectory(Paths.get(computer.getRealPath(path)).toAbsolutePath())
|
||||
val exists = Files.exists(Paths.get(computer.getRealPath(path)).toAbsolutePath())
|
||||
|
||||
return LuaValue.valueOf(isDir || exists)
|
||||
}
|
||||
}
|
||||
|
||||
class IsFile(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(path)
|
||||
|
||||
// check if the path is file by checking:
|
||||
// 1. isfile
|
||||
// 2. canwrite
|
||||
// 3. length
|
||||
// Why? Our Java simply wants to fuck you.
|
||||
|
||||
val path = Paths.get(computer.getRealPath(path)).toAbsolutePath()
|
||||
var result = false
|
||||
result = Files.isRegularFile(path)
|
||||
|
||||
if (!result) result = Files.isWritable(path)
|
||||
|
||||
if (!result)
|
||||
try { result = Files.size(path) > 0 }
|
||||
catch (e: NoSuchFileException) { result = false }
|
||||
|
||||
return LuaValue.valueOf(result)
|
||||
}
|
||||
}
|
||||
|
||||
class IsReadOnly(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(!Files.isWritable(Paths.get(computer.getRealPath(path)).toAbsolutePath()))
|
||||
}
|
||||
}
|
||||
|
||||
/** we have 4GB file size limit */
|
||||
class GetSize(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(Files.size(Paths.get(computer.getRealPath(path)).toAbsolutePath()).toInt())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO class GetFreeSpace
|
||||
|
||||
/**
|
||||
* difference with ComputerCraft: it returns boolean, true on successful.
|
||||
*/
|
||||
class Mkdir(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(File(computer.getRealPath(path)).absoluteFile.mkdir())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* moves a directory, overwrites the target
|
||||
*/
|
||||
class Mv(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : TwoArgFunction() {
|
||||
override fun call(from: LuaValue, to: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(from)
|
||||
FilesystemDir.ensurePathSanity(to)
|
||||
|
||||
val fromFile = File(computer.getRealPath(from)).absoluteFile
|
||||
var success = fromFile.copyRecursively(
|
||||
File(computer.getRealPath(to)).absoluteFile, overwrite = true
|
||||
)
|
||||
if (success) success = fromFile.deleteRecursively()
|
||||
else return LuaValue.valueOf(false)
|
||||
return LuaValue.valueOf(success)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* copies a directory, overwrites the target
|
||||
* difference with ComputerCraft: it returns boolean, true on successful.
|
||||
*/
|
||||
class Cp(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : TwoArgFunction() {
|
||||
override fun call(from: LuaValue, to: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(from)
|
||||
FilesystemDir.ensurePathSanity(to)
|
||||
|
||||
return LuaValue.valueOf(
|
||||
File(computer.getRealPath(from)).absoluteFile.copyRecursively(
|
||||
File(computer.getRealPath(to)).absoluteFile, overwrite = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* difference with ComputerCraft: it returns boolean, true on successful.
|
||||
*/
|
||||
class Rm(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(path)
|
||||
|
||||
return LuaValue.valueOf(
|
||||
File(computer.getRealPath(path)).absoluteFile.deleteRecursively()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ConcatPath(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : TwoArgFunction() {
|
||||
override fun call(base: LuaValue, local: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(base)
|
||||
FilesystemDir.ensurePathSanity(local)
|
||||
|
||||
val combinedPath = combinePath(base.checkIBM437().validatePath(), local.checkIBM437().validatePath())
|
||||
return LuaValue.valueOf(combinedPath)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mode: r, rb, w, wb, a, ab
|
||||
*
|
||||
* Difference: TEXT MODE assumes CP437 instead of UTF-8!
|
||||
*
|
||||
* When you have opened a file you must always close the file handle, or else data may not be saved.
|
||||
*
|
||||
* FILE class in CC:
|
||||
* (when you look thru them using file = fs.open("./test", "w")
|
||||
*
|
||||
* file = {
|
||||
* close = function()
|
||||
* -- write mode
|
||||
* write = function(string)
|
||||
* flush = function() -- write, keep the handle
|
||||
* writeLine = function(string) -- text mode
|
||||
* -- read mode
|
||||
* readLine = function() -- text mode
|
||||
* readAll = function()
|
||||
* -- binary read mode
|
||||
* read = function() -- read single byte. return: number or nil
|
||||
* -- binary write mode
|
||||
* write = function(byte)
|
||||
* writeBytes = function(string as bytearray)
|
||||
* }
|
||||
*/
|
||||
class OpenFile(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : TwoArgFunction() {
|
||||
override fun call(path: LuaValue, mode: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(path)
|
||||
|
||||
|
||||
|
||||
val mode = mode.checkIBM437().toLowerCase()
|
||||
val luaClass = LuaTable()
|
||||
val file = File(computer.getRealPath(path)).absoluteFile
|
||||
|
||||
if (mode.contains(Regex("""[aw]""")) && !file.canWrite())
|
||||
throw LuaError("Cannot open file for " +
|
||||
"${if (mode.startsWith('w')) "read" else "append"} mode" +
|
||||
": is readonly.")
|
||||
|
||||
|
||||
|
||||
|
||||
when (mode) {
|
||||
"r" -> {
|
||||
try {
|
||||
val fr = FileReader(file)
|
||||
luaClass["close"] = FileClassClose(fr)
|
||||
luaClass["readLine"] = FileClassReadLine(fr)
|
||||
luaClass["readAll"] = FileClassReadAll(file.toPath())
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
throw LuaError(
|
||||
if (e.message != null && e.message!!.contains(Regex("""[Aa]ccess (is )?denied""")))
|
||||
"$path: access denied."
|
||||
else
|
||||
"$path: no such file."
|
||||
)
|
||||
}
|
||||
}
|
||||
"rb" -> {
|
||||
try {
|
||||
val fis = FileInputStream(file)
|
||||
luaClass["close"] = FileClassClose(fis)
|
||||
luaClass["read"] = FileClassReadByte(fis)
|
||||
luaClass["readAll"] = FileClassReadAll(file.toPath())
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
throw LuaError("$path: no such file.")
|
||||
}
|
||||
}
|
||||
"w", "a" -> {
|
||||
try {
|
||||
val fw = FileWriter(file, (mode.startsWith('a')))
|
||||
luaClass["close"] = FileClassClose(fw)
|
||||
luaClass["write"] = FileClassPrintText(fw)
|
||||
luaClass["writeLine"] = FileClassPrintlnText(fw)
|
||||
luaClass["flush"] = FileClassFlush(fw)
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
throw LuaError("$path: is a directory.")
|
||||
}
|
||||
}
|
||||
"wb", "ab" -> {
|
||||
try {
|
||||
val fos = FileOutputStream(file, (mode.startsWith('a')))
|
||||
luaClass["close"] = FileClassClose(fos)
|
||||
luaClass["write"] = FileClassWriteByte(fos)
|
||||
luaClass["writeBytes"] = FileClassWriteBytes(fos)
|
||||
luaClass["flush"] = FileClassFlush(fos)
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
throw LuaError("$path: is a directory.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return luaClass
|
||||
}
|
||||
}
|
||||
|
||||
class GetParentDir(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
FilesystemDir.ensurePathSanity(path)
|
||||
|
||||
var pathSB = StringBuilder(path.checkIBM437())
|
||||
|
||||
// backward travel, drop chars until '/' has encountered
|
||||
while (!pathSB.endsWith('/'))
|
||||
pathSB.deleteCharAt(pathSB.lastIndex - 1)
|
||||
|
||||
// drop trailing '/'
|
||||
if (pathSB.endsWith('/'))
|
||||
pathSB.deleteCharAt(pathSB.lastIndex - 1)
|
||||
|
||||
return LuaValue.valueOf(pathSB.toString())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// OpenFile implementations //
|
||||
//////////////////////////////
|
||||
|
||||
private class FileClassClose(val fo: Any) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
if (fo is FileOutputStream)
|
||||
fo.close()
|
||||
else if (fo is FileWriter)
|
||||
fo.close()
|
||||
else if (fo is FileReader)
|
||||
fo.close()
|
||||
else if (fo is FileInputStream)
|
||||
fo.close()
|
||||
else
|
||||
throw IllegalArgumentException("Unacceptable file output: must be either Input/OutputStream or Reader/Writer.")
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassWriteByte(val fos: FileOutputStream) : OneArgFunction() {
|
||||
override fun call(byte: LuaValue) : LuaValue {
|
||||
fos.write(byte.checkint())
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassWriteBytes(val fos: FileOutputStream) : OneArgFunction() {
|
||||
override fun call(byteString: LuaValue) : LuaValue {
|
||||
val byteString = byteString.checkIBM437()
|
||||
val bytearr = ByteArray(byteString.length, { byteString[it].toByte() })
|
||||
fos.write(bytearr)
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassPrintText(val fw: FileWriter) : OneArgFunction() {
|
||||
override fun call(string: LuaValue) : LuaValue {
|
||||
val text = string.checkIBM437()
|
||||
fw.write(text)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassPrintlnText(val fw: FileWriter) : OneArgFunction() {
|
||||
override fun call(string: LuaValue) : LuaValue {
|
||||
val text = string.checkIBM437() + "\n"
|
||||
fw.write(text)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassFlush(val fo: Any) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
if (fo is FileOutputStream)
|
||||
fo.flush()
|
||||
else if (fo is FileWriter)
|
||||
fo.flush()
|
||||
else
|
||||
throw IllegalArgumentException("Unacceptable file output: must be either OutputStream or Writer.")
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadByte(val fis: FileInputStream) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
val readByte = fis.read()
|
||||
return if (readByte == -1) LuaValue.NIL else LuaValue.valueOf(readByte)
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadAllBytes(val path: Path) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
val byteArr = Files.readAllBytes(path)
|
||||
val s: String = java.lang.String(byteArr, "IBM437").toString()
|
||||
return LuaValue.valueOf(s)
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadAll(val path: Path) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
return FileClassReadAllBytes(path).call()
|
||||
}
|
||||
}
|
||||
|
||||
/** returns NO line separator! */
|
||||
private class FileClassReadLine(val fr: FileReader) : ZeroArgFunction() {
|
||||
val scanner = Scanner(fr.readText()) // no closing; keep the scanner status persistent
|
||||
|
||||
override fun call() : LuaValue {
|
||||
return if (scanner.hasNextLine()) LuaValue.valueOf(scanner.nextLine())
|
||||
else LuaValue.NIL
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-09-17.
|
||||
*/
|
||||
class FilesystemFactory {
|
||||
}
|
||||
@@ -1,512 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi
|
||||
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi.Term.Companion.checkIBM437
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.*
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.VDUtil.VDPath
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LuaError
|
||||
import org.luaj.vm2.LuaValue
|
||||
import java.io.IOException
|
||||
import java.nio.charset.Charset
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* computer directory:
|
||||
* .../computers/
|
||||
* media/hda/ -> .../computers/<uuid for the hda>/
|
||||
*
|
||||
* Created by minjaesong on 2016-09-17.
|
||||
*
|
||||
*
|
||||
* NOTES:
|
||||
* Don't convert '\' to '/'! Rev-slash is used for escape character in sh, and we're sh-compatible!
|
||||
* Use .absoluteFile whenever possible; there's fuckin oddity! (http://bugs.java.com/bugdatabase/view_bug.do;:YfiG?bug_id=4483097)
|
||||
*/
|
||||
internal class Filesystem(globals: Globals, computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) {
|
||||
|
||||
/*init {
|
||||
// load things. WARNING: THIS IS MANUAL!
|
||||
globals["fs"] = LuaValue.tableOf()
|
||||
globals["fs"]["list"] = ListFiles(computer) // CC compliant
|
||||
globals["fs"]["exists"] = FileExists(computer) // CC/OC compliant
|
||||
globals["fs"]["isDir"] = IsDirectory(computer) // CC compliant
|
||||
globals["fs"]["isFile"] = IsFile(computer)
|
||||
globals["fs"]["isReadOnly"] = IsReadOnly(computer) // CC compliant
|
||||
globals["fs"]["getSize"] = GetSize(computer) // CC compliant
|
||||
globals["fs"]["mkdir"] = Mkdir(computer)
|
||||
globals["fs"]["mv"] = Mv(computer)
|
||||
globals["fs"]["cp"] = Cp(computer)
|
||||
globals["fs"]["rm"] = Rm(computer)
|
||||
globals["fs"]["concat"] = ConcatPath(computer) // OC compliant
|
||||
globals["fs"]["open"] = OpenFile(computer) //CC compliant
|
||||
globals["fs"]["parent"] = GetParentDir(computer)
|
||||
// fs.dofile defined in BOOT
|
||||
// fs.fetchText defined in ROMLIB
|
||||
}*/
|
||||
|
||||
companion object {
|
||||
val sysCharset = Charset.forName("CP437")
|
||||
|
||||
fun LuaValue.checkPath(): String {
|
||||
if (this.checkIBM437().contains(Regex("""\.\.""")))
|
||||
throw LuaError("'..' on path is not supported.")
|
||||
return this.checkIBM437().validatePath()
|
||||
}
|
||||
|
||||
// Worst-case: we're on Windows or using a FAT32 partition mounted in *nix.
|
||||
// Note: we allow / as the path separator and expect all \s to be converted
|
||||
// accordingly before the path is passed to the file system.
|
||||
private val invalidChars = Regex("""[<>:"|?*\u0000-\u001F]""") // original OC uses Set(); we use regex
|
||||
|
||||
fun isValidFilename(name: String) = !name.contains(invalidChars)
|
||||
|
||||
fun String.validatePath() : String {
|
||||
if (!isValidFilename(this)) {
|
||||
throw IOException("path contains invalid characters")
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* return value is there for chaining only.
|
||||
*/
|
||||
fun VDPath.dropMount(): VDPath {
|
||||
if (this.hierarchy.size >= 2 && this[0].toCanonicalString(sysCharset) == "media") {
|
||||
this.hierarchy.removeAt(0) // drop "media"
|
||||
this.hierarchy.removeAt(0) // drop whatever mount symbol
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* if path is {media, someUUID, subpath}, redirects to
|
||||
* computer.diskRack[SOMEUUID]->subpath
|
||||
* else, computer.diskRack["hda"]->subpath
|
||||
*/
|
||||
fun net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld.getFile(path: VDPath) : DiskEntry? {
|
||||
val disk = this.getTargetDisk(path)
|
||||
|
||||
if (disk == null) return null
|
||||
|
||||
path.dropMount()
|
||||
|
||||
return VDUtil.getFile(disk, path)
|
||||
}
|
||||
|
||||
/**
|
||||
* if path is like {media, fd1, subpath}, return
|
||||
* computer.diskRack["fd1"]
|
||||
* else, computer.diskRack[<boot device>]
|
||||
*/
|
||||
fun net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld.getTargetDisk(path: VDPath) : VirtualDisk? {
|
||||
if (path.hierarchy.size >= 2 &&
|
||||
Arrays.equals(path[0], "media".toEntryName(DiskEntry.NAME_LENGTH, sysCharset))) {
|
||||
val diskName = path[1].toCanonicalString(sysCharset)
|
||||
val disk = this.diskRack[diskName]
|
||||
|
||||
return disk
|
||||
}
|
||||
else {
|
||||
return this.diskRack[this.computerValue.getAsString("boot")]
|
||||
}
|
||||
}
|
||||
|
||||
fun net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld.getDirectoryEntries(path: VDPath) : Array<DiskEntry>? {
|
||||
val directory = this.getFile(path)
|
||||
|
||||
if (directory == null) return null
|
||||
return VDUtil.getDirectoryEntries(this.getTargetDisk(path)!!, directory)
|
||||
}
|
||||
|
||||
fun combinePath(base: String, local: String) : String {
|
||||
return "$base$local".replace("//", "/")
|
||||
}
|
||||
|
||||
private fun tryBool(action: () -> Unit): LuaValue {
|
||||
try {
|
||||
action()
|
||||
return LuaValue.valueOf(true)
|
||||
}
|
||||
catch (gottaCatchemAll: Exception) {
|
||||
return LuaValue.valueOf(false)
|
||||
}
|
||||
}
|
||||
} // end of Companion Object
|
||||
|
||||
/*
|
||||
|
||||
/**
|
||||
* @param cname == UUID of the drive
|
||||
*
|
||||
* actual directory: <appdata>/Saves/<savename>/computers/<drivename>/
|
||||
*/
|
||||
class ListFiles(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
val path = VDPath(path.checkPath(), sysCharset)
|
||||
|
||||
val table = LuaTable()
|
||||
try {
|
||||
val directoryContents = computer.getDirectoryEntries(path)!!
|
||||
println("[Filesystem] directoryContents size: ${directoryContents.size}")
|
||||
directoryContents.forEachIndexed { index, diskEntry ->
|
||||
table.insert(index + 1, LuaValue.valueOf(diskEntry.filename.toCanonicalString(sysCharset)))
|
||||
}
|
||||
}
|
||||
catch (e: KotlinNullPointerException) {}
|
||||
return table
|
||||
}
|
||||
}
|
||||
|
||||
class FileExists(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
val path = VDPath(path.checkPath(), sysCharset)
|
||||
val disk = computer.getTargetDisk(path)
|
||||
|
||||
if (disk == null) return LuaValue.valueOf(false)
|
||||
|
||||
return LuaValue.valueOf(
|
||||
VDUtil.getFile(disk, path.dropMount()) != null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class IsDirectory(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
val path = VDPath(path.checkPath(), sysCharset)
|
||||
return LuaValue.valueOf(computer.getFile(path)?.contents is EntryDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
class IsFile(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
val path = VDPath(path.checkPath(), sysCharset)
|
||||
return LuaValue.valueOf(computer.getFile(path)?.contents is EntryFile)
|
||||
}
|
||||
}
|
||||
|
||||
class IsReadOnly(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
return LuaValue.valueOf(false)
|
||||
}
|
||||
}
|
||||
|
||||
/** we have 2 GB file size limit */
|
||||
class GetSize(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
val path = VDUtil.VDPath(path.checkPath(), sysCharset)
|
||||
val file = computer.getFile(path)
|
||||
try {
|
||||
if (file!!.contents is EntryFile)
|
||||
return LuaValue.valueOf(file.contents.getSizePure().toInt())
|
||||
else if (file.contents is EntryDirectory)
|
||||
return LuaValue.valueOf(file.contents.entryCount)
|
||||
}
|
||||
catch (e: KotlinNullPointerException) {
|
||||
}
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
// TODO class GetFreeSpace
|
||||
|
||||
/**
|
||||
* returns true on success
|
||||
*/
|
||||
class Mkdir(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
return tryBool {
|
||||
val path = VDPath(path.checkPath(), sysCharset)
|
||||
val disk = computer.getTargetDisk(path)!!
|
||||
val dirList = computer.getDirectoryEntries(path.getParent())
|
||||
var makeNew = true
|
||||
|
||||
// check dupes
|
||||
if (dirList != null) {
|
||||
for (entry in dirList) {
|
||||
if (Arrays.equals(path.last(), entry.filename)) {
|
||||
makeNew = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (makeNew) {
|
||||
VDUtil.addDir(disk, path.getParent(), path.last())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* moves a directory, overwrites the target
|
||||
*/
|
||||
class Mv(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : TwoArgFunction() {
|
||||
override fun call(from: LuaValue, to: LuaValue) : LuaValue {
|
||||
return tryBool {
|
||||
val pathFrom = VDPath(from.checkPath(), sysCharset)
|
||||
val disk1 = computer.getTargetDisk(pathFrom)
|
||||
val pathTo = VDPath(to.checkPath(), sysCharset)
|
||||
val disk2 = computer.getTargetDisk(pathTo)
|
||||
|
||||
VDUtil.moveFile(disk1!!, pathFrom, disk2!!, pathTo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* copies a directory, overwrites the target
|
||||
* difference with ComputerCraft: it returns boolean, true on successful.
|
||||
*/
|
||||
class Cp(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : TwoArgFunction() {
|
||||
override fun call(from: LuaValue, to: LuaValue) : LuaValue {
|
||||
return tryBool {
|
||||
val pathFrom = VDPath(from.checkPath(), sysCharset)
|
||||
val disk1 = computer.getTargetDisk(pathFrom)!!
|
||||
val pathTo = VDPath(to.checkPath(), sysCharset)
|
||||
val disk2 = computer.getTargetDisk(pathTo)!!
|
||||
|
||||
val oldFile = VDUtil.getFile(disk2, pathTo)
|
||||
|
||||
try {
|
||||
VDUtil.deleteFile(disk2, pathTo)
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
"Nothing to delete beforehand"
|
||||
}
|
||||
|
||||
val file = VDUtil.getFile(disk1, pathFrom)!!
|
||||
try {
|
||||
VDUtil.addFile(disk2, pathTo.getParent(), file)
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
// roll back delete on disk2
|
||||
if (oldFile != null) {
|
||||
VDUtil.addFile(disk2, oldFile.parentEntryID, oldFile)
|
||||
throw FileNotFoundException("No such destination")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* difference with ComputerCraft: it returns boolean, true on successful.
|
||||
*/
|
||||
class Rm(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
return tryBool {
|
||||
val path = VDPath(path.checkPath(), sysCharset)
|
||||
val disk = computer.getTargetDisk(path)!!
|
||||
|
||||
VDUtil.deleteFile(disk, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ConcatPath(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : TwoArgFunction() {
|
||||
override fun call(base: LuaValue, local: LuaValue) : LuaValue {
|
||||
TODO()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mode: r, rb, w, wb, a, ab
|
||||
*
|
||||
* Difference: TEXT MODE assumes CP437 instead of UTF-8!
|
||||
*
|
||||
* When you have opened a file you must always close the file handle, or else data may not be saved.
|
||||
*
|
||||
* FILE class in CC:
|
||||
* (when you look thru them using file = fs.open("./test", "w")
|
||||
*
|
||||
* file = {
|
||||
* close = function()
|
||||
* -- write mode
|
||||
* write = function(string)
|
||||
* flush = function() -- write, keep the handle
|
||||
* writeLine = function(string) -- text mode
|
||||
* -- read mode
|
||||
* readLine = function() -- text mode
|
||||
* readAll = function()
|
||||
* -- binary read mode
|
||||
* read = function() -- read single byte. return: number or nil
|
||||
* -- binary write mode
|
||||
* write = function(byte)
|
||||
* writeBytes = function(string as bytearray)
|
||||
* }
|
||||
*/
|
||||
class OpenFile(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : TwoArgFunction() {
|
||||
override fun call(path: LuaValue, mode: LuaValue) : LuaValue {
|
||||
val path = VDPath(path.checkPath(), sysCharset)
|
||||
val disk = computer.getTargetDisk(path)!!
|
||||
|
||||
path.dropMount()
|
||||
|
||||
val mode = mode.checkIBM437().toLowerCase()
|
||||
val luaClass = LuaTable()
|
||||
val fileEntry = computer.getFile(path)!!
|
||||
|
||||
if (fileEntry.contents is EntryDirectory) {
|
||||
throw LuaError("File '${fileEntry.getFilenameString(sysCharset)}' is directory.")
|
||||
}
|
||||
|
||||
val file = fileEntry.contents as EntryFile
|
||||
|
||||
if (mode.contains(Regex("""[aw]""")))
|
||||
throw LuaError("Cannot open file for " +
|
||||
"${if (mode.startsWith('w')) "read" else "append"} mode" +
|
||||
": is readonly.")
|
||||
|
||||
|
||||
when (mode) {
|
||||
"r" -> {
|
||||
try {
|
||||
val fr = StringReader(String(file.bytes.toByteArray(), sysCharset))//FileReader(file)
|
||||
luaClass["close"] = FileClassClose(fr)
|
||||
luaClass["readLine"] = FileClassReadLine(fr)
|
||||
luaClass["readAll"] = FileClassReadAll(file)
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
throw LuaError(
|
||||
if (e.message != null && e.message!!.contains(Regex("""[Aa]ccess (is )?denied""")))
|
||||
"$path: access denied."
|
||||
else
|
||||
"$path: no such file."
|
||||
)
|
||||
}
|
||||
}
|
||||
"rb" -> {
|
||||
try {
|
||||
val fis = ByteArrayInputStream(file.bytes.toByteArray())
|
||||
luaClass["close"] = FileClassClose(fis)
|
||||
luaClass["read"] = FileClassReadByte(fis)
|
||||
luaClass["readAll"] = FileClassReadAll(file)
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
throw LuaError("$path: no such file.")
|
||||
}
|
||||
}
|
||||
"w", "a" -> {
|
||||
try {
|
||||
val fw = VDFileWriter(fileEntry, mode.startsWith('a'), sysCharset)
|
||||
luaClass["close"] = FileClassClose(fw)
|
||||
luaClass["write"] = FileClassPrintText(fw)
|
||||
luaClass["writeLine"] = FileClassPrintlnText(fw)
|
||||
luaClass["flush"] = FileClassFlush(fw)
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
throw LuaError("$path: is a directory.")
|
||||
}
|
||||
}
|
||||
"wb", "ab" -> {
|
||||
try {
|
||||
val fos = VDFileOutputStream(fileEntry, mode.startsWith('a'), sysCharset)
|
||||
luaClass["close"] = FileClassClose(fos)
|
||||
luaClass["write"] = FileClassWriteByte(fos)
|
||||
luaClass["writeBytes"] = FileClassWriteBytes(fos)
|
||||
luaClass["flush"] = FileClassFlush(fos)
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
e.printStackTrace()
|
||||
throw LuaError("$path: is a directory.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return luaClass
|
||||
}
|
||||
}
|
||||
|
||||
class GetParentDir(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(path: LuaValue) : LuaValue {
|
||||
val path = VDPath(path.checkPath(), sysCharset).getParent()
|
||||
return LuaValue.valueOf(path.toString())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// OpenFile implementations //
|
||||
//////////////////////////////
|
||||
|
||||
private class FileClassClose(val fo: Closeable) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
fo.close()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassWriteByte(val fos: VDFileOutputStream) : OneArgFunction() {
|
||||
override fun call(byte: LuaValue) : LuaValue {
|
||||
fos.write(byte.checkint())
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassWriteBytes(val fos: VDFileOutputStream) : OneArgFunction() {
|
||||
override fun call(byteString: LuaValue) : LuaValue {
|
||||
val byteString = byteString.checkIBM437()
|
||||
val bytearr = ByteArray(byteString.length, { byteString[it].toByte() })
|
||||
fos.write(bytearr)
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassPrintText(val fw: VDFileWriter) : OneArgFunction() {
|
||||
override fun call(string: LuaValue) : LuaValue {
|
||||
val text = string.checkIBM437()
|
||||
fw.write(text)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassPrintlnText(val fw: VDFileWriter) : OneArgFunction() {
|
||||
override fun call(string: LuaValue) : LuaValue {
|
||||
val text = string.checkIBM437() + "\n"
|
||||
fw.write(text)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassFlush(val fo: Flushable) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
fo.flush()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadByte(val fis: ByteArrayInputStream) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
val readByte = fis.read()
|
||||
return if (readByte == -1) LuaValue.NIL else LuaValue.valueOf(readByte)
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadAllBytes(val file: EntryFile) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
return LuaValue.valueOf(String(file.bytes.toByteArray(), sysCharset))
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadAll(val file: EntryFile) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
return LuaValue.valueOf(String(file.bytes.toByteArray(), sysCharset))
|
||||
}
|
||||
}
|
||||
|
||||
/** returns NO line separator! */
|
||||
private class FileClassReadLine(fr: Reader) : ZeroArgFunction() {
|
||||
val scanner = Scanner(fr.readText()) // no closing; keep the scanner status persistent
|
||||
|
||||
override fun call() : LuaValue {
|
||||
return if (scanner.hasNextLine()) LuaValue.valueOf(scanner.nextLine())
|
||||
else LuaValue.NIL
|
||||
}
|
||||
}*/
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi
|
||||
|
||||
import net.torvald.terrarum.gameactors.ai.toLua
|
||||
import org.luaj.vm2.lib.OneArgFunction
|
||||
import org.luaj.vm2.lib.ZeroArgFunction
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi.Term.Companion.checkIBM437
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype
|
||||
import org.luaj.vm2.*
|
||||
|
||||
/**
|
||||
* Provide Lua an access to computer object that is in Java
|
||||
*
|
||||
* The "machine" refers to the computer fixture itself in the game world.
|
||||
*
|
||||
* Created by minjaesong on 2016-09-19.
|
||||
*/
|
||||
internal class HostAccessProvider(globals: Globals, computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) {
|
||||
|
||||
init {
|
||||
globals["machine"] = LuaTable()
|
||||
globals["machine"]["println"] = PrintLn()
|
||||
globals["machine"]["isHalted"] = IsHalted(computer)
|
||||
|
||||
|
||||
globals["machine"]["__readFromStdin"] = NativeReadStdin(computer)
|
||||
|
||||
globals["machine"]["milliTime"] = NativeGetMilliTime(computer)
|
||||
|
||||
globals["machine"]["sleep"] = NativeThreadSleep(computer)
|
||||
|
||||
globals["__haltsystemexplicit__"] = HaltComputer(computer)
|
||||
}
|
||||
|
||||
class PrintLn(): OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
if (p0.isnumber())
|
||||
println(p0.checkdouble())
|
||||
else
|
||||
println(p0.checkIBM437())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class IsHalted(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(computer.isHalted)
|
||||
}
|
||||
}
|
||||
|
||||
class NativeReadStdin(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return computer.stdin!!.read().toLua()
|
||||
}
|
||||
}
|
||||
|
||||
class HaltComputer(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : ZeroArgFunction() {
|
||||
override fun call() : LuaValue {
|
||||
computer.isHalted = true
|
||||
computer.luaJ_globals.load("""print(DC4.."system halted")""").call()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/** Time elapsed since the power is on. */
|
||||
class NativeGetMilliTime(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(computer.milliTime)
|
||||
}
|
||||
}
|
||||
|
||||
class NativeThreadSleep(val computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : OneArgFunction() {
|
||||
override fun call(mills: LuaValue): LuaValue {
|
||||
computer.currentExecutionThread.join(mills.checklong())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi
|
||||
|
||||
import com.badlogic.gdx.Gdx
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LuaTable
|
||||
import org.luaj.vm2.LuaValue
|
||||
import org.luaj.vm2.lib.OneArgFunction
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-09-25.
|
||||
*/
|
||||
class Input(globals: Globals, computer: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) {
|
||||
|
||||
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi
|
||||
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LuaTable
|
||||
import org.luaj.vm2.LuaValue
|
||||
import org.luaj.vm2.lib.TwoArgFunction
|
||||
import org.luaj.vm2.lib.ZeroArgFunction
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld
|
||||
import org.luaj.vm2.LuaFunction
|
||||
import org.luaj.vm2.lib.OneArgFunction
|
||||
|
||||
/**
|
||||
* PC Speaker driver and arpeggiator (MONOTONE-style 4 channels)
|
||||
*
|
||||
* Notes are tuned to A440, equal temperament. This is an ISO standard.
|
||||
*
|
||||
* Created by minjaesong on 2016-09-27.
|
||||
*/
|
||||
class PcSpeakerDriver(val globals: Globals, host: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) {
|
||||
|
||||
init {
|
||||
globals["speaker"] = LuaTable()
|
||||
globals["speaker"]["enqueue"] = EnqueueTone(host)
|
||||
globals["speaker"]["clear"] = ClearQueue(host)
|
||||
globals["speaker"]["retune"] = Retune(globals)
|
||||
globals["speaker"]["resetTune"] = ResetTune(globals)
|
||||
globals["speaker"]["toFreq"] = StringToFrequency(globals)
|
||||
globals["speaker"]["__basefreq__"] = LuaValue.valueOf(BASE_FREQ) // every other PSGs should use this very variable
|
||||
|
||||
// constants
|
||||
// e.g. speaker.A0 returns number 1
|
||||
fun Int.toNote(): String = NOTE_NAMES[this % 12] + this.plus(8).div(12).toString()
|
||||
fun Int.toNoteAlt(): String = NOTE_NAMES_ALT[this % 12] + this.plus(8).div(12).toString()
|
||||
|
||||
for (i in 1..126) {
|
||||
globals["speaker"][i.toNote()] = i // sharps
|
||||
globals["speaker"][i.toNoteAlt()] = i // flats
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val BASE_FREQ = 27.5 // frequency of A0
|
||||
val NOTE_NAMES = arrayOf("GS", "A", "AS", "B", "C", "CS",
|
||||
"D", "DS", "E", "F", "FS", "G")
|
||||
val NOTE_NAMES_ALT = arrayOf("Ab", "A", "Bb", "B", "C", "Db",
|
||||
"D", "Eb", "E", "F", "Gb", "G")
|
||||
|
||||
/** @param basefreq: Frequency of A-0 */
|
||||
fun Int.toFreq(basefreq: Double): Double = basefreq * Math.pow(2.0, (this - 1.0) / 12.0)
|
||||
|
||||
/** @param "A-5", "B4", "C#5", ... */
|
||||
fun String.toNoteIndex(): Int {
|
||||
var notestr = this.replace("-", "")
|
||||
notestr = notestr.replace("#", "S")
|
||||
|
||||
val baseNote = if (notestr.contains("S") || notestr.contains("b"))
|
||||
notestr.substring(0, 2)
|
||||
else
|
||||
notestr.substring(0, 1)
|
||||
|
||||
var note: Int = NOTE_NAMES.indexOf(baseNote) // [0-11]
|
||||
if (note < 0) note = NOTE_NAMES_ALT.indexOf(baseNote) // search again
|
||||
if (note < 0) throw IllegalArgumentException("Unknown note: $this") // failed to search
|
||||
|
||||
val octave: Int = notestr.replace(Regex("""[^0-9]"""), "").toInt()
|
||||
return octave.minus(if (note >= 4) 1 else 0) * 12 + note
|
||||
}
|
||||
}
|
||||
|
||||
class EnqueueTone(val host: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : TwoArgFunction() {
|
||||
/**
|
||||
* @param freq: number (hertz) or string (A-4, A4, B#2, ...)
|
||||
*/
|
||||
override fun call(second: LuaValue, freq: LuaValue): LuaValue {
|
||||
if (freq.isnumber())
|
||||
host.enqueueBeep(second.checkdouble(), freq.checkdouble())
|
||||
else {
|
||||
host.enqueueBeep(second.checkdouble(),
|
||||
freq.checkjstring().toNoteIndex()
|
||||
.toFreq(host.luaJ_globals["speaker"]["__basefreq__"].checkdouble())
|
||||
)
|
||||
}
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class ClearQueue(val host: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
host.clearBeepQueue()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class Retune(val globals: Globals) : LuaFunction() {
|
||||
/**
|
||||
* Examples: C256, A440, A#440, ...
|
||||
*/
|
||||
override fun call(arg: LuaValue): LuaValue {
|
||||
val tuneName = arg.checkjstring()
|
||||
|
||||
val baseNote = if (tuneName.contains("#") || tuneName.contains("b")) tuneName.substring(0, 2) else tuneName.substring(0, 1)
|
||||
val freq = tuneName.replace(Regex("""[^0-9]"""), "").toInt()
|
||||
|
||||
// we're assuming the input to be C4, C#4, ... A4, A#4, B4
|
||||
// diffPivot corsp. to G#4, A4, ...
|
||||
val diffPivot = arrayOf(-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) // 2^(12 / n)
|
||||
var diff = diffPivot[NOTE_NAMES.indexOf(baseNote)]
|
||||
if (diff < 0) diff = diffPivot[NOTE_NAMES_ALT.indexOf(baseNote)] // search again
|
||||
if (diff < 0) throw IllegalArgumentException("Unknown note: $baseNote") // failed to search
|
||||
|
||||
val exp = -diff / 12.0
|
||||
val basefreq = freq * Math.pow(2.0, exp) / if (diff >= 3) 8.0 else 16.0 // converts whatever baseNote to A0
|
||||
|
||||
globals["speaker"]["__basefreq__"] = basefreq
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
override fun call(): LuaValue {
|
||||
globals["speaker"]["__basefreq__"] = LuaValue.valueOf(BASE_FREQ)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class ResetTune(val globals: Globals) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
globals["speaker"]["__basefreq__"] = LuaValue.valueOf(BASE_FREQ)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* usage = speaker.toFreq(speaker.AS5) --'S' is a substitution for '#'
|
||||
*/
|
||||
class StringToFrequency(val globals: Globals) : OneArgFunction() {
|
||||
/**
|
||||
* @param arg: number (note index) or string (A-4, A4, B#2, ...)
|
||||
*/
|
||||
override fun call(arg: LuaValue): LuaValue {
|
||||
val note = if (arg.isint()) arg.checkint()
|
||||
else {
|
||||
arg.checkjstring().toNoteIndex()
|
||||
}
|
||||
val basefreq = globals["speaker"]["__basefreq__"].checkdouble()
|
||||
|
||||
return LuaValue.valueOf(note.toFreq(basefreq))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi
|
||||
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LuaValue
|
||||
import org.luaj.vm2.lib.OneArgFunction
|
||||
import net.torvald.terrarum.gameworld.toUint
|
||||
import org.apache.commons.codec.binary.Base64
|
||||
import org.apache.commons.codec.digest.DigestUtils
|
||||
import java.security.SecureRandom
|
||||
|
||||
/**
|
||||
* Hashes, CSPRNG, Base64
|
||||
*
|
||||
* Created by minjaesong on 2016-09-15.
|
||||
*/
|
||||
internal class Security(globals: Globals) {
|
||||
|
||||
init {
|
||||
// load things. WARNING: THIS IS MANUAL!
|
||||
globals["security"] = LuaValue.tableOf()
|
||||
globals["security"]["toSHA256"] = SHA256sum()
|
||||
globals["security"]["toSHA1"] = SHA1sum()
|
||||
globals["security"]["toMD5"] = MD5sum()
|
||||
globals["security"]["randomBytes"] = SecureRandomHex()
|
||||
globals["security"]["decodeBase64"] = DecodeBase64()
|
||||
globals["security"]["encodeBase64"] = EncodeBase64()
|
||||
}
|
||||
|
||||
/** @return byteArray as String */
|
||||
class SHA256sum : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
val hashBytes = DigestUtils.sha256(p0.checkjstring())
|
||||
return LuaValue.valueOf(hashBytes.toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
/** @return byteArray as String */
|
||||
class SHA1sum: OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
val hashBytes = DigestUtils.sha1(p0.checkjstring())
|
||||
return LuaValue.valueOf(hashBytes.toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
/** @return byteArray as String */
|
||||
class MD5sum: OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
val hashBytes = DigestUtils.md5(p0.checkjstring())
|
||||
return LuaValue.valueOf(hashBytes.toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
/** @return byteArray as String */
|
||||
class SecureRandomHex: OneArgFunction() {
|
||||
override fun call(byteSize: LuaValue): LuaValue {
|
||||
val bytes = ByteArray(byteSize.checkint())
|
||||
SecureRandom().nextBytes(bytes)
|
||||
|
||||
return LuaValue.valueOf(bytes.toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
/** @return String */
|
||||
class DecodeBase64: OneArgFunction() {
|
||||
override fun call(base64: LuaValue): LuaValue {
|
||||
val decodedBytes = Base64.decodeBase64(base64.checkjstring())
|
||||
return LuaValue.valueOf(decodedBytes.toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
/** @return byteArray as String */
|
||||
class EncodeBase64: OneArgFunction() {
|
||||
override fun call(inputString: LuaValue): LuaValue {
|
||||
val inputBytes = inputString.checkjstring().toByteArray(charset("UTF-8"))
|
||||
return LuaValue.valueOf(Base64.encodeBase64(inputBytes).toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val hexLookup = charArrayOf(
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
)
|
||||
|
||||
fun Byte.toHexString(): String {
|
||||
val bInt = this.toUint()
|
||||
return "${hexLookup[bInt.shr(8).and(0xf)]}${hexLookup[bInt.and(0xf)]}"
|
||||
}
|
||||
|
||||
/** essentially, 0xFC to 0xFC.toChar() */
|
||||
fun ByteArray.toStringRepresentation(): String {
|
||||
val sb = StringBuilder()
|
||||
for (b in this)
|
||||
sb.append(b.toChar())
|
||||
return sb.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,284 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi
|
||||
|
||||
import org.luaj.vm2.*
|
||||
import org.luaj.vm2.lib.*
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/**
|
||||
* Controls terminal as if it was a monitor
|
||||
* (not sending control sequences but just drives it directly)
|
||||
*
|
||||
* Created by minjaesong on 2016-09-12.
|
||||
*/
|
||||
internal class Term(globals: Globals, term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype) {
|
||||
|
||||
init {
|
||||
// load things. WARNING: THIS IS MANUAL!
|
||||
globals["term"] = LuaValue.tableOf()
|
||||
globals["term"]["write"] = Term.WriteString(term)
|
||||
globals["term"]["print"] = Term.PrintString(term)
|
||||
globals["term"]["newLine"] = Term.NewLine(term)
|
||||
globals["term"]["moveCursor"] = Term.MoveCursor(term) // TTY function
|
||||
globals["term"]["width"] = Term.GetWidth(term)
|
||||
globals["term"]["scroll"] = Term.Scroll(term)
|
||||
globals["term"]["isTeletype"] = Term.IsTeletype(term)
|
||||
globals["term"]["bell"] = Term.Bell(term)
|
||||
|
||||
if (term is net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) {
|
||||
globals["term"]["emitRaw"] = Term.EmitRaw(term)
|
||||
globals["term"]["emit"] = Term.Emit(term)
|
||||
globals["term"]["emitString"] = Term.EmitString(term)
|
||||
globals["term"]["resetColor"] = Term.ResetColour(term)
|
||||
globals["term"]["resetColour"] = Term.ResetColour(term)
|
||||
globals["term"]["clear"] = Term.Clear(term)
|
||||
globals["term"]["clearLine"] = Term.ClearLine(term)
|
||||
globals["term"]["setCursor"] = Term.SetCursor(term)
|
||||
globals["term"]["getCursor"] = Term.GetCursorPos(term)
|
||||
globals["term"]["getX"] = Term.GetCursorX(term)
|
||||
globals["term"]["getY"] = Term.GetCursorY(term)
|
||||
globals["term"]["setX"] = Term.SetCursorX(term)
|
||||
globals["term"]["setY"] = Term.SetCursorY(term)
|
||||
globals["term"]["setCursorBlink"] = Term.SetCursorBlink(term)
|
||||
globals["term"]["size"] = Term.GetSize(term)
|
||||
globals["term"]["height"] = Term.GetHeight(term)
|
||||
globals["term"]["isCol"] = Term.IsColour(term)
|
||||
globals["term"]["setForeCol"] = Term.SetForeColour(term)
|
||||
globals["term"]["setBackCol"] = Term.SetBackColour(term)
|
||||
globals["term"]["foreCol"] = Term.GetForeColour(term)
|
||||
globals["term"]["backCol"] = Term.GetBackColour(term)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun LuaValue.checkIBM437(): String {
|
||||
if (this is LuaString)
|
||||
return m_bytes.copyOfRange(m_offset, m_offset + m_length).toString(Charset.forName("CP437"))
|
||||
// it only works if Charset is ISO-8859, despite of the name "IBM437"
|
||||
// --> then would "CP437" work? -- Torvald at 2017-04-05
|
||||
else
|
||||
throw LuaError("bad argument (string expected, got ${this.typename()})")
|
||||
}
|
||||
}
|
||||
|
||||
class Bell(val tty: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype) : OneArgFunction() {
|
||||
override fun call(pattern: LuaValue): LuaValue {
|
||||
tty.bell(pattern.checkjstring())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class WriteString(val tty: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype) : LuaFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
if (tty is net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal)
|
||||
tty.writeString(p0.checkIBM437(), tty.cursorX, tty.cursorY)
|
||||
else
|
||||
tty.writeChars(p0.checkIBM437())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
override fun call(s: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
|
||||
if (tty is net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal)
|
||||
tty.writeString(s.checkIBM437(), x.checkint(), y.checkint())
|
||||
else
|
||||
throw LuaError("couldn't move cursor; TTY is one-dimensional")
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class PrintString(val tty: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype) : LuaFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
if (tty is net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal)
|
||||
tty.printString(p0.checkIBM437(), tty.cursorX, tty.cursorY)
|
||||
else
|
||||
tty.printChars(p0.checkIBM437())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
override fun call(s: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
|
||||
if (tty is net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal)
|
||||
tty.printString(s.checkIBM437(), x.checkint(), y.checkint())
|
||||
else
|
||||
throw LuaError("couldn't move cursor; TTY is one-dimensional")
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class NewLine(val tty: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
tty.newLine()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class EmitRaw(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ThreeArgFunction() {
|
||||
override fun call(p0: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
|
||||
term.emitChar(p0.checkint(), x.checkint() - 1, y.checkint() - 1)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
// emitchar
|
||||
class Emit(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ThreeArgFunction() {
|
||||
override fun call(p0: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
|
||||
term.emitChar(p0.checkint().toChar(), x.checkint() - 1, y.checkint() - 1)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class EmitString(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ThreeArgFunction() {
|
||||
override fun call(p0: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
|
||||
term.emitString(p0.checkIBM437(), x.checkint() - 1, y.checkint() - 1)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class ResetColour(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
term.resetColour()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class Clear(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
term.clear()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class ClearLine(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
term.clearLine()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/** term.setCursorPos(number x) */
|
||||
class MoveCursor(val tty: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
for (i in 1..p0.checkint())
|
||||
tty.printChar(' ')
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class SetCursor(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : TwoArgFunction() {
|
||||
override fun call(x: LuaValue, y: LuaValue): LuaValue {
|
||||
term.setCursor(x.checkint() - 1, y.checkint() - 1)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/** One-based */
|
||||
class GetCursorPos(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : VarArgFunction() {
|
||||
override fun invoke(args: Varargs?): Varargs {
|
||||
val ret = arrayOf(LuaValue.valueOf(term.cursorX + 1), LuaValue.valueOf(term.cursorY + 1))
|
||||
return LuaValue.varargsOf(ret)
|
||||
}
|
||||
}
|
||||
|
||||
class GetCursorX(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.cursorX + 1)
|
||||
}
|
||||
}
|
||||
|
||||
class GetCursorY(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.cursorY + 1)
|
||||
}
|
||||
}
|
||||
|
||||
class SetCursorX(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
term.setCursor(p0.checkint() - 1, term.cursorY)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class SetCursorY(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
term.setCursor(term.cursorX - 1, p0.checkint())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/** term.setCursorBlink(boolean bool) */
|
||||
class SetCursorBlink(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
term.cursorBlink = p0.toboolean()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class GetSize(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : VarArgFunction() {
|
||||
override fun invoke(args: Varargs?): Varargs {
|
||||
val ret = arrayOf(LuaValue.valueOf(term.width), LuaValue.valueOf(term.height))
|
||||
return LuaValue.varargsOf(ret)
|
||||
}
|
||||
}
|
||||
|
||||
class GetWidth(val tty: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(tty.width)
|
||||
}
|
||||
}
|
||||
|
||||
class GetHeight(val terminal: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(terminal.height)
|
||||
}
|
||||
}
|
||||
|
||||
class IsColour(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.coloursCount > 4)
|
||||
}
|
||||
}
|
||||
|
||||
/** term.scroll(number n) */
|
||||
class Scroll(val tty: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
if (tty is net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) tty.scroll(p0.checkint())
|
||||
else for (i in 1..p0.checkint()) tty.newLine()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/** term.setTextColor(number color) */
|
||||
class SetForeColour(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
term.foreColour = p0.checkint()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/** term.setBackgroundColor(number color) */
|
||||
class SetBackColour(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
term.backColour = p0.checkint()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class GetForeColour(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.foreColour)
|
||||
}
|
||||
}
|
||||
|
||||
class GetBackColour(val term: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.backColour)
|
||||
}
|
||||
}
|
||||
|
||||
class IsTeletype(val termInQuestion: net.torvald.terrarum.modulecomputers.virtualcomputer.terminal.Teletype) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(termInQuestion.coloursCount == 0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.luaapi
|
||||
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LuaFunction
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.GameWorldExtension
|
||||
import net.torvald.terrarum.modulebasegame.gameworld.WorldTime
|
||||
import org.luaj.vm2.LuaTable
|
||||
import org.luaj.vm2.LuaValue
|
||||
|
||||
/**
|
||||
* Implementation of lua's os.date, to return world info of the game world.
|
||||
*
|
||||
* Created by minjaesong on 2016-09-28.
|
||||
*/
|
||||
class WorldInformationProvider(globals: Globals) {
|
||||
|
||||
init {
|
||||
globals["os"]["time"] = LuaValue.NIL // history is LONG! Our 32-bit Lua's epoch is destined to break down...
|
||||
globals["os"]["date"] = OsDateImpl()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getWorldTimeInLuaFormat() : LuaTable {
|
||||
val t = LuaTable()
|
||||
val time = if (Terrarum.ingame != null) (Terrarum.ingame!!.world as GameWorldExtension).worldTime else WorldTime()
|
||||
|
||||
// int Terrarum World Time format
|
||||
t["hour"] = time.hours
|
||||
t["min"] = time.minutes
|
||||
t["wday"] = time.dayOfWeek
|
||||
t["year"] = time.years
|
||||
t["yday"] = time.yearlyDays
|
||||
t["month"] = time.months
|
||||
t["sec"] = time.seconds
|
||||
t["day"] = time.days
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
val defaultDateFormat = "%a %d %B %Y %X"
|
||||
|
||||
/** evaluate single C date format */
|
||||
fun String.evalAsDate(): String {
|
||||
val time = if (Terrarum.ingame != null) (Terrarum.ingame!!.world as GameWorldExtension).worldTime else WorldTime()
|
||||
return when (this) {
|
||||
"%a" -> time.getDayNameShort()
|
||||
"%A" -> time.getDayNameFull()
|
||||
"%b" -> time.getMonthNameShort()
|
||||
"%B" -> time.getMonthNameFull()
|
||||
"%c" -> "%x".evalAsDate() + " " + "%X".evalAsDate()
|
||||
"%d" -> time.days.toString()
|
||||
"%H" -> time.hours.toString()
|
||||
"%I" -> throw IllegalArgumentException("%I: AM/PM concept does not exists.")
|
||||
"%M" -> time.minutes.toString()
|
||||
"%m" -> time.months.toString()
|
||||
"%p" -> throw IllegalArgumentException("%p: AM/PM concept does not exists.")
|
||||
"%S" -> time.seconds.toString()
|
||||
"%w" -> time.dayOfWeek.toString()
|
||||
"%x" -> "${String.format("%02d", time.years)}-${String.format("%02d", time.months)}-${String.format("%02d", time.days)}"
|
||||
"%X" -> "${String.format("%02d", time.hours)}:${String.format("%02d", time.minutes)}:${String.format("%02d", time.seconds)}"
|
||||
"%Y" -> time.years.toString()
|
||||
"%y" -> time.years.rem(100).toString()
|
||||
"%%" -> "%"
|
||||
else -> throw IllegalArgumentException("Unknown format string: $this")
|
||||
}
|
||||
}
|
||||
|
||||
val acceptedDateFormats = arrayOf("%a", "%A", "%b", "%B", "%c", "%d", "%H", "%I", "%M", "%m", "%p", "%S", "%w", "%x", "%X", "%Y", "%y", "%%" )
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes: cannot get a representation of arbitrary time.
|
||||
*/
|
||||
class OsDateImpl() : LuaFunction() {
|
||||
// no args
|
||||
override fun call(): LuaValue {
|
||||
return call(defaultDateFormat)
|
||||
}
|
||||
|
||||
override fun call(format: LuaValue): LuaValue {
|
||||
var arg = format.checkjstring()
|
||||
acceptedDateFormats.forEach {
|
||||
if (arg.contains(it))
|
||||
arg = arg.replace(it, it.evalAsDate(), ignoreCase = false)
|
||||
}
|
||||
return LuaValue.valueOf(arg)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral
|
||||
|
||||
/**
|
||||
* Abstraction of the communication line. (e.g. serial cable)
|
||||
*
|
||||
* A cable may have multiple of CommLines (e.g. serial cable need two for Tx and Rx)
|
||||
*
|
||||
* Created by minjaesong on 2019-07-10.
|
||||
*/
|
||||
open class CommLine(val bandwidth: Int) {
|
||||
|
||||
open val postbox = StringBuilder()
|
||||
|
||||
/**
|
||||
* Returns how many bytes are actually posted, e.g. 0 when band limit is exceeded.
|
||||
*/
|
||||
open fun post(msg: String): Int {
|
||||
if (bandwidth >= msg.length) {
|
||||
postbox.append(msg)
|
||||
return msg.length
|
||||
}
|
||||
else if (postbox.length >= bandwidth) {
|
||||
return 0
|
||||
}
|
||||
else {
|
||||
postbox.append(msg.substring(0 until (bandwidth - postbox.length)))
|
||||
return bandwidth - postbox.length
|
||||
}
|
||||
}
|
||||
|
||||
open fun get(): String {
|
||||
val s = postbox.toString()
|
||||
postbox.clear()
|
||||
return s
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral
|
||||
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LuaTable
|
||||
import org.luaj.vm2.LuaValue
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2016-09-29.
|
||||
*/
|
||||
abstract class Peripheral(val tableName: String) {
|
||||
|
||||
abstract fun loadLib(globals: Globals)
|
||||
|
||||
override fun toString(): String = "Peripheral:$tableName"
|
||||
|
||||
abstract val memSize: Int
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import net.torvald.terrarum.ModMgr
|
||||
import org.luaj.vm2.Globals
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-05-31.
|
||||
*/
|
||||
class PeripheralCharLCD(val width: Int, val height: Int) : net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral.Peripheral("charLCD") {
|
||||
/*companion object {
|
||||
private val fontSheet = BitmapFont(ModMgr.getPath("dwarventech", "mt-32.tga"), 16, 16)
|
||||
private val font = BitmapFont(fontSheet, 0.toChar())
|
||||
private val fontW = fontSheet.width / fontSheet.horizontalCount
|
||||
private val fontH = fontSheet.height / fontSheet.verticalCount
|
||||
}
|
||||
|
||||
override fun loadLib(globals: Globals) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return super.toString()
|
||||
}
|
||||
|
||||
override val memSize = width * height
|
||||
|
||||
var cursor: Int = 0 // character LCDs are mostly single long line wrapped
|
||||
|
||||
val memory = ByteArray(memSize) // temporary; replace with proper VMPeripheralWrapper
|
||||
|
||||
/**
|
||||
* @param g Frame Buffer that holds the display of LCD screen
|
||||
*/
|
||||
fun render(batch: SpriteBatch) {
|
||||
memory.forEachIndexed { index, byte ->
|
||||
font.draw(batch, "${byte.toChar()}", (index % width) * fontW.toFloat(), (index / width) * fontH.toFloat())
|
||||
}
|
||||
}*/
|
||||
override fun loadLib(globals: Globals) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return super.toString()
|
||||
}
|
||||
|
||||
override val memSize: Int
|
||||
get() = TODO("not implemented") //To change initializer of created properties use File | Settings | File Templates.
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral
|
||||
|
||||
import org.luaj.vm2.Globals
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld
|
||||
import org.luaj.vm2.LuaTable
|
||||
import org.luaj.vm2.LuaValue
|
||||
import org.luaj.vm2.lib.OneArgFunction
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStreamReader
|
||||
import java.net.URL
|
||||
|
||||
/**
|
||||
* Provides internet access.
|
||||
*
|
||||
* Created by minjaesong on 2016-09-24.
|
||||
*/
|
||||
internal class PeripheralInternet(val host: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld)
|
||||
: net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral.Peripheral("internet"){
|
||||
|
||||
override val memSize = 1024
|
||||
|
||||
override fun loadLib(globals: Globals) {
|
||||
globals["internet"] = LuaTable()
|
||||
globals["internet"]["fetch"] = FetchWebPage()
|
||||
}
|
||||
|
||||
class FetchWebPage() : OneArgFunction() {
|
||||
override fun call(urlstr: LuaValue): LuaValue {
|
||||
val url = URL(urlstr.checkjstring())
|
||||
val inputstream = BufferedReader(InputStreamReader(url.openStream()))
|
||||
|
||||
var inline = ""
|
||||
var readline = inputstream.readLine()
|
||||
while (readline != null) {
|
||||
inline += readline
|
||||
readline = inputstream.readLine()
|
||||
}
|
||||
inputstream.close()
|
||||
|
||||
return LuaValue.valueOf(inline)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral
|
||||
|
||||
import net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld
|
||||
import org.luaj.vm2.Globals
|
||||
import org.luaj.vm2.LuaTable
|
||||
import org.luaj.vm2.LuaValue
|
||||
|
||||
/**
|
||||
* Virtual driver for 4-track squarewave PSG, which has no ability of changing a duty cycle
|
||||
* but has a volume control (you'll need some other tracker than MONOTONE)
|
||||
*
|
||||
* Created by minjaesong on 2016-09-27.
|
||||
*/
|
||||
internal class PeripheralPSG(val host: net.torvald.terrarum.modulecomputers.virtualcomputer.computer.TerrarumComputerOld)
|
||||
: net.torvald.terrarum.modulecomputers.virtualcomputer.peripheral.Peripheral("psg") {
|
||||
|
||||
override val memSize = 1024
|
||||
|
||||
override fun loadLib(globals: Globals) {
|
||||
globals["psg"] = LuaTable()
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user