package logbook.gui.widgets;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
import logbook.config.AppConfig;
import logbook.constants.AppConstants;
import logbook.data.context.GlobalContext;
import logbook.data.context.TimerContext;
import logbook.dto.DeckMissionDto;
import logbook.dto.DockDto;
import logbook.dto.ItemDto;
import logbook.dto.ItemInfoDto;
import logbook.dto.ShipDto;
import logbook.gui.logic.ColorManager;
import logbook.gui.logic.DamageRate;
import logbook.gui.logic.SakutekiString;
import logbook.gui.logic.SeikuString;
import logbook.gui.logic.TimeLogic;
import logbook.gui.logic.TimeString;
import logbook.internal.AkashiTimer;
import logbook.internal.CondTiming;
import logbook.internal.EvaluateExp;
import logbook.internal.LoggerHolder;
import logbook.internal.SeaExp;
import logbook.util.CalcExpUtils;
import logbook.util.SwtUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.wb.swt.SWTResourceManager;
/**
* 艦隊タブのウィジェットです
*
*/
public class FleetComposite extends Composite {
/** ロガー */
private static final LoggerHolder LOG = new LoggerHolder(FleetComposite.class);
/** 警告 */
public static final int WARN = 1;
/** 致命的 */
public static final int FATAL = 2;
/** 1艦隊に編成できる艦娘の数 */
private static final int MAXCHARA = 6;
/** フォント大きい */
private final static int LARGE = 2;
/** フォント小さい */
private final static int SMALL = -1;
/** HPゲージ幅 */
private static final int GAUGE_WIDTH = 50;
/** HPゲージ高さ */
private static final int GAUGE_HEIGHT = 12;
/** 経験値ゲージ高さ */
private static final int EXP_GAUGE_HEIGHT = 4;
/** HPゲージ最小色 */
private static final RGB GAUGE_EMPTY = new RGB(0xff, 0, 0);
/** HPゲージ中間色 */
private static final RGB GAUGE_HALF = new RGB(0xff, 0xd7, 0);
/** HPゲージ最大色 */
private static final RGB GAUGE_FULL = new RGB(0, 0xd7, 0);
/** 経験値ゲージ色 */
private static final RGB EXP_GAUGE = new RGB(0, 0x80, 0xff);
/** 艦隊 */
private DockDto dock;
private final Composite fleetGroup;
/** タブアイコン表示 */
private final BitSet state = new BitSet();
/** コンディション最小値(メッセージ表示用) */
private int cond;
/** 疲労回復時間(メッセージ表示用) */
private String clearDate;
/** 大破している */
private boolean badlyDamage;
/** アイコンラベル */
private final Label[] iconLabels = new Label[MAXCHARA];
/** 名前ラベル */
private final Label[] nameLabels = new Label[MAXCHARA];
/** Lvラベル */
private final Label[] lvLabels = new Label[MAXCHARA];
/** HP */
private final Label[] hpLabels = new Label[MAXCHARA];
/** HPゲージ */
private final Label[] hpgaugeLabels = new Label[MAXCHARA];
/** HPゲージイメージ */
private final Image[] hpgaugeImages = new Image[MAXCHARA];
/** HPメッセージ */
private final Label[] hpmsgLabels = new Label[MAXCHARA];
/** コンディション */
private final Label[] condLabels = new Label[MAXCHARA];
/** コンディションステータス */
private final Label[] condstLabels = new Label[MAXCHARA];
/** 弾ステータス */
private final Label[] bullstLabels = new Label[MAXCHARA];
/** 燃料ステータス */
private final Label[] fuelstLabels = new Label[MAXCHARA];
/** ダメコン */
private final Label[] dmgcLabels = new Label[MAXCHARA];
/** レベリング */
private final Label[] nextLabels = new Label[MAXCHARA];
/** 泊地修理 or 疲労回復 */
private final Label[] timeLabels = new Label[MAXCHARA];
/** メッセージ */
private final StyledText message;
/** 時間表示系の更新タスク */
private final List<Runnable> updators = new ArrayList<>();
private static SimpleDateFormat format = new SimpleDateFormat(AppConstants.DATE_SHORT_FORMAT);
/**
* @param parent 艦隊タブの親
* @param tabItem 艦隊タブ
*/
public FleetComposite(Composite parent) {
super(parent, SWT.NONE);
this.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
GridLayout glParent = new GridLayout(1, false);
glParent.horizontalSpacing = 0;
glParent.marginTop = 0;
glParent.marginWidth = 0;
glParent.marginHeight = 0;
glParent.marginBottom = 0;
glParent.verticalSpacing = 0;
this.setLayout(glParent);
this.fleetGroup = new Composite(this, SWT.NONE);
this.fleetGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
GridLayout glShipGroup = new GridLayout(2, false);
glShipGroup.horizontalSpacing = 0;
glShipGroup.marginTop = 0;
glShipGroup.marginWidth = 1;
glShipGroup.marginHeight = 0;
glShipGroup.marginBottom = 4;
glShipGroup.verticalSpacing = 0;
this.fleetGroup.setLayout(glShipGroup);
this.init();
// セパレーター
Label separator = new Label(this, SWT.SEPARATOR | SWT.HORIZONTAL);
separator.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
// メッセージ
this.message = new StyledText(this, SWT.READ_ONLY | SWT.WRAP);
this.message.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
this.message.setWordWrap(true);
this.message.setBackground(this.getBackground());
this.fleetGroup.layout();
}
/**
* 初期化
*/
private void init() {
for (int i = 0; i < MAXCHARA; i++) {
// アイコン
Label iconlabel = new Label(this.fleetGroup, SWT.NONE);
GridData gdIconlabel = new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 2);
gdIconlabel.widthHint = SwtUtils.DPIAwareWidth(16);
iconlabel.setLayoutData(gdIconlabel);
// 上段
Composite upsideBase = new Composite(this.fleetGroup, SWT.NONE);
upsideBase.setLayout(SwtUtils.makeGridLayout(2, 0, 0, 0, 0));
upsideBase.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// 名前
Composite nameComposite = new Composite(upsideBase, SWT.NONE);
nameComposite.setLayout(SwtUtils.makeGridLayout(2, 0, 0, 1, 0));
nameComposite.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
Label namelabel = new Label(nameComposite, SWT.NONE);
SwtUtils.initLabel(namelabel, "名前", LARGE, new GridData());
Label lvlabel = new Label(nameComposite, SWT.NONE);
SwtUtils.initLabel(lvlabel, "Lv.0", SMALL, 1.4, new GridData(SWT.CENTER, SWT.BOTTOM, false, false, 1, 1));
// HP
Composite hpComposite = new Composite(upsideBase, SWT.NONE);
hpComposite.setLayout(SwtUtils.makeGridLayout(3, 0, 0, 1, 0));
hpComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
Label hp = new Label(hpComposite, SWT.NONE);
SwtUtils.initLabel(hp, "/", SMALL, new GridData(SWT.RIGHT, SWT.CENTER, true, false, 1, 1));
Label hpgauge = new Label(hpComposite, SWT.NONE);
hpgauge.setLayoutData(new GridData(SWT.CENTER, SWT.BOTTOM, false, false, 1, 1));
Label hpmsg = new Label(hpComposite, SWT.NONE);
SwtUtils.initLabel(hpmsg, "健在", new GridData(SWT.CENTER, SWT.CENTER, false, false, 1, 1));
// 下段
Composite downsideBase = new Composite(this.fleetGroup, SWT.NONE);
downsideBase.setLayout(SwtUtils.makeGridLayout(2, 0, 0, 0, 0));
downsideBase.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
// ステータス
Composite stateComposite = new Composite(downsideBase, SWT.NONE);
stateComposite.setLayout(SwtUtils.makeGridLayout(6, 0, 0, 0, 0));
stateComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Label condst = new Label(stateComposite, SWT.NONE);
SwtUtils.initLabel(condst, "疲", new GridData());
Label fuelst = new Label(stateComposite, SWT.NONE);
SwtUtils.initLabel(fuelst, "燃", new GridData());
Label bullst = new Label(stateComposite, SWT.NONE);
SwtUtils.initLabel(bullst, "弾", new GridData());
Label dmgc = new Label(stateComposite, SWT.NONE);
SwtUtils.initLabel(dmgc, "ダ", new GridData());
Label next = new Label(stateComposite, SWT.NONE);
SwtUtils.initLabel(next, "next", new GridData());
Label time = new Label(stateComposite, SWT.NONE);
SwtUtils.initLabel(time, "time", new GridData());
// 疲労
Label cond = new Label(downsideBase, SWT.NONE);
SwtUtils.initLabel(cond, "49 cond.", new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
this.iconLabels[i] = iconlabel;
this.nameLabels[i] = namelabel;
this.lvLabels[i] = lvlabel;
this.hpLabels[i] = hp;
this.hpgaugeLabels[i] = hpgauge;
this.hpmsgLabels[i] = hpmsg;
this.condLabels[i] = cond;
this.condstLabels[i] = condst;
this.bullstLabels[i] = bullst;
this.fuelstLabels[i] = fuelst;
this.dmgcLabels[i] = dmgc;
this.nextLabels[i] = next;
this.timeLabels[i] = time;
}
}
/**
* 艦隊を更新します
*
* @param dock
* @param combinedFleetBadlyDamaed 連合艦隊の他の艦隊の艦が大破している
*/
public void updateFleet(DockDto dock, boolean combinedFleetBadlyDamaed, List<ShipDto> badlyDamaged) {
if ((this.dock == dock) && !this.dock.isUpdate()) {
// 時間表示だけ更新
for (Runnable update : this.updators) {
update.run();
}
return;
}
this.updators.clear();
this.getShell().setRedraw(false);
this.dock = dock;
this.state.set(WARN, false);
this.state.set(FATAL, false);
this.cond = AppConfig.get().getOkCond();
this.clearDate = null;
this.badlyDamage = false;
this.message.setText("");
List<ShipDto> ships = dock.getShips();
boolean[] escaped = dock.getEscaped();
for (int i = ships.size(); i < MAXCHARA; i++) {
this.iconLabels[i].setImage(null);
this.nameLabels[i].setText("");
this.lvLabels[i].setText("");
this.hpLabels[i].setText("");
this.hpgaugeLabels[i].setImage(null);
this.hpmsgLabels[i].setText("");
this.condLabels[i].setText("");
this.condstLabels[i].setText("");
this.bullstLabels[i].setText("");
this.fuelstLabels[i].setText("");
this.dmgcLabels[i].setText("");
this.nextLabels[i].setText("");
this.timeLabels[i].setText("");
}
// 艦隊合計Lv
int totallv = 0;
int dockIndex = Integer.parseInt(dock.getId()) - 1;
CondTiming condTiming = GlobalContext.getCondTiming();
AkashiTimer.RepairState repairState = TimerContext.get().getAkashiRepairState(dockIndex);
List<AkashiTimer.ShipState> repairShips = repairState.isRepairing() ? repairState.get() : null;
boolean isSortie = GlobalContext.isSortie(dock.getId());
Map<Integer, Date> ndockMap = GlobalContext.getNDockCompleteTimeMap();
DeckMissionDto currentMission = (dockIndex == 0) ? null : GlobalContext.getDeckMissions()[dockIndex - 1];
DeckMissionDto previousMission = (dockIndex == 0) ? null : GlobalContext.getPreviousMissions()[dockIndex - 1];
boolean flagshipNeedSupply = false;
boolean needSupply = false;
boolean reqSupply = false;
int lostPlanes = 0;
boolean isBathwater = false;
for (int i = 0; i < ships.size(); i++) {
ShipDto ship = ships.get(i);
// 艦娘のステータス
BitSet shipstatus = new BitSet();
// HP
int nowhp = ship.getNowhp();
// MaxHP
int maxhp = ship.getMaxhp();
// HP割合
float hpratio = (float) nowhp / (float) maxhp;
// 経験値ゲージの割合
float expraito = ship.getExpraito();
// 疲労
int cond = ship.getCond();
// 弾
int bull = ship.getBull();
// 弾Max
int bullmax = ship.getBullMax();
// 残弾比
float bullraito = bullmax != 0 ? (float) bull / (float) bullmax : 1f;
// 燃料
int fuel = ship.getFuel();
// 燃料Max
int fuelmax = ship.getFuelMax();
// 残燃料比
float fuelraito = fuelmax != 0 ? (float) fuel / (float) fuelmax : 1f;
// 艦隊合計Lv
totallv += ship.getLv();
// 損失艦載機
int[] maxeq = ship.getMaxeq();
int[] onslot = ship.getOnSlot();
List<ItemInfoDto> items = ship.getItem();
// 普通はnullにならないが、メンテで艦娘が追加されたあとリロードしていない場合に情報がなくてnullになることがある
if (maxeq != null) {
for (int c = 0; c < items.size(); ++c) {
if (items.get(c).isPlane()) {
lostPlanes += maxeq[c] - onslot[c];
}
}
}
// 入渠中?
isBathwater |= ndockMap.containsKey(ship.getId());
// 疲労している艦娘がいる場合メッセージを表示
final Date condClearDate = ship.getCondClearTime(condTiming, ndockMap.get(ship.getId()));
if (this.cond > cond) {
this.cond = cond;
this.clearDate = new TimeString(condClearDate).toString();
}
// 体力メッセージ
boolean isEscaped = ((escaped != null) && escaped[i]);
if (isEscaped) {
this.hpmsgLabels[i].setText("退避");
this.hpmsgLabels[i].setBackground(ColorManager.getColor(AppConstants.ESCAPED_SHIP_COLOR));
this.hpmsgLabels[i].setForeground(null);
}
else {
DamageRate rate = DamageRate.fromHP(nowhp, maxhp);
this.hpmsgLabels[i].setText(rate.toString());
this.hpmsgLabels[i].setBackground(rate.getBackground());
this.hpmsgLabels[i].setForeground(rate.getForeground());
if (rate == DamageRate.TAIHA) {
if (AppConfig.get().isFatalBybadlyDamage()) {
// 大破で致命的アイコン
this.state.set(FATAL);
shipstatus.set(FATAL);
}
this.badlyDamage = true;
if (isSortie) {
badlyDamaged.add(ship);
}
}
else if (rate == DamageRate.TYUHA) {
if (AppConfig.get().isWarnByHalfDamage()) {
// 中破で警告アイコン
this.state.set(WARN);
shipstatus.set(WARN);
}
}
}
// ステータス
// ステータス.疲労
this.condstLabels[i].setText("疲");
if (cond >= 49) {
this.condstLabels[i].setEnabled(false);
} else {
this.condstLabels[i].setEnabled(true);
}
// ステータス.燃料
this.fuelstLabels[i].setText("燃");
if (fuelraito >= 1f) {
this.fuelstLabels[i].setEnabled(false);
this.fuelstLabels[i].setForeground(null);
} else {
if (AppConfig.get().isWarnByNeedSupply()) {
// 補給不足で警告アイコン
this.state.set(WARN);
shipstatus.set(WARN);
}
this.fuelstLabels[i].setEnabled(true);
if (fuelraito <= AppConstants.EMPTY_SUPPLY) {
// 補給赤
this.fuelstLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_RED_COLOR));
} else if (fuelraito <= AppConstants.LOW_SUPPLY) {
// 補給橙
this.fuelstLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_ORANGE_COLOR));
}
needSupply = true;
if (i == 0) {
flagshipNeedSupply = true;
}
if (fuelraito == 0f) {
reqSupply = true;
}
}
// ステータス.弾
this.bullstLabels[i].setText("弾");
if (bullraito >= 1f) {
this.bullstLabels[i].setEnabled(false);
this.bullstLabels[i].setBackground(null);
this.bullstLabels[i].setForeground(null);
} else {
if (AppConfig.get().isWarnByNeedSupply()) {
// 補給不足で警告アイコン
this.state.set(WARN);
shipstatus.set(WARN);
}
this.bullstLabels[i].setEnabled(true);
if (bullraito <= AppConstants.EMPTY_SUPPLY) {
this.bullstLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_RED_COLOR));
} else if (bullraito <= AppConstants.LOW_SUPPLY) {
this.bullstLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_ORANGE_COLOR));
}
needSupply = true;
if (i == 0) {
flagshipNeedSupply = true;
}
if (bullraito == 0f) {
reqSupply = true;
}
}
// ステータス.ダメコン
List<ItemDto> item = new ArrayList<ItemDto>(ship.getItem2());
item.add(ship.getSlotExItem());
int dmgcsty = 0;
int dmgcstm = 0;
for (ItemDto itemDto : item) {
if (itemDto != null) {
if (itemDto.getName().equals("応急修理要員")) {
dmgcsty++;
} else if (itemDto.getName().equals("応急修理女神")) {
dmgcstm++;
}
}
}
String dmgcstr = "";
if (dmgcsty > 0) {
dmgcstr += "要員x" + dmgcsty + " ";
}
if (dmgcstm > 0) {
dmgcstr += "女神x" + dmgcstm + " ";
}
this.dmgcLabels[i].setText(dmgcstr);
this.dmgcLabels[i].setForeground(SWTResourceManager.getColor(SWT.COLOR_DARK_GREEN));
// ステータス.あと何回
String statusstr = "";
if (AppConfig.get().isDisplayCount()) {
Integer nextcount = this.getNextCount(ship, i == 0);
if (nextcount != null) {
statusstr = MessageFormat.format("あと{0}回", nextcount);
}
}
this.nextLabels[i].setText(statusstr);
// 残り修理時間/疲労回復までの時間/ダメコン表示
Runnable updator = null;
final Label timeLabel = this.timeLabels[i];
boolean isRepairing = (repairShips != null) && (repairShips.get(i) != null);
if (isRepairing && AppConfig.get().isShowAkashiTimer()) {
// 泊地修理中
updator = new AkashiTimerUpdator(timeLabel, dockIndex, i);
}
else if (!isSortie && (condClearDate != null) && AppConfig.get().isShowCondTimer()) {
updator = new Runnable() {
@Override
public void run() {
long rest = TimeLogic.getRest(new Date(), condClearDate);
String str;
String tip = null;
String reststr = TimeLogic.toDateRestString(rest);
if (reststr != null) {
str = "疲労あと" + reststr;
tip = format.format(condClearDate);
}
else {
str = "疲労まもなく回復";
}
timeLabel.setText(str);
timeLabel.setToolTipText(tip);
timeLabel.setForeground(SWTResourceManager.getColor(SWT.COLOR_DARK_GREEN));
timeLabel.getParent().layout();
}
};
}
if (updator != null) {
updator.run();
this.updators.add(updator);
}
else {
timeLabel.setText("");
timeLabel.setForeground(null);
timeLabel.setToolTipText(null);
}
// コンディション
if (cond < AppConstants.COND_RED) {
// 疲労19以下
if (AppConfig.get().isWarnByCondState()) {
// 疲労状態で警告アイコン
this.state.set(WARN);
shipstatus.set(WARN);
}
this.condLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_RED_COLOR));
this.condstLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_RED_COLOR));
} else if (cond < AppConstants.COND_ORANGE) {
// 疲労29以下
if (AppConfig.get().isWarnByCondState()) {
// 疲労状態で警告アイコン
this.state.set(WARN);
shipstatus.set(WARN);
}
this.condLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_ORANGE_COLOR));
this.condstLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_ORANGE_COLOR));
} else if ((cond >= AppConstants.COND_DARK_GREEN) && (cond < AppConstants.COND_GREEN)) {
// 疲労50以上
this.condLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_DARK_GREEN_COLOR));
this.condstLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_DARK_GREEN_COLOR));
} else if (cond >= AppConstants.COND_GREEN) {
// 疲労53以上
this.condLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_GREEN_COLOR));
this.condstLabels[i].setForeground(ColorManager.getColor(AppConstants.COND_GREEN_COLOR));
} else {
this.condLabels[i].setForeground(null);
this.condstLabels[i].setForeground(null);
}
// 艦娘の状態アイコンを更新
if (shipstatus.get(FATAL)) {
this.iconLabels[i].setImage(SWTResourceManager.getImage(FleetComposite.class,
AppConfig.get().isMonoIcon()
? AppConstants.R_ICON_EXCLAMATION_MONO
: AppConstants.R_ICON_EXCLAMATION));
} else if (shipstatus.get(WARN)) {
this.iconLabels[i].setImage(SWTResourceManager.getImage(FleetComposite.class,
AppConfig.get().isMonoIcon()
? AppConstants.R_ICON_ERROR_MONO
: AppConstants.R_ICON_ERROR));
} else {
this.iconLabels[i].setImage(null);
}
// ラベルを更新する
// 名前
this.nameLabels[i].setText(ship.getName());
this.nameLabels[i].setToolTipText(MessageFormat.format(AppConstants.TOOLTIP_FLEETTAB_SHIP, nowhp, maxhp,
fuel, fuelmax, bull, bullmax, ship.getNext()));
this.lvLabels[i].setText(MessageFormat.format("(Lv.{0})", ship.getLv()));
// HP
this.hpLabels[i].setText(MessageFormat.format("{0}/{1} ", nowhp, maxhp));
// HPゲージ
Image gauge = this.getHpGaugeImage(hpratio, expraito);
this.hpgaugeLabels[i].setImage(gauge);
if (this.hpgaugeImages[i] != null) {
// 古いイメージを破棄
this.hpgaugeImages[i].dispose();
}
this.hpgaugeImages[i] = gauge;
// コンディション
this.condLabels[i].setText(MessageFormat.format("{0} cond.", cond));
//this.nameLabels[i].getParent().layout();
//this.hpLabels[i].getParent().layout();
//this.bullstLabels[i].getParent().layout();
}
// ドラム缶の合計
int dram = 0;
int dramKanmusu = 0;
for (ShipDto shipDto : ships) {
if (shipDto.getDram() > 0) {
dramKanmusu++;
dram += shipDto.getDram();
}
}
//大発による遠征効率UP
int daihatsu = 0;
int daihatsuLevel = 0;
double daihatsuUp = 0;
for (ShipDto shipDto : ships) {
for (ItemDto item : shipDto.getItem2()) {
if (item != null) {
if (item.getName().equals("大発動艇")) {
daihatsuUp += 5.0;
++daihatsu;
daihatsuLevel += item.getLevel();
}
else if (item.getName().equals("大発動艇(八九式中戦車&陸戦隊)")) {
daihatsuUp += 2.0;
++daihatsu;
daihatsuLevel += item.getLevel();
}
else if (item.getName().equals("特二式内火艇")) {
daihatsuUp += 1.0;
++daihatsu;
daihatsuLevel += item.getLevel();
}
}
}
}
//大発による遠征効率UPの上限
if (daihatsuUp > 20) {
daihatsuUp = 20;
}
// 改修による補正
daihatsuUp += (0.01 * daihatsuUp * daihatsuLevel) / daihatsu;
// メッセージを更新する
StyleRange messageStyle = new StyleRange();
messageStyle.fontStyle = SWT.BOLD;
messageStyle.foreground = SWTResourceManager.getColor(SWT.COLOR_DARK_BLUE);
StyleRange taihaStyle = new StyleRange();
taihaStyle.fontStyle = SWT.BOLD;
taihaStyle.underline = true;
taihaStyle.underlineStyle = SWT.UNDERLINE_SQUIGGLE;
taihaStyle.underlineColor = SWTResourceManager.getColor(SWT.COLOR_RED);
taihaStyle.foreground = SWTResourceManager.getColor(SWT.COLOR_RED);
if ((currentMission != null) && (currentMission.getMission() != null)) {
// 遠征中
this.addStyledText(this.message, AppConstants.MESSAGE_MISSION, messageStyle);
}
else if (GlobalContext.isSortie(this.dock.getId())) {
// 出撃中
this.addStyledText(this.message, AppConstants.MESSAGE_SORTIE, messageStyle);
if (this.badlyDamage) {
// 大破
this.addStyledText(this.message, AppConstants.MESSAGE_STOP_SORTIE, taihaStyle);
}
else if (combinedFleetBadlyDamaed) {
// 連合艦隊の他の艦隊に大破艦がある
this.addStyledText(this.message, AppConstants.MESSAGE_IN_COMBINED + AppConstants.MESSAGE_STOP_SORTIE,
taihaStyle);
}
else {
// 進撃可能
this.addStyledText(this.message, AppConstants.MESSAGE_GO_NEXT, messageStyle);
}
}
else if (this.badlyDamage) {
// 大破
this.addStyledText(this.message,
MessageFormat.format(AppConstants.MESSAGE_BAD, AppConstants.MESSAGE_BADLY_DAMAGE), taihaStyle);
}
else if (combinedFleetBadlyDamaed) {
// 連合艦隊の他の艦隊に大破艦がある
this.addStyledText(this.message, AppConstants.MESSAGE_IN_COMBINED +
MessageFormat.format(AppConstants.MESSAGE_BAD, AppConstants.MESSAGE_BADLY_DAMAGE), taihaStyle);
}
else {
if (isBathwater) {
// 入渠中
this.addStyledText(this.message,
MessageFormat.format(AppConstants.MESSAGE_BAD, AppConstants.MESSAGE_BATHWATER), messageStyle);
}
else if (flagshipNeedSupply) {
// 未補給
this.addStyledText(this.message, "未補給です。", messageStyle);
if (reqSupply) { // 空
this.addStyledText(this.message, "出撃できません。", messageStyle);
}
}
else {
if (repairState.isRepairing()) {
// 泊地修理中
this.addStyledText(this.message, "泊地修理中。", messageStyle);
}
if (needSupply) {
// 一部未補給
this.addStyledText(this.message, "一部未補給。", messageStyle);
}
// 出撃可能
this.addStyledText(this.message, AppConstants.MESSAGE_GOOD, messageStyle);
}
}
if ((Integer.parseInt(this.dock.getId()) <= 2) && GlobalContext.isCombined()) {
// 連合艦隊
this.addStyledText(this.message, AppConstants.MESSAGE_COMBINED, messageStyle);
}
this.addStyledText(this.message, "\n", null);
// 制空
SeikuString seikuString = new SeikuString(ships);
this.addStyledText(this.message, MessageFormat.format(AppConstants.MESSAGE_SEIKU, seikuString.toString()), null);
if (lostPlanes > 0) {
this.addStyledText(this.message,
MessageFormat.format("損失機:{0}(ボーキ:{1})", lostPlanes, lostPlanes * 5), null);
}
this.addStyledText(this.message, "\n", null);
// 索敵
SakutekiString sakutekiString = new SakutekiString(ships, GlobalContext.hqLevel());
this.addStyledText(this.message,
MessageFormat.format(AppConstants.MESSAGE_SAKUTEKI, sakutekiString.toString()), null);
this.addStyledText(this.message, "\n", null);
// 合計Lv
this.addStyledText(this.message, MessageFormat.format(AppConstants.MESSAGE_TOTAL_LV, totallv), null);
if (dram > 0) {
// ドラム缶合計数
this.addStyledText(this.message, MessageFormat.format(AppConstants.MESSAGE_TOTAL_DRAM, dram, dramKanmusu),
null);
}
if (daihatsu > 0) {
// 大発合計数
this.addStyledText(this.message,
MessageFormat.format(AppConstants.MESSAGE_TOTAL_DAIHATSU, daihatsu, daihatsuUp), null);
}
this.addStyledText(this.message, "\n", null);
if ((currentMission != null) && (currentMission.getMission() == null) && (previousMission.getMission() != null)) {
// 前回の遠征
String text = previousMission.getDisplayText("missioncheck_" + dock.getId() + "p");
this.addStyledText(this.message,
MessageFormat.format(AppConstants.MESSAGE_PREVIOUS_MISSION, text), null);
this.addStyledText(this.message, "\n", null);
}
if (this.clearDate != null) {
this.addStyledText(this.message, MessageFormat.format(AppConstants.MESSAGE_COND, this.clearDate), null);
}
SwtUtils.layoutCompositeRecursively(this.fleetGroup);
this.getShell().setRedraw(true);
}
/**
* HPゲージのイメージを取得します
* @param hpratio HP割合
* @return HPゲージのイメージ
*/
private Image getHpGaugeImage(float hpratio, float expraito) {
Image image = new Image(Display.getDefault(), GAUGE_WIDTH, GAUGE_HEIGHT);
GC gc = new GC(image);
gc.setBackground(ColorManager.getColor(SWT.COLOR_WHITE));
gc.fillRectangle(0, 0, GAUGE_WIDTH, GAUGE_HEIGHT);
gc.setBackground(ColorManager.getColor(gradation(hpratio, GAUGE_EMPTY, GAUGE_HALF, GAUGE_FULL)));
gc.fillRectangle(0, 0, (int) (GAUGE_WIDTH * hpratio), GAUGE_HEIGHT);
gc.setBackground(ColorManager.getColor(EXP_GAUGE));
gc.fillRectangle(0, GAUGE_HEIGHT - EXP_GAUGE_HEIGHT, (int) (GAUGE_WIDTH * expraito), EXP_GAUGE_HEIGHT);
gc.drawImage(image, 0, 0);
gc.dispose();
return image;
}
/**
* スタイル付きテキストを設定します
*
* @param text StyledText
* @param str 文字
* @param style スタイル
*/
private void addStyledText(StyledText text, String str, StyleRange style) {
StyleRange[] oldranges = text.getStyleRanges();
String beforeText = text.getText();
StyleRange addStyle = style;
if (addStyle == null) {
addStyle = new StyleRange();
}
addStyle.start = beforeText.length();
addStyle.length = str.length();
StyleRange[] ranges = new StyleRange[oldranges.length + 1];
for (int i = 0; i < oldranges.length; i++) {
ranges[i] = oldranges[i];
}
ranges[oldranges.length] = addStyle;
text.setText(beforeText + str);
text.setStyleRanges(ranges);
}
/**
* あと何回戦闘すればよいかを取得します
*
* @param ship 艦娘
* @param isFlagship 旗艦
* @return 回数
*/
@CheckForNull
private Integer getNextCount(ShipDto ship, boolean isFlagship) {
// 次のレベルに必要な経験値
Integer nextexp = CalcExpUtils.getNextLvExp(ship.getLv());
if (nextexp != null) {
// 必要経験値
int needexp = nextexp - ship.getExp();
// 海域Exp
Integer baseexp = SeaExp.get().get(AppConfig.get().getDefaultSea());
// 評価倍率
Double eval = EvaluateExp.get().get(AppConfig.get().getDefaultEvaluate());
if ((baseexp != null) && (eval != null)) {
// 得られる経験値
int getexpd = CalcExpUtils.getExp(baseexp, eval, isFlagship, false);
// 戦闘回数
int count = CalcExpUtils.getCount(needexp, getexpd);
return Integer.valueOf(count);
}
}
return null;
}
@Override
public void dispose() {
super.dispose();
for (Image image : this.hpgaugeImages) {
if (image != null) {
image.dispose();
}
}
}
/**
* 複数の色の中間色を取得する
*
* @param raito 割合
* @param rgbs 色たち
* @return 色
*/
private static RGB gradation(float raito, RGB... rgbs) {
if (raito <= 0.0f) {
return rgbs[0];
}
if (raito >= 1.0f) {
return rgbs[rgbs.length - 1];
}
int length = rgbs.length - 1;
// 開始色
int start = (int) (length * raito);
// 終了色
int end = start + 1;
// 開始色と終了色の割合を算出
float startPer = (float) start / length;
float endPer = (float) end / length;
float subPer = (raito - startPer) / (endPer - startPer);
return gradation(subPer, rgbs[start], rgbs[end]);
}
/**
* 2つの色の中間色を取得する
*
* @param raito 割合
* @param start 開始色
* @param end 終了色
* @return 色
*/
private static RGB gradation(float raito, RGB start, RGB end) {
int r = (int) (start.red + ((end.red - start.red) * raito));
int g = (int) (start.green + ((end.green - start.green) * raito));
int b = (int) (start.blue + ((end.blue - start.blue) * raito));
return new RGB(r, g, b);
}
/**
* @return state
*/
public BitSet getState() {
return this.state;
}
/**
* 泊地修理タイマー表示を更新する
* @author Nekopanda
*/
private static class AkashiTimerUpdator implements Runnable {
private final Label label;
private final int dockIndex;
private final int dockPosition;
private int showCount = 0;
public AkashiTimerUpdator(Label l, int i, int p) {
this.label = l;
this.dockIndex = i;
this.dockPosition = p;
}
@Override
public void run() {
String str = "";
String tip = null;
Date now = TimerContext.get().getLastUpdated();
AkashiTimer.RepairState repairState = TimerContext.get().getAkashiRepairState(this.dockIndex);
if (repairState.isRepairing()) {
AkashiTimer.ShipState state = repairState.get().get(this.dockPosition);
if (state != null) {
if (now.before(state.getFinish())) {
String reststr = TimeLogic.toDateRestString(TimeLogic.getRest(now, state.getFinish()), true);
String nextstr = TimeLogic.toDateRestString(state.getNext() / 1000, true);
boolean showRemain;
switch (AppConfig.get().getAkashiTimerFormat()) {
case 1:
showRemain = false;
break;
case 2:
showRemain = ((this.showCount++ / 4) % 2) == 0;
break;
default:
showRemain = true;
break;
}
if (showRemain) {
str = "修理あと" + reststr;
}
else {
str = "次回復まで" + nextstr;
}
tip = "現在までに+" + state.getCurrentGain() + "回復\n" +
"次の回復まで" + nextstr + "\n" +
"全回復まで" + reststr +
"(" + format.format(state.getFinish()) + ")";
}
else {
str = "修理まもなく完了";
}
}
}
this.label.setText(str);
this.label.setToolTipText(tip);
this.label.setForeground(SWTResourceManager.getColor(SWT.COLOR_DARK_BLUE));
this.label.getParent().layout();
}
}
}