public static boolean stateHasChanged(
     int objectType, int objectX, int objectY, int objectHeight) {
   for (StateObject so : stateChanges) {
     if (so.getHeight() != objectHeight) continue;
     if (so.getX() == objectX && so.getY() == objectY && so.getType() == objectType) return true;
   }
   return false;
 }
 public static boolean isCachedObject(int objectX, int objectY, int objectHeight, int objectId) {
   for (StateObject so : stateChanges) {
     if (so == null) continue;
     if (so.getHeight() != objectHeight) continue;
     if (so.getStatedObject() == objectId && so.getX() == objectX && so.getY() == objectY)
       return true;
   }
   return false;
 }
 public static StateObject getStateObject(
     int objectX, int objectY, int objectHeight, int objectId) {
   for (StateObject so : stateChanges) {
     if (so == null) continue;
     if (so.getHeight() != objectHeight) continue;
     if (so.getStatedObject() == objectId && so.getX() == objectX && so.getY() == objectY)
       return so;
   }
   return null;
 }
 /** {@inheritDoc} */
 @Override
 protected void toTextInternal(Appendable writer) throws IOException {
   writer.append(getArithmeticSign());
   if (stateObject != null) {
     writer.append(SPACE);
     stateObject.toString(writer);
   }
 }
 public static boolean withinDoorRange(
     int objectType, int objectX, int objectY, int playerX, int playerY, int atHeight) {
   if (objectSizes.size() == 0) loadObjectSizes();
   boolean isOpen = isCachedObject(objectX, objectY, atHeight, objectType);
   if (isOpen) {
     StateObject so = getStateObject(objectX, objectY, atHeight, objectType);
     int face = so.getFace();
     if (face == 1 || face == 3)
       return playerX >= objectX - 1 && playerX <= objectX + 1 && playerY == objectY;
     else return playerY >= objectY - 1 && playerY <= objectY + 1 && playerX == objectX;
   } else {
     int face = getOrientation(objectX, objectY, atHeight);
     if (face == 1 || face == 3)
       return playerX >= objectX - 1 && playerX <= objectX + 1 && playerY == objectY;
     else return playerY >= objectY - 1 && playerY <= objectY + 1 && playerX == objectX;
   }
 }
  /** {@inheritDoc} */
  @Override
  protected void toTextInternal(Appendable writer) throws IOException {

    if (stateObject != null) {
      stateObject.toString(writer);
    }

    if (!isDefault()) {
      writer.append(SPACE);
      writer.append(ordering.name());
    }
  }
 public static void removeStateChange(int objectType, int objectX, int objectY, int objectHeight) {
   for (int index = 0; index < stateChanges.size(); index++) {
     StateObject so = stateChanges.get(index);
     if (so == null) continue;
     if ((so.getX() == objectX && so.getY() == objectY && so.getHeight() == objectHeight)
             && so.getType() == objectType
         || so.getStatedObject() == objectType) {
       stateChanges.remove(index);
       break;
     }
   }
 }
  /** {@inheritDoc} */
  @Override
  public void parse(String jpqlFragment) {

    StringBuilder sb = new StringBuilder();
    sb.append(TRIM);
    sb.append(LEFT_PARENTHESIS);
    sb.append(jpqlFragment);
    sb.append(RIGHT_PARENTHESIS);

    JPQLExpression jpqlExpression =
        new JPQLExpression(sb, getGrammar(), FunctionsReturningStringsBNF.ID, true);

    TrimExpression trimExpression = (TrimExpression) jpqlExpression.getQueryStatement();
    setSpecification(trimExpression.getSpecification());
    parseTrimCharacter(trimExpression.getTrimCharacter().toParsedText());
    super.parse(trimExpression.getExpression().toParsedText());

    // The trim character is actually the string primary
    if (!hasStateObject() && hasTrimCharacter()) {
      setStateObject(new StringLiteralStateObject(this, trimCharacter.toString()));
      trimCharacter = null;
    }
  }
  /** {@inheritDoc} */
  @Override
  protected void toTextEncapsulatedExpression(Appendable writer) throws IOException {

    // Specification
    if (specification != Specification.DEFAULT) {
      writer.append(specification.name());
      writer.append(SPACE);
    }

    // Trim character
    if (hasTrimCharacter()) {
      trimCharacter.toString(writer);
      writer.append(SPACE);
    }

    // FROM
    if ((specification != Specification.DEFAULT) || hasTrimCharacter()) {
      writer.append(FROM);
      writer.append(SPACE);
    }

    // String primary
    super.toTextEncapsulatedExpression(writer);
  }