All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.legendofdragoon.scripting.tokens.LodString Maven / Gradle / Ivy

There is a newer version: 0.5.6
Show newest version
package org.legendofdragoon.scripting.tokens;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;

import static org.legendofdragoon.scripting.Lexer.CONTROL_PATTERN;
import static org.legendofdragoon.scripting.Lexer.NUMBER_PATTERN;

public class LodString extends Entry {
  private static final Logger LOGGER = LogManager.getFormatterLogger();

  public final int[] chars;

  public LodString(final int address, final int[] chars) {
    super(address);
    this.chars = chars;
  }

  @Override
  public String toString() {
    final StringBuilder out = new StringBuilder();

    for(final int chr : this.chars) {
      if((chr & 0xff00) != 0) {
        final CONTROLS control = CONTROLS.fromControl(chr);

        if(control != null) {
          out.append('<').append(control.name);

          if(control.hasParam) {
            out.append('=').append(chr & 0xff);
          }

          out.append('>');
          continue;
        }
      }

      out.append(switch(chr) {
        case 0x00 -> ' ';
        case 0x01 -> ',';
        case 0x02 -> '.';
        case 0x03 -> '\u00b7';
        case 0x04 -> ':';
        case 0x05 -> '?';
        case 0x06 -> '!';
        case 0x07 -> '_';
        case 0x08 -> '/';
        case 0x09 -> '\'';
        case 0x0a -> '"';
        case 0x0b -> '(';
        case 0x0c -> ')';
        case 0x0d -> '-';
        case 0x0e -> '`';
        case 0x0f -> '%';
        case 0x10 -> '&';
        case 0x11 -> '*';
        case 0x12 -> '@';
        case 0x13 -> '+';
        case 0x14 -> '~';
        case 0x15 -> '0';
        case 0x16 -> '1';
        case 0x17 -> '2';
        case 0x18 -> '3';
        case 0x19 -> '4';
        case 0x1a -> '5';
        case 0x1b -> '6';
        case 0x1c -> '7';
        case 0x1d -> '8';
        case 0x1e -> '9';
        case 0x1f -> 'A';
        case 0x20 -> 'B';
        case 0x21 -> 'C';
        case 0x22 -> 'D';
        case 0x23 -> 'E';
        case 0x24 -> 'F';
        case 0x25 -> 'G';
        case 0x26 -> 'H';
        case 0x27 -> 'I';
        case 0x28 -> 'J';
        case 0x29 -> 'K';
        case 0x2a -> 'L';
        case 0x2b -> 'M';
        case 0x2c -> 'N';
        case 0x2d -> 'O';
        case 0x2e -> 'P';
        case 0x2f -> 'Q';
        case 0x30 -> 'R';
        case 0x31 -> 'S';
        case 0x32 -> 'T';
        case 0x33 -> 'U';
        case 0x34 -> 'V';
        case 0x35 -> 'W';
        case 0x36 -> 'X';
        case 0x37 -> 'Y';
        case 0x38 -> 'Z';
        case 0x39 -> 'a';
        case 0x3a -> 'b';
        case 0x3b -> 'c';
        case 0x3c -> 'd';
        case 0x3d -> 'e';
        case 0x3e -> 'f';
        case 0x3f -> 'g';
        case 0x40 -> 'h';
        case 0x41 -> 'i';
        case 0x42 -> 'j';
        case 0x43 -> 'k';
        case 0x44 -> 'l';
        case 0x45 -> 'm';
        case 0x46 -> 'n';
        case 0x47 -> 'o';
        case 0x48 -> 'p';
        case 0x49 -> 'q';
        case 0x4a -> 'r';
        case 0x4b -> 's';
        case 0x4c -> 't';
        case 0x4d -> 'u';
        case 0x4e -> 'v';
        case 0x4f -> 'w';
        case 0x50 -> 'x';
        case 0x51 -> 'y';
        case 0x52 -> 'z';
        case 0x53 -> '[';
        case 0x54 -> ']';
        case 0x55 -> ';';
        default -> {
          LOGGER.warn("Found invalid character %x", chr);
          yield "".formatted(chr);
        }
      });
    }

    return out.toString();
  }

  public static LodString fromString(final int address, final String string) {
    final List out = new ArrayList<>();

    boolean noTerm = false;

    for(int i = 0; i < string.length(); i++) {
      final char chr = string.charAt(i);

      // Handle controls
      if(chr == '<') {
        final int end = string.indexOf('>', i + 1);
        final String controlString = string.substring(i, end + 1);
        final Matcher controlMatcher = CONTROL_PATTERN.matcher(controlString);

        if(controlMatcher.matches()) {
          final String controlName = controlMatcher.group(1).toLowerCase();

          if("noterm".equalsIgnoreCase(controlName)) {
            noTerm = true;
            i += 7;
            continue;
          }

          final String paramString = controlMatcher.group(2);

          final CONTROLS control = CONTROLS.fromName(controlName);
          int converted = control.control;

          if((control.hasParam)) {
            converted |= parseInt(paramString);
          }

          out.add(converted);
        }

        i = end;
        continue;
      }

      out.add(switch(chr) {
        case ' ' -> 0x00;
        case ',' -> 0x01;
        case '.' -> 0x02;
        case '\u00b7' -> 0x03;
        case ':' -> 0x04;
        case '?' -> 0x05;
        case '!' -> 0x06;
        case '_' -> 0x07;
        case '/' -> 0x08;
        case '\'' -> 0x09;
        case '"' -> 0x0a;
        case '(' -> 0x0b;
        case ')' -> 0x0c;
        case '-' -> 0x0d;
        case '`' -> 0x0e;
        case '%' -> 0x0f;
        case '&' -> 0x10;
        case '*' -> 0x11;
        case '@' -> 0x12;
        case '+' -> 0x13;
        case '~' -> 0x14;
        case '0' -> 0x15;
        case '1' -> 0x16;
        case '2' -> 0x17;
        case '3' -> 0x18;
        case '4' -> 0x19;
        case '5' -> 0x1a;
        case '6' -> 0x1b;
        case '7' -> 0x1c;
        case '8' -> 0x1d;
        case '9' -> 0x1e;
        case 'A' -> 0x1f;
        case 'B' -> 0x20;
        case 'C' -> 0x21;
        case 'D' -> 0x22;
        case 'E' -> 0x23;
        case 'F' -> 0x24;
        case 'G' -> 0x25;
        case 'H' -> 0x26;
        case 'I' -> 0x27;
        case 'J' -> 0x28;
        case 'K' -> 0x29;
        case 'L' -> 0x2a;
        case 'M' -> 0x2b;
        case 'N' -> 0x2c;
        case 'O' -> 0x2d;
        case 'P' -> 0x2e;
        case 'Q' -> 0x2f;
        case 'R' -> 0x30;
        case 'S' -> 0x31;
        case 'T' -> 0x32;
        case 'U' -> 0x33;
        case 'V' -> 0x34;
        case 'W' -> 0x35;
        case 'X' -> 0x36;
        case 'Y' -> 0x37;
        case 'Z' -> 0x38;
        case 'a' -> 0x39;
        case 'b' -> 0x3a;
        case 'c' -> 0x3b;
        case 'd' -> 0x3c;
        case 'e' -> 0x3d;
        case 'f' -> 0x3e;
        case 'g' -> 0x3f;
        case 'h' -> 0x40;
        case 'i' -> 0x41;
        case 'j' -> 0x42;
        case 'k' -> 0x43;
        case 'l' -> 0x44;
        case 'm' -> 0x45;
        case 'n' -> 0x46;
        case 'o' -> 0x47;
        case 'p' -> 0x48;
        case 'q' -> 0x49;
        case 'r' -> 0x4a;
        case 's' -> 0x4b;
        case 't' -> 0x4c;
        case 'u' -> 0x4d;
        case 'v' -> 0x4e;
        case 'w' -> 0x4f;
        case 'x' -> 0x50;
        case 'y' -> 0x51;
        case 'z' -> 0x52;
        case '[' -> 0x53;
        case ']' -> 0x54;
        case ';' -> 0x55;
        default -> throw new RuntimeException("Illegal char %c".formatted(chr));
      });
    }

    if(!noTerm) {
      out.add(0xa0ff);
    }

    return new LodString(address, out.stream().mapToInt(Integer::intValue).toArray());
  }

  private static int parseInt(final String val) {
    if(NUMBER_PATTERN.matcher(val).matches()) {
      if(val.startsWith("0x")) {
        return Integer.parseUnsignedInt(val.substring(2), 16);
      }

      return Integer.parseInt(val);
    }

    throw new NumberFormatException("Invalid number " + val);
  }

  private enum CONTROLS {
    LINE("line", 0xa1ff, false),
    BUTTON("button", 0xa200, false),
    MULTIBOX("multibox", 0xa3ff, false),
    SPEED("speed", 0xa500, true),
    PAUSE("pause", 0xa600, true),
    COLOUR("colour", 0xa700, true),
    VAR("var", 0xa800, true),
    XOFFSET("xoffset", 0xad00, true),
    YOFFSET("yoffset", 0xae00, true),
    SAUTO("sauto", 0xb000, true),
    ELEMENT("element", 0xb100, true),
    ARROW("arrow", 0xb200, true),

    INVALID("chr", 0, true),
    ;

    public static CONTROLS fromControl(final int control) {
      for(final CONTROLS c : CONTROLS.values()) {
        if(c.hasParam) {
          if((c.control & 0xff00) == (control & 0xff00)) {
            return c;
          }
        } else if(c.control == control) {
          return c;
        }
      }

      return null;
    }

    public static CONTROLS fromName(final String name) {
      for(final CONTROLS c : CONTROLS.values()) {
        if(c.name.equals(name)) {
          return c;
        }
      }

      throw new RuntimeException("Unknown control %s".formatted(name));
    }

    public final String name;
    public final int control;
    public final boolean hasParam;

    CONTROLS(final String name, final int control, final boolean hasParam) {
      this.name = name;
      this.control = control;
      this.hasParam = hasParam;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy