Newer
Older
accessory_repo / AbilityTimer / AbilityTimer.pde
// This software is distributed under the terms of the MIT License.
// Copyright (c) 2018, 2019 molelord
// All rights reserved.

import processing.awt.PSurfaceAWT;
import processing.sound.*;

import javax.swing.JFrame;
import java.awt.MouseInfo;
import java.awt.PointerInfo;
import java.awt.Point;

final String AppName        = "AbilityTimer";
final String AppVersion     = "0.80";
final String SaveFileName   = "save.csv";
final String ChimeFileName  = "chime.mp3";
final String JoinedFileName = "joined.mp3";
final String CameraFileName = "camera.png";
final String CoinFileName   = "coin.mp3";
final String FailFileName   = "fail.mp3";

ArrayList<GuiItem> timerModeItems     = new ArrayList<GuiItem>();
ArrayList<GuiItem> checklistModeItems = new ArrayList<GuiItem>();
ArrayList<Mission> missions           = new ArrayList<Mission>();
Scouter            scouter;
Dbg                dbg;

void settings() {
  size(Glbl.W, Glbl.H);
}

void setup() {
  prepareExitHandler();
  surface.setAlwaysOnTop(true);
  
  PSurfaceAWT.SmoothCanvas smoothCanvas;
  smoothCanvas = (PSurfaceAWT.SmoothCanvas)surface.getNative();
  JFrame jframe;
  jframe = (JFrame)smoothCanvas.getFrame();
  jframe.dispose();
  jframe.setUndecorated(true);
  jframe.setVisible(true);

  surface.setResizable(true);
  
  smooth();

  xTableInitialize();
  dbg = new Dbg(false);

  TimerDisplay tmdisp = new TimerDisplay(20, 5);
  timerModeItems.add(tmdisp);

  timerModeItems.add(new CloseButton(
    Glbl.TimerW-CloseButton.W, 0));

  timerModeItems.add(new MinimizeButton(
    Glbl.TimerW-CloseButton.W-MinimizeButton.W, 0));

  TimerBar tmbar = new TimerBar(5, 5, tmdisp);
  checklistModeItems.add(tmbar);

  PFont font12 = loadFont("mplus-2p-bold-12.vlw");
  PFont font24 = loadFont("mplus-2m-bold-24.vlw");
  PImage img0  = loadImage(CameraFileName);
  Glbl.setInstances(surface, jframe, font12, font24,
    new SoundFile(this, ChimeFileName),
    new SoundFile(this, JoinedFileName),
    img0,
    new SoundFile(this, CoinFileName),
    new SoundFile(this, FailFileName)
  );

  Table savedTbl = loadTable(SaveFileName, "header");
  Table itemTbl  = loadTable("Items.csv", "header");
  ZoneId zoneid  = ZoneId.of("America/Los_Angeles"); // for Nutaku
  int i = 0;
  int missionNum = 0;
  if (itemTbl != null) {
    for (TableRow itemRow : itemTbl.rows()) {
      String kind = itemRow.getString("kind");
      if (kind.equals("mission")) {
        String name  = itemRow.getString("name");
        int    items = itemRow.getInt("value");
        int    value = 0;
        if (savedTbl != null && (i < savedTbl.getRowCount())) {
          TableRow savedRow = savedTbl.getRow(i);
          if (savedRow != null) { 
            value = savedRow.getInt("value");
            i++;
          }
        }
        Mission m = new Mission(5, 5 + missionNum*29, name, items, value);
        missionNum++;
        checklistModeItems.add(m);
        missions.add(m);
      } else if (kind.equals("service")) {
        String name  = itemRow.getString("name");
        if (name.equals("DMM")) {
          zoneid = ZoneId.of("Asia/Tokyo");
          Glbl.setServiceProvider(ServiceProvider.Dmm);
        }
      }
    }
  }
  if (missionNum == 0) {
    checklistModeItems.add(new ErrorLabel(
      "Items.csv is corrupted or missing."));
  }

  WallClock wallc = new WallClock(zoneid);
  checklistModeItems.add(wallc);
  checklistModeItems.add(new TimerBarLabel(tmbar));

  checklistModeItems.add(new CloseButton(
    Glbl.W-CloseButton.W, 0));

  checklistModeItems.add(new MinimizeButton(
    Glbl.W-CloseButton.W - MinimizeButton.W, 0));

  scouter = new Scouter(AppName, AppVersion);

  DrawerButton drawerb = new DrawerButton(
    Glbl.W-DrawerButton.W, Glbl.H/2-DrawerButton.H+7, scouter);
  checklistModeItems.add(drawerb);

  checklistModeItems.add(new CameraButton(
    Glbl.W-CloseButton.W - MinimizeButton.W - CameraButton.W, 0,
    scouter));
}

long prevEpochSecond = 0;
int  toggle = 0;

void draw() {
  Glbl.setBgSelected(true);

  boolean changed = (Glbl.prevMode != Glbl.mode);
  if (changed) {
    background(224);
    Glbl.changeSize(dbg);
    // If the drawing is done immediately after changing the window size,
    // it does not seem to be reflected.
    Glbl.mustRedraw = true;
    prevEpochSecond = 0;
    Glbl.prevMode = Glbl.mode;
    return;
  }

  boolean mustRedraw = false;
  ArrayList<GuiItem> gitems = timerModeItems;

  if (Glbl.isTimerMode()) {
    mustRedraw = true;
  } else {
    gitems = checklistModeItems;
    long currentEpochSecond = Instant.now().getEpochSecond();

    if (Glbl.scouterEnabled) {
      if ((millis() & 512) == toggle) {
        scouter.findKamihimeWindow();
        mustRedraw = true;
        toggle = (toggle == 0) ? 512 : 0;
      }
    }

    if (
      Glbl.mustRedraw ||
      mustRedraw ||
      mousePressed ||
      (pmouseX != mouseX) ||
      (pmouseY != mouseY) ||
      (Glbl.isLastOneMinute && currentEpochSecond != prevEpochSecond) ||
      (currentEpochSecond/60 != prevEpochSecond/60) ||
      false) {
      mustRedraw = true;
    }
    prevEpochSecond = currentEpochSecond;
  }

  Glbl.mustRedraw = false;
  if (mustRedraw) {
    background(224);
    for (GuiItem item : gitems) {
      item.render();
    }
  }
}
 
int prevMouseX = 0;
int prevMouseY = 0;

void mousePressed() {
  prevMouseX = mouseX;
  prevMouseY = mouseY;
  ArrayList<GuiItem> gitems = timerModeItems;
  if (Glbl.isChecklistMode()) {
    gitems = checklistModeItems;
  }
  for (GuiItem item : gitems) {
    item.press();
  }
}

void mouseReleased() {
}

void mouseDragged() {
  if (Glbl.isBgSelected()) {
    Point mouse = MouseInfo.getPointerInfo().getLocation();
    surface.setLocation(mouse.x - prevMouseX, mouse.y - prevMouseY - 0);
  }
}

void mouseWheel(MouseEvent event) {
  Glbl.mustRedraw = true;
  ArrayList<GuiItem> gitems = timerModeItems;
  if (Glbl.isChecklistMode()) {
    gitems = checklistModeItems;
  }
  for (GuiItem item : gitems) {
    item.wheel(event);
  }
}

// Thanks to https://forum.processing.org/one/topic/run-code-on-exit
private void prepareExitHandler() {
  Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
    public void run () {
      //System.out.println("SHUTDOWN HOOK");
      try {
        Table tbl = new Table();
        tbl.addColumn("value");
        for (Mission m : missions) {
          TableRow row = tbl.addRow();
          row.setInt("value", m.getValue());
        }
        saveTable(tbl, SaveFileName);
        stop();
      } catch(Exception ex) {
        ex.printStackTrace(); // not much else to do at this point
      }
    }
  }));
}