/** * */ package logbook.gui; import java.util.Arrays; import java.util.Comparator; import java.util.List; import logbook.constants.AppConstants; import logbook.dto.AirBattleDto; import logbook.dto.BattleAtackDto; import logbook.dto.BattleExDto; import logbook.dto.BattlePhaseKind; import logbook.dto.DockDto; import logbook.dto.ResultRank; import logbook.dto.ShipDto; import logbook.gui.logic.ColorManager; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; /** * @author Nekopanda * */ public class BattleWindow extends BattleWindowBase { protected Label title; // 名前 protected final Label[] enemyLabels = new Label[6]; protected final Label[][] infoLabels = new Label[2][12]; protected Label matchLabel; protected final Label resultLabel[] = new Label[3]; protected final int[] yDamages = new int[12]; protected final int[][] friendDamages = new int[2][12]; protected final int[][] enemyDamages = new int[2][6]; protected static String AFTER_DAY = "昼戦後"; protected static String AFTER_NIGHT = "夜戦後"; protected static String FORM_PREFIX = "陣形:"; protected static String TOUCH_PREFIX = "触接:"; protected static String SAKUTEKI_PREFIX = "索敵:"; /** * Create the dialog. * @param parent */ protected BattleWindow(Shell parent, MenuItem menuItem) { super(parent, menuItem, "戦況"); } @Override protected void clearText() { // 情報 for (int i = 0; i < 12; ++i) { setLabelText(this.infoLabels[0][i], ""); setLabelText(this.infoLabels[1][i], ""); } // 敵 for (int i = 0; i < 6; ++i) { setLabelText(this.enemyLabels[i], "-", ""); } // その他 this.matchLabel.setText(""); for (int i = 0; i < 3; ++i) { this.resultLabel[i].setText(""); this.resultLabel[i].setBackground(null); this.resultLabel[i].setForeground(null); } } protected static void setLabelNone(Label label) { label.setBackground(null); label.setForeground(null); } protected static void printHp(Label label, int nowhp, int maxhp) { label.setText(String.valueOf(nowhp) + "/" + maxhp); } protected void printDock() { List<DockDto> docks = this.getDocks(); if (docks == null) return; this.infoLabels[0][0].setText(docks.get(0).getName()); } protected void printMap() { if (this.getMapCellDto() == null) return; // 2015/07/18 先読みできなくなった /* MapCellDto dto = this.getMapCellDto(); EnemyData enemyData = dto.getEnemyData(); if (dto.getEnemyId() == -1) { // 次のマスは敵がいない } else if (enemyData != null) { String name = enemyData.getEnemyName(); if (!StringUtils.isEmpty(name)) { this.infoLabels[1][0].setText(name); } else { this.infoLabels[1][0].setText("KCRDB互換データ"); } int[] ships = enemyData.getEnemyShipsId(); for (int i = 0; i < 6; ++i) { ShipInfoDto shipinfo = Ship.get(String.valueOf(ships[i])); if (shipinfo != null) { String tooltip = ShipBaseDto.makeDetailedString( shipinfo.getFullName(), Item.fromIdList(shipinfo.getDefaultSlot())); this.enemyLabels[i].setText(String.valueOf(i + 1) + "." + shipinfo.getFullName()); this.enemyLabels[i].setToolTipText(tooltip); } } this.infoLabels[1][1].setText(FORM_PREFIX + enemyData.getFormation()); } else { this.infoLabels[1][0].setText("データがありません[" + dto.getEnemyId() + "]"); } */ } // idx: 味方=0, 敵=1 private void printPlaneCount(Label[] labels, int base, AirBattleDto air, int idx) { labels[base + 0].setText(""); labels[base + 1].setText(""); if (air != null) { String[] short1 = air.getStage1ShortString(); String[] short2 = air.getStage2ShortString(); String[] detail1 = air.getStage1DetailedString(); String[] detail2 = air.getStage2DetailedString(); if (air.stage1 != null) setLabelText(labels[base + 0], short1[idx], detail1[idx]); if (air.stage2 != null) setLabelText(labels[base + 1], short2[idx], detail2[idx]); } } private int computeDamages(int[] friend, int[] enemy, int[] ydam, BattleExDto.Phase phase) { BattleAtackDto[][] sequence = phase.getAtackSequence(); for (int i = 0; i < friend.length; ++i) friend[i] = 0; for (int i = 0; i < enemy.length; ++i) enemy[i] = 0; int airDamage = 0; for (BattleAtackDto[] atacks : sequence) { if (atacks != null) { for (BattleAtackDto dto : atacks) { for (int i = 0; i < dto.target.length; ++i) { int target = dto.target[i]; int damage = dto.damage[i]; if (dto.friendAtack) { enemy[target] += damage; } else { friend[target] += damage; } } if (dto.friendAtack) { switch (dto.kind) { case HOUGEKI: for (int damage : dto.damage) { ydam[dto.origin[0]] += damage; } break; case RAIGEKI: for (int i = 0; i < dto.origin.length; ++i) { ydam[dto.origin[i]] += dto.ydam[i]; } break; case AIR: for (int damage : dto.damage) { airDamage += damage; } break; default: break; } } } } } return airDamage; } protected static class MVPShip { public ShipDto ship; public int ydam; MVPShip(ShipDto ship, int ydam) { this.ship = ship; this.ydam = ydam; } } /** * MVP候補を計算 * @param ydam * @param ships * @return */ private MVPShip[] computeMVP(int[] ydam, List<ShipDto> ships) { MVPShip[] sortArray = new MVPShip[ships.size()]; for (int i = 0; i < ships.size(); ++i) { sortArray[i] = new MVPShip(ships.get(i), ydam[i]); } Arrays.sort(sortArray, new Comparator<MVPShip>() { @Override public int compare(MVPShip d1, MVPShip d2) { return -Integer.compare(d1.ydam, d2.ydam); } }); int numPrintShips = 0; for (int i = 0; (i < 2) && (i < ships.size()); ++i) { if (sortArray[i].ydam == 0) { break; } numPrintShips++; } if (numPrintShips == 0) { numPrintShips = 1; } return Arrays.copyOf(sortArray, numPrintShips); } protected String getMVPText(MVPShip[] mvp, int airDamage) { if (mvp == null) { return ""; } String result0 = "MVP(砲雷のみ) "; for (int i = 0; i < mvp.length; ++i) { ShipDto ship = mvp[i].ship; result0 += String.format("%d: %s(%d)", i + 1, (ship == null) ? "?" : ship.getName(), mvp[i].ydam); if (i != (mvp.length - 1)) result0 += ", "; } result0 += " 航空戦ダメージ: " + airDamage; return result0; } protected String getReulstText(double[] damageRate, String rank) { String rateString = (damageRate[0] == 0.0) ? "" : String.format(" (x%.3f)", damageRate[1] / damageRate[0]); return String.format("損害率 自: %.1f%% vs. 敵: %.1f%%%s 結果: %s", damageRate[0] * 100, damageRate[1] * 100, rateString, rank); } protected void printBattle() { BattleExDto battle = this.getBattle(); BattleExDto.Phase phase1 = battle.getPhase1(); BattleExDto.Phase phase2 = battle.getPhase2(); BattleExDto.Phase lastPhase = battle.getLastPhase(); List<ShipDto> friendShips = battle.getDock().getShips(); List<ShipDto> friendShipsCombined = battle.isCombined() ? battle.getDockCombined().getShips() : null; if (lastPhase == null) return; // ダメージ計算 int airDamage = 0; for (int i = 0; i < this.yDamages.length; ++i) this.yDamages[i] = 0; // 連合艦隊夜戦の場合、MVP計算時、昼戦は考慮しない if ((phase1 != null) && (lastPhase.getKind() != BattlePhaseKind.COMBINED_MIDNIGHT)) airDamage += this.computeDamages(this.friendDamages[0], this.enemyDamages[0], this.yDamages, phase1); if (phase2 != null) airDamage += this.computeDamages(this.friendDamages[1], this.enemyDamages[1], this.yDamages, phase2); MVPShip[] mvp1 = this.computeMVP(Arrays.copyOf(this.yDamages, friendShips.size()), friendShips); MVPShip[] mvp2 = battle.isCombined() ? this.computeMVP( Arrays.copyOfRange(this.yDamages, 6, 6 + friendShipsCombined.size()), friendShipsCombined) : null; // 情報表示 String[] formation = battle.getFormation(); int[] rawTouchPlane = lastPhase.getTouchPlane(); String[] touchPlane = null; String[] sakuteki = battle.getSakuteki(); String seiku = lastPhase.getSeiku(); AirBattleDto[] air = lastPhase.getAirBattleDto(); double[] damageRate = lastPhase.getDamageRate(); if (rawTouchPlane != null) { touchPlane = AirBattleDto.toTouchPlaneString(rawTouchPlane); } for (int i = 0; i < 2; ++i) { if (formation[i] != null) { setLabelText(this.infoLabels[i][1], FORM_PREFIX + formation[i]); } if (touchPlane != null) setLabelText(this.infoLabels[i][2], TOUCH_PREFIX + ((rawTouchPlane[i] != -1) ? "あり" : "なし"), TOUCH_PREFIX + touchPlane[i]); if (sakuteki != null) { setLabelText(this.infoLabels[i][3], SAKUTEKI_PREFIX + sakuteki[i]); } if (i == 0) { this.infoLabels[i][4].setText("航空戦:"); this.infoLabels[i][5].setText((seiku != null) ? seiku : "なし"); } this.infoLabels[i][6].setText("Stage1"); this.infoLabels[i][7].setText("Stage2"); if (air != null) { this.printPlaneCount(this.infoLabels[i], 8, air[0], i); this.printPlaneCount(this.infoLabels[i], 10, air[1], i); } } this.matchLabel.setText(battle.getFormationMatch()); ResultRank rank = lastPhase.getEstimatedRank(); this.resultLabel[0].setText(this.getMVPText(mvp1, airDamage)); this.resultLabel[1].setText(this.getMVPText(mvp2, 0)); // 第二艦隊は航空戦ダメージゼロ this.resultLabel[2].setText(this.getReulstText(damageRate, rank.toString())); for (int i = 0; i < 3; ++i) { if ((rank == ResultRank.C) || (rank == ResultRank.D) || (rank == ResultRank.E)) { this.resultLabel[i].setBackground(ColorManager.getColor(AppConstants.LOSE_BATTLE_COLOR)); this.resultLabel[i].setForeground(ColorManager.getColor(SWT.COLOR_WHITE)); } else { this.resultLabel[i].setBackground(null); this.resultLabel[i].setForeground(null); } } } @Override protected void updateData(boolean start) { this.beginDraw(); try { if (this.getBattle() != null) { this.printDock(); this.printMap(); this.printBattle(); } else if (this.getDocks() == null) { // 出撃中でない this.clearText(); this.title.setText("出撃中ではありません"); } else if (this.getMapCellDto() == null) { // 移動中 this.clearText(); if (start) { this.title.setText("出撃しました"); } else { this.title.setText("移動中..."); } this.printDock(); } else { // 移動中 this.printMap(); } } finally { this.endDraw(); } } }