Pārlūkot izejas kodu

refactor #1779: Initial refactor. More to come, likely

tags/v0.9.1^2
Shaun pirms 3 gadiem
vecāks
revīzija
23c2fa503e
7 mainītis faili ar 670 papildinājumiem un 502 dzēšanām
  1. +82
    -0
      src/client/ui/templates/tooltipItem/getCompareItem.js
  2. +369
    -0
      src/client/ui/templates/tooltipItem/helpers.js
  3. +97
    -0
      src/client/ui/templates/tooltipItem/onShowItemTooltip.js
  4. +104
    -1
      src/client/ui/templates/tooltipItem/styles.css
  5. +9
    -9
      src/client/ui/templates/tooltipItem/styles.less
  6. +0
    -20
      src/client/ui/templates/tooltipItem/templateTooltip.html
  7. +9
    -472
      src/client/ui/templates/tooltipItem/tooltipItem.js

+ 82
- 0
src/client/ui/templates/tooltipItem/getCompareItem.js Parādīt failu

@@ -0,0 +1,82 @@
define([
'js/input'
], function (
input
) {
const getCompareItem = msg => {
const shiftDown = input.isKeyDown('shift', true);

let item = msg.item;
let items = window.player.inventory.items;

let compare = null;
if (item.slot) {
compare = items.find(i => i.eq && i.slot === item.slot);

// check special cases for mismatched weapon/offhand scenarios (only valid when comparing)
if (!compare) {
let equippedTwoHanded = items.find(i => i.eq && i.slot === 'twoHanded');
let equippedOneHanded = items.find(i => i.eq && i.slot === 'oneHanded');
let equippedOffhand = items.find(i => i.eq && i.slot === 'offHand');

if (item.slot === 'twoHanded') {
if (!equippedOneHanded)
compare = equippedOffhand;
else if (!equippedOffhand)
compare = equippedOneHanded;
else {
// compare against oneHanded and offHand combined by creating a virtual item that is the sum of the two
compare = $.extend(true, {}, equippedOneHanded);
compare.refItem = equippedOneHanded;

for (let s in equippedOffhand.stats) {
if (!compare.stats[s])
compare.stats[s] = 0;

compare.stats[s] += equippedOffhand.stats[s];
}

if (!compare.implicitStats)
compare.implicitStats = [];

(equippedOffhand.implicitStats || []).forEach(s => {
let f = compare.implicitStats.find(i => i.stat === s.stat);
if (!f) {
compare.implicitStats.push({
stat: s.stat,
value: s.value
});
} else
f.value += s.value;
});
}
}

if (item.slot === 'oneHanded')
compare = equippedTwoHanded;

// this case is kind of ugly, but we don't want to go in when comparing an offHand to (oneHanded + empty offHand) - that should just use the normal compare which is offHand to empty
if (item.slot === 'offHand' && equippedTwoHanded && shiftDown) {
// since we're comparing an offhand to an equipped Twohander, we need to clone the 'spell' values over (setting damage to zero) so that we can properly display how much damage
// the player would lose by switching to the offhand (which would remove the twoHander)
// keep a reference to the original item for use in onHideToolTip
let spellClone = $.extend(true, {}, equippedTwoHanded.spell);
spellClone.name = '';
spellClone.values.damage = 0;

let clone = $.extend(true, {}, item, {
spell: spellClone
});
clone.refItem = item;
msg.item = clone;

compare = equippedTwoHanded;
}
}
}

msg.compare = compare;
};

return getCompareItem;
});

+ 369
- 0
src/client/ui/templates/tooltipItem/helpers.js Parādīt failu

@@ -0,0 +1,369 @@
define([
'js/input',
'js/system/events',
'js/misc/statTranslations',
'ui/templates/tooltipItem/getCompareItem',
'html!ui/templates/tooltipItem/templateTooltip'
], function (
input,
events,
statTranslations,
getCompareItem,
tplTooltip
) {
let item = null;
let compare = null;
let shiftDown = null;
let equipErrors = null;

const percentageStats = [
'addCritChance',
'addCritemultiplier',
'addAttackCritChance',
'addAttackCritemultiplier',
'addSpellCritChance',
'addSpellCritemultiplier',
'sprintChance',
'xpIncrease',
'blockAttackChance',
'blockSpellChance',
'dodgeAttackChance',
'dodgeSpellChance',
'attackSpeed',
'castSpeed',
'itemQuantity',
'magicFind',
'catchChance',
'catchSpeed',
'fishRarity',
'fishWeight',
'fishItems'
];

const getStatStringValue = (statName, statValue) => {
let res = statValue;
if (statName.indexOf('CritChance') > -1)
res = res / 20;

if (percentageStats.includes(statName) || statName.indexOf('Percent') > -1 || (statName.indexOf('element') === 0 && statName.indexOf('Resist') === -1))
res += '%';

return res + '';
};

const init = (_item, _compare, _shiftDown, _equipErrors) => {
item = _item;
compare = _compare;
shiftDown = _shiftDown;
equipErrors = _equipErrors;
};

const helpers = {
div: (className, children = '') => {
if (children.join)
children = children.join('');

return `<div class="${className}">${children}</div>`;
},

name: () => {
let itemName = item.name;
if (item.quantity > 1)
itemName += ' x' + item.quantity;

return itemName;
},

type: () => {
if (!item.type || item.type === item.name)
return;

return item.type;
},

power: () => {
if (!item.power)
return;

return (new Array(item.power + 1)).join('+');
},

implicitStats: () => {
if (!item.implicitStats)
return;

const tempImplicitStats = $.extend(true, [], item.implicitStats);

if (compare && shiftDown && !item.eq) {
const compareImplicitStats = (compare.implicitStats || []);

tempImplicitStats.forEach(s => {
const { stat, value } = s;

const f = compareImplicitStats.find(c => c.stat === stat);

if (!f) {
s.value = `+${value}`;
return;
}

const delta = value - f.value;
if (delta > 0)
s.value = `+${delta}`;
else if (delta < 0)
s.value = delta;
});

compareImplicitStats.forEach(s => {
if (tempImplicitStats.some(f => f.stat === s.stat))
return;

tempImplicitStats.push({
stat: s.stat,
value: -s.value
});
});
}

const html = tempImplicitStats
.map(({ stat, value }) => {
let statName = statTranslations.translate(stat);

const prettyValue = getStatStringValue(statName, value);

let rowClass = '';

if (compare) {
if (prettyValue.indexOf('-') > -1)
rowClass = 'loseStat';
else if (prettyValue.indexOf('+') > -1)
rowClass = 'gainStat';
}

return `<div class="${rowClass}">${prettyValue} ${statName}</div>`;
})
.join('');

return html;
},

stats: () => {
const tempStats = $.extend(true, {}, item.stats);
const enchantedStats = item.enchantedStats || {};

if (compare && shiftDown) {
if (!item.eq) {
const compareStats = compare.stats;
for (let s in tempStats) {
if (compareStats[s]) {
const delta = tempStats[s] - compareStats[s];
if (delta > 0)
tempStats[s] = '+' + delta;
else if (delta < 0)
tempStats[s] = delta;
} else
tempStats[s] = '+' + tempStats[s];
}
for (let s in compareStats) {
if (!tempStats[s])
tempStats[s] = -compareStats[s];
}
}
} else {
Object.keys(tempStats).forEach(s => {
if (enchantedStats[s]) {
tempStats[s] -= enchantedStats[s];
if (tempStats[s] <= 0)
delete tempStats[s];

tempStats['_' + s] = enchantedStats[s];
}
});
}

const html = Object.keys(tempStats)
.map(s => {
const isEnchanted = (s[0] === '_');
let statName = s;
if (isEnchanted)
statName = statName.substr(1);

const prettyValue = getStatStringValue(statName, tempStats[s]);
statName = statTranslations.translate(statName);

let rowClass = '';

if (compare) {
if (prettyValue.indexOf('-') > -1)
rowClass = 'loseStat';
else if (prettyValue.indexOf('+') > -1)
rowClass = 'gainStat';
}
if (isEnchanted)
rowClass += ' enchanted';

return `<div class="${rowClass}">${prettyValue} ${statName}</div>`;
})
.sort((a, b) => {
return (a.replace(' enchanted', '').length - b.replace(' enchanted', '').length);
})
.sort((a, b) => {
if (a.indexOf('enchanted') > -1 && b.indexOf('enchanted') === -1)
return 1;
else if (a.indexOf('enchanted') === -1 && b.indexOf('enchanted') > -1)
return -1;

return 0;
})
.join('');

return html;
},

effects: () => {
if (item.description)
return item.description;

if (!item.effects || !item.effects.length || !item.effects[0].text || item.type === 'mtx')
return;

let html = '';

item.effects.forEach((e, i) => {
html += e.text;
if (i < item.effects.length - 1)
html += '<br />';
});

return html;
},

material: () => {
if (item.material)
return 'crafting material';
},

quest: () => {
if (item.quest)
return 'quest item';
},

spellName: () => {
if (!item.spell || item.ability)
return;

return helpers.div(`spellName q${item.spell.quality}`, item.spell.name);
},

damage: () => {
if (!item.spell || !item.spell.values)
return;

const abilityValues = Object.entries(item.spell.values)
.map(([k, v]) => {
if (!compare || !shiftDown)
return `${k}: ${v}<br/>`;

let delta = v - compare.spell.values[k];
// adjust by EPSILON to handle float point imprecision, otherwise 3.15 - 2 = 1.14 or 2 - 3.15 = -1.14
// have to move away from zero by EPSILON, not a simple add
if (delta >= 0)
delta += Number.EPSILON;
else
delta -= Number.EPSILON;
delta = ~~((delta) * 100) / 100;

let rowClass = '';
if (delta > 0) {
rowClass = 'gainDamage';
delta = '+' + delta;
} else if (delta < 0)
rowClass = 'loseDamage';
return `<div class="${rowClass}">${k}: ${delta}</div>`;
})
.join('');

return abilityValues;
},

requires: (className, children) => {
if (!item.requires && !item.level && (!item.factions || !item.factions.length))
return;

if (equipErrors.length)
className += ' high-level';

return helpers.div(className, children);
},

requireLevel: className => {
if (!item.level)
return;

if (equipErrors.includes('level'))
className += ' high-level';

const level = item.level.push ? `${item.level[0]} - ${item.level[1]}` : item.level;

return helpers.div(className, `level: ${level}`);
},

requireStats: className => {
if (!item.requires || !item.requires[0])
return;

if (equipErrors.includes('stats'))
className += ' high-level';
let html = `${item.requires[0].stat}: ${item.requires[0].value}`;

return helpers.div(className, html);
},

requireFaction: () => {
if (!item.factions)
return;

let htmlFactions = '';

item.factions.forEach((f, i) => {
let htmlF = f.name + ': ' + f.tierName;
if (f.noEquip)
htmlF = '<font class="color-red">' + htmlF + '</font>';

htmlFactions += htmlF;
if (i < item.factions.length - 1)
htmlFactions += '<br />';
});

return htmlFactions;
},

worth: () => {
if (!item.worthText)
return;

return `<br />value: ${item.worthText}`;
},

info: () => {
if (item.material || item.quest || item.eq || item.ability)
return;

if (item.cd)
return `cooldown: ${item.cd}`;
else if (item.uses)
return `uses: ${item.uses}`;
else if (!shiftDown && compare)
return '[shift] to compare';
else if (isMobile && compare && !shiftDown)
return 'tap again to compare';
}
};

return {
init,
helpers
};
});

+ 97
- 0
src/client/ui/templates/tooltipItem/onShowItemTooltip.js Parādīt failu

@@ -0,0 +1,97 @@
define([
'js/input',
'js/system/events',
'js/misc/statTranslations',
'ui/templates/tooltipItem/helpers',
'ui/templates/tooltipItem/getCompareItem'
], function (
input,
events,
statTranslations,
helpers,
getCompareItem,
tplTooltip
) {
const { init: initHelpers, helpers: g } = helpers;

const buildTooltipHtml = ({ quality }) => {
const html = [
g.div(`name q${quality}`, [
g.div('text', g.name()),
g.div('type', g.type()),
g.div('power', g.power())
]),
g.div('implicitStats', g.implicitStats()),
g.div('stats', g.stats()),
g.div('effects', g.effects()),
g.div('material', g.material()),
g.div('quest', g.quest()),
g.spellName(),
g.div('damage', g.damage()),
g.requires('requires', [
'requires',
g.requireLevel('level'),
g.requireStats('stats'),
g.requireFaction('faction')
]),
g.div('worth', g.worth()),
g.div('info', g.info())
]
.filter(t => t !== null)
.join('');

return html;
};

const onShowItemTooltip = (ui, item, pos, canCompare, bottomAlign) => {
let shiftDown = input.isKeyDown('shift', true);
const equipErrors = window.player.inventory.equipItemErrors(item);

const msg = {
item,
compare: null
};
getCompareItem(msg);

const useItem = item = msg.item;
if (isMobile && useItem === ui.item)
shiftDown = true;
ui.item = useItem;

const compare = canCompare ? msg.compare : null;

ui.item = item;
ui.removeButton();

initHelpers(item, compare, shiftDown, equipErrors);

const contents = buildTooltipHtml(item);

const el = ui.tooltip;
el.html(contents);
el.show();

if (pos) {
if (bottomAlign)
pos.y -= el.height();

//correct tooltips that are appearing offscreen
// arbitrary constant -30 is there to stop resize code
// completely squishing the popup
if ((pos.x + el.width()) > window.innerWidth)
pos.x = window.innerWidth - el.width() - 30;

if ((pos.y + el.height()) > window.innerHeight)
pos.y = window.innerHeight - el.height() - 30;

el.css({
left: pos.x,
top: pos.y
});
}

events.emit('onBuiltItemTooltip', ui.tooltip);
};

return onShowItemTooltip;
});

+ 104
- 1
src/client/ui/templates/tooltipItem/styles.css Parādīt failu

@@ -1 +1,104 @@
.uiTooltipItem>*{z-index:999999}.uiTooltipItem .tooltip{display:none;position:absolute;margin-left:-4px;margin-top:-4px;background-color:rgba(60,63,76,0.95);pointer-events:none;padding:10px;color:#f2f5f5;text-align:center;line-height:18px;max-width:300px}.uiTooltipItem .tooltip .name{margin-bottom:8px}.uiTooltipItem .tooltip .name .type{color:#7f9c9c}.uiTooltipItem .tooltip .name .power{color:#80f643;display:none}.uiTooltipItem .tooltip>.implicitStats{color:#b8c9c9;margin-bottom:8px;padding-bottom:8px;border-bottom:2px solid #505360}.uiTooltipItem .tooltip>.implicitStats .gainStat{color:#80f643}.uiTooltipItem .tooltip>.implicitStats .loseStat{color:#d43346}.uiTooltipItem .tooltip>.stats{color:#b8c9c9;margin-bottom:8px;padding-bottom:8px;border-bottom:2px solid #505360}.uiTooltipItem .tooltip>.stats .gainStat{color:#80f643}.uiTooltipItem .tooltip>.stats .loseStat{color:#d43346}.uiTooltipItem .tooltip>.stats .enchanted{color:#44cb95 !important}.uiTooltipItem .tooltip .effects{color:#f2f5f5;margin-bottom:8px}.uiTooltipItem .tooltip .faction{color:#7f9c9c;margin-bottom:8px}.uiTooltipItem .tooltip .requires{margin-top:8px;color:#7f9c9c}.uiTooltipItem .tooltip .requires.high-level{color:#d43346}.uiTooltipItem .tooltip .requires .high-level{color:#d43346}.uiTooltipItem .tooltip .requires>*:not(.high-level){color:#7f9c9c}.uiTooltipItem .tooltip .material{color:#7f9c9c;display:none}.uiTooltipItem .tooltip .quest{color:#7f9c9c;display:none}.uiTooltipItem .tooltip .info{color:#4f6666}.uiTooltipItem .tooltip .damage .gainDamage{color:#80f643}.uiTooltipItem .tooltip .damage .loseDamage{color:#d43346}.uiTooltipItem .tooltip .worth{display:none}.uiTooltipItem .tooltip .worth.no-afford{color:#d43346}.uiTooltipItem .tooltip.no-compare .info{display:none}.uiTooltipItem>.btn{position:absolute;background-color:#3fa7dd;color:#f2f5f5;padding:10px;text-align:center}.mobile .uiTooltipItem{z-index:9999999999}.mobile .uiTooltipItem>*{z-index:9999999999}
.uiTooltipItem > * {
z-index: 999999;
}
.uiTooltipItem .tooltip {
display: none;
position: absolute;
margin-left: -4px;
margin-top: -4px;
background-color: rgba(60, 63, 76, 0.95);
pointer-events: none;
padding: 10px;
color: #f2f5f5;
text-align: center;
line-height: 18px;
max-width: 300px;
}
.uiTooltipItem .tooltip .name {
margin-bottom: 8px;
}
.uiTooltipItem .tooltip .name .type {
color: #7f9c9c;
}
.uiTooltipItem .tooltip .name .power {
color: #80f643;
}
.uiTooltipItem .tooltip > .implicitStats {
color: #b8c9c9;
margin-bottom: 8px;
padding-bottom: 8px;
border-bottom: 2px solid #505360;
}
.uiTooltipItem .tooltip > .implicitStats .gainStat {
color: #80f643;
}
.uiTooltipItem .tooltip > .implicitStats .loseStat {
color: #d43346;
}
.uiTooltipItem .tooltip > .stats {
color: #b8c9c9;
margin-bottom: 8px;
padding-bottom: 8px;
border-bottom: 2px solid #505360;
}
.uiTooltipItem .tooltip > .stats .gainStat {
color: #80f643;
}
.uiTooltipItem .tooltip > .stats .loseStat {
color: #d43346;
}
.uiTooltipItem .tooltip > .stats .enchanted {
color: #44cb95 !important;
}
.uiTooltipItem .tooltip .effects {
color: #f2f5f5;
margin-bottom: 8px;
}
.uiTooltipItem .tooltip .faction {
color: #7f9c9c;
margin-bottom: 8px;
}
.uiTooltipItem .tooltip .requires {
margin-top: 8px;
color: #7f9c9c;
}
.uiTooltipItem .tooltip .requires.high-level {
color: #d43346;
}
.uiTooltipItem .tooltip .requires .high-level {
color: #d43346;
}
.uiTooltipItem .tooltip .requires > *:not(.high-level) {
color: #7f9c9c;
}
.uiTooltipItem .tooltip .material {
color: #7f9c9c;
}
.uiTooltipItem .tooltip .quest {
color: #7f9c9c;
}
.uiTooltipItem .tooltip .info {
color: #4f6666;
}
.uiTooltipItem .tooltip .damage .gainDamage {
color: #80f643;
}
.uiTooltipItem .tooltip .damage .loseDamage {
color: #d43346;
}
.uiTooltipItem .tooltip .worth.no-afford {
color: #d43346;
}
.uiTooltipItem > .btn {
position: absolute;
background-color: #3fa7dd;
color: #f2f5f5;
padding: 10px;
text-align: center;
}
.mobile .uiTooltipItem {
z-index: 9999999999;
}
.mobile .uiTooltipItem > * {
z-index: 9999999999;
}

+ 9
- 9
src/client/ui/templates/tooltipItem/styles.less Parādīt failu

@@ -27,8 +27,8 @@

.power {
color: @green;
display: none;
}

}

> .implicitStats {
@@ -44,6 +44,7 @@
.loseStat {
color: @red;
}

}

> .stats {
@@ -63,6 +64,7 @@
.enchanted {
color: @tealC !important;
}

}

.effects {
@@ -90,17 +92,16 @@
> *:not(.high-level) {
color: darken(@white, 40%);
}

}

.material {
color: darken(@white, 40%);
display: none;
}

.quest {
color: darken(@white, 40%);
display: none;
}
}

.info {
color: darken(@white, 60%);
@@ -114,19 +115,16 @@
.loseDamage {
color: @red;
}

}

.worth {
display: none;

&.no-afford {
color: @red;
}
}

&.no-compare .info {
display: none;
}

}

> .btn {
@@ -136,6 +134,7 @@
padding: 10px;
text-align: center;
}

}

.mobile .uiTooltipItem {
@@ -144,4 +143,5 @@
> * {
z-index: 9999999999;
}

}

+ 0
- 20
src/client/ui/templates/tooltipItem/templateTooltip.html Parādīt failu

@@ -1,20 +0,0 @@
<div class="name q$QUALITY$">
<div class="text">$NAME$</div>
<div class="type">$TYPE$</div>
<div class="power">$POWER$</div>
</div>
<div class="implicitStats">$IMPLICITSTATS$</div>
<div class="stats">$STATS$</div>
<div class="effects">$EFFECTS$</div>
<div class="material">crafting material</div>
<div class="quest">quest item</div>
<div class="spellName">$SPELLNAME$</div>
<div class="damage">$DAMAGE$</div>
<div class="requires">
requires:
<div class="level">level: $LEVEL$</div>
<div class="stats">$ATTRIBUTE$: $ATTRIBUTEVALUE$</div>
<div class="faction">faction: $faction$</div>
</div>
<div class="worth"></div>
<div class="info"><br />[shift] to compare</div>

+ 9
- 472
src/client/ui/templates/tooltipItem/tooltipItem.js Parādīt failu

@@ -1,42 +1,12 @@
define([
'js/system/events',
'ui/templates/tooltipItem/onShowItemTooltip',
'css!ui/templates/tooltipItem/styles',
'html!ui/templates/tooltipItem/template',
'html!ui/templates/tooltipItem/templateTooltip',
'js/misc/statTranslations',
'js/input'
'html!ui/templates/tooltipItem/template'
], function (
events,
onShowItemTooltip,
styles,
template,
tplTooltip,
statTranslations,
input
template
) {
let percentageStats = [
'addCritChance',
'addCritMultiplier',
'addAttackCritChance',
'addAttackCritMultiplier',
'addSpellCritChance',
'addSpellCritMultiplier',
'sprintChance',
'xpIncrease',
'blockAttackChance',
'blockSpellChance',
'dodgeAttackChance',
'dodgeSpellChance',
'attackSpeed',
'castSpeed',
'itemQuantity',
'magicFind',
'catchChance',
'catchSpeed',
'fishRarity',
'fishWeight',
'fishItems'
];

return {
tpl: template,
type: 'tooltipItem',
@@ -47,83 +17,15 @@ define([
postRender: function () {
this.tooltip = this.el.find('.tooltip');

this.onEvent('onShowItemTooltip', this.onShowItemTooltip.bind(this));
this.onEvent('onShowItemTooltip', onShowItemTooltip.bind(null, this));
this.onEvent('onHideItemTooltip', this.onHideItemTooltip.bind(this));
},

getCompareItem: function (msg) {
const shiftDown = input.isKeyDown('shift', true);

let item = msg.item;
let items = window.player.inventory.items;

let compare = null;
if (item.slot) {
compare = items.find(i => i.eq && i.slot === item.slot);

// check special cases for mismatched weapon/offhand scenarios (only valid when comparing)
if (!compare) {
let equippedTwoHanded = items.find(i => i.eq && i.slot === 'twoHanded');
let equippedOneHanded = items.find(i => i.eq && i.slot === 'oneHanded');
let equippedOffhand = items.find(i => i.eq && i.slot === 'offHand');

if (item.slot === 'twoHanded') {
if (!equippedOneHanded)
compare = equippedOffhand;
else if (!equippedOffhand)
compare = equippedOneHanded;
else {
// compare against oneHanded and offHand combined by creating a virtual item that is the sum of the two
compare = $.extend(true, {}, equippedOneHanded);
compare.refItem = equippedOneHanded;

for (let s in equippedOffhand.stats) {
if (!compare.stats[s])
compare.stats[s] = 0;

compare.stats[s] += equippedOffhand.stats[s];
}

if (!compare.implicitStats)
compare.implicitStats = [];

(equippedOffhand.implicitStats || []).forEach(s => {
let f = compare.implicitStats.find(i => i.stat === s.stat);
if (!f) {
compare.implicitStats.push({
stat: s.stat,
value: s.value
});
} else
f.value += s.value;
});
}
}

if (item.slot === 'oneHanded')
compare = equippedTwoHanded;

// this case is kind of ugly, but we don't want to go in when comparing an offHand to (oneHanded + empty offHand) - that should just use the normal compare which is offHand to empty
if (item.slot === 'offHand' && equippedTwoHanded && shiftDown) {
// since we're comparing an offhand to an equipped Twohander, we need to clone the 'spell' values over (setting damage to zero) so that we can properly display how much damage
// the player would lose by switching to the offhand (which would remove the twoHander)
// keep a reference to the original item for use in onHideToolTip
let spellClone = $.extend(true, {}, equippedTwoHanded.spell);
spellClone.name = '';
spellClone.values.damage = 0;

let clone = $.extend(true, {}, item, {
spell: spellClone
});
clone.refItem = item;
msg.item = clone;

compare = equippedTwoHanded;
}
}
}
showWorth: function (canAfford) {
this.tooltip.find('.worth').show();

msg.compare = compare;
if (!canAfford)
this.tooltip.find('.worth').addClass('no-afford');
},

onHideItemTooltip: function (item) {
@@ -143,371 +45,6 @@ define([
this.removeButton();
},

onShowItemTooltip: function (item, pos, canCompare, bottomAlign) {
this.removeButton();

let shiftDown = input.isKeyDown('shift', true);

let msg = {
item: item,
compare: null
};
this.getCompareItem(msg);

let useItem = item = msg.item;
if (isMobile && useItem === this.item)
shiftDown = true;
this.item = useItem;

let compare = canCompare ? msg.compare : null;

let tempStats = $.extend(true, {}, item.stats);
let tempImplicitStats = $.extend(true, [], item.implicitStats);
let enchantedStats = item.enchantedStats || {};

if (compare && shiftDown) {
if (!item.eq) {
let compareStats = compare.stats;
for (let s in tempStats) {
if (compareStats[s]) {
let delta = tempStats[s] - compareStats[s];
if (delta > 0)
tempStats[s] = '+' + delta;
else if (delta < 0)
tempStats[s] = delta;
} else
tempStats[s] = '+' + tempStats[s];
}
for (let s in compareStats) {
if (!tempStats[s])
tempStats[s] = -compareStats[s];
}

let compareImplicitStats = (compare.implicitStats || []);
tempImplicitStats.forEach(s => {
let statValue = s.value;

let f = compareImplicitStats.find(c => c.stat === s.stat);

if (f) {
let delta = statValue - f.value;
if (delta > 0)
s.value = '+' + delta;
else if (delta < 0)
s.value = delta;
} else
s.value = '+' + s.value;
});
compareImplicitStats.forEach(s => {
if (!tempImplicitStats.find(f => f.stat === s.stat)) {
tempImplicitStats.push({
stat: s.stat,
value: -s.value
});
}
});
}
} else {
Object.keys(tempStats).forEach(function (s) {
if (enchantedStats[s]) {
tempStats[s] -= enchantedStats[s];
if (tempStats[s] <= 0)
delete tempStats[s];

tempStats['_' + s] = enchantedStats[s];
}
});
}

let stats = Object.keys(tempStats)
.map(s => {
let isEnchanted = (s[0] === '_');
let statName = s;
if (isEnchanted)
statName = statName.substr(1);

let value = this.getStatValue(statName, tempStats[s]);
statName = statTranslations.translate(statName);

let row = value + ' ' + statName;
let rowClass = '';

if (compare) {
if (row.indexOf('-') > -1)
rowClass = 'loseStat';
else if (row.indexOf('+') > -1)
rowClass = 'gainStat';
}
if (isEnchanted)
rowClass += ' enchanted';

row = '<div class="' + rowClass + '">' + row + '</div>';

return row;
})
.sort(function (a, b) {
return (a.replace(' enchanted', '').length - b.replace(' enchanted', '').length);
})
.sort(function (a, b) {
if ((a.indexOf('enchanted') > -1) && (b.indexOf('enchanted') === -1))
return 1;
else if ((a.indexOf('enchanted') === -1) && (b.indexOf('enchanted') > -1))
return -1;
return 0;
})
.join('');

let implicitStats = tempImplicitStats
.map(s => {
let statName = s.stat;
let value = this.getStatValue(statName, s.value);
statName = statTranslations.translate(statName);

let row = value + ' ' + statName;
let rowClass = '';

if (compare) {
if (row.indexOf('-') > -1)
rowClass = 'loseStat';
else if (row.indexOf('+') > -1)
rowClass = 'gainStat';
}

row = '<div class="' + rowClass + '">' + row + '</div>';

return row;
})
.join('');

let itemName = item.name;
if (item.quantity > 1)
itemName += ' x' + item.quantity;

let level = null;
if (item.level)
level = item.level.push ? item.level[0] + ' - ' + item.level[1] : item.level;

let html = tplTooltip
.replace('$NAME$', itemName)
.replace('$QUALITY$', item.quality)
.replace('$TYPE$', item.type)
.replace('$SLOT$', item.slot)
.replace('$IMPLICITSTATS$', implicitStats)
.replace('$STATS$', stats)
.replace('$LEVEL$', level);

if (item.requires && item.requires[0]) {
html = html
.replace('$ATTRIBUTE$', item.requires[0].stat)
.replace('$ATTRIBUTEVALUE$', item.requires[0].value);
}

if (item.power)
html = html.replace('$POWER$', ' ' + (new Array(item.power + 1)).join('+'));

if ((item.spell) && (item.spell.values)) {
let abilityValues = '';
for (let p in item.spell.values) {
if ((compare) && (shiftDown)) {
let delta = item.spell.values[p] - compare.spell.values[p];
// adjust by EPSILON to handle float point imprecision, otherwise 3.15 - 2 = 1.14 or 2 - 3.15 = -1.14
// have to move away from zero by EPSILON, not a simple add
if (delta >= 0)
delta += Number.EPSILON;
else
delta -= Number.EPSILON;
delta = ~~((delta) * 100) / 100;
let rowClass = '';
if (delta > 0) {
rowClass = 'gainDamage';
delta = '+' + delta;
} else if (delta < 0)
rowClass = 'loseDamage';
abilityValues += '<div class="' + rowClass + '">' + p + ': ' + delta + '</div>';
} else
abilityValues += p + ': ' + item.spell.values[p] + '<br/>';
}
if (!item.ability)
abilityValues = abilityValues;
html = html.replace('$DAMAGE$', abilityValues);
}

let tooltip = this.tooltip;

tooltip.html(html);

if (!item.level)
tooltip.find('.level').hide();
else
tooltip.find('.level').show();

if (!item.implicitStats)
tooltip.find('.implicitStats').hide();
else
tooltip.find('.implicitStats').show();

if (!item.requires) {
if (!item.level && (!item.factions || !item.factions.length))
tooltip.find('.requires').hide();
else
tooltip.find('.requires .stats').hide();
} else
tooltip.find('.requires .stats').show();

if (!stats.length)
tooltip.children('.stats').hide();

if ((!item.type) || (item.type === item.name))
tooltip.find('.type').hide();
else {
tooltip.find('.type')
.html(item.type)
.show();
}

if (item.power)
tooltip.find('.power').show();

let equipErrors = window.player.inventory.equipItemErrors(item);
equipErrors.forEach(function (e) {
tooltip.find('.requires').addClass('high-level');
tooltip.find('.requires .' + e).addClass('high-level');
}, this);

if ((item.material) || (item.quest)) {
tooltip.find('.level').hide();
tooltip.find('.info').hide();

if (item.material)
tooltip.find('.material').show();
else if (item.quest)
tooltip.find('.quest').show();
} else if (item.eq)
tooltip.find('.info').hide();

if (!item.ability)
tooltip.find('.damage').hide();
else
tooltip.find('.info').hide();

if (item.spell) {
tooltip.find('.spellName')
.html(item.spell.name)
.addClass('q' + item.spell.quality)
.show();
tooltip.find('.damage')
.show();
if (item.ability)
tooltip.find('.spellName').hide();
} else
tooltip.find('.spellName').hide();

tooltip.find('.worth').html(item.worthText ? ('<br />value: ' + item.worthText) : '');

if (item.effects && item.effects[0].text && item.type !== 'mtx') {
let htmlEffects = '';

item.effects.forEach(function (e, i) {
htmlEffects += e.text;
if (i < item.effects.length - 1)
htmlEffects += '<br />';
});

this.find('.effects')
.html(htmlEffects)
.show();
} else if (item.description) {
this.find('.effects')
.html(item.description)
.show();
} else
this.find('.effects').hide();

if (item.type === 'Reward Card') {
this.find('.spellName')
.html('Set Size: ' + item.setSize)
.show();
}

if (item.factions) {
let htmlFactions = '';

item.factions.forEach(function (f, i) {
let htmlF = f.name + ': ' + f.tierName;
if (f.noEquip)
htmlF = '<font class="color-red">' + htmlF + '</font>';

htmlFactions += htmlF;
if (i < item.factions.length - 1)
htmlFactions += '<br />';
});

this.find('.faction')
.html(htmlFactions)
.show();
} else
this.find('.faction').hide();

if (shiftDown || !compare)
tooltip.find('.info').hide();
else if (isMobile && compare && !shiftDown)
tooltip.find('.info').html('tap again to compare');

if (item.cd) {
tooltip.find('.info')
.html('cooldown: ' + item.cd)
.show();
} else if (item.uses) {
tooltip.find('.info')
.html('uses: ' + item.uses)
.show();
}

this.tooltip
.show();

if (pos) {
if (bottomAlign)
pos.y -= this.tooltip.height();

//correct tooltips that are appearing offscreen
// arbitrary constant -30 is there to stop resize code
// completely squishing the popup
if ((pos.x + this.tooltip.width()) > window.innerWidth)
pos.x = window.innerWidth - this.tooltip.width() - 30;

if ((pos.y + this.tooltip.height()) > window.innerHeight)
pos.y = window.innerHeight - this.tooltip.height() - 30;

this.tooltip.css({
left: pos.x,
top: pos.y
});
}

events.emit('onBuiltItemTooltip', this.tooltip);
},

getStatValue: function (statName, statValue) {
let res = statValue;
if (statName.indexOf('CritChance') > -1)
res = res / 20;

if (percentageStats.includes(statName) || statName.indexOf('Percent') > -1 || (statName.indexOf('element') === 0 && statName.indexOf('Resist') === -1))
res += '%';

return res;
},

showWorth: function (canAfford) {
this.tooltip.find('.worth').show();

if (!canAfford)
this.tooltip.find('.worth').addClass('no-afford');
},

addButton: function (label, cb) {
let tt = this.tooltip;
let pos = tt.offset();


Notiek ielāde…
Atcelt
Saglabāt