# Conflicts: # src/server/components/passives.js # src/server/security/router.jstags/v0.2.0^2
@@ -3,6 +3,7 @@ storage.db | |||||
*.sublime-project | *.sublime-project | ||||
*.sublime-workspace | *.sublime-workspace | ||||
*.css | *.css | ||||
src/server/mods/iwd-* | |||||
!helpers/item-tooltip/styles.css | !helpers/item-tooltip/styles.css | ||||
!helpers/passives/**/*.css | !helpers/passives/**/*.css | ||||
creds.js | creds.js |
@@ -14,6 +14,7 @@ | |||||
@red: #d43346; | @red: #d43346; | ||||
@blue: #3fa7dd; | @blue: #3fa7dd; | ||||
@green: #80f643; | @green: #80f643; | ||||
@greenA: #80f643; | |||||
@greenB: #4ac441; | @greenB: #4ac441; | ||||
@greenC: #386646; | @greenC: #386646; | ||||
@@ -33,6 +34,7 @@ | |||||
@orangeD: #953f36; | @orangeD: #953f36; | ||||
@yellowB: #faac45; | @yellowB: #faac45; | ||||
@yellowC: #d07840; | |||||
@blueA: #48edff; | @blueA: #48edff; | ||||
@blueB: #3fa7dd; | @blueB: #3fa7dd; | ||||
@@ -48,6 +50,7 @@ | |||||
@purpleD: #393268; | @purpleD: #393268; | ||||
@pinkA: #fc66f7; | @pinkA: #fc66f7; | ||||
@pinkB: #de43ae; | |||||
@grayB: #c0c3cf; | @grayB: #c0c3cf; | ||||
@grayC: #929398; | @grayC: #929398; | ||||
@@ -58,15 +61,15 @@ | |||||
} | } | ||||
.q1 { | .q1 { | ||||
color: @blue; | |||||
color: @greenB; | |||||
} | } | ||||
.q2 { | .q2 { | ||||
color: @yellow; | |||||
color: @blueB; | |||||
} | } | ||||
.q3 { | .q3 { | ||||
color: @purple; | |||||
color: @purpleA; | |||||
} | } | ||||
.q4 { | .q4 { | ||||
@@ -74,9 +77,52 @@ | |||||
} | } | ||||
.color-red { | .color-red { | ||||
color: @red; | |||||
color: @red !important; | |||||
} | |||||
.color-redA { | |||||
color: @redA !important; | |||||
} | |||||
.color-blueA { | |||||
color: @blueA !important; | |||||
} | |||||
.color-blueB { | |||||
color: @blueB !important; | |||||
} | |||||
.color-greenB { | |||||
color: @greenB !important; | |||||
} | |||||
.color-yellowB { | |||||
color: @yellowB !important; | |||||
} | } | ||||
.color-green { | .color-green { | ||||
color: @green; | |||||
color: @green !important; | |||||
} | |||||
.color-brownC { | |||||
color: @brownC !important; | |||||
} | |||||
.color-brownD { | |||||
color: @brownD !important; | |||||
} | |||||
.color-grayA { | |||||
color: @white !important; | |||||
} | |||||
.color-grayB { | |||||
color: @grayB !important; | |||||
} | |||||
.color-grayC { | |||||
color: @grayC !important; | |||||
} | |||||
.color-grayD { | |||||
color: @grayD !important; | |||||
} | |||||
.color-pinkB { | |||||
color: @pinkB !important; | |||||
} | } |
@@ -17,9 +17,13 @@ require.config({ | |||||
'helpers': 'js/misc/helpers', | 'helpers': 'js/misc/helpers', | ||||
'particles': 'plugins/pixi.particles', | 'particles': 'plugins/pixi.particles', | ||||
'picture': 'plugins/pixi.picture', | 'picture': 'plugins/pixi.picture', | ||||
'pixi': 'plugins/pixi.min' | |||||
'pixi': 'plugins/pixi.min', | |||||
'howler': 'plugins/howler.min' | |||||
}, | }, | ||||
shim: { | shim: { | ||||
'howler': { | |||||
exports: 'howl' | |||||
}, | |||||
'socket': { | 'socket': { | ||||
exports: 'io' | exports: 'io' | ||||
}, | }, | ||||
@@ -55,8 +59,8 @@ require.config({ | |||||
require([ | require([ | ||||
'main' | 'main' | ||||
], function( | |||||
], function ( | |||||
main | main | ||||
) { | ) { | ||||
main.init(); | main.init(); | ||||
}); | |||||
}); |
@@ -59,6 +59,31 @@ define([ | |||||
events.emit('onGetItems', this.items, rerender); | 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); | |||||
} | } | ||||
}; | }; | ||||
}); | }); |
@@ -2,7 +2,7 @@ define([ | |||||
'js/input', | 'js/input', | ||||
'js/system/client', | 'js/system/client', | ||||
'js/misc/physics' | 'js/misc/physics' | ||||
], function( | |||||
], function ( | |||||
input, | input, | ||||
client, | client, | ||||
physics | physics | ||||
@@ -17,7 +17,10 @@ define([ | |||||
y: 0 | y: 0 | ||||
}, | }, | ||||
update: function() { | |||||
update: function () { | |||||
if (this.obj.dead) | |||||
return; | |||||
if (this.obj.moveAnimation) | if (this.obj.moveAnimation) | ||||
this.obj.pather.clearPath(); | this.obj.pather.clearPath(); | ||||
@@ -40,17 +43,17 @@ define([ | |||||
this.keyMove(); | this.keyMove(); | ||||
}, | }, | ||||
bump: function(dx, dy) { | |||||
bump: function (dx, dy) { | |||||
if (this.obj.pather.path.length > 0) | if (this.obj.pather.path.length > 0) | ||||
return; | return; | ||||
this.obj.addComponent('bumpAnimation', { | this.obj.addComponent('bumpAnimation', { | ||||
deltaX: dx, | deltaX: dx, | ||||
deltaY: dy | deltaY: dy | ||||
}); | }); | ||||
}, | }, | ||||
keyMove: function() { | |||||
keyMove: function () { | |||||
var delta = { | var delta = { | ||||
x: input.getAxis('horizontal'), | x: input.getAxis('horizontal'), | ||||
y: input.getAxis('vertical') | y: input.getAxis('vertical') | ||||
@@ -74,7 +77,7 @@ define([ | |||||
this.addQueue(newX, newY); | this.addQueue(newX, newY); | ||||
}, | }, | ||||
addQueue: function(x, y) { | |||||
addQueue: function (x, y) { | |||||
if (this.obj.moveAnimation) | if (this.obj.moveAnimation) | ||||
return; | return; | ||||
@@ -95,4 +98,4 @@ define([ | |||||
}); | }); | ||||
} | } | ||||
}; | }; | ||||
}); | |||||
}); |
@@ -1,9 +1,13 @@ | |||||
define([ | define([ | ||||
'js/rendering/renderer', | 'js/rendering/renderer', | ||||
'js/system/events' | |||||
], function( | |||||
'js/system/events', | |||||
'js/misc/physics', | |||||
'js/sound/sound' | |||||
], function ( | |||||
renderer, | renderer, | ||||
events | |||||
events, | |||||
physics, | |||||
sound | |||||
) { | ) { | ||||
var scale = 40; | var scale = 40; | ||||
@@ -15,7 +19,7 @@ define([ | |||||
y: 0 | y: 0 | ||||
}, | }, | ||||
init: function() { | |||||
init: function () { | |||||
this.obj.addComponent('keyboardMover'); | this.obj.addComponent('keyboardMover'); | ||||
this.obj.addComponent('mouseMover'); | this.obj.addComponent('mouseMover'); | ||||
this.obj.addComponent('serverActions'); | this.obj.addComponent('serverActions'); | ||||
@@ -25,7 +29,7 @@ define([ | |||||
events.emit('onGetPortrait', this.obj.portrait); | events.emit('onGetPortrait', this.obj.portrait); | ||||
}, | }, | ||||
update: function() { | |||||
update: function () { | |||||
var obj = this.obj; | var obj = this.obj; | ||||
var oldPos = this.oldPos; | var oldPos = this.oldPos; | ||||
@@ -38,7 +42,7 @@ define([ | |||||
var instant = false; | var instant = false; | ||||
if ((dx > 5) || (dy > 5)) | if ((dx > 5) || (dy > 5)) | ||||
instant = true; | instant = true; | ||||
if (dx != 0) | if (dx != 0) | ||||
dx = dx / Math.abs(dx); | dx = dx / Math.abs(dx); | ||||
if (dy != 0) | if (dy != 0) | ||||
@@ -51,9 +55,21 @@ define([ | |||||
x: dx, | x: dx, | ||||
y: dy | y: dy | ||||
}, instant); | }, instant); | ||||
sound.update(obj.x, obj.y); | |||||
}, | |||||
extend: function (blueprint) { | |||||
if (blueprint.collisionChanges) { | |||||
blueprint.collisionChanges.forEach(function (c) { | |||||
physics.setCollision(c.x, c.y, c.collides); | |||||
}); | |||||
delete blueprint.collisionChanges; | |||||
} | |||||
}, | }, | ||||
canvasFollow: function(delta, instant) { | |||||
canvasFollow: function (delta, instant) { | |||||
var obj = this.obj; | var obj = this.obj; | ||||
delta = delta || { | delta = delta || { | ||||
x: 0, | x: 0, | ||||
@@ -66,4 +82,4 @@ define([ | |||||
}, instant); | }, instant); | ||||
}, | }, | ||||
}; | }; | ||||
}); | |||||
}); |
@@ -1,7 +1,7 @@ | |||||
define([ | define([ | ||||
'js/system/events', | 'js/system/events', | ||||
'js/rendering/renderer' | 'js/rendering/renderer' | ||||
], function( | |||||
], function ( | |||||
events, | events, | ||||
renderer | renderer | ||||
) { | ) { | ||||
@@ -15,7 +15,7 @@ define([ | |||||
hpSprite: null, | hpSprite: null, | ||||
hpSpriteInner: null, | hpSpriteInner: null, | ||||
init: function(blueprint) { | |||||
init: function (blueprint) { | |||||
if (this.obj.self) | if (this.obj.self) | ||||
events.emit('onGetStats', this.values); | events.emit('onGetStats', this.values); | ||||
@@ -50,7 +50,10 @@ define([ | |||||
this.updateHpSprite(); | this.updateHpSprite(); | ||||
}, | }, | ||||
updateHpSprite: function() { | |||||
updateHpSprite: function () { | |||||
if (this.obj.dead) | |||||
return; | |||||
var obj = this.obj; | var obj = this.obj; | ||||
var yOffset = -12; | var yOffset = -12; | ||||
@@ -80,7 +83,7 @@ define([ | |||||
this.hpSpriteInner.visible = this.hpSprite.visible; | this.hpSpriteInner.visible = this.hpSprite.visible; | ||||
}, | }, | ||||
extend: function(blueprint) { | |||||
extend: function (blueprint) { | |||||
var bValues = blueprint.values || {}; | var bValues = blueprint.values || {}; | ||||
var values = this.values; | var values = this.values; | ||||
@@ -99,7 +102,7 @@ define([ | |||||
this.updateHpSprite(); | this.updateHpSprite(); | ||||
}, | }, | ||||
destroy: function() { | |||||
destroy: function () { | |||||
renderer.destroyObject({ | renderer.destroyObject({ | ||||
sprite: this.hpSprite, | sprite: this.hpSprite, | ||||
layerName: 'effects' | layerName: 'effects' | ||||
@@ -111,4 +114,4 @@ define([ | |||||
}); | }); | ||||
} | } | ||||
}; | }; | ||||
}); | |||||
}); |
@@ -58,8 +58,16 @@ define([ | |||||
window.onfocus = this.onFocus.bind(this, true); | window.onfocus = this.onFocus.bind(this, true); | ||||
window.onblur = this.onFocus.bind(this, false); | window.onblur = this.onFocus.bind(this, false); | ||||
$(window).on('contextmenu', function (e) { | $(window).on('contextmenu', function (e) { | ||||
e.preventDefault(); | |||||
return false; | |||||
var allowedList = ['txtUsername', 'txtPassword']; | |||||
var allowed = allowedList.some(function (item) { | |||||
return $(e.target).hasClass(item); | |||||
}); | |||||
if (!allowed) { | |||||
e.preventDefault(); | |||||
return false; | |||||
} | |||||
}); | }); | ||||
objects.init(); | objects.init(); | ||||
@@ -4,7 +4,7 @@ | |||||
// Implements the astar search algorithm in javascript using a Binary Heap. | // Implements the astar search algorithm in javascript using a Binary Heap. | ||||
// Includes Binary Heap (with modifications) from Marijn Haverbeke. | // Includes Binary Heap (with modifications) from Marijn Haverbeke. | ||||
// http://eloquentjavascript.net/appendix2.html | // http://eloquentjavascript.net/appendix2.html | ||||
(function(definition) { | |||||
(function (definition) { | |||||
/* global module, define */ | /* global module, define */ | ||||
if (typeof module === 'object' && typeof module.exports === 'object') { | if (typeof module === 'object' && typeof module.exports === 'object') { | ||||
module.exports = definition(); | module.exports = definition(); | ||||
@@ -15,7 +15,7 @@ | |||||
window.astar = exports.astar; | window.astar = exports.astar; | ||||
window.Graph = exports.Graph; | window.Graph = exports.Graph; | ||||
} | } | ||||
})(function() { | |||||
})(function () { | |||||
function pathTo(node) { | function pathTo(node) { | ||||
var curr = node; | var curr = node; | ||||
@@ -28,7 +28,7 @@ | |||||
} | } | ||||
function getHeap() { | function getHeap() { | ||||
return new BinaryHeap(function(node) { | |||||
return new BinaryHeap(function (node) { | |||||
return node.f; | return node.f; | ||||
}); | }); | ||||
} | } | ||||
@@ -42,10 +42,13 @@ | |||||
* @param {Object} [options] | * @param {Object} [options] | ||||
* @param {bool} [options.closest] Specifies whether to return the | * @param {bool} [options.closest] Specifies whether to return the | ||||
path to the closest node if the target is unreachable. | path to the closest node if the target is unreachable. | ||||
* @param {Function} [options.heuristic] Heuristic function (see | |||||
* @param { | |||||
Function | |||||
}[options.heuristic] Heuristic | |||||
function (see | |||||
* astar.heuristics). | * astar.heuristics). | ||||
*/ | */ | ||||
search: function(graph, start, end, options) { | |||||
search: function (graph, start, end, options) { | |||||
start = graph.grid[start.x][start.y] || start; | start = graph.grid[start.x][start.y] || start; | ||||
end = graph.grid[end.x][end.y] || end; | end = graph.grid[end.x][end.y] || end; | ||||
@@ -77,8 +80,7 @@ | |||||
if (distance) { | if (distance) { | ||||
if (currentNode.h == distance) | if (currentNode.h == distance) | ||||
return pathTo(currentNode); | return pathTo(currentNode); | ||||
} | |||||
else { | |||||
} else { | |||||
// End case -- result has been found, return the traced path. | // End case -- result has been found, return the traced path. | ||||
if (currentNode === end) { | if (currentNode === end) { | ||||
return pathTo(currentNode); | return pathTo(currentNode); | ||||
@@ -142,17 +144,17 @@ | |||||
}, | }, | ||||
// See list of heuristics: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html | // See list of heuristics: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html | ||||
heuristics: { | heuristics: { | ||||
manhattan: function(pos0, pos1) { | |||||
manhattan: function (pos0, pos1) { | |||||
var d1 = Math.abs(pos1.x - pos0.x); | var d1 = Math.abs(pos1.x - pos0.x); | ||||
var d2 = Math.abs(pos1.y - pos0.y); | var d2 = Math.abs(pos1.y - pos0.y); | ||||
return Math.max(d1, d2); | return Math.max(d1, d2); | ||||
}, | }, | ||||
manhattanDistance: function(pos0, pos1, distance) { | |||||
manhattanDistance: function (pos0, pos1, distance) { | |||||
var d1 = Math.abs(pos1.x - pos0.x); | var d1 = Math.abs(pos1.x - pos0.x); | ||||
var d2 = Math.abs(pos1.y - pos0.y); | var d2 = Math.abs(pos1.y - pos0.y); | ||||
return Math.abs(distance - Math.max(d1, d2)) + 1; | return Math.abs(distance - Math.max(d1, d2)) + 1; | ||||
}, | }, | ||||
diagonal: function(pos0, pos1) { | |||||
diagonal: function (pos0, pos1) { | |||||
var D = 1; | var D = 1; | ||||
var D2 = Math.sqrt(2); | var D2 = Math.sqrt(2); | ||||
var d1 = Math.abs(pos1.x - pos0.x); | var d1 = Math.abs(pos1.x - pos0.x); | ||||
@@ -160,7 +162,7 @@ | |||||
return (D * (d1 + d2)) + ((D2 - (2 * D)) * Math.min(d1, d2)); | return (D * (d1 + d2)) + ((D2 - (2 * D)) * Math.min(d1, d2)); | ||||
} | } | ||||
}, | }, | ||||
cleanNode: function(node) { | |||||
cleanNode: function (node) { | |||||
if (!node) | if (!node) | ||||
return; | return; | ||||
node.f = 0; | node.f = 0; | ||||
@@ -198,25 +200,25 @@ | |||||
this.init(); | this.init(); | ||||
} | } | ||||
Graph.prototype.init = function() { | |||||
Graph.prototype.init = function () { | |||||
this.dirtyNodes = []; | this.dirtyNodes = []; | ||||
for (var i = 0; i < this.nodes.length; i++) { | for (var i = 0; i < this.nodes.length; i++) { | ||||
astar.cleanNode(this.nodes[i]); | astar.cleanNode(this.nodes[i]); | ||||
} | } | ||||
}; | }; | ||||
Graph.prototype.cleanDirty = function() { | |||||
Graph.prototype.cleanDirty = function () { | |||||
for (var i = 0; i < this.dirtyNodes.length; i++) { | for (var i = 0; i < this.dirtyNodes.length; i++) { | ||||
astar.cleanNode(this.dirtyNodes[i]); | astar.cleanNode(this.dirtyNodes[i]); | ||||
} | } | ||||
this.dirtyNodes = []; | this.dirtyNodes = []; | ||||
}; | }; | ||||
Graph.prototype.markDirty = function(node) { | |||||
Graph.prototype.markDirty = function (node) { | |||||
this.dirtyNodes.push(node); | this.dirtyNodes.push(node); | ||||
}; | }; | ||||
Graph.prototype.neighbors = function(node) { | |||||
Graph.prototype.neighbors = function (node) { | |||||
var ret = []; | var ret = []; | ||||
var x = node.x; | var x = node.x; | ||||
var y = node.y; | var y = node.y; | ||||
@@ -267,7 +269,7 @@ | |||||
return ret; | return ret; | ||||
}; | }; | ||||
Graph.prototype.toString = function() { | |||||
Graph.prototype.toString = function () { | |||||
var graphString = []; | var graphString = []; | ||||
var nodes = this.grid; | var nodes = this.grid; | ||||
for (var x = 0; x < nodes.length; x++) { | for (var x = 0; x < nodes.length; x++) { | ||||
@@ -287,11 +289,11 @@ | |||||
this.weight = weight; | this.weight = weight; | ||||
} | } | ||||
GridNode.prototype.toString = function() { | |||||
GridNode.prototype.toString = function () { | |||||
return "[" + this.x + " " + this.y + "]"; | return "[" + this.x + " " + this.y + "]"; | ||||
}; | }; | ||||
GridNode.prototype.getCost = function(fromNeighbor) { | |||||
GridNode.prototype.getCost = function (fromNeighbor) { | |||||
// Take diagonal weight into consideration. | // Take diagonal weight into consideration. | ||||
if (fromNeighbor && fromNeighbor.x != this.x && fromNeighbor.y != this.y) { | if (fromNeighbor && fromNeighbor.x != this.x && fromNeighbor.y != this.y) { | ||||
return this.weight * 1.41421; | return this.weight * 1.41421; | ||||
@@ -299,7 +301,7 @@ | |||||
return this.weight; | return this.weight; | ||||
}; | }; | ||||
GridNode.prototype.isWall = function() { | |||||
GridNode.prototype.isWall = function () { | |||||
return this.weight === 0; | return this.weight === 0; | ||||
}; | }; | ||||
@@ -309,14 +311,14 @@ | |||||
} | } | ||||
BinaryHeap.prototype = { | BinaryHeap.prototype = { | ||||
push: function(element) { | |||||
push: function (element) { | |||||
// Add the new element to the end of the array. | // Add the new element to the end of the array. | ||||
this.content.push(element); | this.content.push(element); | ||||
// Allow it to sink down. | // Allow it to sink down. | ||||
this.sinkDown(this.content.length - 1); | this.sinkDown(this.content.length - 1); | ||||
}, | }, | ||||
pop: function() { | |||||
pop: function () { | |||||
// Store the first element so we can return it later. | // Store the first element so we can return it later. | ||||
var result = this.content[0]; | var result = this.content[0]; | ||||
// Get the element at the end of the array. | // Get the element at the end of the array. | ||||
@@ -329,7 +331,7 @@ | |||||
} | } | ||||
return result; | return result; | ||||
}, | }, | ||||
remove: function(node) { | |||||
remove: function (node) { | |||||
var i = this.content.indexOf(node); | var i = this.content.indexOf(node); | ||||
// When it is found, the process seen in 'pop' is repeated | // When it is found, the process seen in 'pop' is repeated | ||||
@@ -346,13 +348,13 @@ | |||||
} | } | ||||
} | } | ||||
}, | }, | ||||
size: function() { | |||||
size: function () { | |||||
return this.content.length; | return this.content.length; | ||||
}, | }, | ||||
rescoreElement: function(node) { | |||||
rescoreElement: function (node) { | |||||
this.sinkDown(this.content.indexOf(node)); | this.sinkDown(this.content.indexOf(node)); | ||||
}, | }, | ||||
sinkDown: function(n) { | |||||
sinkDown: function (n) { | |||||
// Fetch the element that has to be sunk. | // Fetch the element that has to be sunk. | ||||
var element = this.content[n]; | var element = this.content[n]; | ||||
@@ -375,7 +377,7 @@ | |||||
} | } | ||||
} | } | ||||
}, | }, | ||||
bubbleUp: function(n) { | |||||
bubbleUp: function (n) { | |||||
// Look up the target element and its score. | // Look up the target element and its score. | ||||
var length = this.content.length; | var length = this.content.length; | ||||
var element = this.content[n]; | var element = this.content[n]; | ||||
@@ -426,7 +428,7 @@ | |||||
return { | return { | ||||
astar: astar, | astar: astar, | ||||
Graph: Graph, | Graph: Graph, | ||||
GridNode: GridNode | |||||
gridNode: GridNode | |||||
}; | }; | ||||
}); | |||||
}); |
@@ -1,6 +1,6 @@ | |||||
define([ | define([ | ||||
'js/misc/pathfinder' | 'js/misc/pathfinder' | ||||
], function( | |||||
], function ( | |||||
pathfinder | pathfinder | ||||
) { | ) { | ||||
var sqrt = Math.sqrt.bind(Math); | var sqrt = Math.sqrt.bind(Math); | ||||
@@ -15,7 +15,7 @@ define([ | |||||
width: 0, | width: 0, | ||||
height: 0, | height: 0, | ||||
init: function(collisionMap) { | |||||
init: function (collisionMap) { | |||||
this.collisionMap = collisionMap; | this.collisionMap = collisionMap; | ||||
this.width = collisionMap.length; | this.width = collisionMap.length; | ||||
@@ -28,7 +28,7 @@ define([ | |||||
}); | }); | ||||
}, | }, | ||||
addRegion: function(obj) { | |||||
addRegion: function (obj) { | |||||
var lowX = obj.x; | var lowX = obj.x; | ||||
var lowY = obj.y; | var lowY = obj.y; | ||||
var highX = lowX + obj.width; | var highX = lowX + obj.width; | ||||
@@ -43,7 +43,7 @@ define([ | |||||
} | } | ||||
}, | }, | ||||
addObject: function(obj, x, y, fromX, fromY) { | |||||
addObject: function (obj, x, y, fromX, fromY) { | |||||
var row = this.cells[x]; | var row = this.cells[x]; | ||||
if (!row) | if (!row) | ||||
@@ -73,7 +73,7 @@ define([ | |||||
cell.push(obj); | cell.push(obj); | ||||
return true; | return true; | ||||
}, | }, | ||||
removeObject: function(obj, x, y, toX, toY) { | |||||
removeObject: function (obj, x, y, toX, toY) { | |||||
var row = this.cells[x]; | var row = this.cells[x]; | ||||
if (!row) | if (!row) | ||||
@@ -108,7 +108,7 @@ define([ | |||||
} | } | ||||
}, | }, | ||||
isValid: function(x, y) { | |||||
isValid: function (x, y) { | |||||
var row = this.cells[x]; | var row = this.cells[x]; | ||||
if ((!row) || (row.length <= y) || (!this.graph.grid[x][y])) | if ((!row) || (row.length <= y) || (!this.graph.grid[x][y])) | ||||
@@ -117,7 +117,7 @@ define([ | |||||
return true; | return true; | ||||
}, | }, | ||||
getCell: function(x, y) { | |||||
getCell: function (x, y) { | |||||
var row = this.cells[x]; | var row = this.cells[x]; | ||||
if (!row) | if (!row) | ||||
@@ -130,7 +130,7 @@ define([ | |||||
return cell; | return cell; | ||||
}, | }, | ||||
getArea: function(x1, y1, x2, y2, filter) { | |||||
getArea: function (x1, y1, x2, y2, filter) { | |||||
var width = this.width; | var width = this.width; | ||||
var height = this.height; | var height = this.height; | ||||
@@ -177,7 +177,7 @@ define([ | |||||
return result; | return result; | ||||
}, | }, | ||||
getOpenCellInArea: function(x1, y1, x2, y2) { | |||||
getOpenCellInArea: function (x1, y1, x2, y2) { | |||||
var width = this.width; | var width = this.width; | ||||
var height = this.height; | var height = this.height; | ||||
@@ -220,7 +220,7 @@ define([ | |||||
return result; | return result; | ||||
}, | }, | ||||
getPath: function(from, to) { | |||||
getPath: function (from, to) { | |||||
var graph = this.graph; | var graph = this.graph; | ||||
var grid = graph.grid; | var grid = graph.grid; | ||||
@@ -255,22 +255,24 @@ define([ | |||||
return path; | return path; | ||||
}, | }, | ||||
isTileBlocking: function(x, y, mob, obj) { | |||||
isTileBlocking: function (x, y, mob, obj) { | |||||
if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height)) | if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height)) | ||||
return true; | return true; | ||||
x = ~~x; | x = ~~x; | ||||
y = ~~y; | y = ~~y; | ||||
return !this.graph.grid[x][y]; | |||||
var node = this.graph.grid[x][y]; | |||||
return ((!node) || (node.weight == 0)); | |||||
}, | }, | ||||
isCellOpen: function(x, y) { | |||||
isCellOpen: function (x, y) { | |||||
if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height)) | if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height)) | ||||
return true; | return true; | ||||
return (this.cells[x][y].length == 0); | return (this.cells[x][y].length == 0); | ||||
}, | }, | ||||
hasLos: function(fromX, fromY, toX, toY) { | |||||
hasLos: function (fromX, fromY, toX, toY) { | |||||
if ((fromX < 0) || (fromY < 0) || (fromX >= this.width) | (fromY >= this.height) || (toX < 0) || (toY < 0) || (toX >= this.width) | (toY >= this.height)) | if ((fromX < 0) || (fromY < 0) || (fromX >= this.width) | (fromY >= this.height) || (toX < 0) || (toY < 0) || (toX >= this.width) | (toY >= this.height)) | ||||
return false; | return false; | ||||
@@ -311,7 +313,7 @@ define([ | |||||
return true; | return true; | ||||
}, | }, | ||||
getClosestPos: function(fromX, fromY, toX, toY, target) { | |||||
getClosestPos: function (fromX, fromY, toX, toY, target) { | |||||
var tried = {}; | var tried = {}; | ||||
var hasLos = this.hasLos.bind(this, toX, toY); | var hasLos = this.hasLos.bind(this, toX, toY); | ||||
@@ -337,8 +339,7 @@ define([ | |||||
incX = -1; | incX = -1; | ||||
lowX = x2; | lowX = x2; | ||||
highX = x1 - 1; | highX = x1 - 1; | ||||
} | |||||
else { | |||||
} else { | |||||
incX = 1; | incX = 1; | ||||
lowX = x1; | lowX = x1; | ||||
highX = x2 + 1; | highX = x2 + 1; | ||||
@@ -348,8 +349,7 @@ define([ | |||||
incY = -1; | incY = -1; | ||||
lowY = y2; | lowY = y2; | ||||
highY = y1 - 1; | highY = y1 - 1; | ||||
} | |||||
else { | |||||
} else { | |||||
incY = 1; | incY = 1; | ||||
lowY = y1; | lowY = y1; | ||||
highY = y2 + 1; | highY = y2 + 1; | ||||
@@ -405,7 +405,7 @@ define([ | |||||
} | } | ||||
}, | }, | ||||
mobsCollide: function(x, y, obj) { | |||||
mobsCollide: function (x, y, obj) { | |||||
if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height)) | if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height)) | ||||
return true; | return true; | ||||
@@ -427,6 +427,16 @@ define([ | |||||
} | } | ||||
return false; | return false; | ||||
}, | |||||
setCollision: function (x, y, collides) { | |||||
var node = this.graph.grid[x][y]; | |||||
if (!node) { | |||||
var grid = this.graph.grid; | |||||
node = grid[x][y] = new pathfinder.gridNode(x, y, collides ? 0 : 1); | |||||
} | |||||
node.weight = collides ? 0 : 1; | |||||
} | } | ||||
}; | }; | ||||
}); | |||||
}); |
@@ -12,10 +12,19 @@ define([ | |||||
'int': 'intellect', | 'int': 'intellect', | ||||
'dex': 'dexterity', | 'dex': 'dexterity', | ||||
'armor': 'armor', | 'armor': 'armor', | ||||
'blockAttackChance': 'chance to block attacks', | 'blockAttackChance': 'chance to block attacks', | ||||
'blockSpellChance': 'chance to block spells', | 'blockSpellChance': 'chance to block spells', | ||||
'addCritChance': 'increased crit chance', | |||||
'addCritMultiplier': 'increased crit multiplier', | |||||
'dodgeAttackChance': 'chance to dodge attacks', | |||||
'dodgeSpellChance': 'chance to dodge spells', | |||||
'addCritChance': 'global crit chance', | |||||
'addCritMultiplier': 'global crit multiplier', | |||||
'addAttackCritChance': 'attack crit chance', | |||||
'addAttackCritMultiplier': 'attack crit multiplier', | |||||
'addSpellCritChance': 'spell crit chance', | |||||
'addSpellCritMultiplier': 'spell crit multiplier', | |||||
'magicFind': 'increased item quality', | 'magicFind': 'increased item quality', | ||||
'itemQuantity': 'increased item quantity', | 'itemQuantity': 'increased item quantity', | ||||
'sprintChance': 'sprint chance', | 'sprintChance': 'sprint chance', | ||||
@@ -1,11 +1,13 @@ | |||||
define([ | define([ | ||||
'js/objects/objBase', | 'js/objects/objBase', | ||||
'js/system/events', | 'js/system/events', | ||||
'js/rendering/renderer' | |||||
'js/rendering/renderer', | |||||
'js/sound/sound' | |||||
], function ( | ], function ( | ||||
objBase, | objBase, | ||||
events, | events, | ||||
renderer | |||||
renderer, | |||||
sound | |||||
) { | ) { | ||||
var scale = 40; | var scale = 40; | ||||
@@ -146,8 +148,15 @@ define([ | |||||
if (obj.sheetName) { | if (obj.sheetName) { | ||||
obj.sprite = renderer.buildObject(obj); | obj.sprite = renderer.buildObject(obj); | ||||
if (template.hidden) | |||||
if (template.hidden) { | |||||
obj.sprite.visible = false; | obj.sprite.visible = false; | ||||
if (obj.nameSprite) | |||||
obj.nameSprite.visible = false; | |||||
if ((obj.stats) && (obj.stats.hpSprite)) { | |||||
obj.stats.hpSprite.visible = false; | |||||
obj.stats.hpSpriteInner.visible = false; | |||||
} | |||||
} | |||||
} | } | ||||
components.forEach(function (c) { | components.forEach(function (c) { | ||||
@@ -174,6 +183,8 @@ define([ | |||||
events.emit('onGetPlayer', obj); | events.emit('onGetPlayer', obj); | ||||
window.player = obj; | window.player = obj; | ||||
sound.init(obj.zoneName); | |||||
renderer.setPosition({ | renderer.setPosition({ | ||||
x: (obj.x - (renderer.width / (scale * 2))) * scale, | x: (obj.x - (renderer.width / (scale * 2))) * scale, | ||||
y: (obj.y - (renderer.height / (scale * 2))) * scale | y: (obj.y - (renderer.height / (scale * 2))) * scale | ||||
@@ -254,6 +265,12 @@ define([ | |||||
if (sprite) { | if (sprite) { | ||||
if (template.hidden != null) { | if (template.hidden != null) { | ||||
sprite.visible = !template.hidden; | sprite.visible = !template.hidden; | ||||
if (obj.nameSprite) | |||||
obj.nameSprite.visible = this.showNames; | |||||
if ((obj.stats) && (obj.stats.hpSprite)) { | |||||
obj.stats.hpSprite.visible = !template.hidden; | |||||
obj.stats.hpSpriteInner.visible = !template.hidden; | |||||
} | |||||
} | } | ||||
} | } | ||||
@@ -310,8 +327,9 @@ define([ | |||||
var objects = this.objects; | var objects = this.objects; | ||||
var oLen = objects.length; | var oLen = objects.length; | ||||
for (var i = 0; i < oLen; i++) { | for (var i = 0; i < oLen; i++) { | ||||
var ns = objects[i].nameSprite; | |||||
if (!ns) | |||||
var obj = objects[i]; | |||||
var ns = obj.nameSprite; | |||||
if ((!ns) || (obj.dead)) | |||||
continue; | continue; | ||||
ns.visible = showNames; | ns.visible = showNames; | ||||
@@ -76,7 +76,6 @@ define([ | |||||
PIXI.SCALE_MODES.DEFAULT = PIXI.SCALE_MODES.NEAREST; | PIXI.SCALE_MODES.DEFAULT = PIXI.SCALE_MODES.NEAREST; | ||||
events.on('onGetMap', this.onGetMap.bind(this)); | events.on('onGetMap', this.onGetMap.bind(this)); | ||||
events.on('onDeath', this.onDeath.bind(this)); | |||||
events.on('onToggleFullscreen', this.toggleScreen.bind(this)); | events.on('onToggleFullscreen', this.toggleScreen.bind(this)); | ||||
this.width = $('body').width(); | this.width = $('body').width(); | ||||
@@ -240,13 +239,6 @@ define([ | |||||
} | } | ||||
}, | }, | ||||
onDeath: function (pos) { | |||||
this.setPosition({ | |||||
x: (pos.x - (this.width / (scale * 2))) * scale, | |||||
y: (pos.y - (this.height / (scale * 2))) * scale | |||||
}, true); | |||||
}, | |||||
onResize: function () { | onResize: function () { | ||||
var zoom = window.devicePixelRatio; | var zoom = window.devicePixelRatio; | ||||
@@ -0,0 +1,72 @@ | |||||
define([ | |||||
'howler' | |||||
], function ( | |||||
howler | |||||
) { | |||||
return { | |||||
sounds: [], | |||||
init: function (zone) { | |||||
this.unload(); | |||||
if (zone != 'fjolarok') | |||||
return; | |||||
this.addSound('fire.ogg', 123, 123); | |||||
this.addSound('stream.ogg', 107, 69); | |||||
this.addSound('wind.ogg', 176, 104); | |||||
}, | |||||
unload: function () { | |||||
this.sounds.forEach(function (s) { | |||||
if (s.sound) | |||||
s.sound.unload(); | |||||
}); | |||||
this.sounds = []; | |||||
}, | |||||
update: function (x, y) { | |||||
this.sounds.forEach(function (s) { | |||||
var dx = Math.abs(s.x - x); | |||||
if (dx > 10) { | |||||
if (s.sound) | |||||
s.sound.volume(0); | |||||
return; | |||||
} | |||||
var dy = Math.abs(s.y - y); | |||||
if (dy > 10) { | |||||
if (s.sound) | |||||
s.sound.volume(0); | |||||
return; | |||||
} | |||||
var dist = 10 - Math.max(dx, dy); | |||||
dist = (dist * dist) / 100; | |||||
var volume = 0.3 * dist; | |||||
if (!s.sound) { | |||||
s.sound = new Howl({ | |||||
src: ['audio/' + s.file], | |||||
autoplay: true, | |||||
loop: true, | |||||
volume: 0 | |||||
}); | |||||
} | |||||
s.sound.volume(volume); | |||||
}); | |||||
}, | |||||
addSound: function (file, x, y) { | |||||
var sound = { | |||||
file: file, | |||||
x: x, | |||||
y: y, | |||||
sound: null | |||||
}; | |||||
this.sounds.push(sound); | |||||
} | |||||
}; | |||||
}); |
@@ -1,12 +1,12 @@ | |||||
define([ | define([ | ||||
], function( | |||||
], function ( | |||||
) { | ) { | ||||
var events = { | var events = { | ||||
events: {}, | events: {}, | ||||
queue: [], | queue: [], | ||||
on: function(event, callback) { | |||||
on: function (event, callback) { | |||||
var list = this.events[event] || (this.events[event] = []); | var list = this.events[event] || (this.events[event] = []); | ||||
list.push(callback); | list.push(callback); | ||||
@@ -25,13 +25,13 @@ define([ | |||||
return callback; | return callback; | ||||
}, | }, | ||||
clearQueue: function() { | |||||
clearQueue: function () { | |||||
//Hack to allow the player list to persist | //Hack to allow the player list to persist | ||||
this.queue.spliceWhere(function(q) { | |||||
return (q.event != 'onGetConnectedPlayer'); | |||||
this.queue.spliceWhere(function (q) { | |||||
return ((q.event != 'onGetConnectedPlayer') && (q.event != 'onGetDisconnectedPlayer')); | |||||
}); | }); | ||||
}, | }, | ||||
off: function(event, callback) { | |||||
off: function (event, callback) { | |||||
var list = this.events[event] || []; | var list = this.events[event] || []; | ||||
var lLen = list.length; | var lLen = list.length; | ||||
for (var i = 0; i < lLen; i++) { | for (var i = 0; i < lLen; i++) { | ||||
@@ -45,7 +45,7 @@ define([ | |||||
if (lLen == 0) | if (lLen == 0) | ||||
delete this.events[event]; | delete this.events[event]; | ||||
}, | }, | ||||
emit: function(event) { | |||||
emit: function (event) { | |||||
var args = [].slice.call(arguments, 1); | var args = [].slice.call(arguments, 1); | ||||
var list = this.events[event]; | var list = this.events[event]; | ||||
@@ -70,4 +70,4 @@ define([ | |||||
window.addons.init(events); | window.addons.init(events); | ||||
return events; | return events; | ||||
}); | |||||
}); |
@@ -1,59 +0,0 @@ | |||||
const { | |||||
app, | |||||
BrowserWindow | |||||
} = require('electron') | |||||
// Keep a global reference of the window object, if you don't, the window will | |||||
// be closed automatically when the JavaScript object is garbage collected. | |||||
let win | |||||
function createWindow() { | |||||
// Create the browser window. | |||||
win = new BrowserWindow({ | |||||
width: 800, | |||||
height: 600, | |||||
frame: true, | |||||
title: 'Isleward' | |||||
}); | |||||
win.maximize(); | |||||
// and load the index.html of the app. | |||||
//win.loadURL(`http://default-environment.9ymkeaciiv.eu-west-1.elasticbeanstalk.com/index.html`) | |||||
win.loadURL(`http://localhost:4000/index.html`) | |||||
// Open the DevTools. | |||||
//win.webContents.openDevTools() | |||||
// Emitted when the window is closed. | |||||
win.on('closed', () => { | |||||
// Dereference the window object, usually you would store windows | |||||
// in an array if your app supports multi windows, this is the time | |||||
// when you should delete the corresponding element. | |||||
win = null | |||||
}) | |||||
} | |||||
// This method will be called when Electron has finished | |||||
// initialization and is ready to create browser windows. | |||||
// Some APIs can only be used after this event occurs. | |||||
app.on('ready', createWindow) | |||||
// Quit when all windows are closed. | |||||
app.on('window-all-closed', () => { | |||||
// On macOS it is common for applications and their menu bar | |||||
// to stay active until the user quits explicitly with Cmd + Q | |||||
if (process.platform !== 'darwin') { | |||||
app.quit() | |||||
} | |||||
}) | |||||
app.on('activate', () => { | |||||
// On macOS it's common to re-create a window in the app when the | |||||
// dock icon is clicked and there are no other windows open. | |||||
if (win === null) { | |||||
createWindow() | |||||
} | |||||
}) | |||||
// In this file you can include the rest of your app's specific main process | |||||
// code. You can also put them in separate files and require them here. |
@@ -0,0 +1,852 @@ | |||||
/*! howler.js v2.0.9 | (c) 2013-2018, James Simpson of GoldFire Studios | MIT License | howlerjs.com */ ! function () { | |||||
"use strict"; | |||||
var e = function () { | |||||
this.init() | |||||
}; | |||||
e.prototype = { | |||||
init: function () { | |||||
var e = this || n; | |||||
return e._counter = 1e3, e._codecs = {}, e._howls = [], e._muted = !1, e._volume = 1, e._canPlayEvent = "canplaythrough", e._navigator = "undefined" != typeof window && window.navigator ? window.navigator : null, e.masterGain = null, e.noAudio = !1, e.usingWebAudio = !0, e.autoSuspend = !0, e.ctx = null, e.mobileAutoEnable = !0, e._setup(), e | |||||
}, | |||||
volume: function (e) { | |||||
var t = this || n; | |||||
if (e = parseFloat(e), t.ctx || _(), void 0 !== e && e >= 0 && e <= 1) { | |||||
if (t._volume = e, t._muted) return t; | |||||
t.usingWebAudio && t.masterGain.gain.setValueAtTime(e, n.ctx.currentTime); | |||||
for (var o = 0; o < t._howls.length; o++) | |||||
if (!t._howls[o]._webAudio) | |||||
for (var r = t._howls[o]._getSoundIds(), a = 0; a < r.length; a++) { | |||||
var u = t._howls[o]._soundById(r[a]); | |||||
u && u._node && (u._node.volume = u._volume * e) | |||||
} | |||||
return t | |||||
} | |||||
return t._volume | |||||
}, | |||||
mute: function (e) { | |||||
var t = this || n; | |||||
t.ctx || _(), t._muted = e, t.usingWebAudio && t.masterGain.gain.setValueAtTime(e ? 0 : t._volume, n.ctx.currentTime); | |||||
for (var o = 0; o < t._howls.length; o++) | |||||
if (!t._howls[o]._webAudio) | |||||
for (var r = t._howls[o]._getSoundIds(), a = 0; a < r.length; a++) { | |||||
var u = t._howls[o]._soundById(r[a]); | |||||
u && u._node && (u._node.muted = !!e || u._muted) | |||||
} | |||||
return t | |||||
}, | |||||
unload: function () { | |||||
for (var e = this || n, t = e._howls.length - 1; t >= 0; t--) e._howls[t].unload(); | |||||
return e.usingWebAudio && e.ctx && void 0 !== e.ctx.close && (e.ctx.close(), e.ctx = null, _()), e | |||||
}, | |||||
codecs: function (e) { | |||||
return (this || n)._codecs[e.replace(/^x-/, "")] | |||||
}, | |||||
_setup: function () { | |||||
var e = this || n; | |||||
if (e.state = e.ctx ? e.ctx.state || "running" : "running", e._autoSuspend(), !e.usingWebAudio) | |||||
if ("undefined" != typeof Audio) try { | |||||
var t = new Audio; | |||||
void 0 === t.oncanplaythrough && (e._canPlayEvent = "canplay") | |||||
} catch (n) { | |||||
e.noAudio = !0 | |||||
} else e.noAudio = !0; | |||||
try { | |||||
var t = new Audio; | |||||
t.muted && (e.noAudio = !0) | |||||
} catch (e) {} | |||||
return e.noAudio || e._setupCodecs(), e | |||||
}, | |||||
_setupCodecs: function () { | |||||
var e = this || n, | |||||
t = null; | |||||
try { | |||||
t = "undefined" != typeof Audio ? new Audio : null | |||||
} catch (n) { | |||||
return e | |||||
} | |||||
if (!t || "function" != typeof t.canPlayType) return e; | |||||
var o = t.canPlayType("audio/mpeg;").replace(/^no$/, ""), | |||||
r = e._navigator && e._navigator.userAgent.match(/OPR\/([0-6].)/g), | |||||
a = r && parseInt(r[0].split("/")[1], 10) < 33; | |||||
return e._codecs = { | |||||
mp3: !(a || !o && !t.canPlayType("audio/mp3;").replace(/^no$/, "")), | |||||
mpeg: !!o, | |||||
opus: !!t.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ""), | |||||
ogg: !!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""), | |||||
oga: !!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""), | |||||
wav: !!t.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ""), | |||||
aac: !!t.canPlayType("audio/aac;").replace(/^no$/, ""), | |||||
caf: !!t.canPlayType("audio/x-caf;").replace(/^no$/, ""), | |||||
m4a: !!(t.canPlayType("audio/x-m4a;") || t.canPlayType("audio/m4a;") || t.canPlayType("audio/aac;")).replace(/^no$/, ""), | |||||
mp4: !!(t.canPlayType("audio/x-mp4;") || t.canPlayType("audio/mp4;") || t.canPlayType("audio/aac;")).replace(/^no$/, ""), | |||||
weba: !!t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ""), | |||||
webm: !!t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ""), | |||||
dolby: !!t.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/, ""), | |||||
flac: !!(t.canPlayType("audio/x-flac;") || t.canPlayType("audio/flac;")).replace(/^no$/, "") | |||||
}, e | |||||
}, | |||||
_enableMobileAudio: function () { | |||||
var e = this || n, | |||||
t = /iPhone|iPad|iPod|Android|BlackBerry|BB10|Silk|Mobi/i.test(e._navigator && e._navigator.userAgent), | |||||
o = !!("ontouchend" in window || e._navigator && e._navigator.maxTouchPoints > 0 || e._navigator && e._navigator.msMaxTouchPoints > 0); | |||||
if (!e._mobileEnabled && e.ctx && (t || o)) { | |||||
e._mobileEnabled = !1, e._mobileUnloaded || 44100 === e.ctx.sampleRate || (e._mobileUnloaded = !0, e.unload()), e._scratchBuffer = e.ctx.createBuffer(1, 1, 22050); | |||||
var r = function () { | |||||
n._autoResume(); | |||||
var t = e.ctx.createBufferSource(); | |||||
t.buffer = e._scratchBuffer, t.connect(e.ctx.destination), void 0 === t.start ? t.noteOn(0) : t.start(0), "function" == typeof e.ctx.resume && e.ctx.resume(), t.onended = function () { | |||||
t.disconnect(0), e._mobileEnabled = !0, e.mobileAutoEnable = !1, document.removeEventListener("touchstart", r, !0), document.removeEventListener("touchend", r, !0) | |||||
} | |||||
}; | |||||
return document.addEventListener("touchstart", r, !0), document.addEventListener("touchend", r, !0), e | |||||
} | |||||
}, | |||||
_autoSuspend: function () { | |||||
var e = this; | |||||
if (e.autoSuspend && e.ctx && void 0 !== e.ctx.suspend && n.usingWebAudio) { | |||||
for (var t = 0; t < e._howls.length; t++) | |||||
if (e._howls[t]._webAudio) | |||||
for (var o = 0; o < e._howls[t]._sounds.length; o++) | |||||
if (!e._howls[t]._sounds[o]._paused) return e; | |||||
return e._suspendTimer && clearTimeout(e._suspendTimer), e._suspendTimer = setTimeout(function () { | |||||
e.autoSuspend && (e._suspendTimer = null, e.state = "suspending", e.ctx.suspend().then(function () { | |||||
e.state = "suspended", e._resumeAfterSuspend && (delete e._resumeAfterSuspend, e._autoResume()) | |||||
})) | |||||
}, 3e4), e | |||||
} | |||||
}, | |||||
_autoResume: function () { | |||||
var e = this; | |||||
if (e.ctx && void 0 !== e.ctx.resume && n.usingWebAudio) return "running" === e.state && e._suspendTimer ? (clearTimeout(e._suspendTimer), e._suspendTimer = null) : "suspended" === e.state ? (e.ctx.resume().then(function () { | |||||
e.state = "running"; | |||||
for (var n = 0; n < e._howls.length; n++) e._howls[n]._emit("resume") | |||||
}), e._suspendTimer && (clearTimeout(e._suspendTimer), e._suspendTimer = null)) : "suspending" === e.state && (e._resumeAfterSuspend = !0), e | |||||
} | |||||
}; | |||||
var n = new e, | |||||
t = function (e) { | |||||
var n = this; | |||||
if (!e.src || 0 === e.src.length) return void console.error("An array of source files must be passed with any new Howl."); | |||||
n.init(e) | |||||
}; | |||||
t.prototype = { | |||||
init: function (e) { | |||||
var t = this; | |||||
return n.ctx || _(), t._autoplay = e.autoplay || !1, t._format = "string" != typeof e.format ? e.format : [e.format], t._html5 = e.html5 || !1, t._muted = e.mute || !1, t._loop = e.loop || !1, t._pool = e.pool || 5, t._preload = "boolean" != typeof e.preload || e.preload, t._rate = e.rate || 1, t._sprite = e.sprite || {}, t._src = "string" != typeof e.src ? e.src : [e.src], t._volume = void 0 !== e.volume ? e.volume : 1, t._xhrWithCredentials = e.xhrWithCredentials || !1, t._duration = 0, t._state = "unloaded", t._sounds = [], t._endTimers = {}, t._queue = [], t._playLock = !1, t._onend = e.onend ? [{ | |||||
fn: e.onend | |||||
}] : [], t._onfade = e.onfade ? [{ | |||||
fn: e.onfade | |||||
}] : [], t._onload = e.onload ? [{ | |||||
fn: e.onload | |||||
}] : [], t._onloaderror = e.onloaderror ? [{ | |||||
fn: e.onloaderror | |||||
}] : [], t._onplayerror = e.onplayerror ? [{ | |||||
fn: e.onplayerror | |||||
}] : [], t._onpause = e.onpause ? [{ | |||||
fn: e.onpause | |||||
}] : [], t._onplay = e.onplay ? [{ | |||||
fn: e.onplay | |||||
}] : [], t._onstop = e.onstop ? [{ | |||||
fn: e.onstop | |||||
}] : [], t._onmute = e.onmute ? [{ | |||||
fn: e.onmute | |||||
}] : [], t._onvolume = e.onvolume ? [{ | |||||
fn: e.onvolume | |||||
}] : [], t._onrate = e.onrate ? [{ | |||||
fn: e.onrate | |||||
}] : [], t._onseek = e.onseek ? [{ | |||||
fn: e.onseek | |||||
}] : [], t._onresume = [], t._webAudio = n.usingWebAudio && !t._html5, void 0 !== n.ctx && n.ctx && n.mobileAutoEnable && n._enableMobileAudio(), n._howls.push(t), t._autoplay && t._queue.push({ | |||||
event: "play", | |||||
action: function () { | |||||
t.play() | |||||
} | |||||
}), t._preload && t.load(), t | |||||
}, | |||||
load: function () { | |||||
var e = this, | |||||
t = null; | |||||
if (n.noAudio) return void e._emit("loaderror", null, "No audio support."); | |||||
"string" == typeof e._src && (e._src = [e._src]); | |||||
for (var r = 0; r < e._src.length; r++) { | |||||
var u, i; | |||||
if (e._format && e._format[r]) u = e._format[r]; | |||||
else { | |||||
if ("string" != typeof (i = e._src[r])) { | |||||
e._emit("loaderror", null, "Non-string found in selected audio sources - ignoring."); | |||||
continue | |||||
} | |||||
u = /^data:audio\/([^;,]+);/i.exec(i), u || (u = /\.([^.]+)$/.exec(i.split("?", 1)[0])), u && (u = u[1].toLowerCase()) | |||||
} | |||||
if (u || console.warn('No file extension was found. Consider using the "format" property or specify an extension.'), u && n.codecs(u)) { | |||||
t = e._src[r]; | |||||
break | |||||
} | |||||
} | |||||
return t ? (e._src = t, e._state = "loading", "https:" === window.location.protocol && "http:" === t.slice(0, 5) && (e._html5 = !0, e._webAudio = !1), new o(e), e._webAudio && a(e), e) : void e._emit("loaderror", null, "No codec support for selected audio sources.") | |||||
}, | |||||
play: function (e, t) { | |||||
var o = this, | |||||
r = null; | |||||
if ("number" == typeof e) r = e, e = null; | |||||
else { | |||||
if ("string" == typeof e && "loaded" === o._state && !o._sprite[e]) return null; | |||||
if (void 0 === e) { | |||||
e = "__default"; | |||||
for (var a = 0, u = 0; u < o._sounds.length; u++) o._sounds[u]._paused && !o._sounds[u]._ended && (a++, r = o._sounds[u]._id); | |||||
1 === a ? e = null : r = null | |||||
} | |||||
} | |||||
var i = r ? o._soundById(r) : o._inactiveSound(); | |||||
if (!i) return null; | |||||
if (r && !e && (e = i._sprite || "__default"), "loaded" !== o._state) { | |||||
i._sprite = e, i._ended = !1; | |||||
var d = i._id; | |||||
return o._queue.push({ | |||||
event: "play", | |||||
action: function () { | |||||
o.play(d) | |||||
} | |||||
}), d | |||||
} | |||||
if (r && !i._paused) return t || o._loadQueue("play"), i._id; | |||||
o._webAudio && n._autoResume(); | |||||
var _ = Math.max(0, i._seek > 0 ? i._seek : o._sprite[e][0] / 1e3), | |||||
s = Math.max(0, (o._sprite[e][0] + o._sprite[e][1]) / 1e3 - _), | |||||
l = 1e3 * s / Math.abs(i._rate); | |||||
i._paused = !1, i._ended = !1, i._sprite = e, i._seek = _, i._start = o._sprite[e][0] / 1e3, i._stop = (o._sprite[e][0] + o._sprite[e][1]) / 1e3, i._loop = !(!i._loop && !o._sprite[e][2]); | |||||
var c = i._node; | |||||
if (o._webAudio) { | |||||
var f = function () { | |||||
o._refreshBuffer(i); | |||||
var e = i._muted || o._muted ? 0 : i._volume; | |||||
c.gain.setValueAtTime(e, n.ctx.currentTime), i._playStart = n.ctx.currentTime, void 0 === c.bufferSource.start ? i._loop ? c.bufferSource.noteGrainOn(0, _, 86400) : c.bufferSource.noteGrainOn(0, _, s) : i._loop ? c.bufferSource.start(0, _, 86400) : c.bufferSource.start(0, _, s), l !== 1 / 0 && (o._endTimers[i._id] = setTimeout(o._ended.bind(o, i), l)), t || setTimeout(function () { | |||||
o._emit("play", i._id) | |||||
}, 0) | |||||
}; | |||||
"running" === n.state ? f() : (o.once("resume", f), o._clearTimer(i._id)) | |||||
} else { | |||||
var p = function () { | |||||
c.currentTime = _, c.muted = i._muted || o._muted || n._muted || c.muted, c.volume = i._volume * n.volume(), c.playbackRate = i._rate; | |||||
try { | |||||
var r = c.play(); | |||||
if ("undefined" != typeof Promise && r instanceof Promise) { | |||||
o._playLock = !0; | |||||
var a = function () { | |||||
o._playLock = !1, t || o._emit("play", i._id) | |||||
}; | |||||
r.then(a, a) | |||||
} else t || o._emit("play", i._id); | |||||
if (c.paused) return void o._emit("playerror", i._id, "Playback was unable to start. This is most commonly an issue on mobile devices where playback was not within a user interaction."); | |||||
"__default" !== e ? o._endTimers[i._id] = setTimeout(o._ended.bind(o, i), l) : (o._endTimers[i._id] = function () { | |||||
o._ended(i), c.removeEventListener("ended", o._endTimers[i._id], !1) | |||||
}, c.addEventListener("ended", o._endTimers[i._id], !1)) | |||||
} catch (e) { | |||||
o._emit("playerror", i._id, e) | |||||
} | |||||
}, | |||||
m = window && window.ejecta || !c.readyState && n._navigator.isCocoonJS; | |||||
if (c.readyState >= 3 || m) p(); | |||||
else { | |||||
var v = function () { | |||||
p(), c.removeEventListener(n._canPlayEvent, v, !1) | |||||
}; | |||||
c.addEventListener(n._canPlayEvent, v, !1), o._clearTimer(i._id) | |||||
} | |||||
} | |||||
return i._id | |||||
}, | |||||
pause: function (e) { | |||||
var n = this; | |||||
if ("loaded" !== n._state || n._playLock) return n._queue.push({ | |||||
event: "pause", | |||||
action: function () { | |||||
n.pause(e) | |||||
} | |||||
}), n; | |||||
for (var t = n._getSoundIds(e), o = 0; o < t.length; o++) { | |||||
n._clearTimer(t[o]); | |||||
var r = n._soundById(t[o]); | |||||
if (r && !r._paused && (r._seek = n.seek(t[o]), r._rateSeek = 0, r._paused = !0, n._stopFade(t[o]), r._node)) | |||||
if (n._webAudio) { | |||||
if (!r._node.bufferSource) continue; | |||||
void 0 === r._node.bufferSource.stop ? r._node.bufferSource.noteOff(0) : r._node.bufferSource.stop(0), n._cleanBuffer(r._node) | |||||
} else isNaN(r._node.duration) && r._node.duration !== 1 / 0 || r._node.pause(); | |||||
arguments[1] || n._emit("pause", r ? r._id : null) | |||||
} | |||||
return n | |||||
}, | |||||
stop: function (e, n) { | |||||
var t = this; | |||||
if ("loaded" !== t._state) return t._queue.push({ | |||||
event: "stop", | |||||
action: function () { | |||||
t.stop(e) | |||||
} | |||||
}), t; | |||||
for (var o = t._getSoundIds(e), r = 0; r < o.length; r++) { | |||||
t._clearTimer(o[r]); | |||||
var a = t._soundById(o[r]); | |||||
a && (a._seek = a._start || 0, a._rateSeek = 0, a._paused = !0, a._ended = !0, t._stopFade(o[r]), a._node && (t._webAudio ? a._node.bufferSource && (void 0 === a._node.bufferSource.stop ? a._node.bufferSource.noteOff(0) : a._node.bufferSource.stop(0), t._cleanBuffer(a._node)) : isNaN(a._node.duration) && a._node.duration !== 1 / 0 || (a._node.currentTime = a._start || 0, a._node.pause())), n || t._emit("stop", a._id)) | |||||
} | |||||
return t | |||||
}, | |||||
mute: function (e, t) { | |||||
var o = this; | |||||
if ("loaded" !== o._state) return o._queue.push({ | |||||
event: "mute", | |||||
action: function () { | |||||
o.mute(e, t) | |||||
} | |||||
}), o; | |||||
if (void 0 === t) { | |||||
if ("boolean" != typeof e) return o._muted; | |||||
o._muted = e | |||||
} | |||||
for (var r = o._getSoundIds(t), a = 0; a < r.length; a++) { | |||||
var u = o._soundById(r[a]); | |||||
u && (u._muted = e, u._interval && o._stopFade(u._id), o._webAudio && u._node ? u._node.gain.setValueAtTime(e ? 0 : u._volume, n.ctx.currentTime) : u._node && (u._node.muted = !!n._muted || e), o._emit("mute", u._id)) | |||||
} | |||||
return o | |||||
}, | |||||
volume: function () { | |||||
var e, t, o = this, | |||||
r = arguments; | |||||
if (0 === r.length) return o._volume; | |||||
if (1 === r.length || 2 === r.length && void 0 === r[1]) { | |||||
o._getSoundIds().indexOf(r[0]) >= 0 ? t = parseInt(r[0], 10) : e = parseFloat(r[0]) | |||||
} else r.length >= 2 && (e = parseFloat(r[0]), t = parseInt(r[1], 10)); | |||||
var a; | |||||
if (!(void 0 !== e && e >= 0 && e <= 1)) return a = t ? o._soundById(t) : o._sounds[0], a ? a._volume : 0; | |||||
if ("loaded" !== o._state) return o._queue.push({ | |||||
event: "volume", | |||||
action: function () { | |||||
o.volume.apply(o, r) | |||||
} | |||||
}), o; | |||||
void 0 === t && (o._volume = e), t = o._getSoundIds(t); | |||||
for (var u = 0; u < t.length; u++)(a = o._soundById(t[u])) && (a._volume = e, r[2] || o._stopFade(t[u]), o._webAudio && a._node && !a._muted ? a._node.gain.setValueAtTime(e, n.ctx.currentTime) : a._node && !a._muted && (a._node.volume = e * n.volume()), o._emit("volume", a._id)); | |||||
return o | |||||
}, | |||||
fade: function (e, t, o, r) { | |||||
var a = this; | |||||
if ("loaded" !== a._state) return a._queue.push({ | |||||
event: "fade", | |||||
action: function () { | |||||
a.fade(e, t, o, r) | |||||
} | |||||
}), a; | |||||
a.volume(e, r); | |||||
for (var u = a._getSoundIds(r), i = 0; i < u.length; i++) { | |||||
var d = a._soundById(u[i]); | |||||
if (d) { | |||||
if (r || a._stopFade(u[i]), a._webAudio && !d._muted) { | |||||
var _ = n.ctx.currentTime, | |||||
s = _ + o / 1e3; | |||||
d._volume = e, d._node.gain.setValueAtTime(e, _), d._node.gain.linearRampToValueAtTime(t, s) | |||||
} | |||||
a._startFadeInterval(d, e, t, o, u[i], void 0 === r) | |||||
} | |||||
} | |||||
return a | |||||
}, | |||||
_startFadeInterval: function (e, n, t, o, r, a) { | |||||
var u = this, | |||||
i = n, | |||||
d = t - n, | |||||
_ = Math.abs(d / .01), | |||||
s = Math.max(4, _ > 0 ? o / _ : o), | |||||
l = Date.now(); | |||||
e._fadeTo = t, e._interval = setInterval(function () { | |||||
var r = (Date.now() - l) / o; | |||||
l = Date.now(), i += d * r, i = Math.max(0, i), i = Math.min(1, i), i = Math.round(100 * i) / 100, u._webAudio ? e._volume = i : u.volume(i, e._id, !0), a && (u._volume = i), (t < n && i <= t || t > n && i >= t) && (clearInterval(e._interval), e._interval = null, e._fadeTo = null, u.volume(t, e._id), u._emit("fade", e._id)) | |||||
}, s) | |||||
}, | |||||
_stopFade: function (e) { | |||||
var t = this, | |||||
o = t._soundById(e); | |||||
return o && o._interval && (t._webAudio && o._node.gain.cancelScheduledValues(n.ctx.currentTime), clearInterval(o._interval), o._interval = null, t.volume(o._fadeTo, e), o._fadeTo = null, t._emit("fade", e)), t | |||||
}, | |||||
loop: function () { | |||||
var e, n, t, o = this, | |||||
r = arguments; | |||||
if (0 === r.length) return o._loop; | |||||
if (1 === r.length) { | |||||
if ("boolean" != typeof r[0]) return !!(t = o._soundById(parseInt(r[0], 10))) && t._loop; | |||||
e = r[0], o._loop = e | |||||
} else 2 === r.length && (e = r[0], n = parseInt(r[1], 10)); | |||||
for (var a = o._getSoundIds(n), u = 0; u < a.length; u++)(t = o._soundById(a[u])) && (t._loop = e, o._webAudio && t._node && t._node.bufferSource && (t._node.bufferSource.loop = e, e && (t._node.bufferSource.loopStart = t._start || 0, t._node.bufferSource.loopEnd = t._stop))); | |||||
return o | |||||
}, | |||||
rate: function () { | |||||
var e, t, o = this, | |||||
r = arguments; | |||||
if (0 === r.length) t = o._sounds[0]._id; | |||||
else if (1 === r.length) { | |||||
var a = o._getSoundIds(), | |||||
u = a.indexOf(r[0]); | |||||
u >= 0 ? t = parseInt(r[0], 10) : e = parseFloat(r[0]) | |||||
} else 2 === r.length && (e = parseFloat(r[0]), t = parseInt(r[1], 10)); | |||||
var i; | |||||
if ("number" != typeof e) return i = o._soundById(t), i ? i._rate : o._rate; | |||||
if ("loaded" !== o._state) return o._queue.push({ | |||||
event: "rate", | |||||
action: function () { | |||||
o.rate.apply(o, r) | |||||
} | |||||
}), o; | |||||
void 0 === t && (o._rate = e), t = o._getSoundIds(t); | |||||
for (var d = 0; d < t.length; d++) | |||||
if (i = o._soundById(t[d])) { | |||||
i._rateSeek = o.seek(t[d]), i._playStart = o._webAudio ? n.ctx.currentTime : i._playStart, i._rate = e, o._webAudio && i._node && i._node.bufferSource ? i._node.bufferSource.playbackRate.setValueAtTime(e, n.ctx.currentTime) : i._node && (i._node.playbackRate = e); | |||||
var _ = o.seek(t[d]), | |||||
s = (o._sprite[i._sprite][0] + o._sprite[i._sprite][1]) / 1e3 - _, | |||||
l = 1e3 * s / Math.abs(i._rate); | |||||
!o._endTimers[t[d]] && i._paused || (o._clearTimer(t[d]), o._endTimers[t[d]] = setTimeout(o._ended.bind(o, i), l)), o._emit("rate", i._id) | |||||
} | |||||
return o | |||||
}, | |||||
seek: function () { | |||||
var e, t, o = this, | |||||
r = arguments; | |||||
if (0 === r.length) t = o._sounds[0]._id; | |||||
else if (1 === r.length) { | |||||
var a = o._getSoundIds(), | |||||
u = a.indexOf(r[0]); | |||||
u >= 0 ? t = parseInt(r[0], 10) : o._sounds.length && (t = o._sounds[0]._id, e = parseFloat(r[0])) | |||||
} else 2 === r.length && (e = parseFloat(r[0]), t = parseInt(r[1], 10)); | |||||
if (void 0 === t) return o; | |||||
if ("loaded" !== o._state) return o._queue.push({ | |||||
event: "seek", | |||||
action: function () { | |||||
o.seek.apply(o, r) | |||||
} | |||||
}), o; | |||||
var i = o._soundById(t); | |||||
if (i) { | |||||
if (!("number" == typeof e && e >= 0)) { | |||||
if (o._webAudio) { | |||||
var d = o.playing(t) ? n.ctx.currentTime - i._playStart : 0, | |||||
_ = i._rateSeek ? i._rateSeek - i._seek : 0; | |||||
return i._seek + (_ + d * Math.abs(i._rate)) | |||||
} | |||||
return i._node.currentTime | |||||
} | |||||
var s = o.playing(t); | |||||
if (s && o.pause(t, !0), i._seek = e, i._ended = !1, o._clearTimer(t), s && o.play(t, !0), !o._webAudio && i._node && (i._node.currentTime = e), s && !o._webAudio) { | |||||
var l = function () { | |||||
o._playLock ? setTimeout(l, 0) : o._emit("seek", t) | |||||
}; | |||||
setTimeout(l, 0) | |||||
} else o._emit("seek", t) | |||||
} | |||||
return o | |||||
}, | |||||
playing: function (e) { | |||||
var n = this; | |||||
if ("number" == typeof e) { | |||||
var t = n._soundById(e); | |||||
return !!t && !t._paused | |||||
} | |||||
for (var o = 0; o < n._sounds.length; o++) | |||||
if (!n._sounds[o]._paused) return !0; | |||||
return !1 | |||||
}, | |||||
duration: function (e) { | |||||
var n = this, | |||||
t = n._duration, | |||||
o = n._soundById(e); | |||||
return o && (t = n._sprite[o._sprite][1] / 1e3), t | |||||
}, | |||||
state: function () { | |||||
return this._state | |||||
}, | |||||
unload: function () { | |||||
for (var e = this, t = e._sounds, o = 0; o < t.length; o++) { | |||||
if (t[o]._paused || e.stop(t[o]._id), !e._webAudio) { | |||||
/MSIE |Trident\//.test(n._navigator && n._navigator.userAgent) || (t[o]._node.src = "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA"), t[o]._node.removeEventListener("error", t[o]._errorFn, !1), t[o]._node.removeEventListener(n._canPlayEvent, t[o]._loadFn, !1) | |||||
} | |||||
delete t[o]._node, e._clearTimer(t[o]._id); | |||||
var a = n._howls.indexOf(e); | |||||
a >= 0 && n._howls.splice(a, 1) | |||||
} | |||||
var u = !0; | |||||
for (o = 0; o < n._howls.length; o++) | |||||
if (n._howls[o]._src === e._src) { | |||||
u = !1; | |||||
break | |||||
} | |||||
return r && u && delete r[e._src], n.noAudio = !1, e._state = "unloaded", e._sounds = [], e = null, null | |||||
}, | |||||
on: function (e, n, t, o) { | |||||
var r = this, | |||||
a = r["_on" + e]; | |||||
return "function" == typeof n && a.push(o ? { | |||||
id: t, | |||||
fn: n, | |||||
once: o | |||||
} : { | |||||
id: t, | |||||
fn: n | |||||
}), r | |||||
}, | |||||
off: function (e, n, t) { | |||||
var o = this, | |||||
r = o["_on" + e], | |||||
a = 0; | |||||
if ("number" == typeof n && (t = n, n = null), n || t) | |||||
for (a = 0; a < r.length; a++) { | |||||
var u = t === r[a].id; | |||||
if (n === r[a].fn && u || !n && u) { | |||||
r.splice(a, 1); | |||||
break | |||||
} | |||||
} else if (e) o["_on" + e] = []; | |||||
else { | |||||
var i = Object.keys(o); | |||||
for (a = 0; a < i.length; a++) 0 === i[a].indexOf("_on") && Array.isArray(o[i[a]]) && (o[i[a]] = []) | |||||
} | |||||
return o | |||||
}, | |||||
once: function (e, n, t) { | |||||
var o = this; | |||||
return o.on(e, n, t, 1), o | |||||
}, | |||||
_emit: function (e, n, t) { | |||||
for (var o = this, r = o["_on" + e], a = r.length - 1; a >= 0; a--) r[a].id && r[a].id !== n && "load" !== e || (setTimeout(function (e) { | |||||
e.call(this, n, t) | |||||
}.bind(o, r[a].fn), 0), r[a].once && o.off(e, r[a].fn, r[a].id)); | |||||
return o._loadQueue(e), o | |||||
}, | |||||
_loadQueue: function (e) { | |||||
var n = this; | |||||
if (n._queue.length > 0) { | |||||
var t = n._queue[0]; | |||||
t.event === e && (n._queue.shift(), n._loadQueue()), e || t.action() | |||||
} | |||||
return n | |||||
}, | |||||
_ended: function (e) { | |||||
var t = this, | |||||
o = e._sprite; | |||||
if (!t._webAudio && e._node && !e._node.paused && !e._node.ended && e._node.currentTime < e._stop) return setTimeout(t._ended.bind(t, e), 100), t; | |||||
var r = !(!e._loop && !t._sprite[o][2]); | |||||
if (t._emit("end", e._id), !t._webAudio && r && t.stop(e._id, !0).play(e._id), t._webAudio && r) { | |||||
t._emit("play", e._id), e._seek = e._start || 0, e._rateSeek = 0, e._playStart = n.ctx.currentTime; | |||||
var a = 1e3 * (e._stop - e._start) / Math.abs(e._rate); | |||||
t._endTimers[e._id] = setTimeout(t._ended.bind(t, e), a) | |||||
} | |||||
return t._webAudio && !r && (e._paused = !0, e._ended = !0, e._seek = e._start || 0, e._rateSeek = 0, t._clearTimer(e._id), t._cleanBuffer(e._node), n._autoSuspend()), t._webAudio || r || t.stop(e._id), t | |||||
}, | |||||
_clearTimer: function (e) { | |||||
var n = this; | |||||
if (n._endTimers[e]) { | |||||
if ("function" != typeof n._endTimers[e]) clearTimeout(n._endTimers[e]); | |||||
else { | |||||
var t = n._soundById(e); | |||||
t && t._node && t._node.removeEventListener("ended", n._endTimers[e], !1) | |||||
} | |||||
delete n._endTimers[e] | |||||
} | |||||
return n | |||||
}, | |||||
_soundById: function (e) { | |||||
for (var n = this, t = 0; t < n._sounds.length; t++) | |||||
if (e === n._sounds[t]._id) return n._sounds[t]; | |||||
return null | |||||
}, | |||||
_inactiveSound: function () { | |||||
var e = this; | |||||
e._drain(); | |||||
for (var n = 0; n < e._sounds.length; n++) | |||||
if (e._sounds[n]._ended) return e._sounds[n].reset(); | |||||
return new o(e) | |||||
}, | |||||
_drain: function () { | |||||
var e = this, | |||||
n = e._pool, | |||||
t = 0, | |||||
o = 0; | |||||
if (!(e._sounds.length < n)) { | |||||
for (o = 0; o < e._sounds.length; o++) e._sounds[o]._ended && t++; | |||||
for (o = e._sounds.length - 1; o >= 0; o--) { | |||||
if (t <= n) return; | |||||
e._sounds[o]._ended && (e._webAudio && e._sounds[o]._node && e._sounds[o]._node.disconnect(0), e._sounds.splice(o, 1), t--) | |||||
} | |||||
} | |||||
}, | |||||
_getSoundIds: function (e) { | |||||
var n = this; | |||||
if (void 0 === e) { | |||||
for (var t = [], o = 0; o < n._sounds.length; o++) t.push(n._sounds[o]._id); | |||||
return t | |||||
} | |||||
return [e] | |||||
}, | |||||
_refreshBuffer: function (e) { | |||||
var t = this; | |||||
return e._node.bufferSource = n.ctx.createBufferSource(), e._node.bufferSource.buffer = r[t._src], e._panner ? e._node.bufferSource.connect(e._panner) : e._node.bufferSource.connect(e._node), e._node.bufferSource.loop = e._loop, e._loop && (e._node.bufferSource.loopStart = e._start || 0, e._node.bufferSource.loopEnd = e._stop), e._node.bufferSource.playbackRate.setValueAtTime(e._rate, n.ctx.currentTime), t | |||||
}, | |||||
_cleanBuffer: function (e) { | |||||
var t = this; | |||||
if (n._scratchBuffer) { | |||||
e.bufferSource.onended = null, e.bufferSource.disconnect(0); | |||||
try { | |||||
e.bufferSource.buffer = n._scratchBuffer | |||||
} catch (e) {} | |||||
} | |||||
return e.bufferSource = null, t | |||||
} | |||||
}; | |||||
var o = function (e) { | |||||
this._parent = e, this.init() | |||||
}; | |||||
o.prototype = { | |||||
init: function () { | |||||
var e = this, | |||||
t = e._parent; | |||||
return e._muted = t._muted, e._loop = t._loop, e._volume = t._volume, e._rate = t._rate, e._seek = 0, e._paused = !0, e._ended = !0, e._sprite = "__default", e._id = ++n._counter, t._sounds.push(e), e.create(), e | |||||
}, | |||||
create: function () { | |||||
var e = this, | |||||
t = e._parent, | |||||
o = n._muted || e._muted || e._parent._muted ? 0 : e._volume; | |||||
return t._webAudio ? (e._node = void 0 === n.ctx.createGain ? n.ctx.createGainNode() : n.ctx.createGain(), e._node.gain.setValueAtTime(o, n.ctx.currentTime), e._node.paused = !0, e._node.connect(n.masterGain)) : (e._node = new Audio, e._errorFn = e._errorListener.bind(e), e._node.addEventListener("error", e._errorFn, !1), e._loadFn = e._loadListener.bind(e), e._node.addEventListener(n._canPlayEvent, e._loadFn, !1), e._node.src = t._src, e._node.preload = "auto", e._node.volume = o * n.volume(), e._node.load()), e | |||||
}, | |||||
reset: function () { | |||||
var e = this, | |||||
t = e._parent; | |||||
return e._muted = t._muted, e._loop = t._loop, e._volume = t._volume, e._rate = t._rate, e._seek = 0, e._rateSeek = 0, e._paused = !0, e._ended = !0, e._sprite = "__default", e._id = ++n._counter, e | |||||
}, | |||||
_errorListener: function () { | |||||
var e = this; | |||||
e._parent._emit("loaderror", e._id, e._node.error ? e._node.error.code : 0), e._node.removeEventListener("error", e._errorFn, !1) | |||||
}, | |||||
_loadListener: function () { | |||||
var e = this, | |||||
t = e._parent; | |||||
t._duration = Math.ceil(10 * e._node.duration) / 10, 0 === Object.keys(t._sprite).length && (t._sprite = { | |||||
__default: [0, 1e3 * t._duration] | |||||
}), "loaded" !== t._state && (t._state = "loaded", t._emit("load"), t._loadQueue()), e._node.removeEventListener(n._canPlayEvent, e._loadFn, !1) | |||||
} | |||||
}; | |||||
var r = {}, | |||||
a = function (e) { | |||||
var n = e._src; | |||||
if (r[n]) return e._duration = r[n].duration, void d(e); | |||||
if (/^data:[^;]+;base64,/.test(n)) { | |||||
for (var t = atob(n.split(",")[1]), o = new Uint8Array(t.length), a = 0; a < t.length; ++a) o[a] = t.charCodeAt(a); | |||||
i(o.buffer, e) | |||||
} else { | |||||
var _ = new XMLHttpRequest; | |||||
_.open("GET", n, !0), _.withCredentials = e._xhrWithCredentials, _.responseType = "arraybuffer", _.onload = function () { | |||||
var n = (_.status + "")[0]; | |||||
if ("0" !== n && "2" !== n && "3" !== n) return void e._emit("loaderror", null, "Failed loading audio file with status: " + _.status + "."); | |||||
i(_.response, e) | |||||
}, _.onerror = function () { | |||||
e._webAudio && (e._html5 = !0, e._webAudio = !1, e._sounds = [], delete r[n], e.load()) | |||||
}, u(_) | |||||
} | |||||
}, | |||||
u = function (e) { | |||||
try { | |||||
e.send() | |||||
} catch (n) { | |||||
e.onerror() | |||||
} | |||||
}, | |||||
i = function (e, t) { | |||||
n.ctx.decodeAudioData(e, function (e) { | |||||
e && t._sounds.length > 0 && (r[t._src] = e, d(t, e)) | |||||
}, function () { | |||||
t._emit("loaderror", null, "Decoding audio data failed.") | |||||
}) | |||||
}, | |||||
d = function (e, n) { | |||||
n && !e._duration && (e._duration = n.duration), 0 === Object.keys(e._sprite).length && (e._sprite = { | |||||
__default: [0, 1e3 * e._duration] | |||||
}), "loaded" !== e._state && (e._state = "loaded", e._emit("load"), e._loadQueue()) | |||||
}, | |||||
_ = function () { | |||||
try { | |||||
"undefined" != typeof AudioContext ? n.ctx = new AudioContext : "undefined" != typeof webkitAudioContext ? n.ctx = new webkitAudioContext : n.usingWebAudio = !1 | |||||
} catch (e) { | |||||
n.usingWebAudio = !1 | |||||
} | |||||
var e = /iP(hone|od|ad)/.test(n._navigator && n._navigator.platform), | |||||
t = n._navigator && n._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/), | |||||
o = t ? parseInt(t[1], 10) : null; | |||||
if (e && o && o < 9) { | |||||
var r = /safari/.test(n._navigator && n._navigator.userAgent.toLowerCase()); | |||||
(n._navigator && n._navigator.standalone && !r || n._navigator && !n._navigator.standalone && !r) && (n.usingWebAudio = !1) | |||||
} | |||||
n.usingWebAudio && (n.masterGain = void 0 === n.ctx.createGain ? n.ctx.createGainNode() : n.ctx.createGain(), n.masterGain.gain.setValueAtTime(n._muted ? 0 : 1, n.ctx.currentTime), n.masterGain.connect(n.ctx.destination)), n._setup() | |||||
}; | |||||
"function" == typeof define && define.amd && define([], function () { | |||||
return { | |||||
Howler: n, | |||||
Howl: t | |||||
} | |||||
}), "undefined" != typeof exports && (exports.Howler = n, exports.Howl = t), "undefined" != typeof window ? (window.HowlerGlobal = e, window.Howler = n, window.Howl = t, window.Sound = o) : "undefined" != typeof global && (global.HowlerGlobal = e, global.Howler = n, global.Howl = t, global.Sound = o) | |||||
}(); | |||||
/*! Spatial Plugin */ | |||||
! function () { | |||||
"use strict"; | |||||
HowlerGlobal.prototype._pos = [0, 0, 0], HowlerGlobal.prototype._orientation = [0, 0, -1, 0, 1, 0], HowlerGlobal.prototype.stereo = function (n) { | |||||
var e = this; | |||||
if (!e.ctx || !e.ctx.listener) return e; | |||||
for (var t = e._howls.length - 1; t >= 0; t--) e._howls[t].stereo(n); | |||||
return e | |||||
}, HowlerGlobal.prototype.pos = function (n, e, t) { | |||||
var o = this; | |||||
return o.ctx && o.ctx.listener ? (e = "number" != typeof e ? o._pos[1] : e, t = "number" != typeof t ? o._pos[2] : t, "number" != typeof n ? o._pos : (o._pos = [n, e, t], o.ctx.listener.setPosition(o._pos[0], o._pos[1], o._pos[2]), o)) : o | |||||
}, HowlerGlobal.prototype.orientation = function (n, e, t, o, r, a) { | |||||
var i = this; | |||||
if (!i.ctx || !i.ctx.listener) return i; | |||||
var p = i._orientation; | |||||
return e = "number" != typeof e ? p[1] : e, t = "number" != typeof t ? p[2] : t, o = "number" != typeof o ? p[3] : o, r = "number" != typeof r ? p[4] : r, a = "number" != typeof a ? p[5] : a, "number" != typeof n ? p : (i._orientation = [n, e, t, o, r, a], i.ctx.listener.setOrientation(n, e, t, o, r, a), i) | |||||
}, Howl.prototype.init = function (n) { | |||||
return function (e) { | |||||
var t = this; | |||||
return t._orientation = e.orientation || [1, 0, 0], t._stereo = e.stereo || null, t._pos = e.pos || null, t._pannerAttr = { | |||||
coneInnerAngle: void 0 !== e.coneInnerAngle ? e.coneInnerAngle : 360, | |||||
coneOuterAngle: void 0 !== e.coneOuterAngle ? e.coneOuterAngle : 360, | |||||
coneOuterGain: void 0 !== e.coneOuterGain ? e.coneOuterGain : 0, | |||||
distanceModel: void 0 !== e.distanceModel ? e.distanceModel : "inverse", | |||||
maxDistance: void 0 !== e.maxDistance ? e.maxDistance : 1e4, | |||||
panningModel: void 0 !== e.panningModel ? e.panningModel : "HRTF", | |||||
refDistance: void 0 !== e.refDistance ? e.refDistance : 1, | |||||
rolloffFactor: void 0 !== e.rolloffFactor ? e.rolloffFactor : 1 | |||||
}, t._onstereo = e.onstereo ? [{ | |||||
fn: e.onstereo | |||||
}] : [], t._onpos = e.onpos ? [{ | |||||
fn: e.onpos | |||||
}] : [], t._onorientation = e.onorientation ? [{ | |||||
fn: e.onorientation | |||||
}] : [], n.call(this, e) | |||||
} | |||||
}(Howl.prototype.init), Howl.prototype.stereo = function (e, t) { | |||||
var o = this; | |||||
if (!o._webAudio) return o; | |||||
if ("loaded" !== o._state) return o._queue.push({ | |||||
event: "stereo", | |||||
action: function () { | |||||
o.stereo(e, t) | |||||
} | |||||
}), o; | |||||
var r = void 0 === Howler.ctx.createStereoPanner ? "spatial" : "stereo"; | |||||
if (void 0 === t) { | |||||
if ("number" != typeof e) return o._stereo; | |||||
o._stereo = e, o._pos = [e, 0, 0] | |||||
} | |||||
for (var a = o._getSoundIds(t), i = 0; i < a.length; i++) { | |||||
var p = o._soundById(a[i]); | |||||
if (p) { | |||||
if ("number" != typeof e) return p._stereo; | |||||
p._stereo = e, p._pos = [e, 0, 0], p._node && (p._pannerAttr.panningModel = "equalpower", p._panner && p._panner.pan || n(p, r), "spatial" === r ? p._panner.setPosition(e, 0, 0) : p._panner.pan.setValueAtTime(e, Howler.ctx.currentTime)), o._emit("stereo", p._id) | |||||
} | |||||
} | |||||
return o | |||||
}, Howl.prototype.pos = function (e, t, o, r) { | |||||
var a = this; | |||||
if (!a._webAudio) return a; | |||||
if ("loaded" !== a._state) return a._queue.push({ | |||||
event: "pos", | |||||
action: function () { | |||||
a.pos(e, t, o, r) | |||||
} | |||||
}), a; | |||||
if (t = "number" != typeof t ? 0 : t, o = "number" != typeof o ? -.5 : o, void 0 === r) { | |||||
if ("number" != typeof e) return a._pos; | |||||
a._pos = [e, t, o] | |||||
} | |||||
for (var i = a._getSoundIds(r), p = 0; p < i.length; p++) { | |||||
var s = a._soundById(i[p]); | |||||
if (s) { | |||||
if ("number" != typeof e) return s._pos; | |||||
s._pos = [e, t, o], s._node && (s._panner && !s._panner.pan || n(s, "spatial"), s._panner.setPosition(e, t, o)), a._emit("pos", s._id) | |||||
} | |||||
} | |||||
return a | |||||
}, Howl.prototype.orientation = function (e, t, o, r) { | |||||
var a = this; | |||||
if (!a._webAudio) return a; | |||||
if ("loaded" !== a._state) return a._queue.push({ | |||||
event: "orientation", | |||||
action: function () { | |||||
a.orientation(e, t, o, r) | |||||
} | |||||
}), a; | |||||
if (t = "number" != typeof t ? a._orientation[1] : t, o = "number" != typeof o ? a._orientation[2] : o, void 0 === r) { | |||||
if ("number" != typeof e) return a._orientation; | |||||
a._orientation = [e, t, o] | |||||
} | |||||
for (var i = a._getSoundIds(r), p = 0; p < i.length; p++) { | |||||
var s = a._soundById(i[p]); | |||||
if (s) { | |||||
if ("number" != typeof e) return s._orientation; | |||||
s._orientation = [e, t, o], s._node && (s._panner || (s._pos || (s._pos = a._pos || [0, 0, -.5]), n(s, "spatial")), s._panner.setOrientation(e, t, o)), a._emit("orientation", s._id) | |||||
} | |||||
} | |||||
return a | |||||
}, Howl.prototype.pannerAttr = function () { | |||||
var e, t, o, r = this, | |||||
a = arguments; | |||||
if (!r._webAudio) return r; | |||||
if (0 === a.length) return r._pannerAttr; | |||||
if (1 === a.length) { | |||||
if ("object" != typeof a[0]) return o = r._soundById(parseInt(a[0], 10)), o ? o._pannerAttr : r._pannerAttr; | |||||
e = a[0], void 0 === t && (e.pannerAttr || (e.pannerAttr = { | |||||
coneInnerAngle: e.coneInnerAngle, | |||||
coneOuterAngle: e.coneOuterAngle, | |||||
coneOuterGain: e.coneOuterGain, | |||||
distanceModel: e.distanceModel, | |||||
maxDistance: e.maxDistance, | |||||
refDistance: e.refDistance, | |||||
rolloffFactor: e.rolloffFactor, | |||||
panningModel: e.panningModel | |||||
}), r._pannerAttr = { | |||||
coneInnerAngle: void 0 !== e.pannerAttr.coneInnerAngle ? e.pannerAttr.coneInnerAngle : r._coneInnerAngle, | |||||
coneOuterAngle: void 0 !== e.pannerAttr.coneOuterAngle ? e.pannerAttr.coneOuterAngle : r._coneOuterAngle, | |||||
coneOuterGain: void 0 !== e.pannerAttr.coneOuterGain ? e.pannerAttr.coneOuterGain : r._coneOuterGain, | |||||
distanceModel: void 0 !== e.pannerAttr.distanceModel ? e.pannerAttr.distanceModel : r._distanceModel, | |||||
maxDistance: void 0 !== e.pannerAttr.maxDistance ? e.pannerAttr.maxDistance : r._maxDistance, | |||||
refDistance: void 0 !== e.pannerAttr.refDistance ? e.pannerAttr.refDistance : r._refDistance, | |||||
rolloffFactor: void 0 !== e.pannerAttr.rolloffFactor ? e.pannerAttr.rolloffFactor : r._rolloffFactor, | |||||
panningModel: void 0 !== e.pannerAttr.panningModel ? e.pannerAttr.panningModel : r._panningModel | |||||
}) | |||||
} else 2 === a.length && (e = a[0], t = parseInt(a[1], 10)); | |||||
for (var i = r._getSoundIds(t), p = 0; p < i.length; p++) | |||||
if (o = r._soundById(i[p])) { | |||||
var s = o._pannerAttr; | |||||
s = { | |||||
coneInnerAngle: void 0 !== e.coneInnerAngle ? e.coneInnerAngle : s.coneInnerAngle, | |||||
coneOuterAngle: void 0 !== e.coneOuterAngle ? e.coneOuterAngle : s.coneOuterAngle, | |||||
coneOuterGain: void 0 !== e.coneOuterGain ? e.coneOuterGain : s.coneOuterGain, | |||||
distanceModel: void 0 !== e.distanceModel ? e.distanceModel : s.distanceModel, | |||||
maxDistance: void 0 !== e.maxDistance ? e.maxDistance : s.maxDistance, | |||||
refDistance: void 0 !== e.refDistance ? e.refDistance : s.refDistance, | |||||
rolloffFactor: void 0 !== e.rolloffFactor ? e.rolloffFactor : s.rolloffFactor, | |||||
panningModel: void 0 !== e.panningModel ? e.panningModel : s.panningModel | |||||
}; | |||||
var l = o._panner; | |||||
l ? (l.coneInnerAngle = s.coneInnerAngle, l.coneOuterAngle = s.coneOuterAngle, l.coneOuterGain = s.coneOuterGain, l.distanceModel = s.distanceModel, l.maxDistance = s.maxDistance, l.refDistance = s.refDistance, l.rolloffFactor = s.rolloffFactor, l.panningModel = s.panningModel) : (o._pos || (o._pos = r._pos || [0, 0, -.5]), n(o, "spatial")) | |||||
} | |||||
return r | |||||
}, Sound.prototype.init = function (n) { | |||||
return function () { | |||||
var e = this, | |||||
t = e._parent; | |||||
e._orientation = t._orientation, e._stereo = t._stereo, e._pos = t._pos, e._pannerAttr = t._pannerAttr, n.call(this), e._stereo ? t.stereo(e._stereo) : e._pos && t.pos(e._pos[0], e._pos[1], e._pos[2], e._id) | |||||
} | |||||
}(Sound.prototype.init), Sound.prototype.reset = function (n) { | |||||
return function () { | |||||
var e = this, | |||||
t = e._parent; | |||||
return e._orientation = t._orientation, e._pos = t._pos, e._pannerAttr = t._pannerAttr, n.call(this) | |||||
} | |||||
}(Sound.prototype.reset); | |||||
var n = function (n, e) { | |||||
e = e || "spatial", "spatial" === e ? (n._panner = Howler.ctx.createPanner(), n._panner.coneInnerAngle = n._pannerAttr.coneInnerAngle, n._panner.coneOuterAngle = n._pannerAttr.coneOuterAngle, n._panner.coneOuterGain = n._pannerAttr.coneOuterGain, n._panner.distanceModel = n._pannerAttr.distanceModel, n._panner.maxDistance = n._pannerAttr.maxDistance, n._panner.refDistance = n._pannerAttr.refDistance, n._panner.rolloffFactor = n._pannerAttr.rolloffFactor, n._panner.panningModel = n._pannerAttr.panningModel, n._panner.setPosition(n._pos[0], n._pos[1], n._pos[2]), n._panner.setOrientation(n._orientation[0], n._orientation[1], n._orientation[2])) : (n._panner = Howler.ctx.createStereoPanner(), n._panner.pan.setValueAtTime(n._stereo, Howler.ctx.currentTime)), n._panner.connect(n._node), n._paused || n._parent.pause(n._id, !0).play(n._id, !0) | |||||
} | |||||
}(); |
@@ -0,0 +1,160 @@ | |||||
/*! howler.js v2.0.9 | Spatial Plugin | (c) 2013-2018, James Simpson of GoldFire Studios | MIT License | howlerjs.com */ ! function () { | |||||
"use strict"; | |||||
HowlerGlobal.prototype._pos = [0, 0, 0], HowlerGlobal.prototype._orientation = [0, 0, -1, 0, 1, 0], HowlerGlobal.prototype.stereo = function (n) { | |||||
var e = this; | |||||
if (!e.ctx || !e.ctx.listener) return e; | |||||
for (var t = e._howls.length - 1; t >= 0; t--) e._howls[t].stereo(n); | |||||
return e | |||||
}, HowlerGlobal.prototype.pos = function (n, e, t) { | |||||
var o = this; | |||||
return o.ctx && o.ctx.listener ? (e = "number" != typeof e ? o._pos[1] : e, t = "number" != typeof t ? o._pos[2] : t, "number" != typeof n ? o._pos : (o._pos = [n, e, t], o.ctx.listener.setPosition(o._pos[0], o._pos[1], o._pos[2]), o)) : o | |||||
}, HowlerGlobal.prototype.orientation = function (n, e, t, o, r, a) { | |||||
var i = this; | |||||
if (!i.ctx || !i.ctx.listener) return i; | |||||
var p = i._orientation; | |||||
return e = "number" != typeof e ? p[1] : e, t = "number" != typeof t ? p[2] : t, o = "number" != typeof o ? p[3] : o, r = "number" != typeof r ? p[4] : r, a = "number" != typeof a ? p[5] : a, "number" != typeof n ? p : (i._orientation = [n, e, t, o, r, a], i.ctx.listener.setOrientation(n, e, t, o, r, a), i) | |||||
}, Howl.prototype.init = function (n) { | |||||
return function (e) { | |||||
var t = this; | |||||
return t._orientation = e.orientation || [1, 0, 0], t._stereo = e.stereo || null, t._pos = e.pos || null, t._pannerAttr = { | |||||
coneInnerAngle: void 0 !== e.coneInnerAngle ? e.coneInnerAngle : 360, | |||||
coneOuterAngle: void 0 !== e.coneOuterAngle ? e.coneOuterAngle : 360, | |||||
coneOuterGain: void 0 !== e.coneOuterGain ? e.coneOuterGain : 0, | |||||
distanceModel: void 0 !== e.distanceModel ? e.distanceModel : "inverse", | |||||
maxDistance: void 0 !== e.maxDistance ? e.maxDistance : 1e4, | |||||
panningModel: void 0 !== e.panningModel ? e.panningModel : "HRTF", | |||||
refDistance: void 0 !== e.refDistance ? e.refDistance : 1, | |||||
rolloffFactor: void 0 !== e.rolloffFactor ? e.rolloffFactor : 1 | |||||
}, t._onstereo = e.onstereo ? [{ | |||||
fn: e.onstereo | |||||
}] : [], t._onpos = e.onpos ? [{ | |||||
fn: e.onpos | |||||
}] : [], t._onorientation = e.onorientation ? [{ | |||||
fn: e.onorientation | |||||
}] : [], n.call(this, e) | |||||
} | |||||
}(Howl.prototype.init), Howl.prototype.stereo = function (e, t) { | |||||
var o = this; | |||||
if (!o._webAudio) return o; | |||||
if ("loaded" !== o._state) return o._queue.push({ | |||||
event: "stereo", | |||||
action: function () { | |||||
o.stereo(e, t) | |||||
} | |||||
}), o; | |||||
var r = void 0 === Howler.ctx.createStereoPanner ? "spatial" : "stereo"; | |||||
if (void 0 === t) { | |||||
if ("number" != typeof e) return o._stereo; | |||||
o._stereo = e, o._pos = [e, 0, 0] | |||||
} | |||||
for (var a = o._getSoundIds(t), i = 0; i < a.length; i++) { | |||||
var p = o._soundById(a[i]); | |||||
if (p) { | |||||
if ("number" != typeof e) return p._stereo; | |||||
p._stereo = e, p._pos = [e, 0, 0], p._node && (p._pannerAttr.panningModel = "equalpower", p._panner && p._panner.pan || n(p, r), "spatial" === r ? p._panner.setPosition(e, 0, 0) : p._panner.pan.setValueAtTime(e, Howler.ctx.currentTime)), o._emit("stereo", p._id) | |||||
} | |||||
} | |||||
return o | |||||
}, Howl.prototype.pos = function (e, t, o, r) { | |||||
var a = this; | |||||
if (!a._webAudio) return a; | |||||
if ("loaded" !== a._state) return a._queue.push({ | |||||
event: "pos", | |||||
action: function () { | |||||
a.pos(e, t, o, r) | |||||
} | |||||
}), a; | |||||
if (t = "number" != typeof t ? 0 : t, o = "number" != typeof o ? -.5 : o, void 0 === r) { | |||||
if ("number" != typeof e) return a._pos; | |||||
a._pos = [e, t, o] | |||||
} | |||||
for (var i = a._getSoundIds(r), p = 0; p < i.length; p++) { | |||||
var s = a._soundById(i[p]); | |||||
if (s) { | |||||
if ("number" != typeof e) return s._pos; | |||||
s._pos = [e, t, o], s._node && (s._panner && !s._panner.pan || n(s, "spatial"), s._panner.setPosition(e, t, o)), a._emit("pos", s._id) | |||||
} | |||||
} | |||||
return a | |||||
}, Howl.prototype.orientation = function (e, t, o, r) { | |||||
var a = this; | |||||
if (!a._webAudio) return a; | |||||
if ("loaded" !== a._state) return a._queue.push({ | |||||
event: "orientation", | |||||
action: function () { | |||||
a.orientation(e, t, o, r) | |||||
} | |||||
}), a; | |||||
if (t = "number" != typeof t ? a._orientation[1] : t, o = "number" != typeof o ? a._orientation[2] : o, void 0 === r) { | |||||
if ("number" != typeof e) return a._orientation; | |||||
a._orientation = [e, t, o] | |||||
} | |||||
for (var i = a._getSoundIds(r), p = 0; p < i.length; p++) { | |||||
var s = a._soundById(i[p]); | |||||
if (s) { | |||||
if ("number" != typeof e) return s._orientation; | |||||
s._orientation = [e, t, o], s._node && (s._panner || (s._pos || (s._pos = a._pos || [0, 0, -.5]), n(s, "spatial")), s._panner.setOrientation(e, t, o)), a._emit("orientation", s._id) | |||||
} | |||||
} | |||||
return a | |||||
}, Howl.prototype.pannerAttr = function () { | |||||
var e, t, o, r = this, | |||||
a = arguments; | |||||
if (!r._webAudio) return r; | |||||
if (0 === a.length) return r._pannerAttr; | |||||
if (1 === a.length) { | |||||
if ("object" != typeof a[0]) return o = r._soundById(parseInt(a[0], 10)), o ? o._pannerAttr : r._pannerAttr; | |||||
e = a[0], void 0 === t && (e.pannerAttr || (e.pannerAttr = { | |||||
coneInnerAngle: e.coneInnerAngle, | |||||
coneOuterAngle: e.coneOuterAngle, | |||||
coneOuterGain: e.coneOuterGain, | |||||
distanceModel: e.distanceModel, | |||||
maxDistance: e.maxDistance, | |||||
refDistance: e.refDistance, | |||||
rolloffFactor: e.rolloffFactor, | |||||
panningModel: e.panningModel | |||||
}), r._pannerAttr = { | |||||
coneInnerAngle: void 0 !== e.pannerAttr.coneInnerAngle ? e.pannerAttr.coneInnerAngle : r._coneInnerAngle, | |||||
coneOuterAngle: void 0 !== e.pannerAttr.coneOuterAngle ? e.pannerAttr.coneOuterAngle : r._coneOuterAngle, | |||||
coneOuterGain: void 0 !== e.pannerAttr.coneOuterGain ? e.pannerAttr.coneOuterGain : r._coneOuterGain, | |||||
distanceModel: void 0 !== e.pannerAttr.distanceModel ? e.pannerAttr.distanceModel : r._distanceModel, | |||||
maxDistance: void 0 !== e.pannerAttr.maxDistance ? e.pannerAttr.maxDistance : r._maxDistance, | |||||
refDistance: void 0 !== e.pannerAttr.refDistance ? e.pannerAttr.refDistance : r._refDistance, | |||||
rolloffFactor: void 0 !== e.pannerAttr.rolloffFactor ? e.pannerAttr.rolloffFactor : r._rolloffFactor, | |||||
panningModel: void 0 !== e.pannerAttr.panningModel ? e.pannerAttr.panningModel : r._panningModel | |||||
}) | |||||
} else 2 === a.length && (e = a[0], t = parseInt(a[1], 10)); | |||||
for (var i = r._getSoundIds(t), p = 0; p < i.length; p++) | |||||
if (o = r._soundById(i[p])) { | |||||
var s = o._pannerAttr; | |||||
s = { | |||||
coneInnerAngle: void 0 !== e.coneInnerAngle ? e.coneInnerAngle : s.coneInnerAngle, | |||||
coneOuterAngle: void 0 !== e.coneOuterAngle ? e.coneOuterAngle : s.coneOuterAngle, | |||||
coneOuterGain: void 0 !== e.coneOuterGain ? e.coneOuterGain : s.coneOuterGain, | |||||
distanceModel: void 0 !== e.distanceModel ? e.distanceModel : s.distanceModel, | |||||
maxDistance: void 0 !== e.maxDistance ? e.maxDistance : s.maxDistance, | |||||
refDistance: void 0 !== e.refDistance ? e.refDistance : s.refDistance, | |||||
rolloffFactor: void 0 !== e.rolloffFactor ? e.rolloffFactor : s.rolloffFactor, | |||||
panningModel: void 0 !== e.panningModel ? e.panningModel : s.panningModel | |||||
}; | |||||
var l = o._panner; | |||||
l ? (l.coneInnerAngle = s.coneInnerAngle, l.coneOuterAngle = s.coneOuterAngle, l.coneOuterGain = s.coneOuterGain, l.distanceModel = s.distanceModel, l.maxDistance = s.maxDistance, l.refDistance = s.refDistance, l.rolloffFactor = s.rolloffFactor, l.panningModel = s.panningModel) : (o._pos || (o._pos = r._pos || [0, 0, -.5]), n(o, "spatial")) | |||||
} | |||||
return r | |||||
}, Sound.prototype.init = function (n) { | |||||
return function () { | |||||
var e = this, | |||||
t = e._parent; | |||||
e._orientation = t._orientation, e._stereo = t._stereo, e._pos = t._pos, e._pannerAttr = t._pannerAttr, n.call(this), e._stereo ? t.stereo(e._stereo) : e._pos && t.pos(e._pos[0], e._pos[1], e._pos[2], e._id) | |||||
} | |||||
}(Sound.prototype.init), Sound.prototype.reset = function (n) { | |||||
return function () { | |||||
var e = this, | |||||
t = e._parent; | |||||
return e._orientation = t._orientation, e._pos = t._pos, e._pannerAttr = t._pannerAttr, n.call(this) | |||||
} | |||||
}(Sound.prototype.reset); | |||||
var n = function (n, e) { | |||||
e = e || "spatial", "spatial" === e ? (n._panner = Howler.ctx.createPanner(), n._panner.coneInnerAngle = n._pannerAttr.coneInnerAngle, n._panner.coneOuterAngle = n._pannerAttr.coneOuterAngle, n._panner.coneOuterGain = n._pannerAttr.coneOuterGain, n._panner.distanceModel = n._pannerAttr.distanceModel, n._panner.maxDistance = n._pannerAttr.maxDistance, n._panner.refDistance = n._pannerAttr.refDistance, n._panner.rolloffFactor = n._pannerAttr.rolloffFactor, n._panner.panningModel = n._pannerAttr.panningModel, n._panner.setPosition(n._pos[0], n._pos[1], n._pos[2]), n._panner.setOrientation(n._orientation[0], n._orientation[1], n._orientation[2])) : (n._panner = Howler.ctx.createStereoPanner(), n._panner.pan.setValueAtTime(n._stereo, Howler.ctx.currentTime)), n._panner.connect(n._node), n._paused || n._parent.pause(n._id, !0).play(n._id, !0) | |||||
} | |||||
}(); |
@@ -14,6 +14,7 @@ define([ | |||||
events.on('onEnterGame', this.onEnterGame.bind(this)); | events.on('onEnterGame', this.onEnterGame.bind(this)); | ||||
events.on('onKeyDown', this.onKeyDown.bind(this)); | events.on('onKeyDown', this.onKeyDown.bind(this)); | ||||
events.on('onResize', this.onResize.bind(this)); | |||||
}, | }, | ||||
onEnterGame: function () { | onEnterGame: function () { | ||||
events.clearQueue(); | events.clearQueue(); | ||||
@@ -64,7 +65,6 @@ define([ | |||||
return; | return; | ||||
this.getTemplate(type, options); | this.getTemplate(type, options); | ||||
$(window).on('resize', this.onResize.bind(this)); | |||||
}, | }, | ||||
getTemplate: function (type, options) { | getTemplate: function (type, options) { | ||||
require([this.root + 'ui/templates/' + type + '/' + type], this.onGetTemplate.bind(this, options)); | require([this.root + 'ui/templates/' + type + '/' + type], this.onGetTemplate.bind(this, options)); | ||||
@@ -82,7 +82,7 @@ define([ | |||||
.forEach(function (c, i) { | .forEach(function (c, i) { | ||||
var name = c.name; | var name = c.name; | ||||
if (c.level != null) | if (c.level != null) | ||||
name += '<font class="q2"> (' + c.level + ')</font>' | |||||
name += '<font class="color-yellowB"> (' + c.level + ')</font>' | |||||
var html = templateListItem | var html = templateListItem | ||||
.replace('$NAME$', name); | .replace('$NAME$', name); | ||||
@@ -167,7 +167,6 @@ define([ | |||||
var el = $(e.target); | var el = $(e.target); | ||||
var classes = ['owl', 'bear', 'lynx']; | var classes = ['owl', 'bear', 'lynx']; | ||||
var nextIndex = (classes.indexOf(this.class) + 1) % classes.length; | var nextIndex = (classes.indexOf(this.class) + 1) % classes.length; | ||||
this.costume = -1; | |||||
var newClass = classes[nextIndex]; | var newClass = classes[nextIndex]; | ||||
@@ -3,7 +3,7 @@ define([ | |||||
'js/system/client', | 'js/system/client', | ||||
'html!ui/templates/death/template', | 'html!ui/templates/death/template', | ||||
'css!ui/templates/death/styles' | 'css!ui/templates/death/styles' | ||||
], function( | |||||
], function ( | |||||
events, | events, | ||||
client, | client, | ||||
template, | template, | ||||
@@ -15,7 +15,7 @@ define([ | |||||
modal: true, | modal: true, | ||||
centered: true, | centered: true, | ||||
postRender: function() { | |||||
postRender: function () { | |||||
this.onEvent('onDeath', this.onDeath.bind(this)); | this.onEvent('onDeath', this.onDeath.bind(this)); | ||||
this.onEvent('onPermadeath', this.onPermadeath.bind(this)); | this.onEvent('onPermadeath', this.onPermadeath.bind(this)); | ||||
@@ -23,30 +23,49 @@ define([ | |||||
this.find('.btn-respawn').on('click', this.onRespawn.bind(this)); | this.find('.btn-respawn').on('click', this.onRespawn.bind(this)); | ||||
}, | }, | ||||
onLogout: function() { | |||||
onLogout: function () { | |||||
$('.uiOptions').data('ui').charSelect(); | $('.uiOptions').data('ui').charSelect(); | ||||
}, | }, | ||||
onRespawn: function() { | |||||
onRespawn: function () { | |||||
events.emit('onHideOverlay', this.el); | events.emit('onHideOverlay', this.el); | ||||
this.hide(); | this.hide(); | ||||
client.request({ | |||||
cpn: 'player', | |||||
method: 'performAction', | |||||
data: { | |||||
cpn: 'stats', | |||||
method: 'respawn' | |||||
} | |||||
}); | |||||
}, | }, | ||||
doShow: function() { | |||||
doShow: function () { | |||||
this.show(); | this.show(); | ||||
events.emit('onShowOverlay', this.el); | events.emit('onShowOverlay', this.el); | ||||
}, | }, | ||||
onDeath: function(event) { | |||||
this.find('.msg').html('you were killed by [ <div class="inner">' + event.source + '</div> ]'); | |||||
onDeath: function (event) { | |||||
if (!event.source) { | |||||
this.find('.msg').html('you are dead'); | |||||
} else | |||||
this.find('.msg').html('you were killed by [ <div class="inner">' + event.source + '</div> ]'); | |||||
this.find('.penalty') | |||||
.html('you lost ' + event.xpLoss + ' experience') | |||||
.show(); | |||||
if (!event.xpLoss) | |||||
this.find('.penalty').hide(); | |||||
this.el.removeClass('permadeath'); | this.el.removeClass('permadeath'); | ||||
this.doShow(); | this.doShow(); | ||||
}, | }, | ||||
onPermadeath: function(event) { | |||||
onPermadeath: function (event) { | |||||
this.find('.msg').html('you were killed by [ <div class="inner">' + event.source + '</div> ]'); | this.find('.msg').html('you were killed by [ <div class="inner">' + event.source + '</div> ]'); | ||||
this.el.addClass('permadeath'); | this.el.addClass('permadeath'); | ||||
this.doShow(); | this.doShow(); | ||||
} | } | ||||
}; | }; | ||||
}); | |||||
}); |
@@ -18,6 +18,11 @@ | |||||
} | } | ||||
} | } | ||||
.penalty { | |||||
color: @yellowB; | |||||
margin-top: 15px; | |||||
} | |||||
.btn { | .btn { | ||||
color: @white; | color: @white; | ||||
width: 100%; | width: 100%; | ||||
@@ -50,4 +55,4 @@ | |||||
display: none; | display: none; | ||||
} | } | ||||
} | } | ||||
} | |||||
} |
@@ -1,7 +1,8 @@ | |||||
<div class="uiDeath"> | <div class="uiDeath"> | ||||
<div class="msg"></div> | <div class="msg"></div> | ||||
<div class="penalty"></div> | |||||
<div class="buttons"> | <div class="buttons"> | ||||
<div class="btn btn-respawn">respawn</div> | <div class="btn btn-respawn">respawn</div> | ||||
<div class="btn btn-logout">log out</div> | <div class="btn btn-logout">log out</div> | ||||
</div> | </div> | ||||
</div> | |||||
</div> |
@@ -336,8 +336,12 @@ define([ | |||||
vit: stats.vit | vit: stats.vit | ||||
}, | }, | ||||
offense: { | offense: { | ||||
'crit chance': (~~(stats.critChance * 10) / 10) + '%', | |||||
'crit multiplier': (~~(stats.critMultiplier * 10) / 10) + '%', | |||||
'global crit chance': (~~(stats.critChance * 10) / 10) + '%', | |||||
'global crit multiplier': (~~(stats.critMultiplier * 10) / 10) + '%', | |||||
'attack crit chance': (~~((stats.critChance + stats.attackCritChance) * 10) / 10) + '%', | |||||
'attack crit multiplier': (~~((stats.critMultiplier + stats.attackCritMultiplier) * 10) / 10) + '%', | |||||
'spell crit chance': (~~((stats.critChance + stats.spellCritChance) * 10) / 10) + '%', | |||||
'spell crit multiplier': (~~((stats.critMultiplier + stats.spellCritMultiplier) * 10) / 10) + '%', | |||||
gap1: '', | gap1: '', | ||||
'arcane increase': stats.elementArcanePercent + '%', | 'arcane increase': stats.elementArcanePercent + '%', | ||||
'fire increase': stats.elementFirePercent + '%', | 'fire increase': stats.elementFirePercent + '%', | ||||
@@ -355,12 +359,15 @@ define([ | |||||
'chance to block attacks': stats.blockAttackChance + '%', | 'chance to block attacks': stats.blockAttackChance + '%', | ||||
'chance to block spells': stats.blockSpellChance + '%', | 'chance to block spells': stats.blockSpellChance + '%', | ||||
gap1: '', | gap1: '', | ||||
'chance to dodge attacks': (~~(stats.dodgeAttackChance * 10) / 10) + '%', | |||||
'chance to dodge spells': (~~(stats.dodgeSpellChance * 10) / 10) + '%', | |||||
gap2: '', | |||||
'arcane resist': stats.elementArcaneResist, | 'arcane resist': stats.elementArcaneResist, | ||||
'fire resist': stats.elementFireResist, | 'fire resist': stats.elementFireResist, | ||||
'frost resist': stats.elementFrostResist, | 'frost resist': stats.elementFrostResist, | ||||
'holy resist': stats.elementHolyResist, | 'holy resist': stats.elementHolyResist, | ||||
'poison resist': stats.elementPoisonResist, | 'poison resist': stats.elementPoisonResist, | ||||
gap2: '', | |||||
gap3: '', | |||||
'all resist': stats.elementAllResist | 'all resist': stats.elementAllResist | ||||
}, | }, | ||||
misc: { | misc: { | ||||
@@ -5,7 +5,7 @@ | |||||
<div class="row"><span class="topic">Chat: </span><br />Press Enter to open the chat window</div> | <div class="row"><span class="topic">Chat: </span><br />Press Enter to open the chat window</div> | ||||
<div class="row"><span class="topic">Inventory: </span><br />Press i to open your inventory</div> | <div class="row"><span class="topic">Inventory: </span><br />Press i to open your inventory</div> | ||||
<div class="row"><span class="topic">Equipment: </span><br />Right click an item in your inventory to equip it or press j for the equipment panel</div> | <div class="row"><span class="topic">Equipment: </span><br />Right click an item in your inventory to equip it or press j for the equipment panel</div> | ||||
<div class="row"><span class="topic">Stats: </span><br />Wizards and Clerics need Int to deal more damage. Thieves need Dex and Warriors need Str. Necromancers need Int and Str</div> | |||||
<div class="row"><span class="topic">Stats: </span><br />Owl Spirits need Int to deal more damage. Lynxes need Dex and Bears need Str.</div> | |||||
<div class="row"><span class="topic">Show Nameplates: </span><br />V</div> | <div class="row"><span class="topic">Show Nameplates: </span><br />V</div> | ||||
<div class="row"><span class="topic">Who's Online: </span><br />O</div> | <div class="row"><span class="topic">Who's Online: </span><br />O</div> | ||||
</div> | |||||
</div> |
@@ -54,7 +54,7 @@ define([ | |||||
boxes.eq(1).find('.text').html(Math.floor(stats.mana) + '/' + ~~stats.manaMax); | boxes.eq(1).find('.text').html(Math.floor(stats.mana) + '/' + ~~stats.manaMax); | ||||
var level = stats.level; | var level = stats.level; | ||||
if (stats.originalLevel) | |||||
if ((stats.originalLevel) && (stats.originalLevel != level)) | |||||
level = stats.originalLevel + ' (' + stats.level + ')'; | level = stats.originalLevel + ' (' + stats.level + ')'; | ||||
boxes.eq(2).find('.text').html('level: ' + level); | boxes.eq(2).find('.text').html('level: ' + level); | ||||
@@ -66,9 +66,14 @@ define([ | |||||
.on('mousemove', this.onMouseMove.bind(this)) | .on('mousemove', this.onMouseMove.bind(this)) | ||||
.on('mouseleave', this.onMouseDown.bind(this, null, null, false)); | .on('mouseleave', this.onMouseDown.bind(this, null, null, false)); | ||||
this.find('.split-box .amount').on('mousewheel', this.onChangeStackAmount.bind(this)); | |||||
this.find('.split-box .amount') | |||||
.on('mousewheel', this.onChangeStackAmount.bind(this)) | |||||
.on('input', this.onEnterStackAmount.bind(this)); | |||||
this.find('.split-box').on('click', this.splitStackEnd.bind(this, true)); | this.find('.split-box').on('click', this.splitStackEnd.bind(this, true)); | ||||
this.find('.split-box .button').on('click', this.splitStackEnd.bind(this)); | |||||
this.find('.split-box .btnSplit').on('click', this.splitStackEnd.bind(this, null)); | |||||
this.find('.split-box .btnLess').on('click', this.onChangeStackAmount.bind(this, null, -1)); | |||||
this.find('.split-box .btnMore').on('click', this.onChangeStackAmount.bind(this, null, 1)); | |||||
}, | }, | ||||
build: function () { | build: function () { | ||||
@@ -367,14 +372,20 @@ define([ | |||||
var box = this.find('.split-box').show(); | var box = this.find('.split-box').show(); | ||||
box.data('item', item); | box.data('item', item); | ||||
box.find('.amount').html(1); | |||||
box.find('.amount') | |||||
.val('1') | |||||
.focus(); | |||||
}, | }, | ||||
splitStackEnd: function (cancel, e) { | splitStackEnd: function (cancel, e) { | ||||
var box = this.find('.split-box'); | var box = this.find('.split-box'); | ||||
if ((!e) || (e.target != box.find('.button')[0])) | |||||
if ((cancel) || (!e) || (e.target != box.find('.btnSplit')[0])) { | |||||
if ((cancel) && (!$(e.target).hasClass('button'))) | |||||
box.hide(); | |||||
return; | return; | ||||
} | |||||
box.hide(); | box.hide(); | ||||
@@ -386,20 +397,36 @@ define([ | |||||
method: 'splitStack', | method: 'splitStack', | ||||
data: { | data: { | ||||
itemId: box.data('item').id, | itemId: box.data('item').id, | ||||
stackSize: ~~this.find('.split-box .amount').html() | |||||
stackSize: ~~this.find('.split-box .amount').val() | |||||
} | } | ||||
} | } | ||||
}); | }); | ||||
}, | }, | ||||
onChangeStackAmount: function (e) { | |||||
onChangeStackAmount: function (e, amount) { | |||||
var item = this.find('.split-box').data('item'); | var item = this.find('.split-box').data('item'); | ||||
var delta = (e.originalEvent.deltaY > 0) ? -1 : 1; | |||||
var delta = e ? ((e.originalEvent.deltaY > 0) ? -1 : 1) : amount; | |||||
if (this.shiftDown) | if (this.shiftDown) | ||||
delta *= 10; | delta *= 10; | ||||
var amount = this.find('.split-box .amount'); | var amount = this.find('.split-box .amount'); | ||||
amount.html(Math.max(1, Math.min(item.quantity - 1, ~~amount.html() + delta))); | |||||
amount.val(Math.max(1, Math.min(item.quantity - 1, ~~amount.val() + delta))); | |||||
}, | |||||
onEnterStackAmount: function (e) { | |||||
var el = this.find('.split-box .amount'); | |||||
var val = el.val(); | |||||
if (val != ~~val) | |||||
el.val(''); | |||||
else if (val) { | |||||
var item = this.find('.split-box').data('item'); | |||||
if (val < 0) | |||||
val = ''; | |||||
else if (val > item.quantity - 1) | |||||
val = item.quantity - 1; | |||||
el.val(val); | |||||
} | |||||
}, | }, | ||||
hideTooltip: function () { | hideTooltip: function () { | ||||
@@ -448,6 +475,62 @@ define([ | |||||
compare = this.items.find(function (i) { | compare = this.items.find(function (i) { | ||||
return ((i.eq) && (i.slot == item.slot)); | return ((i.eq) && (i.slot == item.slot)); | ||||
}); | }); | ||||
// check special cases for mismatched weapon/offhand scenarios (only valid when comparing) | |||||
if ((!compare) && (this.shiftDown)) { | |||||
var equippedTwoHanded = this.items.find(function (i) { | |||||
return ((i.eq) && (i.slot == 'twoHanded')); | |||||
}); | |||||
var equippedOneHanded = this.items.find(function (i) { | |||||
return ((i.eq) && (i.slot == 'oneHanded')); | |||||
}); | |||||
var equippedOffhand = this.items.find(function (i) { | |||||
return ((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 (var s in equippedOffhand.stats) { | |||||
if (!compare.stats[s]) | |||||
compare.stats[s] = 0; | |||||
compare.stats[s] += equippedOffhand.stats[s] | |||||
} | |||||
} | |||||
} | |||||
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)) { | |||||
// 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 | |||||
var spellClone = $.extend(true, {}, equippedTwoHanded.spell); | |||||
spellClone.name = ''; | |||||
spellClone.values['damage'] = 0; | |||||
var clone = $.extend(true, {}, item, { | |||||
spell: spellClone | |||||
}); | |||||
clone.refItem = item; | |||||
item = clone; | |||||
compare = equippedTwoHanded; | |||||
} | |||||
} | |||||
} | } | ||||
events.emit('onShowItemTooltip', item, ttPos, compare, false, this.shiftDown); | events.emit('onShowItemTooltip', item, ttPos, compare, false, this.shiftDown); | ||||
@@ -506,18 +589,12 @@ define([ | |||||
if (!item) | if (!item) | ||||
return; | 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; | return; | ||||
else if ((action == 'learnAbility') && (item.level > playerLevel)) | |||||
else if ((action == 'learnAbility') && (!window.player.inventory.canEquipItem(item))) | |||||
return; | return; | ||||
else if ((action == 'activateMtx') && (item.type != 'mtx')) | else if ((action == 'activateMtx') && (item.type != 'mtx')) | ||||
return; | return; | ||||
if ((item.factions) && (action == 'equip')) { | |||||
if (item.factions.some(function (f) { | |||||
return f.noEquip; | |||||
})) | |||||
return; | |||||
} | |||||
var cpn = 'inventory'; | var cpn = 'inventory'; | ||||
if (action == 'equip') | if (action == 'equip') | ||||
@@ -133,7 +133,7 @@ | |||||
top: 50%; | top: 50%; | ||||
transform: translate(-50%, -50%); | transform: translate(-50%, -50%); | ||||
width: 200px; | width: 200px; | ||||
height: 143px; | |||||
height: 147px; | |||||
> .heading { | > .heading { | ||||
color: @blueA; | color: @blueA; | ||||
@@ -153,23 +153,46 @@ | |||||
padding: 10px; | padding: 10px; | ||||
.amount { | .amount { | ||||
float: left; | |||||
color: @white; | color: @white; | ||||
text-align: center; | text-align: center; | ||||
width: 100%; | |||||
width: calc(100% - 80px); | |||||
height: 36px; | height: 36px; | ||||
padding-top: 8px; | |||||
padding-top: 3px; | |||||
border: none; | |||||
} | |||||
input, .textbox, input:-webkit-autofill { | |||||
color: @white; | |||||
-webkit-text-fill-color: @white; | |||||
background-color: @blackC; | |||||
} | } | ||||
.button { | .button { | ||||
width: 100%; | width: 100%; | ||||
height: 36px; | height: 36px; | ||||
margin-top: 5px; | |||||
background-color: @blueC; | background-color: @blueC; | ||||
color: @white; | color: @white; | ||||
&:hover { | &:hover { | ||||
background-color: @blueB; | background-color: @blueB; | ||||
} | } | ||||
&:not(.btnSplit) { | |||||
width: 40px; | |||||
float: left; | |||||
color: @white; | |||||
background-color: @blackB; | |||||
&:hover { | |||||
background-color: @blackA; | |||||
} | |||||
} | |||||
&.btnSplit { | |||||
margin-top: 45px; | |||||
clear: both; | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -13,8 +13,10 @@ | |||||
<div class="heading-text">stack size</div> | <div class="heading-text">stack size</div> | ||||
</div> | </div> | ||||
<div class="bottom"> | <div class="bottom"> | ||||
<div class="amount"></div> | |||||
<div class="button">split</div> | |||||
<div class="button btnLess">-</div> | |||||
<input type="text" class="textbox amount"> | |||||
<div class="button btnMore">+</div> | |||||
<div class="button btnSplit">split</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -48,7 +48,7 @@ define([ | |||||
else if (this.offset > this.maxOffset) | else if (this.offset > this.maxOffset) | ||||
this.offset = this.maxOffset; | this.offset = this.maxOffset; | ||||
this.onGetList(this.records, true); | |||||
this.getList(true); | |||||
}, | }, | ||||
onMine: function () { | onMine: function () { | ||||
@@ -90,7 +90,9 @@ define([ | |||||
this.prophecyFilter.push(prophecyName); | this.prophecyFilter.push(prophecyName); | ||||
}, | }, | ||||
getList: function () { | |||||
getList: function (keepOffset) { | |||||
this.el.addClass('disabled'); | |||||
if (!this.prophecyFilter) { | if (!this.prophecyFilter) { | ||||
var prophecies = window.player.prophecies; | var prophecies = window.player.prophecies; | ||||
this.prophecyFilter = prophecies ? prophecies.list : []; | this.prophecyFilter = prophecies ? prophecies.list : []; | ||||
@@ -101,34 +103,34 @@ define([ | |||||
module: 'leaderboard', | module: 'leaderboard', | ||||
method: 'requestList', | method: 'requestList', | ||||
data: { | data: { | ||||
prophecies: this.prophecyFilter | |||||
prophecies: this.prophecyFilter, | |||||
offset: this.offset * this.pageSize | |||||
}, | }, | ||||
callback: this.onGetList.bind(this) | |||||
callback: this.onGetList.bind(this, keepOffset) | |||||
}); | }); | ||||
}, | }, | ||||
onGetList: function (result, keepOffset) { | |||||
onGetList: function (keepOffset, result) { | |||||
this.records = result; | |||||
if (!keepOffset) { | if (!keepOffset) { | ||||
this.offset = 0; | this.offset = 0; | ||||
var foundIndex = result.firstIndex(function (r) { | |||||
var foundIndex = this.records.list.firstIndex(function (r) { | |||||
return (r.name == window.player.name); | return (r.name == window.player.name); | ||||
}, this); | }, this); | ||||
if (foundIndex != -1) | if (foundIndex != -1) | ||||
this.offset = ~~(foundIndex / this.pageSize); | this.offset = ~~(foundIndex / this.pageSize); | ||||
} | } | ||||
this.records = result; | |||||
var container = this.find('.list').empty(); | var container = this.find('.list').empty(); | ||||
var low = this.offset * this.pageSize; | var low = this.offset * this.pageSize; | ||||
var high = Math.min(result.length, low + this.pageSize); | var high = Math.min(result.length, low + this.pageSize); | ||||
this.maxOffset = Math.ceil(result.length / this.pageSize) - 1; | this.maxOffset = Math.ceil(result.length / this.pageSize) - 1; | ||||
for (var i = low; i < high; i++) { | |||||
var r = result[i]; | |||||
for (var i = 0; i < this.records.list.length; i++) { | |||||
var r = this.records.list[i]; | |||||
var html = '<div class="row"><div class="col">' + r.level + '</div><div class="col">' + r.name + '</div></div>'; | var html = '<div class="row"><div class="col">' + r.level + '</div><div class="col">' + r.name + '</div></div>'; | ||||
var el = $(html) | var el = $(html) | ||||
@@ -149,6 +151,8 @@ define([ | |||||
} | } | ||||
this.updatePaging(); | this.updatePaging(); | ||||
this.el.removeClass('disabled'); | |||||
}, | }, | ||||
updatePaging: function () { | updatePaging: function () { | ||||
@@ -11,11 +11,11 @@ | |||||
</div> | </div> | ||||
<div class="message"></div> | <div class="message"></div> | ||||
</div> | </div> | ||||
<div class="news" location="https://gitlab.com/Isleward/isleward/issues/477">[ Test server issues ]</div> | |||||
<div class="news" location="https://gitlab.com/Isleward/isleward/tags/v0.1.11">[ Latest Release Notes ]</div> | |||||
<div class="extra"> | <div class="extra"> | ||||
<div class="el button btnPatreon" location="http://patreon.com/bigbadwaffle">Pledge on Patreon</div> | |||||
<div class="el button btnPatreon" location="https://patreon.com/bigbadwaffle">Pledge on Patreon</div> | |||||
<div class="el button btnPaypal" location="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=BR2CC82WUAVEA">Donate on Paypal</div> | <div class="el button btnPaypal" location="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=BR2CC82WUAVEA">Donate on Paypal</div> | ||||
<div class="el button btnWiki" location="http://wiki.isleward.com/Main_Page">Access the Wiki</div> | <div class="el button btnWiki" location="http://wiki.isleward.com/Main_Page">Access the Wiki</div> | ||||
</div> | </div> | ||||
<div class="version" location="https://gitlab.com/Isleward/isleward/issues/418">v0.1.10</div> | |||||
<div class="version" location="https://gitlab.com/Isleward/isleward/tags/v0.1.11">v0.1.11</div> | |||||
</div> | </div> |
@@ -213,13 +213,13 @@ define([ | |||||
var textbox = this.find('input'); | var textbox = this.find('input'); | ||||
var val = textbox.val() | var val = textbox.val() | ||||
.split('<') | .split('<') | ||||
.join('') | |||||
.join('<') | |||||
.split('>') | .split('>') | ||||
.join(''); | |||||
.join('>'); | |||||
textbox.blur(); | textbox.blur(); | ||||
if (val == '') | |||||
if (val.trim() == '') | |||||
return; | return; | ||||
client.request({ | client.request({ | ||||
@@ -107,11 +107,11 @@ | |||||
} | } | ||||
&.q1 { | &.q1 { | ||||
color: @blue; | |||||
color: @greenB; | |||||
} | } | ||||
a, &.q2 { | a, &.q2 { | ||||
color: @yellow; | |||||
color: @blueB; | |||||
} | } | ||||
&.q3 { | &.q3 { | ||||
@@ -6,7 +6,7 @@ define([ | |||||
'ui/factory', | 'ui/factory', | ||||
'js/objects/objects', | 'js/objects/objects', | ||||
'js/system/client' | 'js/system/client' | ||||
], function( | |||||
], function ( | |||||
events, | events, | ||||
template, | template, | ||||
styles, | styles, | ||||
@@ -21,7 +21,7 @@ define([ | |||||
modal: true, | modal: true, | ||||
postRender: function() { | |||||
postRender: function () { | |||||
//this.onEvent('onKeyDown', this.onKeyDown.bind(this)); | //this.onEvent('onKeyDown', this.onKeyDown.bind(this)); | ||||
this.onEvent('onToggleOptions', this.toggle.bind(this)); | this.onEvent('onToggleOptions', this.toggle.bind(this)); | ||||
@@ -30,15 +30,20 @@ define([ | |||||
this.el.find('.btnLogOut').on('click', this.logOut.bind(this)); | this.el.find('.btnLogOut').on('click', this.logOut.bind(this)); | ||||
this.el.find('.btnContinue').on('click', this.toggle.bind(this)); | this.el.find('.btnContinue').on('click', this.toggle.bind(this)); | ||||
this.el.find('.btnPatreon').on('click', this.patreon.bind(this)); | this.el.find('.btnPatreon').on('click', this.patreon.bind(this)); | ||||
this.el.find('.btnIssue').on('click', this.reportIssue.bind(this)); | |||||
this.onEvent('onResize', this.onResize.bind(this)); | this.onEvent('onResize', this.onResize.bind(this)); | ||||
}, | }, | ||||
reportIssue: function () { | |||||
window.open('https://gitlab.com/Isleward/isleward/issues/new', '_blank'); | |||||
}, | |||||
patreon: function() { | |||||
window.open('http://patreon.com/bigbadwaffle', '_blank'); | |||||
patreon: function () { | |||||
window.open('https://patreon.com/bigbadwaffle', '_blank'); | |||||
}, | }, | ||||
charSelect: function() { | |||||
charSelect: function () { | |||||
client.request({ | client.request({ | ||||
module: 'cons', | module: 'cons', | ||||
method: 'unzone' | method: 'unzone' | ||||
@@ -49,7 +54,7 @@ define([ | |||||
renderer.buildTitleScreen(); | renderer.buildTitleScreen(); | ||||
events.emit('onShowCharacterSelect'); | events.emit('onShowCharacterSelect'); | ||||
$('[class^="ui"]:not(.ui-container)').each(function(i, el) { | |||||
$('[class^="ui"]:not(.ui-container)').each(function (i, el) { | |||||
var ui = $(el).data('ui'); | var ui = $(el).data('ui'); | ||||
if ((ui) && (ui.destroy)) | if ((ui) && (ui.destroy)) | ||||
ui.destroy(); | ui.destroy(); | ||||
@@ -57,11 +62,11 @@ define([ | |||||
factory.build('characters', {}); | factory.build('characters', {}); | ||||
}, | }, | ||||
toggleScreen: function() { | |||||
toggleScreen: function () { | |||||
this.el.find('.btnScreen').html(renderer.toggleScreen()); | this.el.find('.btnScreen').html(renderer.toggleScreen()); | ||||
}, | }, | ||||
onResize: function() { | |||||
onResize: function () { | |||||
var isFullscreen = (window.innerHeight == screen.height); | var isFullscreen = (window.innerHeight == screen.height); | ||||
if (isFullscreen) | if (isFullscreen) | ||||
this.el.find('.btnScreen').html('Windowed'); | this.el.find('.btnScreen').html('Windowed'); | ||||
@@ -69,28 +74,27 @@ define([ | |||||
this.el.find('.btnScreen').html('Fullscreen'); | this.el.find('.btnScreen').html('Fullscreen'); | ||||
}, | }, | ||||
toggle: function() { | |||||
toggle: function () { | |||||
this.onResize(); | this.onResize(); | ||||
this.shown = !this.el.is(':visible'); | this.shown = !this.el.is(':visible'); | ||||
if (this.shown) { | if (this.shown) { | ||||
this.show(); | this.show(); | ||||
events.emit('onShowOverlay', this.el); | events.emit('onShowOverlay', this.el); | ||||
} | |||||
else { | |||||
} else { | |||||
this.hide(); | this.hide(); | ||||
events.emit('onHideOverlay', this.el); | events.emit('onHideOverlay', this.el); | ||||
} | } | ||||
}, | }, | ||||
logOut: function() { | |||||
logOut: function () { | |||||
window.location = window.location; | window.location = window.location; | ||||
}, | }, | ||||
onKeyDown: function(key) { | |||||
onKeyDown: function (key) { | |||||
if (key == 'esc') | if (key == 'esc') | ||||
this.toggle(); | this.toggle(); | ||||
} | } | ||||
} | } | ||||
}); | |||||
}); |
@@ -23,4 +23,13 @@ | |||||
color: @black; | color: @black; | ||||
} | } | ||||
} | } | ||||
.btnIssue { | |||||
background-color: @red; | |||||
&:hover { | |||||
background-color: lighten(@red, 15%); | |||||
color: @black; | |||||
} | |||||
} | |||||
} | } |
@@ -4,4 +4,5 @@ | |||||
<div class="btn btnCharSelect">Character Select</div> | <div class="btn btnCharSelect">Character Select</div> | ||||
<div class="btn btnLogOut">Log Out</div> | <div class="btn btnLogOut">Log Out</div> | ||||
<div class="btn btnPatreon">Pledge on Patreon</div> | <div class="btn btnPatreon">Pledge on Patreon</div> | ||||
<div class="btn btnIssue">Report an Issue</div> | |||||
</div> | </div> |
@@ -7,7 +7,7 @@ | |||||
.party { | .party { | ||||
position: absolute; | position: absolute; | ||||
left: 16px; | left: 16px; | ||||
top: 104px; | |||||
top: 154px; | |||||
.member { | .member { | ||||
width: 160px; | width: 160px; | ||||
@@ -94,41 +94,51 @@ | |||||
.invite { | .invite { | ||||
position: absolute; | position: absolute; | ||||
right: 10px; | |||||
bottom: 164px; | |||||
right: 356px; | |||||
bottom: 10px; | |||||
height: 144px; | |||||
background-color: @gray; | |||||
border: 4px solid @lightGray; | |||||
background-color: fade(@darkGray, 90%); | |||||
padding: 8px; | padding: 8px; | ||||
color: @white; | color: @white; | ||||
.text { | .text { | ||||
height: 16px; | |||||
margin-bottom: 16px; | margin-bottom: 16px; | ||||
text-align: center; | |||||
> * { | |||||
display: block; | |||||
width: 100%; | |||||
} | |||||
.name { | |||||
margin-top: 10px; | |||||
margin-bottom: -4px; | |||||
} | |||||
} | } | ||||
.buttons { | .buttons { | ||||
[class^='btn'] { | [class^='btn'] { | ||||
width: 96px; | |||||
background-color: @lightGray; | |||||
width: 100%; | |||||
background-color: @blackA; | |||||
text-align: center; | text-align: center; | ||||
padding: 8px; | padding: 8px; | ||||
cursor: pointer; | cursor: pointer; | ||||
&:hover { | |||||
background-color: lighten(@lightGray, 20%); | |||||
color: @black; | |||||
} | |||||
color: @white; | |||||
&.btnDecline { | &.btnDecline { | ||||
float: left; | |||||
} | } | ||||
&.btnAccept { | &.btnAccept { | ||||
float: right; | |||||
margin-bottom: 10px; | |||||
} | |||||
&:hover { | |||||
background-color: @grayD; | |||||
color: @black; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | |||||
} |
@@ -1,9 +1,10 @@ | |||||
<div class="invite"> | <div class="invite"> | ||||
<div class="text"> | <div class="text"> | ||||
$NAME$ invited you to a party | |||||
<span class="color-yellowB">party invite</span> | |||||
<span class="name">$NAME$</span> | |||||
</div> | </div> | ||||
<div class="buttons"> | <div class="buttons"> | ||||
<div class="btnDecline">Decline</div> | |||||
<div class="btnAccept">Accept</div> | <div class="btnAccept">Accept</div> | ||||
<div class="btnDecline">Decline</div> | |||||
</div> | </div> | ||||
</div> | |||||
</div> |
@@ -4,7 +4,7 @@ define([ | |||||
'html!ui/templates/quests/template', | 'html!ui/templates/quests/template', | ||||
'html!ui/templates/quests/templateQuest', | 'html!ui/templates/quests/templateQuest', | ||||
'css!ui/templates/quests/styles' | 'css!ui/templates/quests/styles' | ||||
], function( | |||||
], function ( | |||||
client, | client, | ||||
events, | events, | ||||
tpl, | tpl, | ||||
@@ -17,7 +17,7 @@ define([ | |||||
quests: [], | quests: [], | ||||
container: '.right', | container: '.right', | ||||
postRender: function() { | |||||
postRender: function () { | |||||
this.onEvent('onRezone', this.onRezone.bind(this)); | this.onEvent('onRezone', this.onRezone.bind(this)); | ||||
this.onEvent('onObtainQuest', this.onObtainQuest.bind(this)); | this.onEvent('onObtainQuest', this.onObtainQuest.bind(this)); | ||||
@@ -25,24 +25,27 @@ define([ | |||||
this.onEvent('onCompleteQuest', this.onCompleteQuest.bind(this)); | this.onEvent('onCompleteQuest', this.onCompleteQuest.bind(this)); | ||||
}, | }, | ||||
onRezone: function() { | |||||
onRezone: function () { | |||||
this.quests = []; | this.quests = []; | ||||
this.el.find('.list').empty(); | this.el.find('.list').empty(); | ||||
}, | }, | ||||
onObtainQuest: function(quest) { | |||||
onObtainQuest: function (quest) { | |||||
var list = this.el.find('.list'); | var list = this.el.find('.list'); | ||||
var html = templateQuest | var html = templateQuest | ||||
.replace('$ZONE$', quest.zoneName) | |||||
.replace('$NAME$', quest.name) | .replace('$NAME$', quest.name) | ||||
.replace('$DESCRIPTION$', quest.description); | |||||
.replace('$DESCRIPTION$', quest.description) | |||||
.replace('$REWARD$', quest.xp + ' xp'); | |||||
var el = $(html).appendTo(list); | |||||
var el = $(html) | |||||
.appendTo(list); | |||||
if (quest.isReady) | if (quest.isReady) | ||||
el.addClass('ready'); | el.addClass('ready'); | ||||
if (quest.active) | |||||
if (quest.active) | |||||
el.addClass('active'); | el.addClass('active'); | ||||
else if (!quest.isReady) | else if (!quest.isReady) | ||||
el.addClass('disabled'); | el.addClass('disabled'); | ||||
@@ -58,7 +61,7 @@ define([ | |||||
var quests = list.find('.quest'); | var quests = list.find('.quest'); | ||||
quests | quests | ||||
.sort(function(a, b) { | |||||
.sort(function (a, b) { | |||||
a = $(a).hasClass('active') ? 1 : 0; | a = $(a).hasClass('active') ? 1 : 0; | ||||
b = $(b).hasClass('active') ? 1 : 0; | b = $(b).hasClass('active') ? 1 : 0; | ||||
return b - a; | return b - a; | ||||
@@ -66,8 +69,7 @@ define([ | |||||
.appendTo(list); | .appendTo(list); | ||||
}, | }, | ||||
onClick: function(el, quest) { | |||||
onClick: function (el, quest) { | |||||
if (!el.hasClass('ready')) | if (!el.hasClass('ready')) | ||||
return; | return; | ||||
@@ -82,8 +84,8 @@ define([ | |||||
}); | }); | ||||
}, | }, | ||||
onUpdateQuest: function(quest) { | |||||
var q = this.quests.find(function(q) { | |||||
onUpdateQuest: function (quest) { | |||||
var q = this.quests.find(function (q) { | |||||
return (q.id == quest.id); | return (q.id == quest.id); | ||||
}); | }); | ||||
@@ -98,8 +100,8 @@ define([ | |||||
} | } | ||||
}, | }, | ||||
onCompleteQuest: function(id) { | |||||
var q = this.quests.find(function(q) { | |||||
onCompleteQuest: function (id) { | |||||
var q = this.quests.find(function (q) { | |||||
return (q.id == id); | return (q.id == id); | ||||
}); | }); | ||||
@@ -107,9 +109,9 @@ define([ | |||||
return; | return; | ||||
q.el.remove(); | q.el.remove(); | ||||
this.quests.spliceWhere(function(q) { | |||||
this.quests.spliceWhere(function (q) { | |||||
return (q.id == id); | return (q.id == id); | ||||
}); | }); | ||||
} | } | ||||
} | } | ||||
}); | |||||
}); |
@@ -19,6 +19,12 @@ | |||||
background-color: fade(lighten(#3a3b4a, 15%), 90%); | background-color: fade(lighten(#3a3b4a, 15%), 90%); | ||||
} | } | ||||
.zone { | |||||
color: @grayD; | |||||
margin-bottom: 4px; | |||||
text-align: right; | |||||
} | |||||
.name { | .name { | ||||
color: @white; | color: @white; | ||||
margin-bottom: 3px; | margin-bottom: 3px; | ||||
@@ -28,6 +34,21 @@ | |||||
color: darken(@white, 35%); | color: darken(@white, 35%); | ||||
} | } | ||||
.reward { | |||||
display: none; | |||||
color: @tealC; | |||||
} | |||||
&:hover { | |||||
> .description { | |||||
display: none; | |||||
} | |||||
> .reward { | |||||
display: block; | |||||
} | |||||
} | |||||
.ready-text { | .ready-text { | ||||
display: none; | display: none; | ||||
} | } | ||||
@@ -47,6 +68,10 @@ | |||||
display: none; | display: none; | ||||
} | } | ||||
.reward { | |||||
display: none; | |||||
} | |||||
.ready-text { | .ready-text { | ||||
display: block; | display: block; | ||||
color: @white; | color: @white; | ||||
@@ -54,4 +79,4 @@ | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | |||||
} |
@@ -1,5 +1,7 @@ | |||||
<div class="quest"> | <div class="quest"> | ||||
<div class="zone">$ZONE$</div> | |||||
<div class="name">$NAME$</div> | <div class="name">$NAME$</div> | ||||
<div class="description">$DESCRIPTION$</div> | <div class="description">$DESCRIPTION$</div> | ||||
<div class="reward">Reward: $REWARD$</div> | |||||
<div class="ready-text">Click to turn in</div> | <div class="ready-text">Click to turn in</div> | ||||
</div> | |||||
</div> |
@@ -3,7 +3,7 @@ define([ | |||||
'js/system/client', | 'js/system/client', | ||||
'html!ui/templates/reputation/template', | 'html!ui/templates/reputation/template', | ||||
'css!ui/templates/reputation/styles' | 'css!ui/templates/reputation/styles' | ||||
], function( | |||||
], function ( | |||||
events, | events, | ||||
client, | client, | ||||
template, | template, | ||||
@@ -17,12 +17,12 @@ define([ | |||||
list: null, | list: null, | ||||
postRender: function() { | |||||
postRender: function () { | |||||
this.onEvent('onGetReputations', this.onGetReputations.bind(this)); | this.onEvent('onGetReputations', this.onGetReputations.bind(this)); | ||||
this.onEvent('onShowReputation', this.toggle.bind(this, true)); | this.onEvent('onShowReputation', this.toggle.bind(this, true)); | ||||
}, | }, | ||||
build: function() { | |||||
build: function () { | |||||
var list = this.list; | var list = this.list; | ||||
this.find('.info .heading-bottom').html(''); | this.find('.info .heading-bottom').html(''); | ||||
@@ -36,7 +36,10 @@ define([ | |||||
var elList = this.find('.list').empty(); | var elList = this.find('.list').empty(); | ||||
list.forEach(function(l) { | |||||
list.forEach(function (l) { | |||||
if (l.noGainRep) | |||||
return; | |||||
var html = '<div class="faction">' + l.name.toLowerCase() + '</div>'; | var html = '<div class="faction">' + l.name.toLowerCase() + '</div>'; | ||||
var el = $(html) | var el = $(html) | ||||
@@ -47,7 +50,7 @@ define([ | |||||
}, this); | }, this); | ||||
}, | }, | ||||
onSelectFaction: function(el, faction) { | |||||
onSelectFaction: function (el, faction) { | |||||
this.find('.selected').removeClass('selected'); | this.find('.selected').removeClass('selected'); | ||||
$(el).addClass('selected'); | $(el).addClass('selected'); | ||||
@@ -77,9 +80,9 @@ define([ | |||||
this.find('.tier').html(tiers[tier].name.toLowerCase() + ' (' + percentage + '%)'); | this.find('.tier').html(tiers[tier].name.toLowerCase() + ' (' + percentage + '%)'); | ||||
}, | }, | ||||
onGetReputations: function(list) { | |||||
onGetReputations: function (list) { | |||||
this.list = list; | this.list = list; | ||||
this.list.sort(function(a, b) { | |||||
this.list.sort(function (a, b) { | |||||
if (a.name[0] < b.name[0]) | if (a.name[0] < b.name[0]) | ||||
return -1; | return -1; | ||||
else | else | ||||
@@ -90,15 +93,14 @@ define([ | |||||
this.build(); | this.build(); | ||||
}, | }, | ||||
toggle: function() { | |||||
toggle: function () { | |||||
var shown = !this.el.is(':visible'); | var shown = !this.el.is(':visible'); | ||||
if (shown) { | if (shown) { | ||||
this.build(); | this.build(); | ||||
this.show(); | this.show(); | ||||
} | |||||
else | |||||
} else | |||||
this.hide(); | this.hide(); | ||||
} | } | ||||
}; | }; | ||||
}); | |||||
}); |
@@ -34,7 +34,7 @@ define([ | |||||
var x = -(icon[0] * 64); | var x = -(icon[0] * 64); | ||||
var y = -(icon[1] * 64); | var y = -(icon[1] * 64); | ||||
var hotkey = (i == 0) ? 'space' : spells[i].id; | |||||
var hotkey = (spells[i].id == 0) ? 'space' : spells[i].id; | |||||
var html = templateSpell | var html = templateSpell | ||||
.replace('$HOTKEY$', hotkey); | .replace('$HOTKEY$', hotkey); | ||||
@@ -53,7 +53,7 @@ define([ | |||||
.next().html(hotkey); | .next().html(hotkey); | ||||
this.onGetSpellCooldowns({ | this.onGetSpellCooldowns({ | ||||
spell: i, | |||||
spell: spells[i].id, | |||||
cd: spells[i].cd * 350 //HACK - we don't actually know how long a tick is | cd: spells[i].cd * 350 //HACK - we don't actually know how long a tick is | ||||
}); | }); | ||||
} | } | ||||
@@ -101,7 +101,9 @@ define([ | |||||
}, | }, | ||||
onGetSpellCooldowns: function (options) { | onGetSpellCooldowns: function (options) { | ||||
var spell = this.spells[options.spell]; | |||||
var spell = this.spells.find(function (s) { | |||||
return (s.id == options.spell); | |||||
}); | |||||
spell.ttl = options.cd; | spell.ttl = options.cd; | ||||
spell.ttlStart = +new Date; | spell.ttlStart = +new Date; | ||||
}, | }, | ||||
@@ -28,9 +28,18 @@ | |||||
} | } | ||||
} | } | ||||
.stats { | |||||
> .implicitStats { | |||||
color: darken(@white, 20%); | color: darken(@white, 20%); | ||||
margin-bottom: 8px; | margin-bottom: 8px; | ||||
padding-bottom: 8px; | |||||
border-bottom: 2px solid @blackA; | |||||
} | |||||
> .stats { | |||||
color: darken(@white, 20%); | |||||
margin-bottom: 8px; | |||||
padding-bottom: 8px; | |||||
border-bottom: 2px solid @blackA; | |||||
.gainStat { | .gainStat { | ||||
color: @green; | color: @green; | ||||
@@ -39,10 +48,14 @@ | |||||
.loseStat { | .loseStat { | ||||
color: @red; | color: @red; | ||||
} | } | ||||
.enchanted { | |||||
color: @tealC !important; | |||||
} | |||||
} | } | ||||
.effects { | .effects { | ||||
color: @tealC; | |||||
color: @white; | |||||
margin-bottom: 8px; | margin-bottom: 8px; | ||||
} | } | ||||
@@ -51,13 +64,21 @@ | |||||
margin-bottom: 8px; | margin-bottom: 8px; | ||||
} | } | ||||
.level { | |||||
.requires { | |||||
margin-top: 8px; | margin-top: 8px; | ||||
color: darken(@white, 40%); | color: darken(@white, 40%); | ||||
&.high-level { | &.high-level { | ||||
color: @red; | color: @red; | ||||
} | } | ||||
.high-level { | |||||
color: @red; | |||||
} | |||||
> *:not(.high-level) { | |||||
color: darken(@white, 40%); | |||||
} | |||||
} | } | ||||
.material { | .material { | ||||
@@ -75,7 +96,13 @@ | |||||
} | } | ||||
.damage { | .damage { | ||||
.gainDamage { | |||||
color: @green; | |||||
} | |||||
.loseDamage { | |||||
color: @red; | |||||
} | |||||
} | } | ||||
.worth { | .worth { | ||||
@@ -3,13 +3,18 @@ | |||||
<div class="type">$TYPE$</div> | <div class="type">$TYPE$</div> | ||||
<div class="power">$POWER$</div> | <div class="power">$POWER$</div> | ||||
</div> | </div> | ||||
<div class="implicitStats">$IMPLICITSTATS$</div> | |||||
<div class="stats">$STATS$</div> | <div class="stats">$STATS$</div> | ||||
<div class="effects">$EFFECTS$</div> | <div class="effects">$EFFECTS$</div> | ||||
<div class="faction">faction: $faction$</div> | |||||
<div class="material">crafting material</div> | <div class="material">crafting material</div> | ||||
<div class="quest">quest item</div> | <div class="quest">quest item</div> | ||||
<div class="spellName">$SPELLNAME$</div> | <div class="spellName">$SPELLNAME$</div> | ||||
<div class="damage">$DAMAGE$</div> | <div class="damage">$DAMAGE$</div> | ||||
<div class="level">level: $LEVEL$</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="worth"></div> | ||||
<div class="info"><br />[shift] to compare</div> | <div class="info"><br />[shift] to compare</div> |
@@ -14,14 +14,21 @@ define([ | |||||
var percentageStats = [ | var percentageStats = [ | ||||
'addCritChance', | 'addCritChance', | ||||
'addCritMultiplier', | 'addCritMultiplier', | ||||
'addAttackCritChance', | |||||
'addAttackCritMultiplier', | |||||
'addSpellCritChance', | |||||
'addSpellCritMultiplier', | |||||
'sprintChance', | 'sprintChance', | ||||
'dmgPercent', | 'dmgPercent', | ||||
'xpIncrease', | 'xpIncrease', | ||||
'blockAttackChance', | 'blockAttackChance', | ||||
'blockSpellChance', | 'blockSpellChance', | ||||
'dodgeAttackChance', | |||||
'dodgeSpellChance', | |||||
'attackSpeed', | 'attackSpeed', | ||||
'castSpeed', | 'castSpeed', | ||||
'itemQuantity', | 'itemQuantity', | ||||
'magicFind', | |||||
'catchChance', | 'catchChance', | ||||
'catchSpeed', | 'catchSpeed', | ||||
'fishRarity', | 'fishRarity', | ||||
@@ -44,7 +51,7 @@ define([ | |||||
}, | }, | ||||
onHideItemTooltip: function (item) { | onHideItemTooltip: function (item) { | ||||
if (this.item != item) | |||||
if ((this.item != item) && (this.item.refItem) && (this.item.refItem != item)) | |||||
return; | return; | ||||
this.item = null; | this.item = null; | ||||
@@ -55,6 +62,8 @@ define([ | |||||
this.item = item; | this.item = item; | ||||
var tempStats = $.extend(true, {}, item.stats); | var tempStats = $.extend(true, {}, item.stats); | ||||
var enchantedStats = item.enchantedStats || {}; | |||||
if ((compare) && (shiftDown)) { | if ((compare) && (shiftDown)) { | ||||
if (!item.eq) { | if (!item.eq) { | ||||
var compareStats = compare.stats; | var compareStats = compare.stats; | ||||
@@ -74,11 +83,26 @@ define([ | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} 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]; | |||||
} | |||||
}); | |||||
} | } | ||||
stats = Object.keys(tempStats) | stats = Object.keys(tempStats) | ||||
.map(function (s) { | .map(function (s) { | ||||
var statName = statTranslations.translate(s); | |||||
var isEnchanted = (s[0] == '_'); | |||||
var statName = s; | |||||
if (isEnchanted) | |||||
statName = statName.substr(1); | |||||
statName = statTranslations.translate(statName); | |||||
var value = tempStats[s]; | var value = tempStats[s]; | ||||
if (percentageStats.indexOf(s) > -1) | if (percentageStats.indexOf(s) > -1) | ||||
@@ -95,16 +119,43 @@ define([ | |||||
else if (row.indexOf('+') > -1) | else if (row.indexOf('+') > -1) | ||||
rowClass = 'gainStat'; | rowClass = 'gainStat'; | ||||
} | } | ||||
if (isEnchanted) | |||||
rowClass += ' enchanted'; | |||||
row = '<div class="' + rowClass + '">' + row + '</div>'; | row = '<div class="' + rowClass + '">' + row + '</div>'; | ||||
return row; | return row; | ||||
}, this) | }, this) | ||||
.sort(function (a, b) { | .sort(function (a, b) { | ||||
return (a.length - b.length); | |||||
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; | |||||
else | |||||
return 0; | |||||
}) | }) | ||||
.join(''); | .join(''); | ||||
var implicitStats = (item.implicitStats || []).map(function (s) { | |||||
var stat = s.stat; | |||||
var statName = statTranslations.translate(stat); | |||||
var value = s.value; | |||||
if (percentageStats.indexOf(stat) > -1) | |||||
value += '%'; | |||||
else if ((stat.indexOf('element') == 0) && (stat.indexOf('Resist') == -1)) | |||||
value += '%'; | |||||
var row = value + ' ' + statName; | |||||
var rowClass = ''; | |||||
row = '<div class="' + rowClass + '">' + row + '</div>'; | |||||
return row; | |||||
}).join(''); | |||||
var name = item.name; | var name = item.name; | ||||
if (item.quantity > 1) | if (item.quantity > 1) | ||||
name += ' x' + item.quantity; | name += ' x' + item.quantity; | ||||
@@ -118,15 +169,43 @@ define([ | |||||
.replace('$QUALITY$', item.quality) | .replace('$QUALITY$', item.quality) | ||||
.replace('$TYPE$', item.type) | .replace('$TYPE$', item.type) | ||||
.replace('$SLOT$', item.slot) | .replace('$SLOT$', item.slot) | ||||
.replace('$IMPLICITSTATS$', implicitStats) | |||||
.replace('$STATS$', stats) | .replace('$STATS$', stats) | ||||
.replace('$LEVEL$', level); | .replace('$LEVEL$', level); | ||||
if (item.requires) { | |||||
html = html | |||||
.replace('$ATTRIBUTE$', item.requires[0].stat) | |||||
.replace('$ATTRIBUTEVALUE$', item.requires[0].value); | |||||
} | |||||
if (item.power) | if (item.power) | ||||
html = html.replace('$POWER$', ' ' + (new Array(item.power + 1)).join('+')); | html = html.replace('$POWER$', ' ' + (new Array(item.power + 1)).join('+')); | ||||
if ((item.spell) && (item.spell.values)) { | if ((item.spell) && (item.spell.values)) { | ||||
var abilityValues = ''; | var abilityValues = ''; | ||||
for (var p in item.spell.values) { | for (var p in item.spell.values) { | ||||
abilityValues += p + ': ' + item.spell.values[p] + '<br/>'; | |||||
if ((compare) && (shiftDown)) { | |||||
var 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; | |||||
var 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) | if (!item.ability) | ||||
abilityValues = abilityValues; | abilityValues = abilityValues; | ||||
@@ -140,6 +219,16 @@ define([ | |||||
else | else | ||||
this.tooltip.find('.level').show(); | this.tooltip.find('.level').show(); | ||||
if (!item.implicitStats) | |||||
this.tooltip.find('.implicitStats').hide(); | |||||
else | |||||
this.tooltip.find('.implicitStats').show(); | |||||
if (!item.requires) | |||||
this.tooltip.find('.requires .stats').hide(); | |||||
else | |||||
this.tooltip.find('.requires .stats').show(); | |||||
if ((!item.type) || (item.type == item.name)) | if ((!item.type) || (item.type == item.name)) | ||||
this.tooltip.find('.type').hide(); | this.tooltip.find('.type').hide(); | ||||
else { | else { | ||||
@@ -151,10 +240,11 @@ define([ | |||||
if (item.power) | if (item.power) | ||||
this.tooltip.find('.power').show(); | 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)) { | if ((item.material) || (item.quest)) { | ||||
this.tooltip.find('.level').hide(); | this.tooltip.find('.level').hide(); | ||||
@@ -3,7 +3,7 @@ define([ | |||||
'css!ui/templates/tooltips/styles', | 'css!ui/templates/tooltips/styles', | ||||
'html!ui/templates/tooltips/template', | 'html!ui/templates/tooltips/template', | ||||
'html!ui/templates/tooltips/templateTooltip' | 'html!ui/templates/tooltips/templateTooltip' | ||||
], function( | |||||
], function ( | |||||
events, | events, | ||||
styles, | styles, | ||||
template, | template, | ||||
@@ -18,14 +18,14 @@ define([ | |||||
hoverEl: null, | hoverEl: null, | ||||
postRender: function() { | |||||
postRender: function () { | |||||
this.tooltip = this.el.find('.tooltip'); | this.tooltip = this.el.find('.tooltip'); | ||||
this.onEvent('onShowTooltip', this.onShowTooltip.bind(this)); | this.onEvent('onShowTooltip', this.onShowTooltip.bind(this)); | ||||
this.onEvent('onHideTooltip', this.onHideTooltip.bind(this)); | this.onEvent('onHideTooltip', this.onHideTooltip.bind(this)); | ||||
}, | }, | ||||
onHideTooltip: function(el) { | |||||
onHideTooltip: function (el) { | |||||
if (this.hoverEl != el) | if (this.hoverEl != el) | ||||
return; | return; | ||||
@@ -33,7 +33,7 @@ define([ | |||||
this.tooltip.hide(); | this.tooltip.hide(); | ||||
}, | }, | ||||
onShowTooltip: function(text, el, pos, width, bottomAlign, rightAlign, zIndex) { | |||||
onShowTooltip: function (text, el, pos, width, bottomAlign, rightAlign, zIndex) { | |||||
this.hoverEl = el; | this.hoverEl = el; | ||||
this.tooltip | this.tooltip | ||||
@@ -64,4 +64,4 @@ define([ | |||||
this.tooltip.css('zIndex', ''); | this.tooltip.css('zIndex', ''); | ||||
} | } | ||||
}; | }; | ||||
}); | |||||
}); |
@@ -13,6 +13,7 @@ define([ | |||||
var amount = config.damage; | var amount = config.damage; | ||||
var blocked = false; | var blocked = false; | ||||
var dodged = false; | |||||
var isCrit = false; | var isCrit = false; | ||||
//Don't block heals | //Don't block heals | ||||
@@ -22,9 +23,17 @@ define([ | |||||
blocked = true; | blocked = true; | ||||
amount = 0; | amount = 0; | ||||
} | } | ||||
if (!blocked) { | |||||
var dodgeChance = config.isAttack ? tgtValues.dodgeAttackChance : tgtValues.dodgeSpellChance; | |||||
if (mathRandom() * 100 < dodgeChance) { | |||||
dodged = true; | |||||
amount = 0; | |||||
} | |||||
} | |||||
} | } | ||||
if (!blocked) { | |||||
if ((!blocked) && (!dodged)) { | |||||
var statValue = 0; | var statValue = 0; | ||||
if (config.statType) { | if (config.statType) { | ||||
var statType = config.statType; | var statType = config.statType; | ||||
@@ -38,13 +47,13 @@ define([ | |||||
statValue = max(1, statValue); | statValue = max(1, statValue); | ||||
var statMult = config.statMult || 1; | var statMult = config.statMult || 1; | ||||
var dmgPercent = 100 + srcValues.dmgPercent; | |||||
var dmgPercent = 100 + (srcValues.dmgPercent || 0); | |||||
amount *= statValue * statMult; | amount *= statValue * statMult; | ||||
if (config.element) { | if (config.element) { | ||||
var elementName = 'element' + config.element[0].toUpperCase() + config.element.substr(1); | var elementName = 'element' + config.element[0].toUpperCase() + config.element.substr(1); | ||||
dmgPercent += srcValues[elementName + 'Percent']; | |||||
dmgPercent += (srcValues[elementName + 'Percent'] || 0); | |||||
//Don't mitigate heals | //Don't mitigate heals | ||||
if (!config.noMitigate) { | if (!config.noMitigate) { | ||||
@@ -58,9 +67,14 @@ define([ | |||||
if (!config.noCrit) { | if (!config.noCrit) { | ||||
var critChance = srcValues.critChance; | var critChance = srcValues.critChance; | ||||
critChance += (config.isAttack) ? srcValues.attackCritChance : srcValues.spellCritChance; | |||||
var critMultiplier = srcValues.critMultiplier; | |||||
critMultiplier += (config.isAttack) ? srcValues.attackCritMultiplier : srcValues.spellCritMultiplier; | |||||
if ((config.crit) || (mathRandom() * 100 < critChance)) { | if ((config.crit) || (mathRandom() * 100 < critChance)) { | ||||
isCrit = true; | isCrit = true; | ||||
amount *= (srcValues.critMultiplier / 100); | |||||
amount *= (critMultiplier / 100); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -68,6 +82,7 @@ define([ | |||||
return { | return { | ||||
amount: amount, | amount: amount, | ||||
blocked: blocked, | blocked: blocked, | ||||
dodged: dodged, | |||||
crit: isCrit, | crit: isCrit, | ||||
element: config.element | element: config.element | ||||
}; | }; | ||||
@@ -49,6 +49,9 @@ define([ | |||||
}, | }, | ||||
move: function () { | move: function () { | ||||
if (this.obj.dead) | |||||
return; | |||||
var result = { | var result = { | ||||
success: true | success: true | ||||
}; | }; | ||||
@@ -93,7 +96,7 @@ define([ | |||||
//find mobs in range | //find mobs in range | ||||
var range = this.range; | var range = this.range; | ||||
var faction = this.faction; | var faction = this.faction; | ||||
var inRange = this.physics.getArea(x - range, y - range, x + range, y + range, (c => (((!c.player) || (!obj.player)) && (c.aggro) && (c.aggro.willAutoAttack(obj))))); | |||||
var inRange = this.physics.getArea(x - range, y - range, x + range, y + range, (c => (((!c.player) || (!obj.player)) && (!obj.dead) && (c.aggro) && (c.aggro.willAutoAttack(obj))))); | |||||
if (inRange.length == 0) | if (inRange.length == 0) | ||||
return; | return; | ||||
@@ -235,13 +238,16 @@ define([ | |||||
for (var i = 0; i < lLen; i++) { | for (var i = 0; i < lLen; i++) { | ||||
var l = list[i]; | var l = list[i]; | ||||
if (!l) { | if (!l) { | ||||
console.log('aggro obj empty???'); | |||||
lLen--; | |||||
continue; | continue; | ||||
} | } | ||||
//Maybe the aggro component was removed? | //Maybe the aggro component was removed? | ||||
var targetAggro = l.obj.aggro; | var targetAggro = l.obj.aggro; | ||||
if (targetAggro) | |||||
if (targetAggro) { | |||||
targetAggro.unAggro(this.obj); | targetAggro.unAggro(this.obj); | ||||
i--; | |||||
lLen--; | |||||
} | |||||
} | } | ||||
this.list = []; | this.list = []; | ||||
@@ -259,11 +265,13 @@ define([ | |||||
if (amount == null) { | if (amount == null) { | ||||
list.splice(i, 1); | list.splice(i, 1); | ||||
obj.aggro.unAggro(this.obj); | |||||
break; | break; | ||||
} else { | } else { | ||||
l.threat -= amount; | l.threat -= amount; | ||||
if (l.threat <= 0) { | if (l.threat <= 0) { | ||||
list.splice(i, 1); | list.splice(i, 1); | ||||
obj.aggro.unAggro(this.obj); | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
@@ -6,7 +6,10 @@ define([ | |||||
'leaderboard/leaderboard', | 'leaderboard/leaderboard', | ||||
'config/skins', | 'config/skins', | ||||
'config/roles', | 'config/roles', | ||||
'misc/profanities' | |||||
'misc/profanities', | |||||
'fixes/fixes', | |||||
'config/loginRewards', | |||||
'misc/mail' | |||||
], function ( | ], function ( | ||||
bcrypt, | bcrypt, | ||||
io, | io, | ||||
@@ -15,7 +18,10 @@ define([ | |||||
leaderboard, | leaderboard, | ||||
skins, | skins, | ||||
roles, | roles, | ||||
profanities | |||||
profanities, | |||||
fixes, | |||||
loginRewards, | |||||
) { | ) { | ||||
return { | return { | ||||
type: 'auth', | type: 'auth', | ||||
@@ -25,6 +31,7 @@ define([ | |||||
characters: {}, | characters: {}, | ||||
characterList: [], | characterList: [], | ||||
stash: null, | stash: null, | ||||
accountInfo: null, | |||||
customChannels: [], | customChannels: [], | ||||
@@ -44,6 +51,60 @@ define([ | |||||
this.charname = character.name; | this.charname = character.name; | ||||
this.checkLoginReward(data, character); | |||||
}, | |||||
checkLoginReward: function (data, character) { | |||||
var accountInfo = this.accountInfo; | |||||
var scheduler = require('misc/scheduler'); | |||||
var time = scheduler.getTime(); | |||||
var lastLogin = accountInfo.lastLogin; | |||||
if ((!lastLogin) || (lastLogin.day != time.day)) { | |||||
var daysSkipped = 1; | |||||
if (lastLogin) { | |||||
if (time.day > lastLogin.day) | |||||
daysSkipped = time.day - lastLogin.day; | |||||
else { | |||||
var daysInMonth = scheduler.daysInMonth(lastLogin.month); | |||||
daysSkipped = (daysInMonth - lastLogin.day) + time.day; | |||||
for (var i = lastLogin.month + 1; i < time.month - 1; i++) { | |||||
daysSkipped += scheduler.daysInMonth(i); | |||||
} | |||||
} | |||||
} | |||||
if (daysSkipped == 1) { | |||||
accountInfo.loginStreak++; | |||||
if (accountInfo.loginStreak > 21) | |||||
accountInfo.loginStreak = 21; | |||||
} else { | |||||
accountInfo.loginStreak -= (daysSkipped - 1); | |||||
if (accountInfo.loginStreak < 1) | |||||
accountInfo.loginStreak = 1; | |||||
} | |||||
var rewards = loginRewards.generate(accountInfo.loginStreak); | |||||
mail.sendMail(character.name, rewards, this.onSendRewards.bind(this, data, character)); | |||||
} else | |||||
this.onSendRewards(data, character); | |||||
accountInfo.lastLogin = time; | |||||
}, | |||||
onSendRewards: function (data, character) { | |||||
delete mail.busy[character.name]; | |||||
io.set({ | |||||
ent: this.username, | |||||
field: 'accountInfo', | |||||
value: JSON.stringify(this.accountInfo), | |||||
callback: this.onUpdateAccountInfo.bind(this, data, character) | |||||
}); | |||||
}, | |||||
onUpdateAccountInfo: function (data, character) { | |||||
this.obj.player.sessionStart = +new Date; | this.obj.player.sessionStart = +new Date; | ||||
this.obj.player.spawn(character, data.callback); | this.obj.player.spawn(character, data.callback); | ||||
@@ -165,6 +226,7 @@ define([ | |||||
} | } | ||||
var character = JSON.parse(result || '{}'); | var character = JSON.parse(result || '{}'); | ||||
fixes.fixCharacter(character); | |||||
//Hack for old characters | //Hack for old characters | ||||
if (!character.skinId) | if (!character.skinId) | ||||
@@ -219,6 +281,8 @@ define([ | |||||
this.stash = JSON.parse(result || '[]'); | this.stash = JSON.parse(result || '[]'); | ||||
fixes.fixStash(this.stash); | |||||
if (this.skins != null) { | if (this.skins != null) { | ||||
this.verifySkin(character); | this.verifySkin(character); | ||||
data.callback(character); | data.callback(character); | ||||
@@ -238,6 +302,8 @@ define([ | |||||
onGetSkins: function (msg, character, result) { | onGetSkins: function (msg, character, result) { | ||||
this.skins = JSON.parse(result || '[]'); | this.skins = JSON.parse(result || '[]'); | ||||
fixes.fixSkins(this.username, this.skins); | |||||
var list = [...this.skins, ...roles.getSkins(this.username)]; | var list = [...this.skins, ...roles.getSkins(this.username)]; | ||||
var skinList = skins.getSkinList(list); | var skinList = skins.getSkinList(list); | ||||
@@ -335,6 +401,24 @@ define([ | |||||
onLoginVerified: function (msg) { | onLoginVerified: function (msg) { | ||||
this.username = msg.data.username; | this.username = msg.data.username; | ||||
connections.logOut(this.obj); | connections.logOut(this.obj); | ||||
io.get({ | |||||
ent: msg.data.username, | |||||
field: 'accountInfo', | |||||
callback: this.onGetAccountInfo.bind(this, msg) | |||||
}); | |||||
}, | |||||
onGetAccountInfo: function (msg, info) { | |||||
if (!info) { | |||||
info = { | |||||
loginStreak: 0 | |||||
}; | |||||
} else | |||||
info = JSON.parse(info); | |||||
this.accountInfo = info; | |||||
msg.callback(); | msg.callback(); | ||||
}, | }, | ||||
@@ -354,11 +438,6 @@ define([ | |||||
} | } | ||||
} | } | ||||
if (!profanities.isClean(credentials.username)) { | |||||
msg.callback(messages.login.invalid); | |||||
return; | |||||
} | |||||
io.get({ | io.get({ | ||||
ent: credentials.username, | ent: credentials.username, | ||||
field: 'login', | field: 'login', | ||||
@@ -384,6 +463,10 @@ define([ | |||||
}); | }); | ||||
}, | }, | ||||
onRegister: function (msg, result) { | onRegister: function (msg, result) { | ||||
this.accountInfo = { | |||||
loginStreak: 0 | |||||
}; | |||||
io.set({ | io.set({ | ||||
ent: msg.data.username, | ent: msg.data.username, | ||||
field: 'characterList', | field: 'characterList', | ||||
@@ -39,9 +39,11 @@ define([ | |||||
if (!this.global) | if (!this.global) | ||||
this.obj.syncer.set(false, 'chatter', 'msg', pick.msg); | this.obj.syncer.set(false, 'chatter', 'msg', pick.msg); | ||||
else { | else { | ||||
//HACK | |||||
//This shouldn't always be pink, but only events use this atm so it's fine | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
messages: { | messages: { | ||||
class: 'q2', | |||||
class: 'color-pinkB', | |||||
message: this.obj.name + ': ' + pick.msg | message: this.obj.name + ': ' + pick.msg | ||||
} | } | ||||
}); | }); | ||||
@@ -1,38 +1,46 @@ | |||||
define([ | define([ | ||||
'../misc/fileLister' | |||||
'misc/fileLister', | |||||
'misc/events', | |||||
'path' | |||||
], function( | ], function( | ||||
fileLister | |||||
fileLister, | |||||
events, | |||||
pathUtilities | |||||
) { | ) { | ||||
var onReady = null; | var onReady = null; | ||||
var components = { | var components = { | ||||
components: {}, | components: {}, | ||||
waiting: null, | |||||
waiting: [], | |||||
init: function(callback) { | init: function(callback) { | ||||
onReady = callback; | onReady = callback; | ||||
this.getComponentNames(); | |||||
events.emit('onBeforeGetComponents', this.components); | |||||
this.getComponentFolder(); | |||||
}, | }, | ||||
getComponentNames: function() { | |||||
this.waiting = fileLister.getFolder('./components/'); | |||||
this.waiting = this.waiting.filter(w => ( | |||||
(w.indexOf('components') == -1) && | |||||
getComponentFolder: function() { | |||||
var files = fileLister.getFolder('./components/'); | |||||
files = files.filter(w => ( | |||||
(w.indexOf('components') == -1) && | |||||
(w.indexOf('cpnBase') == -1) && | (w.indexOf('cpnBase') == -1) && | ||||
(w.indexOf('projectile') == -1) | (w.indexOf('projectile') == -1) | ||||
)); | )); | ||||
this.onGetComponentNames(); | |||||
}, | |||||
onGetComponentNames: function() { | |||||
for (var i = 0; i < this.waiting.length; i++) { | |||||
var name = this.waiting[i]; | |||||
this.getComponent(name); | |||||
var fLen = files.length; | |||||
for (var i = 0; i < fLen; i++) { | |||||
this.getComponentFile(`./components/${files[i]}`); | |||||
} | } | ||||
}, | }, | ||||
getComponent: function(name) { | |||||
require([ './components/' + name ], this.onGetComponent.bind(this)); | |||||
getComponentFile: function(path) { | |||||
var fileName = pathUtilities.basename(path); | |||||
fileName = fileName.replace('.js', ''); | |||||
this.waiting.push(fileName); | |||||
require([ path ], this.onGetComponent.bind(this)); | |||||
}, | }, | ||||
onGetComponent: function(template) { | onGetComponent: function(template) { | ||||
this.waiting.spliceWhere(w => w == template.type + '.js'); | |||||
this.waiting.spliceWhere(w => w == template.type); | |||||
this.components[template.type] = template; | this.components[template.type] = template; | ||||
@@ -44,4 +52,4 @@ define([ | |||||
}; | }; | ||||
return components; | return components; | ||||
}); | |||||
}); |
@@ -1,6 +1,6 @@ | |||||
define([ | define([ | ||||
], function( | |||||
], function ( | |||||
) { | ) { | ||||
return { | return { | ||||
@@ -11,19 +11,19 @@ define([ | |||||
trigger: null, | trigger: null, | ||||
init: function(blueprint) { | |||||
init: function (blueprint) { | |||||
this.states = blueprint.config; | this.states = blueprint.config; | ||||
}, | }, | ||||
destroy: function() { | |||||
destroy: function () { | |||||
if (this.trigger) | if (this.trigger) | ||||
this.trigger.destroyed = true; | this.trigger.destroyed = true; | ||||
}, | }, | ||||
talk: function(msg) { | |||||
talk: function (msg) { | |||||
if (!msg) | if (!msg) | ||||
return false; | |||||
return false; | |||||
var target = msg.target; | var target = msg.target; | ||||
if ((target == null) && (!msg.targetName)) | if ((target == null) && (!msg.targetName)) | ||||
@@ -33,11 +33,10 @@ define([ | |||||
target = this.obj.instance.objects.objects.find(o => o.id == target); | target = this.obj.instance.objects.objects.find(o => o.id == target); | ||||
if (!target) | if (!target) | ||||
return false; | return false; | ||||
} | |||||
else if (msg.targetName != null) { | |||||
} else if (msg.targetName != null) { | |||||
target = this.obj.instance.objects.objects.find(o => ((o.name) && (o.name.toLowerCase() == msg.targetName.toLowerCase()))); | target = this.obj.instance.objects.objects.find(o => ((o.name) && (o.name.toLowerCase() == msg.targetName.toLowerCase()))); | ||||
if (!target) | if (!target) | ||||
return false; | |||||
return false; | |||||
} | } | ||||
if (!target.dialogue) | if (!target.dialogue) | ||||
@@ -56,11 +55,11 @@ define([ | |||||
this.obj.syncer.set(true, 'dialogue', 'state', state); | this.obj.syncer.set(true, 'dialogue', 'state', state); | ||||
}, | }, | ||||
stopTalk: function() { | |||||
this.obj.syncer.set(true, 'dialogue', 'state', null); | |||||
stopTalk: function () { | |||||
this.obj.syncer.set(true, 'dialogue', 'state', null); | |||||
}, | }, | ||||
getState: function(sourceObj, state) { | |||||
getState: function (sourceObj, state) { | |||||
state = state || 1; | state = state || 1; | ||||
//Goto? | //Goto? | ||||
@@ -72,7 +71,7 @@ define([ | |||||
var goto = (config.options[state] || {}).goto; | var goto = (config.options[state] || {}).goto; | ||||
if (goto instanceof Array) { | if (goto instanceof Array) { | ||||
var gotos = []; | var gotos = []; | ||||
goto.forEach(function(g) { | |||||
goto.forEach(function (g) { | |||||
var rolls = (g.chance * 100) || 100; | var rolls = (g.chance * 100) || 100; | ||||
for (var i = 0; i < rolls; i++) { | for (var i = 0; i < rolls; i++) { | ||||
gotos.push(g.number); | gotos.push(g.number); | ||||
@@ -80,15 +79,14 @@ define([ | |||||
}); | }); | ||||
state = gotos[~~(Math.random() * gotos.length)]; | state = gotos[~~(Math.random() * gotos.length)]; | ||||
} | |||||
else | |||||
} else | |||||
state = goto; | state = goto; | ||||
} | } | ||||
this.sourceStates[sourceObj.id] = state; | this.sourceStates[sourceObj.id] = state; | ||||
if (!this.states) { | if (!this.states) { | ||||
console.log(sourceObj.name, this.obj.name, state); | |||||
console.log(sourceObj.name, this.obj.name, state); | |||||
return null; | return null; | ||||
} | } | ||||
var stateConfig = this.states[state]; | var stateConfig = this.states[state]; | ||||
@@ -108,16 +106,14 @@ define([ | |||||
return this.getState(sourceObj, stateConfig.goto.success); | return this.getState(sourceObj, stateConfig.goto.success); | ||||
else | else | ||||
return this.getState(sourceObj, stateConfig.goto.failure); | return this.getState(sourceObj, stateConfig.goto.failure); | ||||
} | |||||
else { | |||||
} else { | |||||
if (result) { | if (result) { | ||||
useMsg = extend(true, [], useMsg); | useMsg = extend(true, [], useMsg); | ||||
useMsg[0].msg = result; | useMsg[0].msg = result; | ||||
} else | } else | ||||
return null; | return null; | ||||
} | } | ||||
} | |||||
else if (stateConfig.method) { | |||||
} else if (stateConfig.method) { | |||||
var methodResult = stateConfig.method.call(this.obj, sourceObj); | var methodResult = stateConfig.method.call(this.obj, sourceObj); | ||||
if (methodResult) { | if (methodResult) { | ||||
useMsg = extend(true, [], useMsg); | useMsg = extend(true, [], useMsg); | ||||
@@ -137,7 +133,7 @@ define([ | |||||
if (useMsg instanceof Array) { | if (useMsg instanceof Array) { | ||||
var msgs = []; | var msgs = []; | ||||
useMsg.forEach(function(m, i) { | |||||
useMsg.forEach(function (m, i) { | |||||
var rolls = (m.chance * 100) || 100; | var rolls = (m.chance * 100) || 100; | ||||
for (var j = 0; j < rolls; j++) { | for (var j = 0; j < rolls; j++) { | ||||
msgs.push({ | msgs.push({ | ||||
@@ -151,8 +147,7 @@ define([ | |||||
result.msg = pick.msg.msg; | result.msg = pick.msg.msg; | ||||
result.options = useMsg[pick.index].options; | result.options = useMsg[pick.index].options; | ||||
} | |||||
else { | |||||
} else { | |||||
result.msg = useMsg; | result.msg = useMsg; | ||||
result.options = stateConfig.options; | result.options = stateConfig.options; | ||||
} | } | ||||
@@ -160,12 +155,12 @@ define([ | |||||
if (!(result.options instanceof Array)) { | if (!(result.options instanceof Array)) { | ||||
if (result.options[0] == '$') | if (result.options[0] == '$') | ||||
result.options = this.states[result.options.replace('$', '')].options; | result.options = this.states[result.options.replace('$', '')].options; | ||||
result.options = Object.keys(result.options); | result.options = Object.keys(result.options); | ||||
} | } | ||||
result.options = result.options | result.options = result.options | ||||
.map(function(o) { | |||||
.map(function (o) { | |||||
var gotoState = this.states[(o + '').split('.')[0]]; | var gotoState = this.states[(o + '').split('.')[0]]; | ||||
var picked = gotoState.options[o]; | var picked = gotoState.options[o]; | ||||
@@ -192,7 +187,7 @@ define([ | |||||
return result; | return result; | ||||
}, | }, | ||||
simplify: function(self) { | |||||
simplify: function (self) { | |||||
return { | return { | ||||
type: 'dialogue' | type: 'dialogue' | ||||
}; | }; | ||||
@@ -200,22 +195,21 @@ define([ | |||||
//These don't belong here, but I can't figure out where to put them right now | //These don't belong here, but I can't figure out where to put them right now | ||||
//They are actions that can be performed while chatting with someone | //They are actions that can be performed while chatting with someone | ||||
teleport: function(msg) { | |||||
this.obj.syncer.set(true, 'dialogue', 'state', null); | |||||
teleport: function (msg) { | |||||
this.obj.syncer.set(true, 'dialogue', 'state', null); | |||||
var portal = extend(true, {}, require('./components/portal'), msg); | var portal = extend(true, {}, require('./components/portal'), msg); | ||||
portal.collisionEnter(this.obj); | portal.collisionEnter(this.obj); | ||||
}, | }, | ||||
getItem: function(msg, source) { | |||||
getItem: function (msg, source) { | |||||
var inventory = this.obj.inventory; | var inventory = this.obj.inventory; | ||||
var exists = inventory.items.find(i => (i.name == msg.item.name)); | var exists = inventory.items.find(i => (i.name == msg.item.name)); | ||||
if (!exists) { | if (!exists) { | ||||
inventory.getItem(msg.item); | inventory.getItem(msg.item); | ||||
return msg.successMsg || false; | return msg.successMsg || false; | ||||
} | |||||
else | |||||
} else | |||||
return msg.existsMsg || false; | return msg.existsMsg || false; | ||||
} | } | ||||
}; | }; | ||||
}); | |||||
}); |
@@ -23,8 +23,10 @@ define([ | |||||
this.destroyKey = blueprint.destroyKey; | this.destroyKey = blueprint.destroyKey; | ||||
this.autoClose = blueprint.autoClose; | this.autoClose = blueprint.autoClose; | ||||
if (this.closed) | |||||
if (this.closed) { | |||||
this.obj.instance.physics.setCollision(this.obj.x, this.obj.y, true); | this.obj.instance.physics.setCollision(this.obj.x, this.obj.y, true); | ||||
this.obj.instance.objects.notifyCollisionChange(this.obj.x, this.obj.y, true); | |||||
} | |||||
var o = this.obj.instance.objects.buildObjects([{ | var o = this.obj.instance.objects.buildObjects([{ | ||||
properties: { | properties: { | ||||
@@ -126,12 +128,12 @@ define([ | |||||
return; | return; | ||||
if (((key.singleUse) || (this.destroyKey)) && (key.keyId != 'world')) { | if (((key.singleUse) || (this.destroyKey)) && (key.keyId != 'world')) { | ||||
obj.inventory.destroyItem(key.id); | |||||
obj.inventory.destroyItem(key.id, 1); | |||||
obj.instance.syncer.queue('onGetMessages', { | obj.instance.syncer.queue('onGetMessages', { | ||||
id: obj.id, | id: obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-redA', | |||||
message: 'The ' + key.name + ' disintegrates on use', | message: 'The ' + key.name + ' disintegrates on use', | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -143,6 +145,7 @@ define([ | |||||
thisObj.cell = this.openSprite; | thisObj.cell = this.openSprite; | ||||
syncO.cell = this.openSprite; | syncO.cell = this.openSprite; | ||||
this.obj.instance.physics.setCollision(thisObj.x, thisObj.y, false); | this.obj.instance.physics.setCollision(thisObj.x, thisObj.y, false); | ||||
this.obj.instance.objects.notifyCollisionChange(thisObj.x, thisObj.y, false); | |||||
this.closed = false; | this.closed = false; | ||||
this.enterArea(obj); | this.enterArea(obj); | ||||
@@ -150,6 +153,7 @@ define([ | |||||
thisObj.cell = this.closedSprite; | thisObj.cell = this.closedSprite; | ||||
syncO.cell = this.closedSprite; | syncO.cell = this.closedSprite; | ||||
this.obj.instance.physics.setCollision(thisObj.x, thisObj.y, true); | this.obj.instance.physics.setCollision(thisObj.x, thisObj.y, true); | ||||
this.obj.instance.objects.notifyCollisionChange(thisObj.x, thisObj.y, true); | |||||
this.closed = true; | this.closed = true; | ||||
this.enterArea(obj); | this.enterArea(obj); | ||||
@@ -9,6 +9,11 @@ define([ | |||||
effects: [], | effects: [], | ||||
nextId: 0, | nextId: 0, | ||||
ccResistances: { | |||||
stunned: 0, | |||||
slowed: 0 | |||||
}, | |||||
init: function (blueprint) { | init: function (blueprint) { | ||||
var effects = blueprint.effects || []; | var effects = blueprint.effects || []; | ||||
var eLen = effects.length; | var eLen = effects.length; | ||||
@@ -114,19 +119,33 @@ define([ | |||||
} | } | ||||
}, | }, | ||||
canApplyEffect: function (type) { | |||||
var ccResistances = this.ccResistances; | |||||
if ((100 - ccResistances[type]) >= 50) { | |||||
ccResistances[type] += 50; | |||||
return true; | |||||
} else | |||||
return false; | |||||
}, | |||||
addEffect: function (options) { | addEffect: function (options) { | ||||
var exists = this.effects.find(e => e.type == options.type); | |||||
if (exists) { | |||||
exists.ttl += options.ttl; | |||||
if (!this.canApplyEffect(options.type)) | |||||
return; | |||||
for (var p in options) { | |||||
if (p == 'ttl') | |||||
continue; | |||||
if (!options.new) { | |||||
var exists = this.effects.find(e => e.type == options.type); | |||||
if (exists) { | |||||
exists.ttl += options.ttl; | |||||
exists[p] = options[p]; | |||||
} | |||||
for (var p in options) { | |||||
if (p == 'ttl') | |||||
continue; | |||||
exists[p] = options[p]; | |||||
} | |||||
return exists; | |||||
return exists; | |||||
} | |||||
} | } | ||||
var typeTemplate = null; | var typeTemplate = null; | ||||
@@ -269,6 +288,11 @@ define([ | |||||
this.syncRemove(e.id, e.type, e.noMsg); | this.syncRemove(e.id, e.type, e.noMsg); | ||||
} | } | ||||
} | } | ||||
for (var p in this.ccResistances) { | |||||
if (this.ccResistances[p] > 0) | |||||
this.ccResistances[p]--; | |||||
} | |||||
} | } | ||||
}; | }; | ||||
}); | }); |
@@ -37,14 +37,9 @@ define([ | |||||
var item = this.obj.inventory.findItem(itemId); | var item = this.obj.inventory.findItem(itemId); | ||||
if (!item) | if (!item) | ||||
return; | 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; | item.eq = false; | ||||
return; | return; | ||||
} else if ((item.factions) && (this.obj.player)) { | |||||
if (!this.obj.reputation.canEquipItem(item)) { | |||||
item.eq = false; | |||||
return; | |||||
} | |||||
} | } | ||||
var currentEqId = this.eq[item.slot]; | var currentEqId = this.eq[item.slot]; | ||||
@@ -61,19 +56,12 @@ define([ | |||||
itemId = itemId.itemId; | itemId = itemId.itemId; | ||||
} | } | ||||
var level = this.obj.stats.originalValues || this.obj.stats.values; | |||||
var item = this.obj.inventory.findItem(itemId); | var item = this.obj.inventory.findItem(itemId); | ||||
if (!item) | if (!item) | ||||
return; | 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; | item.eq = false; | ||||
return; | return; | ||||
} else if ((item.factions) && (this.obj.player)) { | |||||
if (!this.obj.reputation.canEquipItem(item)) { | |||||
item.eq = false; | |||||
return; | |||||
} | |||||
} | } | ||||
if (!slot) | if (!slot) | ||||
@@ -102,7 +90,7 @@ define([ | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-redA', | |||||
message: equipMsg.msg || 'you cannot equip that item', | message: equipMsg.msg || 'you cannot equip that item', | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -149,6 +137,10 @@ define([ | |||||
this.obj.stats.addStat(s, val); | this.obj.stats.addStat(s, val); | ||||
} | } | ||||
(item.implicitStats || []).forEach(function (s) { | |||||
this.obj.stats.addStat(s.stat, s.value); | |||||
}, this); | |||||
item.eq = true; | item.eq = true; | ||||
this.eq[slot] = itemId; | this.eq[slot] = itemId; | ||||
item.equipSlot = slot; | item.equipSlot = slot; | ||||
@@ -221,6 +213,10 @@ define([ | |||||
this.obj.stats.addStat(s, -val); | this.obj.stats.addStat(s, -val); | ||||
} | } | ||||
(item.implicitStats || []).forEach(function (s) { | |||||
this.obj.stats.addStat(s.stat, -s.value); | |||||
}, this); | |||||
delete item.eq; | delete item.eq; | ||||
delete this.eq[item.equipSlot]; | delete this.eq[item.equipSlot]; | ||||
delete item.equipSlot; | delete item.equipSlot; | ||||
@@ -297,7 +293,7 @@ define([ | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q4', | |||||
class: 'color-redA', | |||||
message: 'you unequip your ' + item.name + ' as it zaps you', | message: 'you unequip your ' + item.name + ' as it zaps you', | ||||
type: 'rep' | type: 'rep' | ||||
}] | }] | ||||
@@ -314,17 +310,24 @@ define([ | |||||
var eq = this.eq; | var eq = this.eq; | ||||
for (var p in eq) { | for (var p in eq) { | ||||
var item = items.find(i => (i.id == eq[p])); | var item = items.find(i => (i.id == eq[p])); | ||||
if ((!item.slot) || (item.slot == 'tool') || (item.level <= level)) | |||||
if ((!item.slot) || (item.slot == 'tool')) { | |||||
continue; | continue; | ||||
} | |||||
var item = items.find(i => (i.id == eq[p])); | var item = items.find(i => (i.id == eq[p])); | ||||
var nItemStats = generatorStats.rescale(item, level); | |||||
var nItemStats = item.stats; | |||||
if (item.level > level) | |||||
nItemStats = generatorStats.rescale(item, level); | |||||
var tempItem = extend(true, {}, item); | |||||
tempItem.stats = extend(true, {}, nItemStats); | |||||
this.obj.fireEvent('afterRescaleItemStats', tempItem); | |||||
for (var s in nItemStats) { | |||||
for (var s in tempItem.stats) { | |||||
if (!stats[s]) | if (!stats[s]) | ||||
stats[s] = 0; | stats[s] = 0; | ||||
stats[s] += nItemStats[s]; | |||||
stats[s] += tempItem.stats[s]; | |||||
} | } | ||||
} | } | ||||
@@ -108,13 +108,14 @@ define([ | |||||
var itemCount = blueprint.items.min + ~~(Math.random() * (blueprint.items.max - blueprint.items.min)); | var itemCount = blueprint.items.min + ~~(Math.random() * (blueprint.items.max - blueprint.items.min)); | ||||
for (var i = 0; i < itemCount; i++) { | for (var i = 0; i < itemCount; i++) { | ||||
var minLevel = Math.max(1, list.level * 0.75); | |||||
var maxLevel = list.level * 1.25; | |||||
var minLevel = blueprint.items.minLevel || Math.max(1, list.level * 0.75); | |||||
var maxLevel = blueprint.items.maxLevel || (list.level * 1.25); | |||||
var level = ~~(minLevel + (Math.random() * (maxLevel - minLevel))); | var level = ~~(minLevel + (Math.random() * (maxLevel - minLevel))); | ||||
var item = generator.generate({ | var item = generator.generate({ | ||||
noSpell: true, | noSpell: true, | ||||
magicFind: 150, | magicFind: 150, | ||||
slot: blueprint.items.slot, | |||||
level: level | level: level | ||||
}); | }); | ||||
@@ -157,6 +158,7 @@ define([ | |||||
if (item.type == 'skin') { | if (item.type == 'skin') { | ||||
var skinBlueprint = skins.getBlueprint(item.id); | var skinBlueprint = skins.getBlueprint(item.id); | ||||
item.skinId = item.id; | |||||
item.name = skinBlueprint.name; | item.name = skinBlueprint.name; | ||||
item.sprite = skinBlueprint.sprite; | item.sprite = skinBlueprint.sprite; | ||||
} else if (item.generate) { | } else if (item.generate) { | ||||
@@ -165,6 +167,10 @@ define([ | |||||
generated.worth = item.worth; | generated.worth = item.worth; | ||||
if (item.infinite) | if (item.infinite) | ||||
generated.infinite = true; | generated.infinite = true; | ||||
if (item.factions) | |||||
generated.factions = item.factions; | |||||
item = generated; | item = generated; | ||||
} | } | ||||
@@ -195,7 +201,7 @@ define([ | |||||
requestedBy.instance.syncer.queue('onGetMessages', { | requestedBy.instance.syncer.queue('onGetMessages', { | ||||
id: requestedBy.id, | id: requestedBy.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-redA', | |||||
message: `your reputation is too low to buy that item`, | message: `your reputation is too low to buy that item`, | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -5,7 +5,8 @@ define([ | |||||
'misc/random', | 'misc/random', | ||||
'items/config/slots', | 'items/config/slots', | ||||
'security/io', | 'security/io', | ||||
'config/factions' | |||||
'config/factions', | |||||
'security/connections' | |||||
], function ( | ], function ( | ||||
roles, | roles, | ||||
atlas, | atlas, | ||||
@@ -13,12 +14,20 @@ define([ | |||||
random, | random, | ||||
configSlots, | configSlots, | ||||
io, | io, | ||||
factions | |||||
factions, | |||||
connections | |||||
) { | ) { | ||||
var commandRoles = { | var commandRoles = { | ||||
//Regular players | |||||
join: 0, | join: 0, | ||||
leave: 0, | leave: 0, | ||||
unEq: 0, | unEq: 0, | ||||
//Mods | |||||
mute: 5, | |||||
unmute: 5, | |||||
//Admin | |||||
getItem: 10, | getItem: 10, | ||||
getGold: 10, | getGold: 10, | ||||
setLevel: 10, | setLevel: 10, | ||||
@@ -28,12 +37,15 @@ define([ | |||||
getReputation: 10, | getReputation: 10, | ||||
loseReputation: 10, | loseReputation: 10, | ||||
setStat: 10, | setStat: 10, | ||||
die: 10 | |||||
die: 10, | |||||
getXp: 10 | |||||
}; | }; | ||||
var localCommands = [ | var localCommands = [ | ||||
'join', | 'join', | ||||
'leave' | |||||
'leave', | |||||
'mute', | |||||
'unmute' | |||||
]; | ]; | ||||
return { | return { | ||||
@@ -115,7 +127,7 @@ define([ | |||||
obj.socket.emit('events', { | obj.socket.emit('events', { | ||||
onGetMessages: [{ | onGetMessages: [{ | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-yellowB', | |||||
message: 'joined channel: ' + value, | message: 'joined channel: ' + value, | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -139,7 +151,7 @@ define([ | |||||
obj.socket.emit('events', { | obj.socket.emit('events', { | ||||
onGetMessages: [{ | onGetMessages: [{ | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-redA', | |||||
message: 'you are not currently in that channel', | message: 'you are not currently in that channel', | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -167,7 +179,7 @@ define([ | |||||
this.obj.socket.emit('events', { | this.obj.socket.emit('events', { | ||||
onGetMessages: [{ | onGetMessages: [{ | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-yellowB', | |||||
message: 'left channel: ' + value, | message: 'left channel: ' + value, | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -186,6 +198,108 @@ define([ | |||||
}); | }); | ||||
}, | }, | ||||
mute: function (target, reason) { | |||||
if (typeof (target) == 'object') { | |||||
var keys = Object.keys(target); | |||||
target = keys[0]; | |||||
reason = keys[1]; | |||||
} | |||||
if (target == this.obj.name) | |||||
return; | |||||
var o = connections.players.find(o => (o.name == target)); | |||||
if (!o) | |||||
return; | |||||
var role = roles.getRoleLevel(o); | |||||
if (role >= this.roleLevel) | |||||
return; | |||||
var social = o.social; | |||||
if (social.muted) { | |||||
this.sendMessage('That player has already been muted', 'color-redA'); | |||||
return; | |||||
} | |||||
var reasonMsg = ''; | |||||
if (reason) | |||||
reasonMsg = ' (' + reason + ')'; | |||||
social.muted = true; | |||||
this.sendMessage('Successfully muted ' + target, 'color-yellowB'); | |||||
this.sendMessage('You have been muted' + reasonMsg, 'color-yellowB', o); | |||||
atlas.updateObject(o, { | |||||
components: [{ | |||||
type: 'social', | |||||
muted: true | |||||
}] | |||||
}); | |||||
io.set({ | |||||
ent: new Date(), | |||||
field: 'modLog', | |||||
value: JSON.stringify({ | |||||
source: this.obj.name, | |||||
command: 'mute', | |||||
target: target, | |||||
reason: reason | |||||
}) | |||||
}); | |||||
}, | |||||
unmute: function (target, reason) { | |||||
if (typeof (target) == 'object') { | |||||
var keys = Object.keys(target); | |||||
target = keys[0]; | |||||
reason = keys[1]; | |||||
} | |||||
if (target == this.obj.name) | |||||
return; | |||||
var o = connections.players.find(o => (o.name == target)); | |||||
if (!o) | |||||
return; | |||||
var role = roles.getRoleLevel(o); | |||||
if (role >= this.roleLevel) | |||||
return; | |||||
var social = o.social; | |||||
if (!social.muted) { | |||||
this.sendMessage('That player is not muted', 'color-redA'); | |||||
return; | |||||
} | |||||
var reasonMsg = ''; | |||||
if (reason) | |||||
reasonMsg = ' (' + reason + ')'; | |||||
delete social.muted; | |||||
this.sendMessage('Successfully unmuted ' + target, 'color-yellowB'); | |||||
this.sendMessage('You have been unmuted' + reasonMsg, 'color-yellowB', o); | |||||
atlas.updateObject(o, { | |||||
components: [{ | |||||
type: 'social', | |||||
muted: null | |||||
}] | |||||
}); | |||||
io.set({ | |||||
ent: new Date(), | |||||
field: 'modLog', | |||||
value: JSON.stringify({ | |||||
source: this.obj.name, | |||||
command: 'unmute', | |||||
target: target, | |||||
reason: reason | |||||
}) | |||||
}) | |||||
}, | |||||
clearInventory: function () { | clearInventory: function () { | ||||
var inventory = this.obj.inventory; | var inventory = this.obj.inventory; | ||||
@@ -360,6 +474,10 @@ define([ | |||||
this.obj.stats.values[config.stat] = ~~config.value; | this.obj.stats.values[config.stat] = ~~config.value; | ||||
}, | }, | ||||
getXp: function (amount) { | |||||
this.obj.stats.getXp(amount, this.obj, this.obj); | |||||
}, | |||||
die: function () { | die: function () { | ||||
this.obj.stats.takeDamage({ | this.obj.stats.takeDamage({ | ||||
amount: 99999 | amount: 99999 | ||||
@@ -3,7 +3,7 @@ define([ | |||||
'items/salvager', | 'items/salvager', | ||||
'items/enchanter', | 'items/enchanter', | ||||
'objects/objects', | 'objects/objects', | ||||
'config/classes', | |||||
'config/spirits', | |||||
'mtx/mtx', | 'mtx/mtx', | ||||
'config/factions', | 'config/factions', | ||||
'items/itemEffects' | 'items/itemEffects' | ||||
@@ -18,6 +18,7 @@ define([ | |||||
itemEffects | itemEffects | ||||
) { | ) { | ||||
return { | return { | ||||
//Properties | |||||
type: 'inventory', | type: 'inventory', | ||||
inventorySize: 50, | inventorySize: 50, | ||||
@@ -25,6 +26,8 @@ define([ | |||||
blueprint: null, | blueprint: null, | ||||
//Base Methods | |||||
init: function (blueprint, isTransfer) { | init: function (blueprint, isTransfer) { | ||||
var items = blueprint.items || []; | var items = blueprint.items || []; | ||||
var iLen = items.length; | var iLen = items.length; | ||||
@@ -68,51 +71,74 @@ define([ | |||||
this.hookItemEvents(); | 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); | |||||
} | } | ||||
}, | }, | ||||
@@ -165,7 +191,7 @@ define([ | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-redA', | |||||
message: learnMsg.msg || 'you cannot learn that ability', | message: learnMsg.msg || 'you cannot learn that ability', | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -439,6 +465,7 @@ define([ | |||||
callback: this.onCheckCharExists.bind(this, msg, item) | callback: this.onCheckCharExists.bind(this, msg, item) | ||||
}); | }); | ||||
}, | }, | ||||
onCheckCharExists: function (msg, item, res) { | onCheckCharExists: function (msg, item, res) { | ||||
if (!res) { | if (!res) { | ||||
this.resolveCallback(msg, 'Recipient does not exist'); | this.resolveCallback(msg, 'Recipient does not exist'); | ||||
@@ -454,6 +481,54 @@ define([ | |||||
//Helpers | //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) { | setItemPosition: function (id) { | ||||
var item = this.findItem(id); | var item = this.findItem(id); | ||||
if (!item) | if (!item) | ||||
@@ -630,8 +705,8 @@ define([ | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
message: 'you bags are too full to loot any more items', | |||||
class: 'color-redA', | |||||
message: 'your bags are too full to loot any more items', | |||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
}, [this.obj.serverId]); | }, [this.obj.serverId]); | ||||
@@ -735,7 +810,7 @@ define([ | |||||
this.obj.equipment.equip(item.id); | this.obj.equipment.equip(item.id); | ||||
} else { | } else { | ||||
if (!item.effects) | if (!item.effects) | ||||
this.obj.syncer.setArray(true, 'inventory', 'getItems', item); | |||||
this.obj.syncer.setArray(true, 'inventory', 'getItems', item, true); | |||||
else { | else { | ||||
var result = extend(true, {}, item); | var result = extend(true, {}, item); | ||||
result.effects = result.effects.map(e => ({ | result.effects = result.effects.map(e => ({ | ||||
@@ -765,7 +840,7 @@ define([ | |||||
}, this); | }, this); | ||||
} | } | ||||
this.obj.syncer.setArray(true, 'inventory', 'getItems', result); | |||||
this.obj.syncer.setArray(true, 'inventory', 'getItems', result, true); | |||||
} | } | ||||
} | } | ||||
@@ -950,75 +1025,24 @@ define([ | |||||
this.items = []; | this.items = []; | ||||
}, | }, | ||||
save: function () { | |||||
return { | |||||
type: 'inventory', | |||||
items: this.items | |||||
}; | |||||
}, | |||||
simplify: function (self) { | |||||
if (!self) | |||||
return null; | |||||
var reputation = this.obj.reputation; | |||||
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); | |||||
canEquipItem: function (item) { | |||||
var stats = this.obj.stats.values; | |||||
var noEquip = null; | |||||
if (factionTier < f.tier) | |||||
noEquip = true; | |||||
var playerLevel = (stats.originalLevel || stats.level); | |||||
if (item.level > playerLevel) | |||||
return false; | |||||
if (!faction) | |||||
console.log(f); | |||||
if ((item.requires) && (stats[item.requires[0].stat] < item.requires[0].value)) | |||||
return false; | |||||
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; | |||||
} | } | ||||
}; | }; | ||||
}); | }); |
@@ -207,7 +207,7 @@ define([ | |||||
canChase: function (obj) { | canChase: function (obj) { | ||||
var distanceFromHome = Math.max(Math.abs(this.originX - obj.x), Math.abs(this.originY - obj.y)); | var distanceFromHome = Math.max(Math.abs(this.originX - obj.x), Math.abs(this.originY - obj.y)); | ||||
return (distanceFromHome <= this.maxChaseDistance) | |||||
return ((!this.goHome) && (distanceFromHome <= this.maxChaseDistance)); | |||||
} | } | ||||
}; | }; | ||||
}); | }); |
@@ -1,11 +1,13 @@ | |||||
define([ | define([ | ||||
'world/atlas', | 'world/atlas', | ||||
'config/classes', | |||||
'config/roles' | |||||
'config/spirits', | |||||
'config/roles', | |||||
'config/serverConfig' | |||||
], function ( | ], function ( | ||||
atlas, | atlas, | ||||
classes, | classes, | ||||
roles | |||||
roles, | |||||
serverConfig | |||||
) { | ) { | ||||
return { | return { | ||||
type: 'player', | type: 'player', | ||||
@@ -26,6 +28,9 @@ define([ | |||||
spawn: function (character, cb) { | spawn: function (character, cb) { | ||||
var obj = this.obj; | var obj = this.obj; | ||||
if (character.dead) | |||||
obj.dead = true; | |||||
extend(true, obj, { | extend(true, obj, { | ||||
layerName: 'mobs', | layerName: 'mobs', | ||||
cell: character.cell, | cell: character.cell, | ||||
@@ -33,9 +38,10 @@ define([ | |||||
skinId: character.skinId, | skinId: character.skinId, | ||||
name: character.name, | name: character.name, | ||||
class: character.class, | class: character.class, | ||||
zoneName: character.zoneName || 'fjolarok', | |||||
zoneName: character.zoneName || serverConfig.defaultZone, | |||||
x: character.x, | x: character.x, | ||||
y: character.y, | y: character.y, | ||||
hidden: character.dead, | |||||
account: character.account, | account: character.account, | ||||
instanceId: character.instanceId | instanceId: character.instanceId | ||||
}); | }); | ||||
@@ -56,7 +62,6 @@ define([ | |||||
for (var s in blueprintStats.stats) { | for (var s in blueprintStats.stats) { | ||||
stats.stats[s] = blueprintStats.stats[s]; | stats.stats[s] = blueprintStats.stats[s]; | ||||
} | } | ||||
stats.vitScale = blueprintStats.vitScale; | |||||
var gainStats = classes.stats[character.class].gainStats; | var gainStats = classes.stats[character.class].gainStats; | ||||
for (var s in gainStats) { | for (var s in gainStats) { | ||||
@@ -121,7 +126,7 @@ define([ | |||||
io.sockets.emit('events', { | io.sockets.emit('events', { | ||||
onGetMessages: [{ | onGetMessages: [{ | ||||
messages: [{ | messages: [{ | ||||
class: 'q3', | |||||
class: 'color-blueB', | |||||
message: this.obj.name + ' has come online' | message: this.obj.name + ' has come online' | ||||
}] | }] | ||||
}], | }], | ||||
@@ -163,6 +168,9 @@ define([ | |||||
var physics = this.obj.instance.physics; | var physics = this.obj.instance.physics; | ||||
physics.removeObject(this.obj, this.obj.x, this.obj.y); | physics.removeObject(this.obj, this.obj.x, this.obj.y); | ||||
this.obj.dead = true; | |||||
this.obj.aggro.die(); | |||||
if (!permadeath) { | if (!permadeath) { | ||||
var level = this.obj.stats.values.level; | var level = this.obj.stats.values.level; | ||||
@@ -181,20 +189,21 @@ define([ | |||||
this.obj.x = spawnPos.x; | this.obj.x = spawnPos.x; | ||||
this.obj.y = spawnPos.y; | this.obj.y = spawnPos.y; | ||||
var syncer = this.obj.syncer; | |||||
syncer.o.x = this.obj.x; | |||||
syncer.o.y = this.obj.y; | |||||
physics.addObject(this.obj, this.obj.x, this.obj.y); | |||||
this.obj.stats.die(source); | this.obj.stats.die(source); | ||||
} else { | |||||
this.obj.stats.dead = true; | |||||
process.send({ | process.send({ | ||||
method: 'object', | method: 'object', | ||||
serverId: this.obj.serverId, | serverId: this.obj.serverId, | ||||
obj: { | obj: { | ||||
dead: true | |||||
} | |||||
}); | |||||
} else { | |||||
process.send({ | |||||
method: 'object', | |||||
serverId: this.obj.serverId, | |||||
obj: { | |||||
dead: true, | |||||
permadead: true | permadead: true | ||||
} | } | ||||
}); | }); | ||||
@@ -202,11 +211,18 @@ define([ | |||||
this.obj.fireEvent('onAfterDeath', source); | this.obj.fireEvent('onAfterDeath', source); | ||||
this.obj.aggro.die(); | |||||
this.obj.spellbook.die(); | this.obj.spellbook.die(); | ||||
this.obj.effects.die(); | this.obj.effects.die(); | ||||
}, | |||||
respawn: function () { | |||||
var syncer = this.obj.syncer; | |||||
syncer.o.x = this.obj.x; | |||||
syncer.o.y = this.obj.y; | |||||
this.obj.aggro.move(); | this.obj.aggro.move(); | ||||
this.obj.instance.physics.addObject(this.obj, this.obj.x, this.obj.y); | |||||
}, | }, | ||||
move: function (msg) { | move: function (msg) { | ||||
@@ -40,8 +40,10 @@ define([ | |||||
factionBlueprint = factions.getFaction(factionId); | factionBlueprint = factions.getFaction(factionId); | ||||
} catch (e) {} | } catch (e) {} | ||||
if (factionBlueprint == null) | |||||
if (factionBlueprint == null) { | |||||
console.log('No faction blueprint found'); | |||||
return; | return; | ||||
} | |||||
factionBlueprint = extend(true, {}, factionBase, factionBlueprint); | factionBlueprint = extend(true, {}, factionBase, factionBlueprint); | ||||
@@ -127,25 +129,25 @@ define([ | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q1', | |||||
class: (action == 'gained') ? 'color-greenB' : 'color-redA', | |||||
message: 'you ' + action + ' ' + Math.abs(gain) + ' reputation with ' + blueprint.name, | message: 'you ' + action + ' ' + Math.abs(gain) + ' reputation with ' + blueprint.name, | ||||
type: 'rep' | type: 'rep' | ||||
}] | }] | ||||
}, [this.obj.serverId]); | }, [this.obj.serverId]); | ||||
if (faction.tier != oldTier) { | if (faction.tier != oldTier) { | ||||
this.sendMessage(blueprint.tiers[faction.tier].name, blueprint.name); | |||||
this.sendMessage(blueprint.tiers[faction.tier].name, blueprint.name, (faction.tier > oldTier)); | |||||
this.obj.equipment.unequipFactionGear(faction.id, faction.tier); | this.obj.equipment.unequipFactionGear(faction.id, faction.tier); | ||||
} | } | ||||
this.syncFaction(factionId, fullSync); | this.syncFaction(factionId, fullSync); | ||||
}, | }, | ||||
sendMessage: function (tierName, factionName) { | |||||
sendMessage: function (tierName, factionName, didIncrease) { | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q4', | |||||
class: didIncrease ? 'color-greenB' : 'color-redA', | |||||
message: 'you are now ' + tierName + ' with ' + factionName, | message: 'you are now ' + tierName + ' with ' + factionName, | ||||
type: 'rep' | type: 'rep' | ||||
}] | }] | ||||
@@ -1,9 +1,11 @@ | |||||
define([ | define([ | ||||
'world/atlas', | 'world/atlas', | ||||
'config/roles' | |||||
'config/roles', | |||||
'misc/events' | |||||
], function ( | ], function ( | ||||
atlas, | atlas, | ||||
roles | |||||
roles, | |||||
events | |||||
) { | ) { | ||||
return { | return { | ||||
type: 'social', | type: 'social', | ||||
@@ -14,6 +16,8 @@ define([ | |||||
customChannels: null, | customChannels: null, | ||||
messageHistory: [], | |||||
init: function (blueprint) { | init: function (blueprint) { | ||||
this.obj.extendComponent('social', 'socialCommands', {}); | this.obj.extendComponent('social', 'socialCommands', {}); | ||||
}, | }, | ||||
@@ -22,16 +26,17 @@ define([ | |||||
return { | return { | ||||
type: 'social', | type: 'social', | ||||
party: this.party, | party: this.party, | ||||
customChannels: self ? this.customChannels : null | |||||
customChannels: self ? this.customChannels : null, | |||||
muted: this.muted | |||||
}; | }; | ||||
}, | }, | ||||
sendMessage: function (msg) { | |||||
this.obj.socket.emit('event', { | |||||
sendMessage: function (msg, color, target) { | |||||
(target || this.obj).socket.emit('event', { | |||||
event: 'onGetMessages', | event: 'onGetMessages', | ||||
data: { | data: { | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: color || 'q0', | |||||
message: msg, | message: msg, | ||||
type: 'chat' | type: 'chat' | ||||
}] | }] | ||||
@@ -44,7 +49,7 @@ define([ | |||||
this.obj.socket.emit('events', { | this.obj.socket.emit('events', { | ||||
onGetMessages: [{ | onGetMessages: [{ | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-redA', | |||||
message: 'you are not in a party', | message: 'you are not in a party', | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -63,7 +68,7 @@ define([ | |||||
player.socket.emit('events', { | player.socket.emit('events', { | ||||
onGetMessages: [{ | onGetMessages: [{ | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-grayB', | |||||
message: '(party: ' + charname + '): ' + message, | message: '(party: ' + charname + '): ' + message, | ||||
type: 'chat' | type: 'chat' | ||||
}] | }] | ||||
@@ -84,7 +89,7 @@ define([ | |||||
this.obj.socket.emit('events', { | this.obj.socket.emit('events', { | ||||
onGetMessages: [{ | onGetMessages: [{ | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-redA', | |||||
message: 'syntax: $channel message', | message: 'syntax: $channel message', | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -95,7 +100,7 @@ define([ | |||||
this.obj.socket.emit('events', { | this.obj.socket.emit('events', { | ||||
onGetMessages: [{ | onGetMessages: [{ | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-redA', | |||||
message: 'you are not currently in channel: ' + channel, | message: 'you are not currently in channel: ' + channel, | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -108,7 +113,7 @@ define([ | |||||
pList[i].socket.emit('events', { | pList[i].socket.emit('events', { | ||||
onGetMessages: [{ | onGetMessages: [{ | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-grayB', | |||||
message: '[' + channel + '] ' + this.obj.auth.charname + ': ' + message, | message: '[' + channel + '] ' + this.obj.auth.charname + ': ' + message, | ||||
type: channel.trim() | type: channel.trim() | ||||
}] | }] | ||||
@@ -125,22 +130,57 @@ define([ | |||||
msg.data.message = msg.data.message | msg.data.message = msg.data.message | ||||
.split('<') | .split('<') | ||||
.join('') | |||||
.join('<') | |||||
.split('>') | .split('>') | ||||
.join(''); | |||||
.join('>'); | |||||
if (!msg.data.message) | if (!msg.data.message) | ||||
return; | return; | ||||
if (msg.data.message.trim() == '') | |||||
return; | |||||
this.onBeforeChat(msg.data); | this.onBeforeChat(msg.data); | ||||
if (msg.data.ignore) | if (msg.data.ignore) | ||||
return; | return; | ||||
if (this.muted) { | |||||
this.sendMessage('You have been muted from talking', 'color-redA'); | |||||
return; | |||||
} | |||||
var messageString = msg.data.message; | |||||
var history = this.messageHistory; | |||||
var time = +new Date; | |||||
history.spliceWhere(h => ((time - h.time) > 5000)); | |||||
if (history.length > 0) { | |||||
if (history[history.length - 1].msg == messageString) { | |||||
this.sendMessage('You have already sent that message', 'color-redA'); | |||||
return; | |||||
} else if (history.length >= 3) { | |||||
this.sendMessage('You are sending too many messages', 'color-redA'); | |||||
return; | |||||
} | |||||
} | |||||
history.push({ | |||||
msg: messageString, | |||||
time: time | |||||
}); | |||||
var charname = this.obj.auth.charname; | var charname = this.obj.auth.charname; | ||||
var msgStyle = roles.getRoleMessageStyle(this.obj) || ('q'); | |||||
var msgStyle = roles.getRoleMessageStyle(this.obj) || ('color-grayB'); | |||||
var messageString = msg.data.message; | |||||
var msgEvent = { | |||||
source: charname, | |||||
msg: messageString | |||||
}; | |||||
events.emit('onBeforeSendMessage', msgEvent); | |||||
messageString = msgEvent.msg; | |||||
if (messageString[0] == '@') { | if (messageString[0] == '@') { | ||||
var playerName = ''; | var playerName = ''; | ||||
//Check if there's a space in the name | //Check if there's a space in the name | ||||
@@ -163,7 +203,7 @@ define([ | |||||
event: 'onGetMessages', | event: 'onGetMessages', | ||||
data: { | data: { | ||||
messages: [{ | messages: [{ | ||||
class: msgStyle, | |||||
class: 'color-yellowB', | |||||
message: '(you to ' + playerName + '): ' + messageString, | message: '(you to ' + playerName + '): ' + messageString, | ||||
type: 'chat' | type: 'chat' | ||||
}] | }] | ||||
@@ -174,7 +214,7 @@ define([ | |||||
event: 'onGetMessages', | event: 'onGetMessages', | ||||
data: { | data: { | ||||
messages: [{ | messages: [{ | ||||
class: msgStyle, | |||||
class: 'color-yellowB', | |||||
message: '(' + this.obj.name + ' to you): ' + messageString, | message: '(' + this.obj.name + ' to you): ' + messageString, | ||||
type: 'chat' | type: 'chat' | ||||
}] | }] | ||||
@@ -223,8 +263,8 @@ define([ | |||||
if (!source) | if (!source) | ||||
return; | return; | ||||
source.social.sendMessage('invite sent'); | |||||
this.sendMessage(source.name + ' has invited you to join a party'); | |||||
source.social.sendMessage('invite sent', 'color-yellowB'); | |||||
this.sendMessage(source.name + ' has invited you to join a party', 'color-yellowB'); | |||||
this.obj.socket.emit('event', { | this.obj.socket.emit('event', { | ||||
event: 'onGetInvite', | event: 'onGetInvite', | ||||
@@ -259,7 +299,7 @@ define([ | |||||
var msg = source.name + ' has joined the party'; | var msg = source.name + ' has joined the party'; | ||||
if (p == sourceId) | if (p == sourceId) | ||||
msg = 'you have joined a party'; | msg = 'you have joined a party'; | ||||
player.social.sendMessage(msg); | |||||
player.social.sendMessage(msg, 'color-yellowB'); | |||||
player | player | ||||
.socket.emit('event', { | .socket.emit('event', { | ||||
@@ -274,7 +314,7 @@ define([ | |||||
if (!target) | if (!target) | ||||
return; | return; | ||||
this.sendMessage(target.name + ' declined your party invitation'); | |||||
this.sendMessage(target.name + ' declined your party invitation', 'color-redA'); | |||||
}, | }, | ||||
//Gets called on the player that requested to leave | //Gets called on the player that requested to leave | ||||
@@ -355,7 +395,7 @@ define([ | |||||
//Gets called on the player that requested the removal | //Gets called on the player that requested the removal | ||||
removeFromParty: function (msg) { | removeFromParty: function (msg) { | ||||
if (!this.isPartyLeader) { | if (!this.isPartyLeader) { | ||||
this.sendMessage('you are not the party leader'); | |||||
this.sendMessage('you are not the party leader', 'color-redA'); | |||||
return; | return; | ||||
} | } | ||||
@@ -371,7 +411,7 @@ define([ | |||||
onGetParty: [this.party], | onGetParty: [this.party], | ||||
onGetMessages: [{ | onGetMessages: [{ | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-yellowB', | |||||
message: target.name + ' has been removed from the party' | message: target.name + ' has been removed from the party' | ||||
}] | }] | ||||
}] | }] | ||||
@@ -381,7 +421,7 @@ define([ | |||||
target.socket.emit('events', { | target.socket.emit('events', { | ||||
onGetMessages: [{ | onGetMessages: [{ | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-redA', | |||||
message: 'you have been removed from the party' | message: 'you have been removed from the party' | ||||
}] | }] | ||||
}], | }], | ||||
@@ -397,7 +437,7 @@ define([ | |||||
this.isPartyLeader = null; | this.isPartyLeader = null; | ||||
this.updatePartyOnThread(); | this.updatePartyOnThread(); | ||||
this.sendMessage('your party has been disbanded'); | |||||
this.sendMessage('your party has been disbanded', 'color-yellowB'); | |||||
} | } | ||||
}, | }, | ||||
@@ -155,7 +155,6 @@ define([ | |||||
var type = runeSpell.type; | var type = runeSpell.type; | ||||
var playerSpell = playerSpells.spells.find(s => (s.name.toLowerCase() == runeSpell.name.toLowerCase())) || playerSpells.spells.find(s => (s.type == type)); | var playerSpell = playerSpells.spells.find(s => (s.name.toLowerCase() == runeSpell.name.toLowerCase())) || playerSpells.spells.find(s => (s.type == type)); | ||||
var playerSpellConfig = playerSpellsConfig.spells[runeSpell.name.toLowerCase()] || playerSpellsConfig.spells[runeSpell.type]; | var playerSpellConfig = playerSpellsConfig.spells[runeSpell.name.toLowerCase()] || playerSpellsConfig.spells[runeSpell.type]; | ||||
if (!playerSpellConfig) | if (!playerSpellConfig) | ||||
return -1; | return -1; | ||||
@@ -167,7 +166,7 @@ define([ | |||||
var builtSpell = extend(true, { | var builtSpell = extend(true, { | ||||
type: runeSpell.type, | type: runeSpell.type, | ||||
values: {} | values: {} | ||||
}, playerSpell, playerSpellConfig); | |||||
}, playerSpell, playerSpellConfig, runeSpell); | |||||
for (var r in builtSpell.random) { | for (var r in builtSpell.random) { | ||||
var range = builtSpell.random[r]; | var range = builtSpell.random[r]; | ||||
@@ -576,6 +575,17 @@ define([ | |||||
events: { | events: { | ||||
beforeRezone: function () { | beforeRezone: function () { | ||||
this.spells.forEach(function (s) { | |||||
if (s.active) { | |||||
s.active = false; | |||||
var reserve = s.manaReserve; | |||||
if ((reserve) && (reserve.percentage)) | |||||
this.obj.stats.addStat('manaReservePercent', -reserve.percentage); | |||||
} | |||||
}, this); | |||||
var callbacks = this.callbacks; | var callbacks = this.callbacks; | ||||
var cLen = callbacks.length; | var cLen = callbacks.length; | ||||
for (var i = 0; i < cLen; i++) { | for (var i = 0; i < cLen; i++) { | ||||
@@ -1,11 +1,11 @@ | |||||
define([ | define([ | ||||
'config/animations', | 'config/animations', | ||||
'config/loginRewards', | |||||
'config/classes' | |||||
'config/spirits', | |||||
'misc/scheduler' | |||||
], function ( | ], function ( | ||||
animations, | animations, | ||||
loginRewards, | |||||
classes | |||||
classes, | |||||
scheduler | |||||
) { | ) { | ||||
var baseStats = { | var baseStats = { | ||||
mana: 20, | mana: 20, | ||||
@@ -26,16 +26,29 @@ define([ | |||||
itemQuantity: 0, | itemQuantity: 0, | ||||
regenHp: 0, | regenHp: 0, | ||||
regenMana: 5, | regenMana: 5, | ||||
addCritChance: 0, | addCritChance: 0, | ||||
addCritMultiplier: 0, | addCritMultiplier: 0, | ||||
addAttackCritChance: 0, | |||||
addAttackCritMultiplier: 0, | |||||
addSpellCritChance: 0, | |||||
addSpellCritMultiplier: 0, | |||||
critChance: 5, | critChance: 5, | ||||
critMultiplier: 150, | critMultiplier: 150, | ||||
attackCritChance: 0, | |||||
attackCritMultiplier: 0, | |||||
spellCritChance: 0, | |||||
spellCritMultiplier: 0, | |||||
armor: 0, | armor: 0, | ||||
dmgPercent: 0, | dmgPercent: 0, | ||||
vit: 0, | vit: 0, | ||||
blockAttackChance: 0, | blockAttackChance: 0, | ||||
blockSpellChance: 0, | blockSpellChance: 0, | ||||
dodgeAttackChance: 0, | |||||
dodgeSpellChance: 0, | |||||
attackSpeed: 0, | attackSpeed: 0, | ||||
castSpeed: 0, | castSpeed: 0, | ||||
@@ -72,7 +85,12 @@ define([ | |||||
values: baseStats, | values: baseStats, | ||||
originalValues: null, | originalValues: null, | ||||
vitScale: 10, | |||||
statScales: { | |||||
vitToHp: 10, | |||||
strToArmor: 1, | |||||
intToMana: (1 / 6), | |||||
dexToDodge: (1 / 12) | |||||
}, | |||||
syncer: null, | syncer: null, | ||||
@@ -81,7 +99,8 @@ define([ | |||||
played: 0, | played: 0, | ||||
lastLogin: null, | lastLogin: null, | ||||
loginStreak: 0, | loginStreak: 0, | ||||
mobKillStreaks: {} | |||||
mobKillStreaks: {}, | |||||
lootStats: {} | |||||
}, | }, | ||||
dead: false, | dead: false, | ||||
@@ -113,7 +132,7 @@ define([ | |||||
}, | }, | ||||
update: function () { | update: function () { | ||||
if (((this.obj.mob) && (!this.obj.follower)) || (this.dead)) | |||||
if (((this.obj.mob) && (!this.obj.follower)) || (this.obj.dead)) | |||||
return; | return; | ||||
var values = this.values; | var values = this.values; | ||||
@@ -173,36 +192,42 @@ define([ | |||||
}, | }, | ||||
addStat: function (stat, value) { | addStat: function (stat, value) { | ||||
var values = this.values; | |||||
if (['lvlRequire', 'allAttributes'].indexOf(stat) == -1) | if (['lvlRequire', 'allAttributes'].indexOf(stat) == -1) | ||||
this.values[stat] += value; | |||||
values[stat] += value; | |||||
var sendOnlyToSelf = (['hp', 'hpMax', 'mana', 'manaMax', 'vit'].indexOf(stat) == -1); | var sendOnlyToSelf = (['hp', 'hpMax', 'mana', 'manaMax', 'vit'].indexOf(stat) == -1); | ||||
this.obj.syncer.setObject(sendOnlyToSelf, 'stats', 'values', stat, this.values[stat]); | |||||
if (stat == 'addCritChance') { | |||||
this.values.critChance += (0.05 * value); | |||||
this.obj.syncer.setObject(true, 'stats', 'values', 'critChance', this.values.critChance); | |||||
} else if (stat == 'addCritMultiplier') { | |||||
this.values.critMultiplier += value; | |||||
this.obj.syncer.setObject(true, 'stats', 'values', 'critMultiplier', this.values.critMultiplier); | |||||
this.obj.syncer.setObject(sendOnlyToSelf, 'stats', 'values', stat, values[stat]); | |||||
if (sendOnlyToSelf) | |||||
this.obj.syncer.setObject(false, 'stats', 'values', stat, values[stat]); | |||||
if (['addCritChance', 'addAttackCritChance', 'addSpellCritChance'].indexOf(stat) > -1) { | |||||
var morphStat = stat.substr(3); | |||||
morphStat = morphStat[0].toLowerCase() + morphStat.substr(1); | |||||
this.addStat(morphStat, (0.05 * value)); | |||||
} else if (['addCritMultiplier', 'addAttackCritMultiplier', 'addSpellCritMultiplier'].indexOf(stat) > -1) { | |||||
var morphStat = stat.substr(3); | |||||
morphStat = morphStat[0].toLowerCase() + morphStat.substr(1); | |||||
this.addStat(morphStat, value); | |||||
} else if (stat == 'vit') { | } else if (stat == 'vit') { | ||||
this.values.hpMax += (value * this.vitScale); | |||||
this.obj.syncer.setObject(true, 'stats', 'values', 'hpMax', this.values.hpMax); | |||||
this.obj.syncer.setObject(false, 'stats', 'values', 'hpMax', this.values.hpMax); | |||||
this.addStat('hpMax', (value * this.statScales.vitToHp)); | |||||
} else if (stat == 'allAttributes') { | } else if (stat == 'allAttributes') { | ||||
['int', 'str', 'dex'].forEach(function (s) { | ['int', 'str', 'dex'].forEach(function (s) { | ||||
this.values[s] += value; | |||||
this.obj.syncer.setObject(true, 'stats', 'values', s, this.values[s]); | |||||
this.addStat(s, value) | |||||
}, this); | }, this); | ||||
} else if (stat == 'elementAllResist') { | } else if (stat == 'elementAllResist') { | ||||
['arcane', 'frost', 'fire', 'holy', 'poison'].forEach(function (s) { | ['arcane', 'frost', 'fire', 'holy', 'poison'].forEach(function (s) { | ||||
var element = 'element' + (s[0].toUpperCase() + s.substr(1)) + 'Resist'; | var element = 'element' + (s[0].toUpperCase() + s.substr(1)) + 'Resist'; | ||||
this.values[element] += value; | |||||
this.obj.syncer.setObject(true, 'stats', 'values', element, this.values[element]); | |||||
this.addStat(element, value); | |||||
}, this); | }, this); | ||||
} | |||||
} else if (stat == 'str') | |||||
this.addStat('armor', (value * this.statScales.strToArmor)); | |||||
else if (stat == 'int') | |||||
this.addStat('manaMax', (value * this.statScales.intToMana)); | |||||
else if (stat == 'dex') | |||||
this.addStat('dodgeAttackChance', (value * this.statScales.dexToDodge)); | |||||
}, | }, | ||||
calcXpMax: function () { | calcXpMax: function () { | ||||
@@ -251,10 +276,13 @@ define([ | |||||
didLevelUp = true; | didLevelUp = true; | ||||
values.xp -= values.xpMax; | values.xp -= values.xpMax; | ||||
this.obj.syncer.setObject(true, 'stats', 'values', 'xp', values.xp); | this.obj.syncer.setObject(true, 'stats', 'values', 'xp', values.xp); | ||||
if (this.originalValues) | |||||
if (this.originalValues) { | |||||
this.originalValues.level++; | this.originalValues.level++; | ||||
else | |||||
values.level++; | |||||
} | |||||
if (values.originalLevel) | |||||
values.originalLevel++; | |||||
values.level++; | |||||
this.obj.fireEvent('onLevelUp', (this.originalValues || this.values).level); | this.obj.fireEvent('onLevelUp', (this.originalValues || this.values).level); | ||||
@@ -265,8 +293,7 @@ define([ | |||||
var gainStats = classes.stats[this.obj.class].gainStats; | var gainStats = classes.stats[this.obj.class].gainStats; | ||||
for (var s in gainStats) { | for (var s in gainStats) { | ||||
values[s] += gainStats[s]; | |||||
this.obj.syncer.setObject(true, 'stats', 'values', s, values[s]); | |||||
this.addStat(s, gainStats[s]); | |||||
} | } | ||||
this.obj.spellbook.calcDps(); | this.obj.spellbook.calcDps(); | ||||
@@ -299,19 +326,36 @@ define([ | |||||
if (didLevelUp) { | if (didLevelUp) { | ||||
var maxLevel = this.obj.instance.zone.level[1] | var maxLevel = this.obj.instance.zone.level[1] | ||||
if (maxLevel < (this.originalValues || values).level) | |||||
if (maxLevel < (this.originalValues || values).level) { | |||||
this.rescale(maxLevel, false); | this.rescale(maxLevel, false); | ||||
else { | |||||
} else { | |||||
this.obj.syncer.setObject(true, 'stats', 'values', 'hpMax', values.hpMax); | this.obj.syncer.setObject(true, 'stats', 'values', 'hpMax', values.hpMax); | ||||
this.obj.syncer.setObject(true, 'stats', 'values', 'level', values.level); | |||||
this.obj.syncer.setObject(true, 'stats', 'values', 'level', this.values.level); | |||||
this.obj.syncer.setObject(true, 'stats', 'values', 'originalLevel', this.values.originalLevel); | |||||
this.obj.syncer.setObject(false, 'stats', 'values', 'hpMax', values.hpMax); | this.obj.syncer.setObject(false, 'stats', 'values', 'hpMax', values.hpMax); | ||||
this.obj.syncer.setObject(false, 'stats', 'values', 'level', values.level); | |||||
this.obj.syncer.setObject(false, 'stats', 'values', 'level', this.values.level); | |||||
this.obj.syncer.setObject(true, 'stats', 'values', 'originalLevel', this.values.originalLevel); | |||||
} | } | ||||
} | } | ||||
var originalValues = this.originalValues; | |||||
if (originalValues) { | |||||
originalValues.xp = values.xp; | |||||
originalValues.xpMax = values.xpMax; | |||||
originalValues.xpTotal = values.xpTotal; | |||||
} | |||||
}, | }, | ||||
kill: function (target) { | kill: function (target) { | ||||
if (target.player) | |||||
return; | |||||
var level = target.stats.values.level; | var level = target.stats.values.level; | ||||
var mobDiffMult = 1; | |||||
if (target.isRare) | |||||
mobDiffMult = 2; | |||||
else if (target.isChampion) | |||||
mobDiffMult = 5; | |||||
//Who should get xp? | //Who should get xp? | ||||
var aggroList = target.aggro.list; | var aggroList = target.aggro.list; | ||||
@@ -341,9 +385,10 @@ define([ | |||||
//We don't currently do this for quests/herb gathering | //We don't currently do this for quests/herb gathering | ||||
var sourceLevel = a.obj.stats.values.level; | var sourceLevel = a.obj.stats.values.level; | ||||
var levelDelta = level - sourceLevel; | var levelDelta = level - sourceLevel; | ||||
var amount = level * 10 * mult; | |||||
var amount = null; | |||||
if (Math.abs(levelDelta) <= 10) | if (Math.abs(levelDelta) <= 10) | ||||
amount = ~~(((sourceLevel + levelDelta) * 10) * Math.pow(1 - (Math.abs(levelDelta) / 10), 2) * mult); | |||||
amount = ~~(((sourceLevel + levelDelta) * 10) * Math.pow(1 - (Math.abs(levelDelta) / 10), 2) * mult * mobDiffMult); | |||||
else | else | ||||
amount = 0; | amount = 0; | ||||
@@ -355,24 +400,87 @@ define([ | |||||
}, | }, | ||||
die: function (source) { | die: function (source) { | ||||
this.values.hp = this.values.hpMax; | |||||
this.values.mana = this.values.manaMax; | |||||
this.obj.syncer.setObject(false, 'stats', 'values', 'hp', this.values.hp); | |||||
this.obj.syncer.setObject(false, 'stats', 'values', 'mana', this.values.mana); | |||||
var obj = this.obj; | |||||
var values = this.values; | |||||
this.syncer.queue('onGetDamage', { | this.syncer.queue('onGetDamage', { | ||||
id: this.obj.id, | |||||
id: obj.id, | |||||
event: true, | event: true, | ||||
text: 'death' | text: 'death' | ||||
}); | }); | ||||
obj.syncer.set(true, null, 'dead', true); | |||||
var obj = obj; | |||||
var syncO = obj.syncer.o; | |||||
obj.hidden = true; | |||||
obj.nonSelectable = true; | |||||
syncO.hidden = true; | |||||
syncO.nonSelectable = true; | |||||
var xpLoss = ~~Math.min(values.xp, values.xpMax / 10); | |||||
values.xp -= xpLoss; | |||||
obj.syncer.setObject(true, 'stats', 'values', 'xp', values.xp); | |||||
this.syncer.queue('onDeath', { | this.syncer.queue('onDeath', { | ||||
x: this.obj.x, | |||||
y: this.obj.y, | |||||
source: source.name | |||||
}, [this.obj.serverId]); | |||||
source: source.name, | |||||
xpLoss: xpLoss | |||||
}, [obj.serverId]); | |||||
obj.instance.syncer.queue('onGetObject', { | |||||
x: obj.x, | |||||
y: obj.y, | |||||
components: [{ | |||||
type: 'attackAnimation', | |||||
row: 0, | |||||
col: 4 | |||||
}] | |||||
}); | |||||
}, | |||||
respawn: function () { | |||||
this.obj.syncer.set(true, null, 'dead', false); | |||||
var obj = this.obj; | |||||
var syncO = obj.syncer.o; | |||||
this.obj.dead = false; | |||||
var values = this.values; | |||||
values.hp = values.hpMax; | |||||
values.mana = values.manaMax; | |||||
obj.syncer.setObject(false, 'stats', 'values', 'hp', values.hp); | |||||
obj.syncer.setObject(false, 'stats', 'values', 'mana', values.mana); | |||||
obj.hidden = false; | |||||
obj.nonSelectable = false; | |||||
syncO.hidden = false; | |||||
syncO.nonSelectable = false; | |||||
process.send({ | |||||
method: 'object', | |||||
serverId: this.obj.serverId, | |||||
obj: { | |||||
dead: false | |||||
} | |||||
}); | |||||
obj.instance.syncer.queue('onGetObject', { | |||||
x: obj.x, | |||||
y: obj.y, | |||||
components: [{ | |||||
type: 'attackAnimation', | |||||
row: 0, | |||||
col: 4 | |||||
}] | |||||
}); | |||||
this.obj.player.respawn(); | |||||
}, | }, | ||||
takeDamage: function (damage, threatMult, source) { | takeDamage: function (damage, threatMult, source) { | ||||
source.fireEvent('beforeDealDamage', damage, this.obj); | source.fireEvent('beforeDealDamage', damage, this.obj); | ||||
this.obj.fireEvent('beforeTakeDamage', damage, source); | this.obj.fireEvent('beforeTakeDamage', damage, source); | ||||
@@ -390,6 +498,8 @@ define([ | |||||
if (amount > this.values.hp) | if (amount > this.values.hp) | ||||
amount = this.values.hp; | amount = this.values.hp; | ||||
damage.dealt = amount; | |||||
this.values.hp -= amount; | this.values.hp -= amount; | ||||
var recipients = []; | var recipients = []; | ||||
if (this.obj.serverId != null) | if (this.obj.serverId != null) | ||||
@@ -402,7 +512,7 @@ define([ | |||||
recipients.push(this.obj.follower.master.serverId); | recipients.push(this.obj.follower.master.serverId); | ||||
if (recipients.length > 0) { | if (recipients.length > 0) { | ||||
if (!damage.blocked) { | |||||
if ((!damage.blocked) && (!damage.dodged)) { | |||||
this.syncer.queue('onGetDamage', { | this.syncer.queue('onGetDamage', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
source: source.id, | source: source.id, | ||||
@@ -449,7 +559,7 @@ define([ | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
messages: { | messages: { | ||||
class: 'color-red', | |||||
class: 'color-redA', | |||||
message: `(level ${this.values.level}) ${this.obj.name} has forever left the shores of the living.` | message: `(level ${this.values.level}) ${this.obj.name} has forever left the shores of the living.` | ||||
} | } | ||||
}); | }); | ||||
@@ -480,12 +590,12 @@ define([ | |||||
var aggroList = this.obj.aggro.list; | var aggroList = this.obj.aggro.list; | ||||
var aLen = aggroList.length; | var aLen = aggroList.length; | ||||
for (var i = 0; i < aLen; i++) { | for (var i = 0; i < aLen; i++) { | ||||
var a = aggroList[i].obj; | |||||
var a = aggroList[i]; | |||||
if (a.serverId == null) | |||||
if ((!a.threat) || (a.obj.serverId == null)) | |||||
continue; | continue; | ||||
this.obj.inventory.dropBag(a.serverId, killSource); | |||||
this.obj.inventory.dropBag(a.obj.serverId, killSource); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -554,9 +664,13 @@ define([ | |||||
delete this.sessionDuration; | delete this.sessionDuration; | ||||
} | } | ||||
var values = extend(true, {}, this.originalValues || this.values); | |||||
values.hp = this.values.hp; | |||||
values.mana = this.values.mana; | |||||
return { | return { | ||||
type: 'stats', | type: 'stats', | ||||
values: this.originalValues || this.values, | |||||
values: values, | |||||
stats: this.stats | stats: this.stats | ||||
}; | }; | ||||
}, | }, | ||||
@@ -589,47 +703,15 @@ define([ | |||||
onLogin: function () { | onLogin: function () { | ||||
var stats = this.stats; | var stats = this.stats; | ||||
var scheduler = require('misc/scheduler'); | |||||
var time = scheduler.getTime(); | var time = scheduler.getTime(); | ||||
var lastLogin = stats.lastLogin; | |||||
if ((!lastLogin) || (lastLogin.day != time.day)) { | |||||
var daysSkipped = 1; | |||||
if (lastLogin) { | |||||
if (time.day > lastLogin.day) | |||||
daysSkipped = time.day - lastLogin.day; | |||||
else { | |||||
var daysInMonth = scheduler.daysInMonth(lastLogin.month); | |||||
daysSkipped = (daysInMonth - lastLogin.day) + time.day; | |||||
for (var i = lastLogin.month + 1; i < time.month - 1; i++) { | |||||
daysSkipped += scheduler.daysInMonth(i); | |||||
} | |||||
} | |||||
} | |||||
if (daysSkipped == 1) { | |||||
stats.loginStreak++; | |||||
if (stats.loginStreak > 21) | |||||
stats.loginStreak = 21; | |||||
} else { | |||||
stats.loginStreak -= (daysSkipped - 1); | |||||
if (stats.loginStreak < 1) | |||||
stats.loginStreak = 1; | |||||
} | |||||
var mail = this.obj.instance.mail; | |||||
var rewards = loginRewards.generate(stats.loginStreak); | |||||
mail.sendMail(this.obj.name, rewards); | |||||
} else | |||||
this.obj.instance.mail.getMail(this.obj.name); | |||||
stats.lastLogin = time; | stats.lastLogin = time; | ||||
this.obj.instance.mail.getMail(this.obj.name); | |||||
}, | }, | ||||
rescale: function (level, isMob) { | rescale: function (level, isMob) { | ||||
if (level >= (this.originalValues || this.values).level) | |||||
return; | |||||
if (level > this.values.level) | |||||
level = this.values.level; | |||||
var sync = this.obj.syncer.setObject.bind(this.obj.syncer); | var sync = this.obj.syncer.setObject.bind(this.obj.syncer); | ||||
@@ -647,7 +729,7 @@ define([ | |||||
var gainStats = classes.stats[this.obj.class].gainStats; | var gainStats = classes.stats[this.obj.class].gainStats; | ||||
for (var s in gainStats) { | for (var s in gainStats) { | ||||
newValues[s] += (gainStats[s] * level); | |||||
this.addStat(s, (gainStats[s] * level)); | |||||
} | } | ||||
newValues.level = level; | newValues.level = level; | ||||
@@ -704,7 +786,26 @@ define([ | |||||
return Math.max(0, (10000 - Math.pow(killStreak, 2)) / 10000); | return Math.max(0, (10000 - Math.pow(killStreak, 2)) / 10000); | ||||
}, | }, | ||||
canGetMobLoot: function (mob) { | |||||
if (!mob.inventory.dailyDrops) | |||||
return true; | |||||
var lootStats = this.stats.lootStats[mob.name]; | |||||
var time = scheduler.getTime(); | |||||
if (!lootStats) { | |||||
this.stats.lootStats[mob.name] = time; | |||||
} else | |||||
return ((lootStats.day != time.day), (lootStats.month != time.month)); | |||||
}, | |||||
events: { | events: { | ||||
transferComplete: function () { | |||||
var maxLevel = this.obj.instance.zone.level[1]; | |||||
if (maxLevel > this.obj.stats.values.level) | |||||
maxLevel = this.obj.stats.values.level; | |||||
this.obj.stats.rescale(maxLevel); | |||||
}, | |||||
afterKillMob: function (mob) { | afterKillMob: function (mob) { | ||||
var mobKillStreaks = this.stats.mobKillStreaks; | var mobKillStreaks = this.stats.mobKillStreaks; | ||||
var mobName = mob.name; | var mobName = mob.name; | ||||
@@ -726,7 +827,7 @@ define([ | |||||
}, | }, | ||||
beforeGetXp: function (event) { | beforeGetXp: function (event) { | ||||
if (!event.target.mob) | |||||
if ((!event.target.mob) && (!event.target.player)) | |||||
return; | return; | ||||
event.amount *= this.getKillStreakCoefficient(event.target.name); | event.amount *= this.getKillStreakCoefficient(event.target.name); | ||||
@@ -737,6 +838,9 @@ define([ | |||||
return; | return; | ||||
event.chanceMultiplier *= this.getKillStreakCoefficient(event.source.name); | event.chanceMultiplier *= this.getKillStreakCoefficient(event.source.name); | ||||
if ((event.chanceMultiplier > 0) && (!this.canGetMobLoot(event.source))) | |||||
event.chanceMultiplier = 0; | |||||
}, | }, | ||||
afterMove: function (event) { | afterMove: function (event) { | ||||
@@ -78,7 +78,7 @@ define([ | |||||
obj[property] = value; | obj[property] = value; | ||||
}, | }, | ||||
setArray: function (self, cpnType, property, value) { | |||||
setArray: function (self, cpnType, property, value, noDuplicate) { | |||||
var o = this.o; | var o = this.o; | ||||
if (self) | if (self) | ||||
o = this.oSelf; | o = this.oSelf; | ||||
@@ -94,6 +94,9 @@ define([ | |||||
if (cpn[property] == null) | if (cpn[property] == null) | ||||
cpn[property] = []; | cpn[property] = []; | ||||
if ((noDuplicate) && (cpn[property].find(f => (f == value)))) | |||||
return; | |||||
cpn[property].push(value); | cpn[property].push(value); | ||||
}, | }, | ||||
@@ -41,7 +41,7 @@ define([ | |||||
item.name = skinBlueprint.name; | item.name = skinBlueprint.name; | ||||
item.sprite = skinBlueprint.sprite; | item.sprite = skinBlueprint.sprite; | ||||
item.spritesheet = skinBlueprint.spritesheet; | item.spritesheet = skinBlueprint.spritesheet; | ||||
id = item.id; | |||||
item.skinId = skinBlueprint.id; | |||||
} | } | ||||
item.id = id; | item.id = id; | ||||
@@ -155,7 +155,7 @@ define([ | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-redA', | |||||
message: `you can't afford that item`, | message: `you can't afford that item`, | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -171,13 +171,13 @@ define([ | |||||
} | } | ||||
if (item.type == 'skin') { | if (item.type == 'skin') { | ||||
var haveSkin = this.obj.auth.doesOwnSkin(item.id); | |||||
var haveSkin = this.obj.auth.doesOwnSkin(item.skinId); | |||||
if (haveSkin) { | if (haveSkin) { | ||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-redA', | |||||
message: `you have already unlocked that skin`, | message: `you have already unlocked that skin`, | ||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
@@ -226,13 +226,13 @@ define([ | |||||
this.obj.inventory.getItem(clonedItem); | this.obj.inventory.getItem(clonedItem); | ||||
} else { | } else { | ||||
this.obj.auth.saveSkin(item.id); | |||||
this.obj.auth.saveSkin(item.skinId); | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
message: item.name + ' (unlocked)', | |||||
class: 'color-greenB', | |||||
message: 'Unlocked skin: ' + item.name, | |||||
type: 'info' | type: 'info' | ||||
}] | }] | ||||
}, [this.obj.serverId]); | }, [this.obj.serverId]); | ||||
@@ -120,7 +120,7 @@ define([ | |||||
onGetSkins: function (obj, skins) { | onGetSkins: function (obj, skins) { | ||||
this.obj.instance.syncer.queue('onGetWardrobeSkins', { | this.obj.instance.syncer.queue('onGetWardrobeSkins', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
skins: skins[obj.class] | |||||
skins: skins | |||||
}, [obj.serverId]); | }, [obj.serverId]); | ||||
} | } | ||||
}; | }; | ||||
@@ -1,72 +0,0 @@ | |||||
define([ | |||||
'../misc/events' | |||||
], function ( | |||||
events | |||||
) { | |||||
var classes = { | |||||
list: ['bear', 'owl', 'lynx'], | |||||
portraits: { | |||||
bear: { | |||||
x: 0, | |||||
y: 0 | |||||
}, | |||||
owl: { | |||||
x: 2, | |||||
y: 0 | |||||
}, | |||||
lynx: { | |||||
x: 3, | |||||
y: 0 | |||||
} | |||||
}, | |||||
spells: { | |||||
owl: ['magic missile', 'ice spear'], | |||||
bear: ['slash', 'charge'], | |||||
lynx: ['flurry', 'smokebomb'] | |||||
}, | |||||
stats: { | |||||
owl: { | |||||
values: { | |||||
hpMax: 50 | |||||
}, | |||||
vitScale: 10, | |||||
gainStats: { | |||||
int: 1 | |||||
} | |||||
}, | |||||
bear: { | |||||
values: { | |||||
hpMax: 80 | |||||
}, | |||||
vitScale: 10, | |||||
gainStats: { | |||||
str: 1 | |||||
} | |||||
}, | |||||
lynx: { | |||||
values: { | |||||
hpMax: 70 | |||||
}, | |||||
vitScale: 10, | |||||
gainStats: { | |||||
dex: 1 | |||||
} | |||||
} | |||||
}, | |||||
weapons: { | |||||
owl: 'Gnarled Staff', | |||||
lynx: 'Dagger', | |||||
bear: 'Sword' | |||||
}, | |||||
getSpritesheet: function (className) { | |||||
return this.stats[className].spritesheet || 'characters'; | |||||
}, | |||||
init: function () { | |||||
events.emit('onBeforeGetClasses', classes); | |||||
} | |||||
}; | |||||
return classes; | |||||
}); |
@@ -10,9 +10,9 @@ define([ | |||||
events: { | events: { | ||||
afterDealDamage: function(damage, target) { | afterDealDamage: function(damage, target) { | ||||
damage.amount *= 0.5; | |||||
damage.dealt *= 0.5; | |||||
this.obj.stats.getHp(damage, this.obj); | this.obj.stats.getHp(damage, this.obj); | ||||
} | } | ||||
} | } | ||||
}; | }; | ||||
}); | |||||
}); |
@@ -9,11 +9,11 @@ define([ | |||||
amount: 1, | amount: 1, | ||||
init: function () { | init: function () { | ||||
this.obj.stats.addStat('regenHp', this.amount * 3); | |||||
this.obj.stats.addStat('regenHp', this.amount); | |||||
}, | }, | ||||
destroy: function () { | destroy: function () { | ||||
this.obj.stats.addStat('regenHp', -(this.amount * 3)); | |||||
this.obj.stats.addStat('regenHp', -this.amount); | |||||
}, | }, | ||||
update: function () { | update: function () { | ||||
@@ -34,7 +34,9 @@ define([ | |||||
result = { | result = { | ||||
factionId: 'akarei', | factionId: 'akarei', | ||||
chance: chanceRoll, | |||||
properties: { | |||||
chance: chanceRoll, | |||||
}, | |||||
text: chanceRoll + '% chance on crit to cast a lightning bolt', | text: chanceRoll + '% chance on crit to cast a lightning bolt', | ||||
events: {} | events: {} | ||||
}; | }; | ||||
@@ -60,7 +62,7 @@ define([ | |||||
var effect = item.effects.find(e => (e.factionId == 'akarei')); | var effect = item.effects.find(e => (e.factionId == 'akarei')); | ||||
var roll = Math.random() * 100; | var roll = Math.random() * 100; | ||||
if (roll >= effect.chance) | |||||
if (roll >= effect.properties.chance) | |||||
return; | return; | ||||
var cbExplode = function (target) { | var cbExplode = function (target) { | ||||
@@ -70,7 +72,7 @@ define([ | |||||
var damage = combat.getDamage({ | var damage = combat.getDamage({ | ||||
source: this, | source: this, | ||||
target: target, | target: target, | ||||
damage: 1, | |||||
damage: item.level * 5, | |||||
element: 'arcane', | element: 'arcane', | ||||
noCrit: true | noCrit: true | ||||
}); | }); | ||||
@@ -0,0 +1,17 @@ | |||||
define([ | |||||
], function ( | |||||
) { | |||||
return { | |||||
id: 'players', | |||||
name: 'Players', | |||||
description: `The players faction.`, | |||||
relations: { | |||||
}, | |||||
noGainRep: true | |||||
}; | |||||
}); |
@@ -1,10 +1,12 @@ | |||||
define([ | define([ | ||||
'combat/combat' | |||||
], function ( | ], function ( | ||||
combat | |||||
) { | ) { | ||||
return { | return { | ||||
events: { | events: { | ||||
element: null, | |||||
onGetText: function (item) { | onGetText: function (item) { | ||||
var rolls = item.effects.find(e => (e.type == 'damageSelf')).rolls; | var rolls = item.effects.find(e => (e.type == 'damageSelf')).rolls; | ||||
@@ -12,14 +14,27 @@ define([ | |||||
}, | }, | ||||
afterDealDamage: function (item, damage, target) { | afterDealDamage: function (item, damage, target) { | ||||
var rolls = item.effects.find(e => (e.type == 'damageSelf')).rolls; | |||||
var effect = item.effects.find(e => (e.type == 'damageSelf')); | |||||
var rolls = effect.rolls; | |||||
var amount = (damage.dealt / 100) * rolls.percentage; | |||||
var newDamage = combat.getDamage({ | |||||
source: { | |||||
stats: { | |||||
values: {} | |||||
} | |||||
}, | |||||
isAttack: false, | |||||
target: this, | |||||
damage: amount, | |||||
element: effect.properties.element, | |||||
noCrit: true | |||||
}); | |||||
var amount = (damage.amount / 100) * rolls.percentage; | |||||
newDamage.noEvents = true; | |||||
this.stats.takeDamage({ | |||||
amount: amount, | |||||
noEvents: true | |||||
}, 1, this); | |||||
this.stats.takeDamage(newDamage, 1, this); | |||||
} | } | ||||
} | } | ||||
}; | }; | ||||
@@ -36,7 +36,7 @@ define([ | |||||
if (chanceRoll >= (rolls.chance || 100)) | if (chanceRoll >= (rolls.chance || 100)) | ||||
return; | return; | ||||
var amount = rolls.amount || ((damage.amount / 100) * rolls.percentage); | |||||
var amount = rolls.amount || ((damage.dealt / 100) * rolls.percentage); | |||||
this.stats.getHp({ | this.stats.getHp({ | ||||
amount: amount | amount: amount | ||||
@@ -269,16 +269,19 @@ module.exports = { | |||||
'akarei scout': { | 'akarei scout': { | ||||
level: 20, | level: 20, | ||||
faction: 'akarei', | faction: 'akarei', | ||||
attackable: false, | |||||
deathRep: -3 | deathRep: -3 | ||||
}, | }, | ||||
'biorn': { | 'biorn': { | ||||
level: 22, | level: 22, | ||||
attackable: false, | |||||
walkDistance: 0, | walkDistance: 0, | ||||
faction: 'akarei', | faction: 'akarei', | ||||
deathRep: -3 | deathRep: -3 | ||||
}, | }, | ||||
'veleif': { | 'veleif': { | ||||
level: 22, | level: 22, | ||||
attackable: false, | |||||
walkDistance: 0, | walkDistance: 0, | ||||
faction: 'akarei', | faction: 'akarei', | ||||
deathRep: -3 | deathRep: -3 | ||||
@@ -286,11 +289,13 @@ module.exports = { | |||||
'akarei artificer': { | 'akarei artificer': { | ||||
level: 24, | level: 24, | ||||
attackable: false, | |||||
faction: 'akarei', | faction: 'akarei', | ||||
deathRep: -6 | deathRep: -6 | ||||
}, | }, | ||||
'thaumaturge yala': { | 'thaumaturge yala': { | ||||
level: 30, | level: 30, | ||||
attackable: false, | |||||
walkDistance: 0, | walkDistance: 0, | ||||
faction: 'akarei', | faction: 'akarei', | ||||
@@ -308,8 +313,11 @@ module.exports = { | |||||
properties: { | properties: { | ||||
cpnTrade: { | cpnTrade: { | ||||
items: { | items: { | ||||
min: 5, | |||||
max: 10, | |||||
min: 2, | |||||
max: 5, | |||||
minLevel: 14, | |||||
maxLevel: 18, | |||||
slot: 'neck', | |||||
extra: [] | extra: [] | ||||
}, | }, | ||||
faction: { | faction: { | ||||
@@ -318,7 +326,7 @@ module.exports = { | |||||
}, | }, | ||||
markup: { | markup: { | ||||
buy: 0.25, | buy: 0.25, | ||||
sell: 10 | |||||
sell: 20 | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -330,6 +338,7 @@ module.exports = { | |||||
cpnBlocker: { | cpnBlocker: { | ||||
init: function () { | init: function () { | ||||
this.obj.instance.physics.setCollision(this.obj.x, this.obj.y, true); | this.obj.instance.physics.setCollision(this.obj.x, this.obj.y, true); | ||||
this.obj.instance.objects.notifyCollisionChange(this.obj.x, this.obj.y, true); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -523,6 +532,7 @@ module.exports = { | |||||
walls.forEach(function (w) { | walls.forEach(function (w) { | ||||
w.destroyed = true; | w.destroyed = true; | ||||
physics.setCollision(w.x, w.y, false); | physics.setCollision(w.x, w.y, false); | ||||
this.obj.instance.objects.notifyCollisionChange(w.x, w.y, false); | |||||
syncer.queue('onGetObject', { | syncer.queue('onGetObject', { | ||||
x: w.x, | x: w.x, | ||||
@@ -533,7 +543,7 @@ module.exports = { | |||||
col: 4 | col: 4 | ||||
}] | }] | ||||
}); | }); | ||||
}); | |||||
}, this); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -25,6 +25,17 @@ module.exports = { | |||||
rolls: 1, | rolls: 1, | ||||
magicFind: 500 | magicFind: 500 | ||||
} | } | ||||
}, | |||||
rare: { | |||||
hpMult: 7, | |||||
dmgMult: 3, | |||||
drops: { | |||||
chance: 100, | |||||
rolls: 1, | |||||
magicFind: 2000 | |||||
} | |||||
} | } | ||||
}, | }, | ||||
'giant gull': { | 'giant gull': { | ||||
@@ -9,7 +9,7 @@ module.exports = { | |||||
}, | }, | ||||
rat: { | rat: { | ||||
faction: 'flolgard', | |||||
faction: 'fjolgard', | |||||
grantRep: { | grantRep: { | ||||
fjolgard: 6 | fjolgard: 6 | ||||
}, | }, | ||||
@@ -23,10 +23,12 @@ module.exports = { | |||||
blueprints: [{ | blueprints: [{ | ||||
chance: 2, | chance: 2, | ||||
type: 'key', | type: 'key', | ||||
noSalvage: true, | |||||
name: 'Rusted Key', | name: 'Rusted Key', | ||||
keyId: 'rustedSewer', | keyId: 'rustedSewer', | ||||
singleUse: true, | singleUse: true, | ||||
sprite: [12, 1] | |||||
sprite: [12, 1], | |||||
quantity: 1 | |||||
}] | }] | ||||
} | } | ||||
}, | }, | ||||
@@ -37,7 +39,7 @@ module.exports = { | |||||
}, | }, | ||||
stinktooth: { | stinktooth: { | ||||
faction: 'flolgard', | |||||
faction: 'fjolgard', | |||||
grantRep: { | grantRep: { | ||||
fjolgard: 15 | fjolgard: 15 | ||||
}, | }, | ||||
@@ -51,10 +53,12 @@ module.exports = { | |||||
blueprints: [{ | blueprints: [{ | ||||
chance: 0.5, | chance: 0.5, | ||||
type: 'key', | type: 'key', | ||||
noSalvage: true, | |||||
name: 'Rusted Key', | name: 'Rusted Key', | ||||
keyId: 'rustedSewer', | keyId: 'rustedSewer', | ||||
singleUse: true, | singleUse: true, | ||||
sprite: [12, 1] | |||||
sprite: [12, 1], | |||||
quantity: 1 | |||||
}] | }] | ||||
} | } | ||||
}, | }, | ||||
@@ -105,10 +109,12 @@ module.exports = { | |||||
blueprints: [{ | blueprints: [{ | ||||
chance: 100, | chance: 100, | ||||
type: 'key', | type: 'key', | ||||
noSalvage: true, | |||||
name: 'Rusted Key', | name: 'Rusted Key', | ||||
keyId: 'rustedSewer', | keyId: 'rustedSewer', | ||||
singleUse: true, | singleUse: true, | ||||
sprite: [12, 1] | |||||
sprite: [12, 1], | |||||
quantity: 1 | |||||
}] | }] | ||||
} | } | ||||
}, | }, | ||||
@@ -122,7 +128,7 @@ module.exports = { | |||||
sewerdoor: { | sewerdoor: { | ||||
properties: { | properties: { | ||||
cpnDoor: { | cpnDoor: { | ||||
autoClose: 15, | |||||
autoClose: 171, | |||||
locked: true, | locked: true, | ||||
key: 'rustedSewer', | key: 'rustedSewer', | ||||
destroyKey: true | destroyKey: true | ||||
@@ -138,6 +144,10 @@ module.exports = { | |||||
properties: { | properties: { | ||||
cpnDoor: {} | cpnDoor: {} | ||||
} | } | ||||
}, | |||||
treasure: { | |||||
cron: '0 2 * * *' | |||||
} | } | ||||
} | } | ||||
}; | }; |
@@ -1,7 +1,7 @@ | |||||
define([ | define([ | ||||
'items/generators/stats' | |||||
], function ( | ], function ( | ||||
generatorStats | |||||
) { | ) { | ||||
return { | return { | ||||
type: 'titangrip', | type: 'titangrip', | ||||
@@ -20,6 +20,10 @@ define([ | |||||
return; | return; | ||||
var stats = item.stats; | var stats = item.stats; | ||||
var maxLevel = this.obj.instance.zone.level[1]; | |||||
if (maxLevel < item.level) | |||||
stats = generatorStats.rescale(item, maxLevel); | |||||
for (var s in stats) { | for (var s in stats) { | ||||
var val = stats[s]; | var val = stats[s]; | ||||
@@ -31,11 +35,25 @@ define([ | |||||
return; | return; | ||||
var stats = item.stats; | var stats = item.stats; | ||||
var maxLevel = this.obj.instance.zone.level[1]; | |||||
if (maxLevel < item.level) | |||||
stats = generatorStats.rescale(item, maxLevel); | |||||
for (var s in stats) { | for (var s in stats) { | ||||
var val = stats[s]; | var val = stats[s]; | ||||
this.obj.stats.addStat(s, -val); | this.obj.stats.addStat(s, -val); | ||||
} | } | ||||
}, | |||||
afterRescaleItemStats: function (item) { | |||||
if (['oneHanded', 'twoHanded'].indexOf(item.slot) == -1) | |||||
return; | |||||
var stats = item.stats; | |||||
for (var s in stats) { | |||||
stats[s] *= 2; | |||||
} | |||||
} | } | ||||
} | } | ||||
}; | }; | ||||
@@ -46,8 +46,6 @@ define([ | |||||
if (template) | if (template) | ||||
quest.xp = template.xp; | quest.xp = template.xp; | ||||
else | |||||
quest.xp = Math.pow(this.instance.spawners.zone.level, 2) * 10; | |||||
//Calculate next id | //Calculate next id | ||||
var id = 0; | var id = 0; | ||||
@@ -62,6 +60,13 @@ define([ | |||||
quest.obj = obj; | quest.obj = obj; | ||||
quest.zoneName = zoneName; | quest.zoneName = zoneName; | ||||
if (!template) { | |||||
var level = this.instance.spawners.zone.level; | |||||
level = level[0]; | |||||
var xp = ~~(level * 22 * quest.getXpMultiplier()); | |||||
quest.xp = xp; | |||||
} | |||||
if (!oQuests.obtain(quest, !!template)) | if (!oQuests.obtain(quest, !!template)) | ||||
this.obtain(obj, template); | this.obtain(obj, template); | ||||
} | } | ||||
@@ -38,6 +38,15 @@ define([ | |||||
return true; | return true; | ||||
}, | }, | ||||
getXpMultiplier: function () { | |||||
if (this.requiredQuality == 2) | |||||
return 8; | |||||
else if (this.requiredQuality == 1) | |||||
return 6; | |||||
else | |||||
return this.need; | |||||
}, | |||||
updateDescription: function () { | updateDescription: function () { | ||||
var typeName = this.typeName; | var typeName = this.typeName; | ||||
if (this.requiredQuality > 0) | if (this.requiredQuality > 0) | ||||
@@ -55,7 +64,7 @@ define([ | |||||
afterGatherResource: function (gatherResult) { | afterGatherResource: function (gatherResult) { | ||||
if (gatherResult.nodeType != this.gatherType) | if (gatherResult.nodeType != this.gatherType) | ||||
return; | return; | ||||
else if ((this.requiredQuality) && (gatherResult.items[0].quality != this.requiredQuality)) | |||||
else if ((this.requiredQuality) && (gatherResult.items[0].quality < this.requiredQuality)) | |||||
return; | return; | ||||
if ((this.obj.zoneName != this.zoneName) || (this.have >= this.need)) | if ((this.obj.zoneName != this.zoneName) || (this.have >= this.need)) | ||||
@@ -34,7 +34,8 @@ define([ | |||||
(mobBlueprint.attackable) || | (mobBlueprint.attackable) || | ||||
(mobBlueprint.attackable == null) | (mobBlueprint.attackable == null) | ||||
) && | ) && | ||||
(mobBlueprint.level <= ~~(this.obj.stats.values.level * 1.35)) | |||||
(mobBlueprint.level <= ~~(this.obj.stats.values.level * 1.35)) && | |||||
(mobCounts[m] > 1) | |||||
); | ); | ||||
}, this); | }, this); | ||||
@@ -57,6 +58,10 @@ define([ | |||||
return true; | return true; | ||||
}, | }, | ||||
getXpMultiplier: function () { | |||||
return this.need; | |||||
}, | |||||
events: { | events: { | ||||
afterKillMob: function (mob) { | afterKillMob: function (mob) { | ||||
if ((mob.name.toLowerCase() != this.mobName.toLowerCase()) || (this.have >= this.need)) | if ((mob.name.toLowerCase() != this.mobName.toLowerCase()) || (this.have >= this.need)) | ||||
@@ -64,6 +64,19 @@ define([ | |||||
return true; | return true; | ||||
}, | }, | ||||
getXpMultiplier: function () { | |||||
var multiplier = 1; | |||||
if (!this.quality) | |||||
multiplier *= 8; | |||||
else if (this.quality == 2) | |||||
multiplier *= 6; | |||||
else if (this.quality == 1) | |||||
multiplier *= 4; | |||||
return multiplier; | |||||
}, | |||||
events: { | events: { | ||||
afterLootMobItem: function (item) { | afterLootMobItem: function (item) { | ||||
if ( | if ( | ||||
@@ -71,7 +84,7 @@ define([ | |||||
(this.obj.zoneName != this.zoneName) || | (this.obj.zoneName != this.zoneName) || | ||||
( | ( | ||||
(this.quality) && | (this.quality) && | ||||
(item.quality != this.quality) | |||||
(item.quality < this.quality) | |||||
) || | ) || | ||||
( | ( | ||||
(this.slot.indexOf) && | (this.slot.indexOf) && | ||||
@@ -48,6 +48,10 @@ define([ | |||||
return true; | return true; | ||||
}, | }, | ||||
getXpMultiplier: function () { | |||||
return (this.need * 1.5); | |||||
}, | |||||
oComplete: function () { | oComplete: function () { | ||||
var inventory = this.obj.inventory; | var inventory = this.obj.inventory; | ||||
var item = inventory.items.find((i => i.name == this.item.name).bind(this)); | var item = inventory.items.find((i => i.name == this.item.name).bind(this)); | ||||
@@ -16,7 +16,7 @@ define([ | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-yellowB', | |||||
message: 'quest obtained (' + this.name + ')' | message: 'quest obtained (' + this.name + ')' | ||||
}] | }] | ||||
}, [this.obj.serverId]); | }, [this.obj.serverId]); | ||||
@@ -34,7 +34,7 @@ define([ | |||||
this.obj.instance.syncer.queue('onGetMessages', { | this.obj.instance.syncer.queue('onGetMessages', { | ||||
id: this.obj.id, | id: this.obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-yellowB', | |||||
message: 'quest ready for turn-in (' + this.name + ')' | message: 'quest ready for turn-in (' + this.name + ')' | ||||
}] | }] | ||||
}, [this.obj.serverId]); | }, [this.obj.serverId]); | ||||
@@ -53,7 +53,7 @@ define([ | |||||
obj.instance.syncer.queue('onGetMessages', { | obj.instance.syncer.queue('onGetMessages', { | ||||
id: obj.id, | id: obj.id, | ||||
messages: [{ | messages: [{ | ||||
class: 'q0', | |||||
class: 'color-yellowB', | |||||
message: 'quest completed (' + this.name + ')' | message: 'quest completed (' + this.name + ')' | ||||
}] | }] | ||||
}, [obj.serverId]); | }, [obj.serverId]); | ||||
@@ -1,53 +0,0 @@ | |||||
define([ | |||||
], function ( | |||||
) { | |||||
var empty = []; | |||||
var regular = ['1.0', '1.2', '1.6']; | |||||
var mtx = [ | |||||
['10.0', '10.1', '10.2', '10.3', '10.4'], | |||||
['11.0', '11.1', '11.2', '11.3', '11.4'] | |||||
]; | |||||
var pA = []; | |||||
var pB = []; | |||||
var pC = []; | |||||
var pD = []; | |||||
mtx.forEach(function (m) { | |||||
m.forEach(function (s, i) { | |||||
var has = [pD]; | |||||
if (i <= 2) | |||||
has.push(pC); | |||||
if (i <= 1) | |||||
has.push(pB); | |||||
if (i == 0) | |||||
has.push(pA); | |||||
has.forEach(function (h) { | |||||
h.push(s); | |||||
}); | |||||
}); | |||||
}); | |||||
return [ | |||||
//Regular Player | |||||
empty.concat(...regular), [], | |||||
[], | |||||
[], | |||||
[], | |||||
//Moderator | |||||
empty.concat(...regular), | |||||
//Patron Level 1 | |||||
empty.concat(...regular, ...pA), | |||||
//Patron Level 2 | |||||
empty.concat(...regular, ...pB), | |||||
//Patron Level 3 | |||||
empty.concat(...regular, ...pC), | |||||
//Patron Level 4 | |||||
empty.concat(...regular, ...pD), | |||||
//Admin | |||||
['*'] | |||||
]; | |||||
}); |