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,