// along with this program; if not, see <http://www.gnu.org/licenses/>.\r
\r
using System;\r
+using System.Collections.Generic;\r
using System.Linq;\r
\r
namespace KancolleSniffer\r
private readonly MissionInfo _missionInfo;\r
private readonly RepairStatus[] _repairStatuses = new RepairStatus[ShipInfo.FleetCount];\r
\r
- private struct RepairStatus\r
+ public class RepairTime\r
{\r
- public DateTime Timer { get; set; }\r
+ public int Diff { get; set; }\r
+ public DateTime Time { get; set; }\r
+\r
+ public RepairTime(int diff, DateTime time)\r
+ {\r
+ Diff = diff;\r
+ Time = time;\r
+ }\r
+ }\r
+\r
+ public class RepairSpan\r
+ {\r
+ public int Diff { get; set; }\r
+ public TimeSpan Span { get; set; }\r
+\r
+ public RepairSpan(int diff, TimeSpan span)\r
+ {\r
+ Diff = diff;\r
+ Span = span;\r
+ }\r
+\r
+ public RepairSpan(RepairTime time)\r
+ {\r
+ Diff = time.Diff;\r
+ Span = TimeSpan.FromSeconds(Math.Ceiling((time.Time - DateTime.Now).TotalSeconds));\r
+ }\r
+ }\r
+\r
+ private class RepairStatus\r
+ {\r
+ public DateTime Start { get; set; }\r
+ public RepairTime[][] Times { get; set; }\r
public int TotalHp { get; set; }\r
- public int[] Deck { private get; set; }\r
+ public int[] Deck { get; set; }\r
\r
public void Invalidate()\r
{\r
- Timer = DateTime.MinValue;\r
+ Start = DateTime.MinValue;\r
+ Times = null;\r
TotalHp = 0;\r
Deck = null;\r
}\r
_itemInfo = item;\r
_dockInfo = dock;\r
_missionInfo = mission;\r
+ for (var i = 0; i < _repairStatuses.Length; i++)\r
+ _repairStatuses[i] = new RepairStatus();\r
}\r
\r
public void SetTimer(bool port = false)\r
if (_repairStatuses[fleet].DeckChanged(deck))\r
InvalidateTimer(fleet);\r
var cap = _shipInfo[fs].Slot.Count(item => _itemInfo[item].Name == "艦艇修理施設") + 2;\r
- var targets = deck.Take(cap).Where(id => !_dockInfo.InNDock(id)).ToArray();\r
- var totalHp = (from id in targets\r
- let status = _shipInfo[id]\r
- where status.NowHp < status.MaxHp && status.DamageLevel < ShipStatus.Damage.Half\r
- select status.NowHp).Sum();\r
+ var target = (from id in deck.Take(cap) select IsRepairable(id) ? id : -1).ToList();\r
+ var totalHp = target.Sum(id => _shipInfo[id].NowHp);\r
if (totalHp == 0)\r
{\r
InvalidateTimer(fleet);\r
return;\r
}\r
var r = _repairStatuses[fleet];\r
- if (r.TotalHp == totalHp)\r
+ if (totalHp == r.TotalHp)\r
return;\r
- var timer = r.Timer;\r
/*\r
* 母港に遷移したときに、耐久値が回復しているか修理開始から20分経過しているときに\r
* タイマーをリスタートする。\r
* 反映されて回復が起こったことがわからない。耐久値の回復だけを基準にすると\r
* リスタートできないので、20分経過していたらリスタートする。\r
*/\r
- if (timer == DateTime.MinValue ||\r
- (port && (totalHp > r.TotalHp || (DateTime.Now - timer).TotalMinutes > 20)))\r
- timer = DateTime.Now;\r
- _repairStatuses[fleet] = new RepairStatus\r
+ if (r.Start == DateTime.MinValue ||\r
+ (port && (totalHp > r.TotalHp || (DateTime.Now - r.Start).TotalMinutes > 20)))\r
{\r
- Timer = timer,\r
- TotalHp = totalHp,\r
- Deck = deck.ToArray()\r
- };\r
+ r.Start = DateTime.Now;\r
+ r.Times = EnumTimers(target).ToArray();\r
+ }\r
+ else if (totalHp < r.TotalHp && r.Times != null)\r
+ {\r
+ // 修理対象から外れた艦のタイマーを消す。\r
+ r.Times = target.Zip(r.Times, (id, times) => id != -1 ? times : null).ToArray();\r
+ }\r
+ r.TotalHp = totalHp;\r
+ r.Deck = deck.ToArray();\r
+ }\r
+\r
+ private bool IsRepairable(int id)\r
+ {\r
+ var s = _shipInfo[id];\r
+ return !_dockInfo.InNDock(id) && s.NowHp < s.MaxHp && s.DamageLevel < ShipStatus.Damage.Half;\r
+ }\r
+\r
+ private IEnumerable<RepairTime[]> EnumTimers(IEnumerable<int> deck)\r
+ {\r
+ return from id in deck\r
+ let s = _shipInfo[id]\r
+ let damage = s.MaxHp - s.NowHp\r
+ let first = new RepairTime(0, DateTime.Now.AddMinutes(20))\r
+ select damage == 0\r
+ ? null\r
+ : new[] {first}.Concat(from d in Enumerable.Range(2, damage < 2 ? 0 : damage - 1)\r
+ let span = s.RepairTime(d) + TimeSpan.FromSeconds((d - 1) * 10 * s.Spec.RepairWeight)\r
+ where span.TotalSeconds > 20 * 60\r
+ select new RepairTime(d - 1, DateTime.Now + span)).ToArray();\r
}\r
\r
private void InvalidateTimer(int fleet)\r
_repairStatuses[fleet].Invalidate();\r
}\r
\r
- public DateTime this[int fleet]\r
+ public RepairSpan[] GetTimers(int fleet)\r
{\r
- get { return _repairStatuses[fleet].Timer; }\r
+ var repair = _repairStatuses[fleet];\r
+ if (repair.Times == null)\r
+ return null;\r
+ return (from e in repair.Times.Zip(repair.Deck, (times, id) => new {times, id})\r
+ select e.times == null || _dockInfo.InNDock(e.id)\r
+ ? new RepairSpan(0, TimeSpan.MinValue)\r
+ : (from t in e.times select new RepairSpan(t)).FirstOrDefault(s => s.Span > TimeSpan.Zero)\r
+ ?? new RepairSpan(e.times.Last().Diff + 1, TimeSpan.Zero)\r
+ ).ToArray();\r
}\r
}\r
}
\ No newline at end of file
this.labelFormation = new System.Windows.Forms.Label();\r
this.label29 = new System.Windows.Forms.Label();\r
this.label19 = new System.Windows.Forms.Label();\r
- this.labelAkashiTimer = new System.Windows.Forms.Label();\r
this.labelAirSuperiority = new System.Windows.Forms.Label();\r
this.label27 = new System.Windows.Forms.Label();\r
this.label21 = new System.Windows.Forms.Label();\r
this.panelFleet1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;\r
this.panelFleet1.Controls.Add(this.panelBattleInfo);\r
this.panelFleet1.Controls.Add(this.label19);\r
- this.panelFleet1.Controls.Add(this.labelAkashiTimer);\r
this.panelFleet1.Controls.Add(this.labelAirSuperiority);\r
this.panelFleet1.Controls.Add(this.label27);\r
this.panelFleet1.Controls.Add(this.label21);\r
this.label19.TabIndex = 34;\r
this.label19.Text = "疲労";\r
// \r
- // labelAkashiTimer\r
- // \r
- this.labelAkashiTimer.Location = new System.Drawing.Point(48, 20);\r
- this.labelAkashiTimer.Name = "labelAkashiTimer";\r
- this.labelAkashiTimer.Size = new System.Drawing.Size(45, 12);\r
- this.labelAkashiTimer.TabIndex = 23;\r
- this.labelAkashiTimer.Text = "00:00:00";\r
- this.labelAkashiTimer.TextAlign = System.Drawing.ContentAlignment.MiddleRight;\r
- this.labelAkashiTimer.Visible = false;\r
- // \r
// labelAirSuperiority\r
// \r
this.labelAirSuperiority.Location = new System.Drawing.Point(29, 117);\r
private System.Windows.Forms.Label labelAirSuperiority;\r
private System.Windows.Forms.Label label27;\r
private System.Windows.Forms.Label labelLogin;\r
- private System.Windows.Forms.Label labelAkashiTimer;\r
private System.Windows.Forms.Label labelAchievement;\r
private System.Windows.Forms.Label label28;\r
private System.Windows.Forms.Panel panelBattleInfo;\r
private readonly int _labelRightDistance;\r
private int _currentFleet;\r
private readonly Label[] _labelCheckFleets;\r
+ private readonly Label[] _labelHPs;\r
private readonly Label[][] _damagedShipList = new Label[14][];\r
+ private readonly Label[] _akashiTimers = new Label[ShipInfo.MemberCount];\r
private bool _started;\r
\r
public MainForm()\r
_configDialog = new ConfigDialog(_config, this);\r
_labelRightDistance = labelHP1.Parent.Width - labelHP1.Right;\r
_labelCheckFleets = new[] {labelCheckFleet1, labelCheckFleet2, labelCheckFleet3, labelCheckFleet4};\r
+ _labelHPs = new[] {labelHP1, labelHP2, labelHP3, labelHP4, labelHP5, labelHP6};\r
+\r
var i = 0;\r
foreach (var label in new[] {labelFleet1, labelFleet2, labelFleet3, labelFleet4})\r
label.Tag = i++;\r
CreateDamagedShipList();\r
+ CreateAkashiTimers();\r
}\r
\r
private void FiddlerApplication_BeforeRequest(Session oSession)\r
_sniffer.Item.MarginShips = _config.MarginShips;\r
_sniffer.Achievement.ResetHours = _config.ResetHours;\r
_sniffer.LogFile = _config.Logging ? _config.LogFile : null;\r
- \r
+\r
if (_config.Location.X == int.MinValue)\r
return;\r
var newBounds = Bounds;\r
var message = string.Format("残り{0:D}隻", _sniffer.Item.MaxShips - _sniffer.Item.NowShips);\r
Ring("艦娘が多すぎます", message, _config.MaxShipsSoundFile);\r
item.NeedRing = false;\r
- } \r
+ }\r
}\r
\r
private void UpdateBucketHistory()\r
\r
private void UpdateMaterialHistry()\r
{\r
- var labels = new[] { labelFuelHistory, labelBulletHistory, labelSteelHistory, labelBouxiteHistory };\r
- var text = new[] { "燃料", "弾薬", "鋼材", "ボーキ" };\r
+ var labels = new[] {labelFuelHistory, labelBulletHistory, labelSteelHistory, labelBouxiteHistory};\r
+ var text = new[] {"燃料", "弾薬", "鋼材", "ボーキ"};\r
for (var i = 0; i < labels.Length; i++)\r
{\r
var count = _sniffer.Item.MaterialHistory[i];\r
{\r
var name = new[] {labelShip1, labelShip2, labelShip3, labelShip4, labelShip5, labelShip6};\r
var lv = new[] {labelLv1, labelLv2, labelLv3, labelLv4, labelLv5, labelLv6};\r
- var hp = new[] {labelHP1, labelHP2, labelHP3, labelHP4, labelHP5, labelHP6};\r
var cond = new[] {labelCond1, labelCond2, labelCond3, labelCond4, labelCond5, labelCond6};\r
var next = new[] {labelNextLv1, labelNextLv2, labelNextLv3, labelNextLv4, labelNextLv5, labelNextLv6};\r
\r
var stat = i < statuses.Length ? statuses[i] : empty;\r
name[i].Text = stat.Name;\r
lv[i].Text = stat.Level.ToString("D");\r
- SetHpLavel(hp[i], stat);\r
+ SetHpLavel(_labelHPs[i], stat);\r
if (stat == empty)\r
{\r
// SetCondLabelでは背景色が赤になってしまう\r
\r
private void SetHpLavel(Label label, ShipStatus status)\r
{\r
+ SetHpLavel(label, status.NowHp, status.MaxHp);\r
+ }\r
+\r
+ private void SetHpLavel(Label label, int now, int max)\r
+ {\r
var colors = new[] {DefaultBackColor, Color.FromArgb(255, 240, 240, 100), Color.Orange, Color.Red};\r
- label.Text = string.Format("{0:D}/{1:D}", status.NowHp, status.MaxHp);\r
- label.BackColor = colors[(int)status.DamageLevel];\r
+ label.Text = string.Format("{0:D}/{1:D}", now, max);\r
+ label.BackColor = colors[(int)ShipStatus.CalcDamage(now, max)];\r
}\r
\r
private void SetCondLabel(Label label, int cond)\r
entry.label.Text = entry.timer;\r
}\r
\r
- private void UpdateAkashiTimer()\r
+ private void CreateAkashiTimers()\r
{\r
- var stat = _sniffer.GetShipStatuses(_currentFleet);\r
- if (stat.Length == 0 || !stat[0].Name.StartsWith("明石"))\r
+ var parent = panelFleet1;\r
+ parent.SuspendLayout();\r
+ for (var i = 0; i < _akashiTimers.Length; i++)\r
{\r
- labelAkashiTimer.Visible = false;\r
- return;\r
+ const int width = 31, height = 12;\r
+ const int x = 56;\r
+ var y = 20 + 16 * i;\r
+ parent.Controls.Add(\r
+ _akashiTimers[i] =\r
+ new Label {Location = new Point(x, y), Size = new Size(width, height), Visible = false});\r
+ parent.Controls.SetChildIndex(_akashiTimers[i], 0);\r
}\r
- labelAkashiTimer.Visible = true;\r
- var start = _sniffer.GetAkashiStartTime(_currentFleet);\r
- if (start == DateTime.MinValue)\r
+ parent.ResumeLayout();\r
+ }\r
+\r
+ private void UpdateAkashiTimer()\r
+ {\r
+ var timers = _sniffer.GetAkashiTimers(_currentFleet);\r
+ var statuses = _sniffer.GetShipStatuses(_currentFleet);\r
+ for (var i = 0; i < _akashiTimers.Length; i++)\r
{\r
- labelAkashiTimer.Text = "00:00:00";\r
- return;\r
+ var label = _akashiTimers[i];\r
+ var labelHp = _labelHPs[i];\r
+ if (timers == null || i >= timers.Length || timers[i].Span == TimeSpan.MinValue)\r
+ {\r
+ label.Visible = false;\r
+ label.ForeColor = DefaultForeColor;\r
+ labelHp.ForeColor = DefaultForeColor;\r
+ continue;\r
+ }\r
+ var timer = timers[i];\r
+ var stat = statuses[i];\r
+ label.Visible = true;\r
+ label.Text = timer.Span.ToString(@"mm\:ss");\r
+ if (timer.Diff == 0)\r
+ {\r
+ label.ForeColor = DefaultForeColor;\r
+ labelHp.ForeColor = DefaultForeColor;\r
+ continue;\r
+ }\r
+ label.ForeColor = Color.Gray;\r
+ labelHp.ForeColor = Color.Gray;\r
+ SetHpLavel(labelHp, stat.NowHp + timer.Diff, stat.MaxHp);\r
}\r
- var span = DateTime.Now - start;\r
- labelAkashiTimer.Text = span.Days == 0 ? span.ToString(@"hh\:mm\:ss") : span.ToString(@"d\.hh\:mm");\r
}\r
\r
public void CreateDamagedShipList()\r
return;\r
}\r
parent.Size = new Size(width, num * 16 + 3);\r
- var fn = new[] { "", "1", "2", "3", "4" };\r
+ var fn = new[] {"", "1", "2", "3", "4"};\r
for (var i = 0; i < num; i++)\r
{\r
var entry = _damagedShipList[i];\r
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w\r
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0\r
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAQ\r
- CwAAAk1TRnQBSQFMAgEBBQEAAagBAAGoAQABDgEAAQ8BAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo\r
+ CwAAAk1TRnQBSQFMAgEBBQEAAbABAAGwAQABDgEAAQ8BAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo\r
AwABOAMAAR4DAAEBAQABCAUAAZABBhgAAYACAAGAAwACgAEAAYADAAGAAQABgAEAAoACAAPAAQABwAHc\r
AcABAAHwAcoBpgEAATMFAAEzAQABMwEAATMBAAIzAgADFgEAAxwBAAMiAQADKQEAA1UBAANNAQADQgEA\r
AzkBAAGAAXwB/wEAAlAB/wEAAZMBAAHWAQAB/wHsAcwBAAHGAdYB7wEAAdYC5wEAAZABqQGtAgAB/wEz\r
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w\r
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0\r
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA0\r
- CwAAAk1TRnQBSQFMAgEBBQEAAagBAAGoAQABDgEAAQ4BAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo\r
+ CwAAAk1TRnQBSQFMAgEBBQEAAbABAAGwAQABDgEAAQ4BAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo\r
AwABOAMAARwDAAEBAQABCAUAASABBhgAAYACAAGAAwACgAEAAYADAAGAAQABgAEAAoACAAPAAQABwAHc\r
AcABAAHwAcoBpgEAATMFAAEzAQABMwEAATMBAAIzAgADFgEAAxwBAAMiAQADKQEAA1UBAANNAQADQgEA\r
AzkBAAGAAXwB/wEAAlAB/wEAAZMBAAHWAQAB/wHsAcwBAAHGAdYB7wEAAdYC5wEAAZABqQGtAgAB/wEz\r
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w\r
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0\r
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABI\r
- BwAAAk1TRnQBSQFMAwEBAAFwAQABcAEAAQUBAAENAQAE/wEJAQAI/wFCAU0BNgEEBgABNgEEAgABKAMA\r
+ BwAAAk1TRnQBSQFMAwEBAAF4AQABeAEAAQUBAAENAQAE/wEJAQAI/wFCAU0BNgEEBgABNgEEAgABKAMA\r
ARQDAAENAwABAQEAAQgFAAEEAQEYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA\r
AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5\r
AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA\r
return ratio > 0.75 ? Damage.Minor : ratio > 0.5 ? Damage.Small : ratio > 0.25 ? Damage.Half : Damage.Badly;\r
}\r
\r
- public TimeSpan RepairTime\r
+ public TimeSpan RepairTime()\r
{\r
- get\r
- {\r
- var weight = Spec.RepairWeight;\r
- var level = Level < 12 ? Level * 10 : Level * 5 + Math.Floor(Math.Sqrt(Level - 11)) * 10 + 50;\r
- return TimeSpan.FromSeconds(Math.Floor(level * weight * (MaxHp - NowHp)) + 30);\r
- }\r
+ return RepairTime(MaxHp - NowHp);\r
+ }\r
+\r
+ public TimeSpan RepairTime(int damage)\r
+ {\r
+ var weight = Spec.RepairWeight;\r
+ var level = Level < 12 ? Level * 10 : Level * 5 + Math.Floor(Math.Sqrt(Level - 11)) * 10 + 50;\r
+ return TimeSpan.FromSeconds(Math.Floor(level * weight * damage) + 30);\r
}\r
}\r
\r
return (from entry in _shipInfo\r
let status = entry.Value\r
where status.NowHp < status.MaxHp && !dockInfo.InNDock(entry.Key)\r
- select new RepairStatus(FindFleet(entry.Key, out oi), status.Name, status.RepairTime)).\r
+ select new RepairStatus(FindFleet(entry.Key, out oi), status.Name, status.RepairTime())).\r
OrderByDescending(entry => entry.Time).ToArray();\r
}\r
}\r
if (url.EndsWith("api_req_nyukyo/start"))\r
{\r
_dockInfo.InspectNyukyo(request);\r
+ _akashiTimer.SetTimer();\r
return Update.Item | Update.Ship;\r
}\r
if (url.EndsWith("api_req_nyukyo/speedchange"))\r
get { return _shipInfo.GetDamagedShipList(_dockInfo); }\r
}\r
\r
- public DateTime GetAkashiStartTime(int fleet)\r
+ public AkashiTimer.RepairSpan[] GetAkashiTimers(int fleet)\r
{\r
- return _akashiTimer[fleet];\r
+ return _akashiTimer.GetTimers(fleet);\r
}\r
\r
public Achievement Achievement\r