/**
*
*/
package logbook.gui.logic;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import logbook.constants.AppConstants;
import logbook.dto.AirBattleDto;
import logbook.dto.AtackKind;
import logbook.dto.BattleAtackDto;
import logbook.dto.BattleExDto;
import logbook.dto.BattleExDto.Phase;
import logbook.dto.BattlePhaseKind;
import logbook.dto.BattleResultDto;
import logbook.dto.ItemDto;
import logbook.dto.ShipBaseDto;
import logbook.dto.ShipDto;
import org.apache.commons.lang3.StringUtils;
/**
* @author Nekopanda
*
*/
public class BattleHtmlGenerator extends HTMLGenerator {
private static String getRowSpan(int span) {
return "rowspan=\"" + span + "\"";
}
private static String getColSpan(int span) {
return "colspan=\"" + span + "\"";
}
private static DateFormat dateFormat = new SimpleDateFormat(AppConstants.DATE_FORMAT);
private static String[] BOX_CLASS = new String[] { "box" };
private static String[][][] TEXT_CLASS = new String[][][] {
new String[][] {
new String[] { "friend" },
new String[] { "enemy" }
}, new String[][] {
new String[] { "enemy" },
new String[] { "friend" }
}
};
private static String[][][] DAMAGE_CLASS = new String[][][] {
new String[][] {
new String[] { "friend-damage" },
new String[] { "enemy-damage" }
}, new String[][] {
new String[] { "enemy-damage" },
new String[] { "friend-damage" }
}
};
private static String[][] DAMAGE_LABEL_CLASS = new String[][] {
new String[] { "label-mukizu" },
new String[] { "label-kenzai" },
new String[] { "label-syoha" },
new String[] { "label-tyuha" },
new String[] { "label-taiha" },
new String[] { "label-gotin" }
};
private static String[][] PARAM_TABLE_CLASS = new String[][] {
new String[] { "friend", "friend-param" },
new String[] { "enemy", "enemy-param" }
};
private static String[][] SLOTITEM_TABLE_CLASS = new String[][] {
new String[] { "friend", "friend-slotitem" },
new String[] { "enemy", "enemy-slotitem" }
};
private static String[][] FORMATION_CLASS = new String[][] {
new String[] { "friend", "friend-formation" },
new String[] { "enemy", "enemy-formation" }
};
private static String[][] DAMAGE_TABLE_CLASS = new String[][] {
new String[] { "friend", "friend-damage" },
new String[] { "enemy", "enemy-damage" }
};
private static String[][][] AIR_DAMAGE_TABLE_CLASS = new String[][][] {
new String[][] {
new String[] { "friend", "friend-air-atack" },
new String[] { "enemy", "enemy-air-damage" }
},
new String[][] {
new String[] { "enemy", "enemy-air-atack" },
new String[] { "friend", "friend-air-damage" }
}
};
private static String[] AIR_TABLE_CLASS = new String[] { "air-stage12" };
private static String[][][] RAIGEKI_DAMAGE_TABLE_CLASS = new String[][][] {
new String[][] {
new String[] { "friend", "friend-raigeki-atack" },
new String[] { "enemy", "enemy-raigeki-damage" }
},
new String[][] {
new String[] { "enemy", "enemy-raigeki-atack" },
new String[] { "friend", "friend-raigeki-damage" }
}
};
private String getShipName(ShipBaseDto[] ships, int index) {
return String.valueOf(index + 1) + "." + ships[index].getFriendlyName();
}
/**
* パラメータテーブルを生成
* @param gen
* @param tableTitle
* @param ships
* @param hp
* @param phaseName
*/
private <SHIP extends ShipBaseDto>
void genParmeters(String tableTitle,
List<SHIP> ships, int[][] hp, String[] phaseName, int hqLv)
{
if (ships.size() == 0) {
return;
}
boolean isFriend;
int ci;
if (ships.get(0) instanceof ShipDto) {
isFriend = true;
ci = 0;
}
else {
isFriend = false;
ci = 1;
}
int numPhases = (hp.length / 2) - 1;
this.begin("div", BOX_CLASS);
this.begin("table", PARAM_TABLE_CLASS[ci]);
this.inline("caption", tableTitle, null);
this.begin("tr", null);
this.inline("th", "", null);
this.inline("th", "艦名", null);
this.inline("th", "cond.", null);
this.inline("th", "制空", null);
this.inline("th", "索敵", null);
this.inline("th", "開始時", null);
for (int i = 0; i < numPhases; ++i) {
this.inline("th", "", null);
this.inline("th", "Dmg", null);
this.inline("th", "残", null);
this.inline("th", "", null);
}
this.inline("th", "火力", null);
this.inline("th", "雷装", null);
this.inline("th", "対空", null);
this.inline("th", "装甲", null);
this.inline("th", "回避", null);
this.inline("th", "対潜", null);
this.inline("th", "索敵", null);
this.inline("th", "運", null);
this.inline("th", "速力", null);
this.inline("th", "射程", null);
this.end(); // tr
int totalNowHp = 0;
int totalMaxHp = 0;
for (int i = 0; i < ships.size(); ++i) {
SHIP ship = ships.get(i);
SeikuString seiku = new SeikuString(ship);
SakutekiString sakuteki = new SakutekiString(ship);
int nowhp = hp[0][i];
int maxhp = hp[1][i];
totalNowHp += nowhp;
totalMaxHp += maxhp;
this.begin("tr", null);
this.inline("td", String.valueOf(i + 1), null);
this.inline("td", ship.getFriendlyName(), null);
if (isFriend) {
this.inline("td", String.valueOf(((ShipDto) ship).getCond()), null);
}
else {
this.inline("td", "", null);
}
this.inline("td", seiku.toString(), null);
this.inline("td", sakuteki.toString(), null);
this.inline("td", nowhp + "/" + maxhp, null);
for (int p = 1; p <= numPhases; ++p) {
if (i == 0) {
this.inline("td", getRowSpan(ships.size()), "→", null);
}
int dam = hp[(p * 2) + 0][i];
int remain = hp[(p * 2) + 1][i];
DamageRate rate = DamageRate.fromHP(remain, maxhp);
this.inline("td", String.valueOf(dam), null);
this.inline("td", String.valueOf(remain), null);
this.inline("td", rate.toString(isFriend), DAMAGE_LABEL_CLASS[rate.getLevel()]);
}
this.inline("td", String.valueOf(ship.getKaryoku()), null);
this.inline("td", String.valueOf(ship.getRaisou()), null);
this.inline("td", String.valueOf(ship.getTaiku()), null);
this.inline("td", String.valueOf(ship.getSoukou()), null);
this.inline("td", String.valueOf(ship.getKaihi()), null);
this.inline("td", String.valueOf(ship.getTaisen()), null);
this.inline("td", String.valueOf(ship.getSakuteki()), null);
this.inline("td", String.valueOf(ship.getLucky()), null);
this.inline("td", String.valueOf(ship.getParam().getSokuString()), null);
this.inline("td", String.valueOf(ship.getParam().getLengString()), null);
this.end(); // tr
}
this.begin("tr", null);
SeikuString totalSeiku = new SeikuString(ships);
SakutekiString totalSakuteki = new SakutekiString(ships, hqLv);
this.inline("td", "", null);
this.inline("td", "合計", null);
this.inline("td", "", null);
this.inline("td", totalSeiku.toString(), null);
this.inline("td", totalSakuteki.toString(), null);
this.inline("td", totalNowHp + "/" + totalMaxHp, null);
for (int i = 0; i < numPhases; ++i) {
this.inline("td", "", null);
this.inline("td", getColSpan(3), phaseName[i], null);
}
this.inline("td", getColSpan(10), "", null);
this.end(); // tr
this.end(); // table
this.end(); // p
}
/**
* 装備テーブルを生成
* @param gen
* @param ships
*/
private <SHIP extends ShipBaseDto>
void genSlotitemTable(List<SHIP> ships)
{
if (ships.size() == 0) {
return;
}
boolean isFriend = ships.get(0) instanceof ShipDto;
int ci = isFriend ? 0 : 1;
this.begin("div", BOX_CLASS);
this.begin("table", SLOTITEM_TABLE_CLASS[ci]);
this.begin("tr", null);
this.inline("th", "艦名", null);
for (int c = 0; c < 5; ++c) {
this.inline("th", getColSpan(2), "装備" + (c + 1), null);
}
if (isFriend) {
this.inline("th", "補助装備", null);
}
this.end(); // tr
for (int i = 0; i < ships.size(); ++i) {
this.begin("tr", null);
SHIP ship = ships.get(i);
this.inline("td", String.valueOf(i + 1) + "." + ship.getFriendlyName(), null);
List<ItemDto> items = ship.getItem2();
for (int c = 0; c < 5; ++c) {
String onSlot = "";
String itemName = "";
int[] onSlots = ship.getOnSlot(); // 現在の艦載機搭載数
int[] maxeq = ship.getShipInfo().getMaxeq2(); // 艦載機最大搭載数
if (c < items.size()) {
ItemDto item = items.get(c);
if (item != null) {
if (item.isPlane()) {
String max = (maxeq == null) ? "?" : String.valueOf(maxeq[c]);
String cur = (onSlots == null) ? "?" : String.valueOf(onSlots[c]);
onSlot = cur + "/" + max;
}
itemName += item.getFriendlyName();
}
}
this.inline("td", itemName, null);
this.inline("td", onSlot, null);
}
if (isFriend) {
String itemName = "";
ItemDto dto = ((ShipDto) ship).getSlotExItem();
if (dto != null) {
itemName = dto.getFriendlyName();
}
this.inline("td", itemName, null);
}
this.end(); // tr
}
this.end(); // table
this.end(); // p
}
/**
* 会敵情報を生成
* @param gen
* @param battle
*/
private void genFormation(BattleExDto battle) {
String fSakuteki = "";
String eSakuteki = "";
if (battle.getSakuteki() != null) { // 夜戦開始マスは索敵なし
fSakuteki = battle.getSakuteki()[0];
eSakuteki = battle.getSakuteki()[1];
}
this.inline("span", "会敵: " + battle.getFormationMatch(), null);
this.begin("table", null);
this.begin("tr", null);
this.inline("th", "", null);
this.inline("th", "陣形", null);
this.inline("th", "索敵", null);
this.end(); // tr
this.begin("tr", FORMATION_CLASS[0]);
this.inline("td", "自", null);
this.inline("td", battle.getFormation()[0], null);
this.inline("td", fSakuteki, null);
this.end(); // tr
this.begin("tr", FORMATION_CLASS[1]);
this.inline("td", "敵", null);
this.inline("td", battle.getFormation()[1], null);
this.inline("td", eSakuteki, null);
this.end(); // tr
this.end(); // table
}
private static <T> void copyToOffset(List<? extends T> src, T[] array, int offset) {
if (src == null) {
return;
}
for (int i = 0; i < src.size(); ++i) {
array[i + offset] = src.get(i);
}
}
private static void copyToOffset(int[] src, int[] dst, int offset) {
if (src == null) {
return;
}
System.arraycopy(src, 0, dst, offset, src.length);
}
/**
* ダメージによる変化を計算して表示用文字列を返す
* @param hp
* @param target
* @param damage
* @param index
* @return
*/
private static String doDamage(int[] hp, int[] target, int[] damage, int index) {
int before = hp[target[index]];
int after = before - damage[index];
if (after < 0) {
after = 0;
}
if (before == after) {
return "";
}
hp[target[index]] = after;
return String.valueOf(before) + "→" + after;
}
private static String getDamageString(int damage, int critical) {
if (damage == 0) {
return "ミス";
}
if (critical == 2) {
return "<b>" + damage + "</b>";
}
return String.valueOf(damage);
}
/**
* 「○ ダメージ ○→○」のテーブルを生成
* @param gen
* @param atack
* @param targetShips
* @param targetHp
*/
private void genDamageTableContent(BattleAtackDto atack,
ShipBaseDto[] targetShips, int[] targetHp) {
int ci = (atack.friendAtack) ? 0 : 1;
if (atack.damage.length == 0) {
this.begin("tr", null);
this.inline("td", "なし", null);
this.end(); // tr
return;
}
this.begin("tr", null);
this.inline("th", "艦", null);
this.inline("th", "ダメージ", DAMAGE_CLASS[ci][1]);
this.inline("th", "残りHP", null);
this.end(); // tr
for (int i = 0; i < atack.damage.length; ++i) {
this.begin("tr", null);
this.inline("td", this.getShipName(targetShips, atack.target[i]), TEXT_CLASS[ci][1]);
this.inline("td", getDamageString(atack.damage[i], 0), DAMAGE_CLASS[ci][1]);
this.inline("td", doDamage(targetHp, atack.target, atack.damage, i), TEXT_CLASS[ci][1]);
this.end(); // tr
}
}
/**
* 「○→○ ダメージ」のテーブルを生成
* @param gen
* @param atack
* @param originShips
* @param targetShips
*/
private void genAtackTableContent(BattleAtackDto atack,
ShipBaseDto[] originShips, ShipBaseDto[] targetShips)
{
if (atack.origin.length == 0) {
this.begin("tr", null);
this.inline("td", "なし", null);
this.end(); // tr
return;
}
int ci = (atack.friendAtack) ? 0 : 1;
this.begin("tr", null);
this.inline("th", "艦", TEXT_CLASS[ci][0]);
this.inline("th", "", null);
this.inline("th", "艦", TEXT_CLASS[ci][1]);
this.inline("th", "ダメージ", DAMAGE_CLASS[ci][1]);
this.end(); // tr
for (int i = 0; i < atack.origin.length; ++i) {
this.begin("tr", null);
this.inline("td", this.getShipName(originShips, atack.origin[i]), TEXT_CLASS[ci][0]);
this.inline("td", "→", null);
this.inline("td", this.getShipName(targetShips, atack.target[atack.ot[i]]), TEXT_CLASS[ci][1]);
int critical = atack.critical != null ? atack.critical[i] : 0;
this.inline("td", getDamageString(atack.ydam[i], critical), DAMAGE_CLASS[ci][1]);
this.end(); // tr
}
}
/**
* 砲撃戦を生成
* @param gen
* @param atacks
* @param friendShips
* @param enemyShips
* @param friendHp
* @param enemyHp
*/
private void genHougekiTableContent(List<BattleAtackDto> atacks,
ShipBaseDto[] friendShips, ShipBaseDto[] enemyShips, int[] friendHp, int[] enemyHp) {
this.begin("tr", null);
this.inline("th", "", null);
this.inline("th", "艦", null);
this.inline("th", "", null);
this.inline("th", "", null);
this.inline("th", "艦", null);
this.inline("th", "攻撃タイプ", null);
this.inline("th", "ダメージ", null);
this.inline("th", "残りHP", null);
this.end(); // tr
for (BattleAtackDto atack : atacks) {
ShipBaseDto[] origin;
ShipBaseDto[] target;
int[] targetHp;
String[] text;
String[][] textClass;
String[][] damageClass;
if (atack.friendAtack) {
origin = friendShips;
target = enemyShips;
targetHp = enemyHp;
text = new String[] { "自軍", "敵軍" };
textClass = TEXT_CLASS[0];
damageClass = DAMAGE_CLASS[0];
}
else {
origin = enemyShips;
target = friendShips;
targetHp = friendHp;
text = new String[] { "敵軍", "自軍" };
textClass = TEXT_CLASS[1];
damageClass = DAMAGE_CLASS[1];
}
for (int i = 0; i < atack.damage.length; ++i) {
this.begin("tr", null);
if (i == 0) {
this.inline("td", text[0], null);
this.inline("td", this.getShipName(origin, atack.origin[0]), textClass[0]);
}
else {
this.inline("td", getColSpan(2), "", null);
}
this.inline("td", "→", null);
this.inline("td", text[1], null);
this.inline("td", this.getShipName(target, atack.target[i]), textClass[1]);
if (i == 0) {
this.inline("td", getRowSpan(atack.damage.length), atack.getHougekiTypeString(), null);
}
int critical = atack.critical != null ? atack.critical[i] : 0;
this.inline("td", getDamageString(atack.damage[i], critical), damageClass[1]);
this.inline("td", doDamage(targetHp, atack.target, atack.damage, i), textClass[1]);
this.end(); // tr
}
}
}
/**
* 航空戦を生成
* @param gen
* @param air
* @param title
* @param friendShips
* @param enemyShips
* @param friendHp
* @param enemyHp
*/
private void genAirBattle(AirBattleDto air, String title,
ShipBaseDto[] friendShips, ShipBaseDto[] enemyShips, int[] friendHp, int[] enemyHp)
{
if (air == null) {
return;
}
this.inline("h3", title, AIR_TABLE_CLASS);
String[] stage1 = air.getStage1DetailedString();
String[] stage2 = air.getStage2DetailedString();
String[] touch = air.getTouchPlane();
this.begin("table", null);
this.begin("tr", null);
this.inline("th", getRowSpan(2), "", null);
this.inline("th", getRowSpan(2), "制空権", null);
this.inline("th", getColSpan(2), "艦載機", null);
this.inline("th", getRowSpan(2), "触接", null);
this.end(); // tr
this.begin("tr", null);
this.inline("th", "ステージ1", null);
this.inline("th", "ステージ2", null);
this.end(); // tr
this.begin("tr", TEXT_CLASS[0][0]);
this.inline("td", "自", null);
this.inline("td", air.seiku, null);
this.inline("td", stage1[0], null);
this.inline("td", stage2[0], null);
this.inline("td", touch[0], null);
this.end(); // tr
this.begin("tr", TEXT_CLASS[0][1]);
this.inline("td", "敵", null);
this.inline("td", "", null);
this.inline("td", stage1[1], null);
this.inline("td", stage2[1], null);
this.inline("td", touch[1], null);
this.end(); // tr
this.end(); // table
if (air.airFire != null) {
this.inline("span", "対空カットイン", null);
this.begin("table", null);
this.begin("tr", null);
this.inline("th", "発動艦娘", null);
this.inline("th", "種別", null);
this.inline("th", "使用装備", null);
this.end(); // tr
this.begin("tr", null);
this.inline("td", this.getShipName(friendShips, air.airFire[0]), null);
this.inline("td", air.getTaikuCutinString(), null);
this.inline("td", air.getTaikuCutinItemsString(), null);
this.end(); // tr
this.end(); // table
}
if ((air.atacks == null) || (air.atacks.size() == 0)) {
//this.inline("h4", "航空戦による攻撃なし", null);
return;
}
for (BattleAtackDto atack : air.atacks) {
ShipBaseDto[] origin;
ShipBaseDto[] target;
int[] targetHp;
String[] text;
String[][] tableClass;
String[][] textClass;
if (atack.friendAtack) {
origin = friendShips;
target = enemyShips;
targetHp = enemyHp;
text = new String[] { "自軍", "敵軍ダメージ" };
tableClass = AIR_DAMAGE_TABLE_CLASS[0];
textClass = TEXT_CLASS[0];
}
else {
origin = enemyShips;
target = friendShips;
targetHp = friendHp;
text = new String[] { "敵軍", "自軍ダメージ" };
tableClass = AIR_DAMAGE_TABLE_CLASS[1];
textClass = TEXT_CLASS[1];
}
if (atack.kind != AtackKind.AIRBASE) { // 基地航空隊の攻撃機表示は未実装
this.begin("div", BOX_CLASS);
this.inline("span", text[0] + ": 攻撃に参加した艦", null);
this.begin("table", tableClass[0]);
if (atack.origin.length == 0) {
this.begin("tr", null);
this.inline("td", "なし", null);
this.end(); // tr
}
else {
for (int i = 0; i < atack.origin.length; ++i) {
this.begin("tr", null);
this.inline("td", this.getShipName(origin, atack.origin[i]), textClass[0]);
this.end(); // tr
}
}
this.end(); // table
this.end(); // p
}
this.begin("div", BOX_CLASS);
this.inline("span", text[1], null);
this.begin("table", tableClass[1]);
this.genDamageTableContent(atack, target, targetHp);
this.end(); // table
this.end(); // p
}
}
/**
* 雷撃戦を生成
* @param gen
* @param raigeki
* @param title
* @param friendShips
* @param enemyShips
* @param friendHp
* @param enemyHp
*/
private void genRaigekiBattle(List<BattleAtackDto> raigeki, String title,
ShipBaseDto[] friendShips, ShipBaseDto[] enemyShips, int[] friendHp, int[] enemyHp)
{
if ((raigeki == null) || (raigeki.size() == 0)) {
return;
}
this.inline("h3", title, null);
for (BattleAtackDto atack : raigeki) {
ShipBaseDto[] origin;
ShipBaseDto[] target;
int[] targetHp;
String[] text;
String[][] textClass;
if (atack.friendAtack) {
origin = friendShips;
target = enemyShips;
targetHp = enemyHp;
text = new String[] { "自軍攻撃", "敵軍ダメージ" };
textClass = RAIGEKI_DAMAGE_TABLE_CLASS[0];
}
else {
origin = enemyShips;
target = friendShips;
targetHp = friendHp;
text = new String[] { "敵軍攻撃", "自軍ダメージ" };
textClass = RAIGEKI_DAMAGE_TABLE_CLASS[1];
}
// 攻撃
this.begin("div", BOX_CLASS);
this.inline("span", text[0], null);
this.begin("table", textClass[0]);
this.genAtackTableContent(atack, origin, target);
this.end(); // table
this.end(); // p
// ダメージ
this.begin("div", BOX_CLASS);
this.inline("span", text[1], null);
this.begin("table", textClass[1]);
this.genDamageTableContent(atack, target, targetHp);
this.end(); // table
this.end(); // p
}
}
/**
* フェイズを生成
* @param gen
* @param battle
* @param index
*/
private void genPhase(BattleExDto battle, int index,
ShipBaseDto[] friendShips, ShipBaseDto[] enemyShips, int[] friendHp, int[] enemyHp)
{
BattleExDto.Phase phase = battle.getPhaseList().get(index);
List<AirBattleDto> airList = new ArrayList<>();
List<List<BattleAtackDto>> hougekiList = new ArrayList<>();
if (phase.getAir() != null)
airList.add(phase.getAir());
if (phase.getAir2() != null)
airList.add(phase.getAir2());
if (phase.getHougeki1() != null)
hougekiList.add(phase.getHougeki1());
if (phase.getHougeki2() != null)
hougekiList.add(phase.getHougeki2());
if (phase.getHougeki3() != null)
hougekiList.add(phase.getHougeki3());
// 基地航空隊
List<AirBattleDto> airBaseList = phase.getAirBase();
if (airBaseList != null) {
for (int i = 0; i < airBaseList.size(); ++i) {
AirBattleDto attack = airBaseList.get(i);
this.genAirBattle(attack, "基地航空隊攻撃(" + (i + 1) + "/" + airBaseList.size() + ")",
friendShips, enemyShips, friendHp, enemyHp);
}
}
// 航空戦 → 支援艦隊による攻撃 → 開幕対潜 → 開幕 → 航空戦2回目
for (int i = 0; i < airList.size(); ++i) {
this.genAirBattle(airList.get(i), "航空戦(" + (i + 1) + "/" + airList.size() + ")",
friendShips, enemyShips, friendHp, enemyHp);
if (i == 0) {
if (phase.getSupport() != null) {
for (BattleAtackDto atack : phase.getSupport()) {
this.inline("span", "支援艦隊による攻撃", null);
this.begin("table", DAMAGE_TABLE_CLASS[1]);
this.genDamageTableContent(atack, enemyShips, enemyHp);
this.end(); // table
}
}
if (phase.getOpeningTaisen() != null) {
this.inline("h3", "対潜先制爆雷攻撃", null);
this.begin("table", null);
this.genHougekiTableContent(phase.getOpeningTaisen(), friendShips, enemyShips, friendHp, enemyHp);
this.end(); // table
}
if (phase.getOpening() != null) {
this.genRaigekiBattle(phase.getOpening(), "開幕",
friendShips, enemyShips, friendHp, enemyHp);
}
}
}
// 夜戦
if (phase.getHougeki() != null) {
//
if ((phase.getTouchPlane() != null) || (phase.getFlarePos() != null)) {
String[] touch = AirBattleDto.toTouchPlaneString(phase.getTouchPlane());
String[] flare = { "", "" };
int[] flarePos = phase.getFlarePos();
if (flarePos != null) {
if (flarePos[0] != -1) {
int base = phase.getKind().isHougekiSecond() ? 6 : 0;
flare[0] = this.getShipName(friendShips, (flarePos[0] - 1) + base);
}
if (flarePos[1] != -1) {
flare[1] = this.getShipName(enemyShips, flarePos[1] - 1);
}
}
this.begin("table", null);
this.begin("tr", null);
this.inline("th", "", null);
this.inline("th", "触接", null);
this.inline("th", "照明弾", null);
this.end(); // tr
this.begin("tr", null);
this.inline("td", "自", null);
this.inline("td", touch[0], null);
this.inline("td", flare[0], null);
this.end(); // tr
this.begin("tr", null);
this.inline("td", "敵", null);
this.inline("td", touch[1], null);
this.inline("td", flare[1], null);
this.end(); // tr
this.end(); // table
}
this.inline("h3", "砲雷撃", null);
this.begin("table", null);
this.genHougekiTableContent(phase.getHougeki(), friendShips, enemyShips, friendHp, enemyHp);
this.end(); // table
}
// 砲撃+雷撃
for (int i = 0; i < hougekiList.size(); ++i) {
this.inline("h3", "砲撃(" + (i + 1) + "/" + hougekiList.size() + ")", null);
this.begin("table", null);
this.genHougekiTableContent(hougekiList.get(i), friendShips, enemyShips, friendHp, enemyHp);
this.end(); // table
if ((phase.getKind() == BattlePhaseKind.COMBINED_BATTLE) && (i == 0)) {
// 空母機動部隊の昼戦の場合はここで雷撃
this.genRaigekiBattle(phase.getRaigeki(), "雷撃戦",
friendShips, enemyShips, friendHp, enemyHp);
}
}
// 空母機動部隊の昼戦以外の雷撃
if (phase.getKind() != BattlePhaseKind.COMBINED_BATTLE) {
this.genRaigekiBattle(phase.getRaigeki(), "雷撃戦",
friendShips, enemyShips, friendHp, enemyHp);
}
}
/**
* フェイズのダメージ合計を計算
* @param friend
* @param enemy
* @param phase
*/
private void computeDamages(int[] friend, int[] enemy, BattleExDto.Phase phase) {
for (int i = 0; i < friend.length; ++i) {
friend[i] = 0;
}
for (int i = 0; i < enemy.length; ++i) {
enemy[i] = 0;
}
for (BattleAtackDto[] atacks : phase.getAtackSequence()) {
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;
}
}
}
}
}
}
/**
* 開始時HPとダメージ -> ダメージと戦闘後のHP
* @param start
* @param inDam
* @param offset
* @param dam
* @param after
*/
private void storeDamageAndHp(int[] start, int[] inDam, int offset, int[] dam, int[] after) {
if (start != null) {
for (int i = 0; i < start.length; ++i) {
dam[i] = inDam[offset + i];
after[i] = Math.max(0, start[i] - inDam[offset + i]);
}
}
}
/**
* パラメータテーブルに表示するHPを計算
* 配列インデックスは [艦隊][now, max, フェイズ, ダメージ][艦]
* @param battle
* @return
*/
private int[][][] calcHP(BattleExDto battle) {
int[][][] hp = new int[3][2 + (battle.getPhaseList().size() * 2)][6];
int[][] startHp = new int[][] {
battle.getStartFriendHp(),
battle.getStartFriendHpCombined(),
battle.getStartEnemyHp() };
hp[0][0] = battle.getStartFriendHp();
hp[1][0] = battle.getStartFriendHpCombined();
hp[2][0] = battle.getStartEnemyHp();
hp[0][1] = battle.getMaxFriendHp();
hp[1][1] = battle.getMaxFriendHpCombined();
hp[2][1] = battle.getMaxEnemyHp();
int[] friendDamages = new int[12];
int[] enemyDamages = new int[6];
for (int pi = 0; pi < battle.getPhaseList().size(); ++pi) {
BattleExDto.Phase phase = battle.getPhaseList().get(pi);
this.computeDamages(friendDamages, enemyDamages, phase);
this.storeDamageAndHp(startHp[0], friendDamages, 0, hp[0][(pi * 2) + 2], hp[0][(pi * 2) + 3]);
this.storeDamageAndHp(startHp[1], friendDamages, 6, hp[1][(pi * 2) + 2], hp[1][(pi * 2) + 3]);
this.storeDamageAndHp(startHp[2], enemyDamages, 0, hp[2][(pi * 2) + 2], hp[2][(pi * 2) + 3]);
startHp = new int[][] { hp[0][(pi * 2) + 3], hp[1][(pi * 2) + 3], hp[2][(pi * 2) + 3] };
}
return hp;
}
private void genResultTable(BattleResultDto result, BattleExDto detail) {
this.begin("table", null);
this.begin("tr", null);
this.inline("td", "ランク", null);
this.inline("td", detail.getRank().toString(), null);
this.end(); // tr
// MVP
String mvp1 = "なし";
String mvp2 = "なし";
if (detail.getMvp() != -1) { // 敗北Eの時はMVPなし
mvp1 = detail.getDock().getShips().get(detail.getMvp() - 1).getFriendlyName();
}
if (detail.isCombined()) {
if (detail.getMvpCombined() != -1) { // 敗北Eの時はMVPなし
mvp2 = detail.getDockCombined().getShips()
.get(detail.getMvpCombined() - 1).getFriendlyName();
}
}
if (detail.isCombined()) {
this.begin("tr", null);
this.inline("td", "MVP(第一艦隊)", null);
this.inline("td", mvp1, null);
this.end(); // tr
this.begin("tr", null);
this.inline("td", "MVP(第二艦隊)", null);
this.inline("td", mvp2, null);
this.end(); // tr
}
else {
this.begin("tr", null);
this.inline("td", "MVP", null);
this.inline("td", mvp1, null);
this.end(); // tr
}
this.begin("tr", null);
this.inline("td", "ドロップ", null);
String dropText = StringUtils.join(
detail.getDropName(),
(detail.isDropShip() && detail.isDropItem()) ? "," : null,
detail.getDropItemName());
this.inline("td", StringUtils.isEmpty(dropText) ? "なし" : dropText, null);
this.end(); // tr
this.end(); // table
}
/** 戦闘結果が不完全の場合はnullが返ることがある
* @param title HTMLのタイトル
* @param result 戦闘結果概要データ
* @param battle 戦闘結果詳細データ
* @param getCharset charsetを生成するか。生成する場合UTF-8が指定される
* @return 生成されたHTML
* @throws java.io.IOException ファイルの書き込みに失敗した
* */
public String generateHTML(String title, BattleResultDto result, BattleExDto battle, boolean genCharset)
throws IOException
{
if (battle.isCompleteResult() == false) {
return null;
}
this.genHeader(title, genCharset);
this.begin("body", null);
String[] sectionTitleClass = new String[] { "sec-title" };
// タイトル
String time = dateFormat.format(result.getBattleDate());
String header;
if (battle.isPractice()) {
header = "「" + battle.getEnemyName() + "」との演習 (" + time + ")";
}
else {
header = result.getMapCell().detailedString() + " (" + time + ")";
}
this.inline("div", "<h1>" + header + "</h1>", new String[] { "title" });
// 結果
this.inline("div", "<h2>結果</h2>", sectionTitleClass);
this.genResultTable(result, battle);
// パラメータテーブル生成 //
this.inline("div", "<h2>パラメータ</h2>", sectionTitleClass);
int[][][] hpList = this.calcHP(battle);
String[] phaseName = (battle.getPhase1().isNight() ?
new String[] { "夜戦後", "昼戦後" } : new String[] { "昼戦後", "夜戦後" });
this.genParmeters(battle.getDock().getName(),
battle.getDock().getShips(), hpList[0], phaseName, battle.getHqLv());
if (battle.isCombined()) {
this.genParmeters(battle.getDockCombined().getName(),
battle.getDockCombined().getShips(), hpList[1], phaseName, battle.getHqLv());
}
this.genParmeters(battle.getEnemyName(), battle.getEnemy(), hpList[2], phaseName, 0);
// 装備を生成 //
this.genSlotitemTable(battle.getDock().getShips());
if (battle.isCombined()) {
this.genSlotitemTable(battle.getDockCombined().getShips());
}
this.genSlotitemTable(battle.getEnemy());
// 会敵情報 //
this.inline("div", "<h2>会敵情報</h2>", sectionTitleClass);
this.genFormation(battle);
// フェイズ //
ShipBaseDto[] friendShips = new ShipBaseDto[12];
ShipBaseDto[] enemyShips = new ShipBaseDto[6];
int[] friendHp = new int[12];
int[] enemyHp = new int[6];
copyToOffset(battle.getDock().getShips(), friendShips, 0);
copyToOffset(battle.getEnemy(), enemyShips, 0);
copyToOffset(battle.getStartFriendHp(), friendHp, 0);
copyToOffset(battle.getStartEnemyHp(), enemyHp, 0);
if (battle.isCombined()) {
copyToOffset(battle.getDockCombined().getShips(), friendShips, 6);
copyToOffset(battle.getStartFriendHpCombined(), friendHp, 6);
}
int numPhases = battle.getPhaseList().size();
for (int i = 0; i < numPhases; ++i) {
Phase phase = battle.getPhaseList().get(i);
String phaseTitle = (i + 1) + "/" + numPhases + "フェイズ: " + (phase.isNight() ? "夜戦" : "昼戦");
this.inline("div", "<h2>" + phaseTitle + "</h2>", sectionTitleClass);
this.genPhase(battle, i, friendShips, enemyShips, friendHp, enemyHp);
}
this.inline("p", "※<b>太字</b>はクリティカルヒットです<br>" +
"<i>Generated by " + AppConstants.TITLEBAR_TEXT + " (BattleEx ver." + battle.getExVersion() + ")"
+ "</i>", null);
this.end(); // body
return this.result();
}
}