diff --git a/src/client/js/components/inventory.js b/src/client/js/components/inventory.js index 59a07b3c..a02fe44d 100644 --- a/src/client/js/components/inventory.js +++ b/src/client/js/components/inventory.js @@ -59,6 +59,31 @@ define([ events.emit('onGetItems', this.items, rerender); } + }, + + equipItemErrors: function (item) { + var errors = []; + var stats = this.obj.stats.values; + + var playerLevel = (stats.originalLevel || stats.level); + if (item.level > playerLevel) + errors.push('level'); + + if ((item.requires) && (stats[item.requires[0].stat] < item.requires[0].value)) + errors.push('stats'); + + if (item.factions) { + if (item.factions.some(function (f) { + return f.noEquip; + })) + errors.push('faction'); + } + + return errors; + }, + + canEquipItem: function (item) { + return (this.equipItemErrors.length == 0); } }; }); diff --git a/src/client/ui/templates/inventory/inventory.js b/src/client/ui/templates/inventory/inventory.js index 108d4bdc..bba3eff1 100644 --- a/src/client/ui/templates/inventory/inventory.js +++ b/src/client/ui/templates/inventory/inventory.js @@ -503,7 +503,7 @@ define([ for (var s in equippedOffhand.stats) { if (!compare.stats[s]) compare.stats[s] = 0; - + compare.stats[s] += equippedOffhand.stats[s] } } @@ -530,7 +530,7 @@ define([ compare = equippedTwoHanded; } - } + } } events.emit('onShowItemTooltip', item, ttPos, compare, false, this.shiftDown); @@ -589,18 +589,12 @@ define([ if (!item) return; - else if ((action == 'equip') && ((item.material) || (item.quest) || (item.type == 'mtx') || (item.level > playerLevel))) + else if ((action == 'equip') && ((item.material) || (item.quest) || (item.type == 'mtx') || (!window.player.inventory.canEquipItem(item)))) return; - else if ((action == 'learnAbility') && (item.level > playerLevel)) + else if ((action == 'learnAbility') && (!window.player.inventory.canEquipItem(item))) return; else if ((action == 'activateMtx') && (item.type != 'mtx')) return; - if ((item.factions) && (action == 'equip')) { - if (item.factions.some(function (f) { - return f.noEquip; - })) - return; - } var cpn = 'inventory'; if (action == 'equip') diff --git a/src/client/ui/templates/tooltipItem/styles.less b/src/client/ui/templates/tooltipItem/styles.less index 93d84915..56ee76f1 100644 --- a/src/client/ui/templates/tooltipItem/styles.less +++ b/src/client/ui/templates/tooltipItem/styles.less @@ -28,7 +28,7 @@ } } - .stats { + > .stats { color: darken(@white, 20%); margin-bottom: 8px; @@ -55,13 +55,21 @@ margin-bottom: 8px; } - .level { + .requires { margin-top: 8px; color: darken(@white, 40%); &.high-level { color: @red; } + + .high-level { + color: @red; + } + + > *:not(.high-level) { + color: darken(@white, 40%); + } } .material { diff --git a/src/client/ui/templates/tooltipItem/templateTooltip.html b/src/client/ui/templates/tooltipItem/templateTooltip.html index a4ff97d6..ea546e46 100644 --- a/src/client/ui/templates/tooltipItem/templateTooltip.html +++ b/src/client/ui/templates/tooltipItem/templateTooltip.html @@ -5,11 +5,15 @@
$STATS$
$EFFECTS$
-
faction: $faction$
crafting material
quest item
$SPELLNAME$
$DAMAGE$
-
level: $LEVEL$
+
+ requires: +
level: $LEVEL$
+
$ATTRIBUTE$: $ATTRIBUTEVALUE$
+
faction: $faction$
+

[shift] to compare
diff --git a/src/client/ui/templates/tooltipItem/tooltipItem.js b/src/client/ui/templates/tooltipItem/tooltipItem.js index cfcc58bb..043ea85c 100644 --- a/src/client/ui/templates/tooltipItem/tooltipItem.js +++ b/src/client/ui/templates/tooltipItem/tooltipItem.js @@ -154,6 +154,13 @@ define([ .replace('$SLOT$', item.slot) .replace('$STATS$', stats) .replace('$LEVEL$', level); + + if (item.requires) { + 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('+')); @@ -194,6 +201,11 @@ define([ else this.tooltip.find('.level').show(); + if (!item.requires) + this.tooltip.find('.stats').hide(); + else + this.tooltip.find('.stats').show(); + if ((!item.type) || (item.type == item.name)) this.tooltip.find('.type').hide(); else { @@ -205,10 +217,11 @@ define([ if (item.power) this.tooltip.find('.power').show(); - var playerStats = window.player.stats.values; - var level = playerStats.originalLevel || playerStats.level; - if (item.level > level) - this.tooltip.find('.level').addClass('high-level'); + var equipErrors = window.player.inventory.equipItemErrors(item); + equipErrors.forEach(function (e) { + this.tooltip.find('.requires').addClass('high-level'); + this.tooltip.find('.requires .' + e).addClass('high-level'); + }, this); if ((item.material) || (item.quest)) { this.tooltip.find('.level').hide(); diff --git a/src/server/components/equipment.js b/src/server/components/equipment.js index 1df903f5..64557e7e 100644 --- a/src/server/components/equipment.js +++ b/src/server/components/equipment.js @@ -37,14 +37,9 @@ define([ var item = this.obj.inventory.findItem(itemId); if (!item) return; - else if ((!item.slot) || (item.material) || (item.quest) || (item.ability) || (item.level > (stats.originalLevel || stats.level))) { + else if ((!item.slot) || (item.material) || (item.quest) || (item.ability) || (!this.obj.inventory.canEquipItem(item))) { item.eq = false; return; - } else if ((item.factions) && (this.obj.player)) { - if (!this.obj.reputation.canEquipItem(item)) { - item.eq = false; - return; - } } var currentEqId = this.eq[item.slot]; @@ -61,18 +56,12 @@ define([ itemId = itemId.itemId; } - var level = (this.obj.stats.originalValues || this.obj.stats.values).level; var item = this.obj.inventory.findItem(itemId); if (!item) return; - else if ((!item.slot) || (item.material) || (item.quest) || (item.ability) || (item.level > level)) { + else if ((!item.slot) || (item.material) || (item.quest) || (item.ability) || (!this.obj.inventory.canEquipItem(item))) { item.eq = false; return; - } else if ((item.factions) && (this.obj.player)) { - if (!this.obj.reputation.canEquipItem(item)) { - item.eq = false; - return; - } } if (!slot) diff --git a/src/server/components/inventory.js b/src/server/components/inventory.js index d921df58..79bf883f 100644 --- a/src/server/components/inventory.js +++ b/src/server/components/inventory.js @@ -18,6 +18,7 @@ define([ itemEffects ) { return { + //Properties type: 'inventory', inventorySize: 50, @@ -25,6 +26,8 @@ define([ blueprint: null, + //Base Methods + init: function (blueprint, isTransfer) { var items = blueprint.items || []; var iLen = items.length; @@ -68,51 +71,74 @@ define([ this.hookItemEvents(); }, - hookItemEvents: function (items) { - var items = items || this.items; - var iLen = items.length; - for (var i = 0; i < iLen; i++) { - var item = items[i]; + save: function () { + return { + type: 'inventory', + items: this.items + }; + }, - if (item.effects) { - item.effects.forEach(function (e) { - if (e.mtx) { - var mtxUrl = mtx.get(e.mtx); - var mtxModule = require(mtxUrl); + simplify: function (self) { + if (!self) + return null; - e.events = mtxModule.events; - } else if (e.factionId) { - var faction = factions.getFaction(e.factionId); - var statGenerator = faction.uniqueStat; - statGenerator.generate(item); - } else { - var effectUrl = itemEffects.get(e.type); - var effectModule = require(effectUrl); + var reputation = this.obj.reputation; - e.events = effectModule.events; - } - }); - } + return { + type: 'inventory', + items: this.items + .map(function (i) { + var item = extend(true, {}, i); - if ((item.pos == null) && (!item.eq)) { - var pos = i; - for (var j = 0; j < iLen; j++) { - if (!items.some(fj => (fj.pos == j))) { - pos = j; - break; + if (item.effects) { + item.effects = item.effects.map(e => ({ + factionId: e.factionId, + text: e.text, + properties: e.properties, + mtx: e.mtx, + type: e.type, + rolls: e.rolls + })); } - } - item.pos = pos; - } else if ((!item.eq) && (items.some(ii => ((ii != item) && (ii.pos == item.pos))))) { - var pos = item.pos; - for (var j = 0; j < iLen; j++) { - if (!items.some(fi => ((fi != item) && (fi.pos == j)))) { - pos = j; - break; + + if (item.factions) { + item.factions = item.factions.map(function (f) { + var faction = reputation.getBlueprint(f.id); + var factionTier = reputation.getTier(f.id); + + var noEquip = null; + if (factionTier < f.tier) + noEquip = true; + + if (!faction) + console.log(f); + + return { + id: f.id, + name: faction.name, + tier: f.tier, + tierName: ['Hated', 'Hostile', 'Unfriendly', 'Neutral', 'Friendly', 'Honored', 'Revered', 'Exalted'][f.tier], + noEquip: noEquip + }; + }, this); } - } - item.pos = pos; - } + + return item; + }) + }; + }, + + update: function () { + var items = this.items; + var iLen = items.length; + for (var i = 0; i < iLen; i++) { + var item = items[i]; + if (!item.cd) + continue; + + item.cd--; + + this.obj.syncer.setArray(true, 'inventory', 'getItems', item); } }, @@ -439,6 +465,7 @@ define([ callback: this.onCheckCharExists.bind(this, msg, item) }); }, + onCheckCharExists: function (msg, item, res) { if (!res) { this.resolveCallback(msg, 'Recipient does not exist'); @@ -454,6 +481,54 @@ define([ //Helpers + hookItemEvents: function (items) { + var items = items || this.items; + var iLen = items.length; + for (var i = 0; i < iLen; i++) { + var item = items[i]; + + if (item.effects) { + item.effects.forEach(function (e) { + if (e.mtx) { + var mtxUrl = mtx.get(e.mtx); + var mtxModule = require(mtxUrl); + + e.events = mtxModule.events; + } else if (e.factionId) { + var faction = factions.getFaction(e.factionId); + var statGenerator = faction.uniqueStat; + statGenerator.generate(item); + } else { + var effectUrl = itemEffects.get(e.type); + var effectModule = require(effectUrl); + + e.events = effectModule.events; + } + }); + } + + if ((item.pos == null) && (!item.eq)) { + var pos = i; + for (var j = 0; j < iLen; j++) { + if (!items.some(fj => (fj.pos == j))) { + pos = j; + break; + } + } + item.pos = pos; + } else if ((!item.eq) && (items.some(ii => ((ii != item) && (ii.pos == item.pos))))) { + var pos = item.pos; + for (var j = 0; j < iLen; j++) { + if (!items.some(fi => ((fi != item) && (fi.pos == j)))) { + pos = j; + break; + } + } + item.pos = pos; + } + } + }, + setItemPosition: function (id) { var item = this.findItem(id); if (!item) @@ -950,75 +1025,24 @@ define([ this.items = []; }, - save: function () { - return { - type: 'inventory', - items: this.items - }; - }, + canEquipItem: function (item) { + var stats = this.obj.stats.values; - simplify: function (self) { - if (!self) - return null; + var playerLevel = (stats.originalLevel || stats.level); + if (item.level > playerLevel) + return false; - var reputation = this.obj.reputation; + if ((item.requires) && (stats[item.requires[0].stat] < item.requires[0].value)) + return false; - return { - type: 'inventory', - items: this.items - .map(function (i) { - var item = extend(true, {}, i); - - if (item.effects) { - item.effects = item.effects.map(e => ({ - factionId: e.factionId, - text: e.text, - properties: e.properties, - mtx: e.mtx, - type: e.type, - rolls: e.rolls - })); - } - - if (item.factions) { - item.factions = item.factions.map(function (f) { - var faction = reputation.getBlueprint(f.id); - var factionTier = reputation.getTier(f.id); - - var noEquip = null; - if (factionTier < f.tier) - noEquip = true; - - if (!faction) - console.log(f); - - return { - id: f.id, - name: faction.name, - tier: f.tier, - tierName: ['Hated', 'Hostile', 'Unfriendly', 'Neutral', 'Friendly', 'Honored', 'Revered', 'Exalted'][f.tier], - noEquip: noEquip - }; - }, this); - } - - return item; - }) - }; - }, - - update: function () { - var items = this.items; - var iLen = items.length; - for (var i = 0; i < iLen; i++) { - var item = items[i]; - if (!item.cd) - continue; - - item.cd--; - - this.obj.syncer.setArray(true, 'inventory', 'getItems', item); + if (item.factions) { + if (item.factions.some(function (f) { + return f.noEquip; + })) + return false; } + + return true; } }; }); diff --git a/src/server/items/config/armorMaterials.js b/src/server/items/config/armorMaterials.js index 5ea5633a..ec2de9da 100644 --- a/src/server/items/config/armorMaterials.js +++ b/src/server/items/config/armorMaterials.js @@ -1,23 +1,26 @@ define([ - -], function( - + +], function ( + ) { return { plate: { + attrRequire: 'str', statMult: { armor: 1 } }, leather: { + attrRequire: 'dex', statMult: { armor: 0.6 } }, cloth: { + attrRequire: 'int', statMult: { armor: 0.35 } } }; -}); \ No newline at end of file +}); diff --git a/src/server/items/config/types.js b/src/server/items/config/types.js index d6530d06..3b8d3712 100644 --- a/src/server/items/config/types.js +++ b/src/server/items/config/types.js @@ -159,6 +159,7 @@ define([ }, oneHanded: { 'Sword': { + attrRequire: 'str', sprite: [9, 0], spellName: 'melee', spellConfig: { @@ -173,6 +174,7 @@ define([ } }, 'Dagger': { + attrRequire: 'dex', sprite: [9, 2], spellName: 'melee', spellConfig: { @@ -186,6 +188,7 @@ define([ } }, 'Axe': { + attrRequire: 'str', sprite: [9, 3], spellName: 'melee', spellConfig: { @@ -200,6 +203,7 @@ define([ } }, 'Wand': { + attrRequire: 'int', sprite: [9, 8], spellName: 'projectile', spellConfig: { @@ -217,6 +221,7 @@ define([ }, twoHanded: { 'Gnarled Staff': { + attrRequire: 'int', sprite: [9, 1], spellName: 'projectile', spellConfig: { @@ -233,6 +238,7 @@ define([ } }, 'Spear': { + attrRequire: 'str', sprite: [9, 6], spellName: 'melee', range: 2, @@ -250,19 +256,23 @@ define([ }, offHand: { 'Wooden Shield': { + attrRequire: 'str', sprite: [13, 0], armorMult: 0.3, blockAttackMult: 1 }, 'Gilded Shield': { + attrRequire: 'str', sprite: [13, 1], armorMult: 0.6, blockAttackMult: 0.5 }, 'Brittle Tome': { + attrRequire: 'int', sprite: [13, 2] }, 'Ancient Tome': { + attrRequire: 'int', sprite: [13, 3] } }, diff --git a/src/server/items/generator.js b/src/server/items/generator.js index fc419221..576bcfb7 100644 --- a/src/server/items/generator.js +++ b/src/server/items/generator.js @@ -9,11 +9,12 @@ define([ 'items/generators/quantity', 'items/generators/spellbook', 'items/generators/currency', - 'items/generators/effects' + 'items/generators/effects', + 'items/generators/attrRequire' ], function ( - g1, g2, g3, g4, g5, g6, g7, g8, g9, g10, g11 + g1, g2, g3, g4, g5, g6, g7, g8, g9, g10, g11, g12 ) { - var generators = [g1, g2, g3, g4, g5, g6, g11, g7]; + var generators = [g1, g2, g3, g4, g5, g6, g11, g12, g7]; var materialGenerators = [g6, g8]; var spellGenerators = [g1, g9, g7]; var currencyGenerators = [g10]; diff --git a/src/server/items/generators/attrRequire.js b/src/server/items/generators/attrRequire.js new file mode 100644 index 00000000..a805288e --- /dev/null +++ b/src/server/items/generators/attrRequire.js @@ -0,0 +1,41 @@ +define([ + './stats' +], function ( + generatorStats +) { + return { + minSlotPerfection: 0.5, + maxSlotPerfection: 1, + minLevelMult: 0., + maxLevelMult: 1, + + generate: function (item, blueprint) { + if (!blueprint.attrRequire) + return; + + if (!item.requires) + item.requires = []; + + var tempItem = { + quality: 0, + level: 20, + stats: {} + }; + + var perfection = ~~(11 * (this.minSlotPerfection + (Math.random() * (this.maxSlotPerfection - this.minSlotPerfection)))); + + generatorStats.generate(tempItem, { + forceStats: [blueprint.attrRequire], + perfection: perfection + }); + + var statValue = tempItem.stats[Object.keys(tempItem.stats)[0]]; + statValue += ~~(item.level * (this.minLevelMult + ~~(Math.random() * (this.maxLevelMult - this.minLevelMult)))); + + item.requires.push({ + stat: blueprint.attrRequire, + value: statValue + }); + } + }; +}); diff --git a/src/server/items/generators/types.js b/src/server/items/generators/types.js index 15a0a2b4..8c57361c 100644 --- a/src/server/items/generators/types.js +++ b/src/server/items/generators/types.js @@ -26,8 +26,16 @@ define([ if (typeBlueprint.range) item.range = typeBlueprint.range; - if ((typeBlueprint.material) && (blueprint.statMult.armor)) - blueprint.statMult.armor *= armorMaterials[typeBlueprint.material].statMult.armor; + if (typeBlueprint.material) { + var material = armorMaterials[typeBlueprint.material]; + blueprint.attrRequire = material.attrRequire; + + if (blueprint.statMult.armor) + blueprint.statMult.armor *= material.statMult.armor + } + + if (typeBlueprint.attrRequire) + blueprint.attrRequire = typeBlueprint.attrRequire; if (typeBlueprint.armorMult) blueprint.statMult.armor = typeBlueprint.armorMult; diff --git a/src/server/mods/class-necromancer/index.js b/src/server/mods/class-necromancer/index.js index bcb2cd3f..7a535cfa 100644 --- a/src/server/mods/class-necromancer/index.js +++ b/src/server/mods/class-necromancer/index.js @@ -130,6 +130,7 @@ define([ types.oneHanded[s] = { sprite: [i, 0], spellName: 'melee', + attrRequire: ['int'], spellConfig: { statType: ['str', 'int'], statMult: 0.76,