diff --git a/includes/basetype.class.php b/includes/basetype.class.php
index 3ad4dd6b..ceb0b281 100644
--- a/includes/basetype.class.php
+++ b/includes/basetype.class.php
@@ -942,7 +942,7 @@ abstract class Filter
public function getExtraCols()
{
- return $this->formData['extraCols'];
+ return array_unique($this->formData['extraCols']);
}
public function getSetCriteria()
diff --git a/includes/types/item.class.php b/includes/types/item.class.php
index 96d07d4a..a5051369 100644
--- a/includes/types/item.class.php
+++ b/includes/types/item.class.php
@@ -604,16 +604,6 @@ class ItemList extends BaseType
$x .= '
'.sprintf(Lang::item($limit['isGem'] ? 'uniqueEquipped' : 'unique', 2), Util::localizedString($limit, 'name'), $limit['count']);
}
- // max duration
- if ($dur = $this->curTpl['duration'])
- {
- $rt = '';
- if ($this->curTpl['flagsCustom'] & 0x1)
- $rt = $interactive ? ' ('.sprintf(Util::$dfnString, 'LANG.tooltip_realduration', Lang::item('realTime')).')' : ' ('.Lang::item('realTime').')';
-
- $x .= "
".Lang::game('duration').Lang::main('colon').Util::formatTime(abs($dur) * 1000).$rt;
- }
-
// required holiday
if ($eId = $this->curTpl['eventId'])
if ($hName = DB::Aowow()->selectRow('SELECT h.* FROM ?_holidays h JOIN ?_events e ON e.holidayId = h.id WHERE e.id = ?d', $eId))
@@ -875,6 +865,16 @@ class ItemList extends BaseType
if ($dur = $this->curTpl['durability'])
$x .= sprintf(Lang::item('durability'), $dur, $dur).'
';
+ // max duration
+ if ($dur = $this->curTpl['duration'])
+ {
+ $rt = '';
+ if ($this->curTpl['flagsCustom'] & 0x1)
+ $rt = $interactive ? ' ('.sprintf(Util::$dfnString, 'LANG.tooltip_realduration', Lang::item('realTime')).')' : ' ('.Lang::item('realTime').')';
+
+ $x .= Lang::formatTime(abs($dur) * 1000, 'item', 'duration').$rt."
";
+ }
+
$jsg = [];
// required classes
if ($classes = Lang::getClassString($this->curTpl['requiredClass'], $jsg))
@@ -959,12 +959,18 @@ class ItemList extends BaseType
$extra = [];
if ($cd >= 5000)
- $extra[] = Lang::game('cooldown', [Util::formatTime($cd, true)]);
+ {
+ $pt = Util::parseTime($cd);
+ if (count(array_filter($pt)) == 1) // simple time: use simple method
+ $extra[] = Lang::formatTime($cd, 'item', 'cooldown');
+ else // build block with generic time
+ $extra[] = Lang::item('cooldown', 0, [Lang::formatTime($cd, 'game', 'timeAbbrev', true)]);
+ }
if ($this->curTpl['spellTrigger'.$j] == 2)
if ($ppm = $this->curTpl['spellppmRate'.$j])
$extra[] = Lang::spell('ppm', [$ppm]);
- $itemSpellsAndTrigger[$this->curTpl['spellId'.$j]] = [$this->curTpl['spellTrigger'.$j], $extra ? ' ('.implode(', ', $extra).')' : ''];
+ $itemSpellsAndTrigger[$this->curTpl['spellId'.$j]] = [$this->curTpl['spellTrigger'.$j], $extra ? ' '.implode(', ', $extra) : ''];
}
}
@@ -2437,7 +2443,7 @@ class ItemListFilter extends Filter
$cr[2] *= 1000; // field supplied in milliseconds
$this->formData['extraCols'][] = $cr[0];
- $this->extraOpts['is']['s'][] = ', IF(spellCooldown1 > 1, spellCooldown1, IF(spellCooldown2 > 1, spellCooldown2, IF(spellCooldown3 > 1, spellCooldown3, IF(spellCooldown4 > 1, spellCooldown4, IF(spellCooldown5 > 1, spellCooldown5,))))) AS cooldown';
+ $this->extraOpts['is']['s'][] = ', GREATEST(spellCooldown1, spellCooldown2, spellCooldown3, spellCooldown4, spellCooldown5) AS cooldown';
return [
'OR',
diff --git a/includes/types/spell.class.php b/includes/types/spell.class.php
index 0b258c14..3a44ec3a 100644
--- a/includes/types/spell.class.php
+++ b/includes/types/spell.class.php
@@ -1123,10 +1123,7 @@ class SpellList extends BaseType
case 'D': // todo (med): min/max?; /w unit?
$base = $srcSpell->getField('duration');
- if ($base <= 0)
- $result[2] = Lang::spell('untilCanceled');
- else
- $result[2] = Util::formatTime($base, true);
+ $result[2] = Lang::formatTime($srcSpell->getField('duration'), 'spell', 'duration');
if (in_array($op, $signs) && is_numeric($oparg) && is_numeric($base))
eval("\$base = $base $op $oparg;");
@@ -1907,7 +1904,7 @@ class SpellList extends BaseType
// duration
if ($this->curTpl['duration'] > 0)
- $x .= ''.sprintf(Lang::spell('remaining'), Util::formatTime($this->curTpl['duration'])).'';
+ $x .= ''.Lang::formatTime($this->curTpl['duration'], 'spell', 'timeRemaining').'';
$x .= '';
diff --git a/includes/utilities.php b/includes/utilities.php
index 49ee92f5..1f7f75cf 100644
--- a/includes/utilities.php
+++ b/includes/utilities.php
@@ -573,7 +573,7 @@ abstract class Util
return $money;
}
- private static function parseTime(int $msec) : array
+ public static function parseTime(int $msec) : array
{
$time = [0, 0, 0, 0, 0];
@@ -671,7 +671,7 @@ abstract class Util
else if ($h) // hours, minutes ago
return Lang::main('timeAgo', [$h . ' ' . Lang::timeUnits('ab', 4) . ' ' . $m . ' ' . Lang::timeUnits('ab', 5)]);
else if ($m) // minutes, seconds ago
- return Lang::main('timeAgo', [$m . ' ' . Lang::timeUnits('ab', 5) . ' ' . $m . ' ' . Lang::timeUnits('ab', 6)]);
+ return Lang::main('timeAgo', [$m . ' ' . Lang::timeUnits('ab', 5) . ' ' . $s . ' ' . Lang::timeUnits('ab', 6)]);
else // seconds ago
return Lang::main('timeAgo', [$s . ' ' . Lang::timeUnits($s == 1 ? 'sg' : 'pl', 6)]);
}
diff --git a/localization/lang.class.php b/localization/lang.class.php
index b8076ea0..6953b6c9 100644
--- a/localization/lang.class.php
+++ b/localization/lang.class.php
@@ -487,8 +487,39 @@ class Lang
return Util::ucFirst(self::game(Type::getFileString($type)));
}
+ public static function formatTime(int $msec, string $prop = 'game', string $src = 'timeAbbrev', bool $concat = false) : string
+ {
+ if ($msec < 0)
+ $msec = 0;
- private static function vspf($var, $args)
+ [$ms, $s, $m, $h, $d] = Util::parseTime($msec);
+ $ref = [];
+ $result = [];
+
+ if (is_array(self::$$prop[$src]))
+ $ref = &self::$$prop[$src];
+ else
+ {
+ trigger_error('Lang::formatTime - tried to access undefined property Lang::$'.$prop, E_USER_WARNING);
+ return '';
+ }
+
+ if ($d >= 1)
+ $result[] = self::vspf($ref[4], [$d + $h / 24]);
+ if ($h >= 1 && ($concat || !$result))
+ $result[] = self::vspf($ref[3], [$h + $m / 60]);
+ if ($m >= 1 && ($concat || !$result))
+ $result[] = self::vspf($ref[2], [$m + $s / 60]);
+ if ($s >= 1 && ($concat || !$result))
+ $result[] = self::vspf($ref[1], [$s]);
+
+ if (!$result)
+ $result[] = self::vspf($ref[0]);
+
+ return implode(', ', $result);
+ }
+
+ private static function vspf($var, array $args = [])
{
if (is_array($var))
{
diff --git a/localization/locale_dede.php b/localization/locale_dede.php
index f835fe5f..d60ed1e1 100644
--- a/localization/locale_dede.php
+++ b/localization/locale_dede.php
@@ -358,6 +358,13 @@ $lang = array(
'modes' => [-1 => "Beliebig", "Normal / Normal 10", "Heroisch / Normal 25", "Heroisch 10", "Heroisch 25"],
'expansions' => ["Classic", "The Burning Crusade", "Wrath of the Lich King"],
'stats' => ["Stärke", "Beweglichkeit", "Ausdauer", "Intelligenz", "Willenskraft"],
+ 'timeAbbrev' => array(
+ '',
+ "%d |4Sek.:Sek.;",
+ "%d |4Min.:Min.;",
+ "%d |4Std.:Std.;",
+ "%d |4Tag:Tage;"
+ ),
'sources' => array(
"Unbekannt", "Hergestellt", "Drop", "PvP", "Quest", "Händler",
"Lehrer", "Entdeckung", "Einlösung", "Talent", "Startausrüstung", "Ereignis",
@@ -1445,12 +1452,10 @@ $lang = array(
'_transfer' => 'Dieser Zauber wird mit %s vertauscht, wenn Ihr zur %s wechselt.',
'currentArea' => '<Momentanes Gebiet>',
'discovered' => "Durch Geistesblitz erlernt",
- 'ppm' => "%s Auslösungen pro Minute",
+ 'ppm' => "(%s Auslösungen pro Minute)",
'procChance' => "Procchance",
'starter' => "Basiszauber",
'trainingCost' => "Trainingskosten",
- 'remaining' => "Noch %s",
- 'untilCanceled' => "bis Abbruch",
'castIn' => "Wirken in %s Sek.",
'instantPhys' => "Sofort",
'instantMagic' => "Spontanzauber",
@@ -1467,6 +1472,20 @@ $lang = array(
'stackGroup' => "Stack Gruppierung",
'linkedWith' => "Verknüpft mit",
'_scaling' => "Skalierung",
+ 'duration' => array(
+ "bis Abbruch",
+ "%.2G Sek.",
+ "%.2G Min.",
+ "%.2G |4Stunde:Stunden;",
+ "%.2G |4Tag:Tage;"
+ ),
+ 'timeRemaining' => array(
+ "",
+ "Noch %d |4Sekunde:Sekunden;",
+ "Noch %d |4Minute:Minuten;",
+ "Noch %d |4Stunde:Stunden;",
+ "Noch %d |4Tag:Tage;"
+ ),
'scaling' => array(
'directSP' => "+%.2f%% der Zaubermacht zum direkten Effekt", 'directAP' => "+%.2f%% der Angriffskraft zum direkten Effekt",
'dotSP' => "+%.2f%% der Zaubermacht pro Tick", 'dotAP' => "+%.2f%% der Angriffskraft pro Tick"
@@ -1783,6 +1802,20 @@ $lang = array(
'uniqueEquipped'=> ["Einzigartig anlegbar", null, "Einzigartig angelegt: %s (%d)"],
'speed' => "Tempo",
'dps' => "(%.1f Schaden pro Sekunde)",
+ 'duration' => array( // ITEM_DURATION_*
+ '',
+ "Dauer: %d Sek.",
+ "Dauer: %d Min.",
+ "Dauer: %d |4Stunde:Stunden;",
+ "Dauer: %d |4Tag:Tage;"
+ ),
+ 'cooldown' => array( // ITEM_COOLDOWN_TOTAL*
+ '(%s Abklingzeit)',
+ "(%d Sek. Abklingzeit)",
+ "(%d Min. Abklingzeit)",
+ "(%d |4Stunde:Stunden; Abklingzeit)",
+ "(%d |4Tag:Tage; Abklingzeit)"
+ ),
'damage' => array( // *DAMAGE_TEMPLATE*
// basic, basic /w school, add basic, add basic /w school
'single' => ['%d Schaden', '%1$d %2$sschaden', '+ %1$d Schaden', '+ %1$d %2$sschaden' ],
diff --git a/localization/locale_enus.php b/localization/locale_enus.php
index 14b4dd0e..9779d1c2 100644
--- a/localization/locale_enus.php
+++ b/localization/locale_enus.php
@@ -358,6 +358,13 @@ $lang = array(
'modes' => [-1 => "Any", "Normal / Normal 10", "Heroic / Normal 25", "Heroic 10", "Heroic 25"],
'expansions' => ["Classic", "The Burning Crusade", "Wrath of the Lich King"],
'stats' => ["Strength", "Agility", "Stamina", "Intellect", "Spirit"],
+ 'timeAbbrev' => array( //