@@ -32,7 +32,8 @@ let components = [ | |||
'reputation', | |||
'serverActions', | |||
'social', | |||
'passives' | |||
'passives', | |||
'sound' | |||
].map(function (c) { | |||
return 'js/components/' + c; | |||
}); | |||
@@ -39,14 +39,14 @@ define([ | |||
max: 18 | |||
} | |||
}, | |||
particlesPerWave: 14, | |||
particleSpacing: 0, | |||
particleSpacing: 0, | |||
lifetime: { | |||
min: 1, | |||
max: 3 | |||
}, | |||
randomColor: true, | |||
randomColor: true, | |||
randomScale: true, | |||
randomSpeed: true, | |||
frequency: 1 | |||
@@ -65,7 +65,7 @@ define([ | |||
} | |||
} | |||
}) | |||
}; | |||
}; | |||
}, | |||
explode: function (blueprint) { | |||
@@ -31,6 +31,7 @@ define([ | |||
let maxAlpha = (1 + ((halfRange * 2) - (Math.abs(halfRange - i) + Math.abs(halfRange - j)))) * 0.1; | |||
this.emitters[n] = renderer.buildEmitter({ | |||
obj: this.obj, | |||
pos: { | |||
x: ((x + i - halfRange) * scale) + (scale / 2), | |||
y: ((y + j - halfRange) * scale) + (scale / 2) | |||
@@ -81,6 +82,12 @@ define([ | |||
}, | |||
setVisible: function (visible) { | |||
let emitters = this.emitters; | |||
for (let p in emitters) | |||
emitters[p].emit = visible; | |||
}, | |||
destroy: function () { | |||
let keys = Object.keys(this.emitters); | |||
for (let i = 0; i < keys.length; i++) { | |||
@@ -89,6 +89,16 @@ define([ | |||
} | |||
}, | |||
setVisible: function (visible) { | |||
this.patches.forEach(function (p) { | |||
p.visible = visible; | |||
}); | |||
this.rays.forEach(function (r) { | |||
r.visible = visible; | |||
}); | |||
}, | |||
destroy: function () { | |||
this.patches.forEach(function (p) { | |||
p.parent.removeChild(p); | |||
@@ -14,6 +14,7 @@ define([ | |||
y: (this.obj.y * scale) + (scale / 2) | |||
}; | |||
this.ttl = blueprint.ttl; | |||
this.blueprint.obj = this.obj; | |||
this.emitter = renderer.buildEmitter(this.blueprint); | |||
}, | |||
@@ -82,8 +82,13 @@ define([ | |||
}, | |||
renderManual: function () { | |||
<<<<<<< HEAD | |||
let source = this.obj; | |||
let target = this.target; | |||
======= | |||
var source = this.obj; | |||
var target = this.target; | |||
>>>>>>> 555-new-dungeon | |||
let dx = target.x - this.x; | |||
let dy = target.y - this.y; | |||
@@ -95,8 +100,13 @@ define([ | |||
source.y = target.y; | |||
this.particles.emitter.emit = false; | |||
if (!this.noExplosion) | |||
<<<<<<< HEAD | |||
source.explosion.explode(); | |||
source.destroyed = true; | |||
======= | |||
this.obj.explosion.explode(); | |||
this.obj.destroyed = true; | |||
>>>>>>> 555-new-dungeon | |||
} else { | |||
dx /= ticksLeft; | |||
dy /= ticksLeft; | |||
@@ -0,0 +1,17 @@ | |||
define([ | |||
'js/sound/sound' | |||
], function ( | |||
sound | |||
) { | |||
return { | |||
type: 'sound', | |||
sound: null, | |||
volume: 0, | |||
init: function () { | |||
var obj = this.obj; | |||
sound.addSound(obj.zoneId, this.sound, this.volume, obj.x, obj.y, obj.width, obj.height, obj.area); | |||
} | |||
}; | |||
}); |
@@ -0,0 +1,44 @@ | |||
define([ | |||
], function ( | |||
) { | |||
return { | |||
distanceBetweenPoints: function (a, b) { | |||
return Math.sqrt(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2)); | |||
}, | |||
distanceToLine: function (p, la, lb) { | |||
var xD = lb[0] - la[0]; | |||
var yD = lb[1] - la[1]; | |||
var u = (((p[0] - la[0]) * xD) + ((p[1] - la[1]) * yD)) / ((xD * xD) + (yD * yD)); | |||
var closestLine; | |||
if (u < 0) | |||
closestLine = [la[0], la[1]]; | |||
else if (u > 1) | |||
closestLine = [lb[0], lb[1]]; | |||
else | |||
closestLine = [la[0] + (u * xD), la[1] + (u * yD)]; | |||
return this.distanceBetweenPoints(p, closestLine); | |||
}, | |||
calculate: function (p, verts) { | |||
var minDistance = 9999; | |||
var vLen = verts.length; | |||
for (var i = 0, j = vLen - 1; i < vLen; j = i++) { | |||
var vi = verts[i]; | |||
var vj = verts[j]; | |||
var distance = this.distanceToLine(p, vi, vj); | |||
if (distance < minDistance) | |||
minDistance = distance; | |||
} | |||
return minDistance; | |||
} | |||
}; | |||
}); |
@@ -1,12 +1,17 @@ | |||
define([ | |||
'js/misc/pathfinder' | |||
'js/misc/pathfinder', | |||
'js/misc/distanceToPolygon' | |||
], function ( | |||
pathfinder | |||
pathfinder, | |||
distanceToPolygon | |||
) { | |||
<<<<<<< HEAD | |||
let sqrt = Math.sqrt.bind(Math); | |||
let ceil = Math.ceil.bind(Math); | |||
let random = Math.random.bind(Math); | |||
======= | |||
>>>>>>> 555-new-dungeon | |||
return { | |||
graph: null, | |||
@@ -28,6 +33,7 @@ define([ | |||
}); | |||
}, | |||
<<<<<<< HEAD | |||
addRegion: function (obj) { | |||
let lowX = obj.x; | |||
let lowY = obj.y; | |||
@@ -253,6 +259,8 @@ define([ | |||
return path; | |||
}, | |||
======= | |||
>>>>>>> 555-new-dungeon | |||
isTileBlocking: function (x, y, mob, obj) { | |||
if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height)) | |||
return true; | |||
@@ -264,6 +272,7 @@ define([ | |||
return ((!node) || (node.weight === 0)); | |||
}, | |||
<<<<<<< HEAD | |||
isCellOpen: function (x, y) { | |||
if ((x < 0) || (y < 0) || (x >= this.width) | (y >= this.height)) | |||
return true; | |||
@@ -289,28 +298,51 @@ define([ | |||
fromX += 0.5; | |||
fromY += 0.5; | |||
======= | |||
>>>>>>> 555-new-dungeon | |||
distance = ceil(distance); | |||
isInPolygon: function (x, y, verts) { | |||
var inside = false; | |||
<<<<<<< HEAD | |||
let x = 0; | |||
let y = 0; | |||
for (let i = 0; i < distance; i++) { | |||
fromX += dx; | |||
fromY += dy; | |||
x = ~~fromX; | |||
y = ~~fromY; | |||
======= | |||
var vLen = verts.length; | |||
for (var i = 0, j = vLen - 1; i < vLen; j = i++) { | |||
var vi = verts[i]; | |||
var vj = verts[j]; | |||
var xi = vi[0]; | |||
var yi = vi[1]; | |||
var xj = vj[0]; | |||
var yj = vj[1]; | |||
>>>>>>> 555-new-dungeon | |||
var doesIntersect = ( | |||
((yi > y) != (yj > y)) && | |||
(x < ((((xj - xi) * (y - yi)) / (yj - yi)) + xi)) | |||
); | |||
<<<<<<< HEAD | |||
if (!graphGrid[x][y]) | |||
return false; | |||
else if ((x === toX) && (y === toY)) | |||
return true; | |||
======= | |||
if (doesIntersect) | |||
inside = !inside | |||
>>>>>>> 555-new-dungeon | |||
} | |||
return true; | |||
return inside; | |||
}, | |||
<<<<<<< HEAD | |||
getClosestPos: function (fromX, fromY, toX, toY, target) { | |||
let tried = {}; | |||
@@ -438,6 +470,10 @@ define([ | |||
node = grid[x][y] = new pathfinder.gridNode(x, y, collides ? 0 : 1); | |||
node.weight = collides ? 0 : 1; | |||
======= | |||
distanceToPolygon: function (p, verts) { | |||
return distanceToPolygon.calculate(p, verts); | |||
>>>>>>> 555-new-dungeon | |||
} | |||
}; | |||
}); |
@@ -1,11 +1,13 @@ | |||
define([ | |||
'js/components/components', | |||
'js/rendering/renderer', | |||
'js/system/events' | |||
'js/system/events', | |||
'js/config' | |||
], function ( | |||
components, | |||
renderer, | |||
events | |||
events, | |||
config | |||
) { | |||
return { | |||
components: [], | |||
@@ -120,6 +122,19 @@ define([ | |||
this.stats.updateHpSprite(); | |||
}, | |||
setVisible: function (visible) { | |||
if (this.sprite) | |||
this.sprite.visible = visible; | |||
if (this.nameSprite) | |||
this.nameSprite.visible = ((visible) && (config.showNames)); | |||
this.components.forEach(function (c) { | |||
if (c.setVisible) | |||
c.setVisible(visible); | |||
}); | |||
}, | |||
destroy: function () { | |||
if (this.sprite) | |||
renderer.destroyObject(this); | |||
@@ -2,12 +2,14 @@ define([ | |||
'js/objects/objBase', | |||
'js/system/events', | |||
'js/rendering/renderer', | |||
'js/sound/sound' | |||
'js/sound/sound', | |||
'js/config' | |||
], function ( | |||
objBase, | |||
events, | |||
renderer, | |||
sound | |||
sound, | |||
config | |||
) { | |||
return { | |||
showNames: false, | |||
@@ -20,21 +22,36 @@ define([ | |||
events.on('onGetObject', this.onGetObject.bind(this)); | |||
events.on('onRezone', this.onRezone.bind(this)); | |||
events.on('onChangeHoverTile', this.getLocation.bind(this)); | |||
events.on('onTilesVisible', this.onTilesVisible.bind(this)); | |||
//Get saved value for showNames, or use the value set above | |||
<<<<<<< HEAD | |||
let showNames = window.localStorage.getItem('iwd_opt_shownames'); | |||
this.showNames = showNames ? (showNames === 'true') : this.showNames; | |||
======= | |||
var showNames = window.localStorage.getItem('iwd_opt_shownames'); | |||
this.showNames = showNames ? (showNames == 'true') : this.showNames; | |||
config.showNames = this.showNames; | |||
>>>>>>> 555-new-dungeon | |||
}, | |||
getLocation: function (x, y) { | |||
let objects = this.objects; | |||
let oLen = objects.length; | |||
<<<<<<< HEAD | |||
let closest = 999; | |||
let mob = null; | |||
for (let i = 0; i < oLen; i++) { | |||
let o = objects[i]; | |||
if ((!o.stats) || (o.nonSelectable)) | |||
======= | |||
var closest = 999; | |||
var mob = null; | |||
for (var i = 0; i < oLen; i++) { | |||
var o = objects[i]; | |||
if ((!o.stats) || (o.nonSelectable) || (o == window.player) || (!o.sprite.visible)) | |||
>>>>>>> 555-new-dungeon | |||
continue; | |||
let dx = Math.abs(o.x - x); | |||
@@ -53,8 +70,13 @@ define([ | |||
getClosest: function (x, y, maxDistance, reverse, fromMob) { | |||
let objects = this.objects; | |||
<<<<<<< HEAD | |||
let list = objects.filter(function (o) { | |||
if ((!o.stats) || (o.nonSelectable) || (o === window.player)) | |||
======= | |||
var list = objects.filter(function (o) { | |||
if ((!o.stats) || (o.nonSelectable) || (o == window.player) || (!o.sprite.visible)) | |||
>>>>>>> 555-new-dungeon | |||
return false; | |||
let dx = Math.abs(o.x - x); | |||
@@ -120,13 +142,18 @@ define([ | |||
else | |||
this.updateObject(exists, obj); | |||
}, | |||
buildObject: function (template) { | |||
let obj = $.extend(true, {}, objBase); | |||
let components = template.components || []; | |||
delete template.components; | |||
<<<<<<< HEAD | |||
let syncTypes = ['portrait']; | |||
======= | |||
var syncTypes = ['portrait', 'area']; | |||
>>>>>>> 555-new-dungeon | |||
for (let p in template) { | |||
let value = template[p]; | |||
@@ -139,19 +166,6 @@ define([ | |||
obj[p] = value; | |||
} | |||
if (obj.sheetName) { | |||
obj.sprite = renderer.buildObject(obj); | |||
if (template.hidden) { | |||
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) { | |||
//Map ids to objects | |||
let keys = Object.keys(c).filter(function (k) { | |||
@@ -170,13 +184,26 @@ define([ | |||
obj.addComponent(c.type, c); | |||
}, this); | |||
if (obj.sheetName) { | |||
obj.sprite = renderer.buildObject(obj); | |||
if (template.hidden) { | |||
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; | |||
} | |||
} | |||
} | |||
this.objects.push(obj); | |||
if (obj.self) { | |||
events.emit('onGetPlayer', obj); | |||
window.player = obj; | |||
sound.init(obj.zoneName); | |||
sound.init(obj.zoneId); | |||
renderer.setPosition({ | |||
x: (obj.x - (renderer.width / (scale * 2))) * scale, | |||
@@ -191,11 +218,16 @@ define([ | |||
x: (obj.x * scale) + (scale / 2), | |||
y: (obj.y * scale) + scale | |||
}); | |||
obj.nameSprite.visible = this.showNames; | |||
} | |||
if (renderer.sprites) { | |||
var isVisible = ((obj.self) || ((renderer.sprites[obj.x]) && (renderer.sprites[obj.x][obj.y].length > 0))); | |||
obj.setVisible(isVisible); | |||
} | |||
return obj; | |||
}, | |||
updateObject: function (obj, template) { | |||
let components = template.components || []; | |||
@@ -240,6 +272,13 @@ define([ | |||
if ((p === 'x') || (p === 'y')) | |||
moved = true; | |||
if (p == 'casting') { | |||
if (obj == window.player) | |||
events.emit('onGetSelfCasting', value); | |||
else | |||
events.emit('onGetTargetCasting', value); | |||
} | |||
if (sprite) { | |||
if (p === 'x') { | |||
if (obj.x < oldX) | |||
@@ -285,8 +324,14 @@ define([ | |||
obj.nameSprite.visible = this.showNames; | |||
} | |||
if (obj.sprite) { | |||
var isVisible = ((!!obj.player) || (renderer.sprites[obj.x][obj.y].length > 0)); | |||
obj.setVisible(isVisible); | |||
} | |||
obj.setSpritePosition(); | |||
}, | |||
update: function () { | |||
let objects = this.objects; | |||
let len = objects.length; | |||
@@ -314,20 +359,46 @@ define([ | |||
//Set new value in localStorage for showNames | |||
window.localStorage.setItem('iwd_opt_shownames', this.showNames); | |||
config.showNames = this.showNames; | |||
let showNames = this.showNames; | |||
<<<<<<< HEAD | |||
let objects = this.objects; | |||
let oLen = objects.length; | |||
for (let i = 0; i < oLen; i++) { | |||
let obj = objects[i]; | |||
let ns = obj.nameSprite; | |||
if ((!ns) || (obj.dead)) | |||
======= | |||
var objects = this.objects; | |||
var oLen = objects.length; | |||
for (var i = 0; i < oLen; i++) { | |||
var obj = objects[i]; | |||
var ns = obj.nameSprite; | |||
if ((!ns) || (obj.dead) || ((obj.sprite) && (!obj.sprite.visible))) | |||
>>>>>>> 555-new-dungeon | |||
continue; | |||
ns.visible = showNames; | |||
} | |||
} | |||
}, | |||
onTilesVisible: function (tiles, visible) { | |||
var objects = this.objects; | |||
var oLen = objects.length; | |||
for (var i = 0; i < oLen; i++) { | |||
var o = objects[i]; | |||
var onPos = tiles.some(function (t) { | |||
return ((t.x == o.x) && (t.y == o.y)); | |||
}); | |||
if (!onPos) | |||
continue; | |||
o.setVisible(visible); | |||
} | |||
} | |||
}; | |||
}); |
@@ -23,9 +23,18 @@ define([ | |||
}, | |||
buildEmitter: function (config) { | |||
<<<<<<< HEAD | |||
let options = $.extend(true, {}, particleDefaults, config); | |||
let emitter = new PIXI.particles.Emitter(this.r.layers.particles, ['images/particles.png'], options); | |||
======= | |||
var obj = config.obj; | |||
delete config.obj; | |||
var options = $.extend(true, {}, particleDefaults, config); | |||
var emitter = new PIXI.particles.Emitter(this.r.layers.particles, ['images/particles.png'], options); | |||
emitter.obj = obj; | |||
>>>>>>> 555-new-dungeon | |||
emitter.emit = true; | |||
this.emitters.push(emitter); | |||
@@ -38,20 +47,33 @@ define([ | |||
}, | |||
update: function () { | |||
<<<<<<< HEAD | |||
let renderer = this.r; | |||
let now = Date.now(); | |||
======= | |||
var renderer = this.r; | |||
var now = Date.now(); | |||
>>>>>>> 555-new-dungeon | |||
let emitters = this.emitters; | |||
let eLen = emitters.length; | |||
for (let i = 0; i < eLen; i++) { | |||
let e = emitters[i]; | |||
<<<<<<< HEAD | |||
let visible = null; | |||
let destroy = !e.emit; | |||
======= | |||
var visible = null; | |||
var destroy = ( | |||
(!e.emit) && | |||
(e.obj.destroyed) | |||
); | |||
>>>>>>> 555-new-dungeon | |||
if (destroy) { | |||
if (e.particleCount > 0) { | |||
visible = renderer.isVisible(e.spawnPos.x, e.spawnPos.y); | |||
if (visible) | |||
if (visible) | |||
destroy = false; | |||
} | |||
} | |||
@@ -64,16 +86,22 @@ define([ | |||
i--; | |||
eLen--; | |||
continue; | |||
} | |||
} | |||
if (visible === null) | |||
visible = renderer.isVisible(e.spawnPos.x, e.spawnPos.y); | |||
if (!visible) | |||
continue; | |||
<<<<<<< HEAD | |||
let r = e.update((now - this.lastTick) * 0.001); | |||
r.forEach(function (rr) { | |||
if (e.blendMode === 'overlay') | |||
======= | |||
var r = e.update((now - this.lastTick) * 0.001); | |||
r.forEach(function (rr) { | |||
if (e.blendMode == 'overlay') | |||
>>>>>>> 555-new-dungeon | |||
rr.pluginName = 'picture'; | |||
}, this); | |||
} | |||
@@ -19,6 +19,7 @@ define([ | |||
spritePool, | |||
picture | |||
) { | |||
<<<<<<< HEAD | |||
let pixi = PIXI; | |||
return { | |||
@@ -796,4 +797,869 @@ define([ | |||
this.renderer.render(this.stage); | |||
} | |||
}; | |||
======= | |||
var scale = 40; | |||
var scaleMult = 5; | |||
var pixi = PIXI; | |||
var mRandom = Math.random.bind(Math); | |||
return { | |||
stage: null, | |||
layers: { | |||
objects: null, | |||
mobs: null, | |||
characters: null, | |||
attacks: null, | |||
effects: null, | |||
particles: null, | |||
lightPatches: null, | |||
lightBeams: null, | |||
tileSprites: null, | |||
hiders: null | |||
}, | |||
titleScreen: false, | |||
width: 0, | |||
height: 0, | |||
showTilesW: 0, | |||
showTilesH: 0, | |||
pos: { | |||
x: 0, | |||
y: 0 | |||
}, | |||
moveTo: null, | |||
moveSpeed: 0, | |||
moveSpeedMax: 1.50, | |||
moveSpeedInc: 0.5, | |||
lastUpdatePos: { | |||
x: 0, | |||
y: 0 | |||
}, | |||
zoneId: null, | |||
textures: {}, | |||
textureCache: {}, | |||
sprites: [], | |||
lastTick: null, | |||
hiddenRooms: null, | |||
init: function () { | |||
PIXI.GC_MODES.DEFAULT = PIXI.GC_MODES.AUTO; | |||
PIXI.SCALE_MODES.DEFAULT = PIXI.SCALE_MODES.NEAREST; | |||
events.on('onGetMap', this.onGetMap.bind(this)); | |||
events.on('onToggleFullscreen', this.toggleScreen.bind(this)); | |||
this.width = $('body').width(); | |||
this.height = $('body').height(); | |||
this.showTilesW = Math.ceil((this.width / scale) / 2) + 3; | |||
this.showTilesH = Math.ceil((this.height / scale) / 2) + 3; | |||
this.renderer = pixi.autoDetectRenderer(this.width, this.height, { | |||
backgroundColor: '0x2d2136' | |||
}); | |||
window.onresize = this.onResize.bind(this); | |||
$(this.renderer.view) | |||
.appendTo('.canvasContainer'); | |||
this.stage = new pixi.Container(); | |||
var layers = this.layers; | |||
Object.keys(layers).forEach(function (l) { | |||
if (l == 'tileSprites') { | |||
layers[l] = new pixi.Container(); | |||
layers[l].layer = 'tiles'; | |||
} else { | |||
layers[l] = new pixi.Container(); | |||
layers[l].layer = l; | |||
} | |||
this.stage.addChild(layers[l]) | |||
}, this); | |||
var spriteNames = ['tiles', 'mobs', 'bosses', 'animBigObjects', 'bigObjects', 'objects', 'characters', 'attacks', 'auras', 'walls', 'ui', 'animChar', 'animMob', 'animBoss', 'white', 'ray']; | |||
resources.spriteNames.forEach(function (s) { | |||
if (s.indexOf('.png') > -1) | |||
spriteNames.push(s); | |||
}); | |||
spriteNames.forEach(function (t) { | |||
this.textures[t] = new pixi.BaseTexture(resources.sprites[t].image); | |||
this.textures[t].scaleMode = pixi.SCALE_MODES.NEAREST; | |||
}, this); | |||
particles.init({ | |||
r: this, | |||
renderer: this.renderer, | |||
stage: this.layers.particles | |||
}); | |||
this.buildSpritesTexture(); | |||
}, | |||
buildSpritesTexture: function () { | |||
var container = new pixi.Container(); | |||
var totalHeight = 0; | |||
['tiles', 'walls', 'objects'].forEach(function (t) { | |||
var texture = this.textures[t]; | |||
var tile = new pixi.Sprite(new pixi.Texture(texture)); | |||
tile.width = texture.width; | |||
tile.height = texture.height; | |||
tile.x = 0; | |||
tile.y = totalHeight; | |||
container.addChild(tile); | |||
totalHeight += tile.height; | |||
}, this); | |||
var renderTexture = pixi.RenderTexture.create(this.textures.tiles.width, totalHeight); | |||
this.renderer.render(container, renderTexture); | |||
this.textures.sprites = renderTexture; | |||
this.textures.scaleMult = pixi.SCALE_MODES.NEAREST; | |||
}, | |||
toggleScreen: function () { | |||
var screenMode = 0; | |||
var isFullscreen = (window.innerHeight == screen.height); | |||
if (isFullscreen) | |||
screenMode = 0; | |||
else | |||
screenMode = 1; | |||
if (screenMode == 0) { | |||
(document.cancelFullscreen || document.msCancelFullscreen || document.mozCancelFullscreen || document.webkitCancelFullScreen).call(document); | |||
return 'Windowed'; | |||
} else if (screenMode == 1) { | |||
var el = $('body')[0]; | |||
(el.requestFullscreen || el.msRequestFullscreen || el.mozRequestFullscreen || el.webkitRequestFullscreen).call(el); | |||
return 'Fullscreen'; | |||
} | |||
}, | |||
buildTitleScreen: function () { | |||
this.titleScreen = true; | |||
this.setPosition({ | |||
x: 0, | |||
y: 0 | |||
}, true); | |||
var w = Math.ceil(this.width / scale) + 1; | |||
var h = Math.ceil(this.height / scale) + 1; | |||
var container = this.layers.tileSprites; | |||
for (var i = 0; i < w; i++) { | |||
for (var j = 0; j < h; j++) { | |||
var ii = i / 10; | |||
var alpha = Math.sin(((j * 0.2) % 5) + Math.cos(ii % 8)); | |||
var tile = 5; | |||
if (j < 7) | |||
tile = 5; | |||
else if (alpha < -0.2) | |||
tile = 3; | |||
else if (alpha < 0.2) | |||
tile = 4; | |||
else if ((alpha < 0.5) && (j > 7)) | |||
tile = 53; | |||
alpha = Math.random(); | |||
if (tile == 5) | |||
alpha *= 2; | |||
else if (tile == 3) | |||
alpha *= 1; | |||
else if (tile == 4) | |||
alpha *= 1; | |||
else if (tile == 53) | |||
alpha *= 2; | |||
alpha = Math.min(Math.max(0.15, alpha), 0.65); | |||
if (Math.random() < 0.35) { | |||
tile = { | |||
'2': 7, | |||
'5': 6, | |||
'3': 0, | |||
'4': 1, | |||
'53': 54 | |||
}[tile]; | |||
} | |||
var tile = new pixi.Sprite(this.getTexture('sprites', tile)); | |||
tile.alpha = alpha; | |||
tile.position.x = i * scale; | |||
tile.position.y = j * scale; | |||
tile.width = scale; | |||
tile.height = scale; | |||
if (Math.random() < 0.5) { | |||
tile.position.x += scale; | |||
tile.scale.x = -scaleMult; | |||
} | |||
container.addChild(tile); | |||
} | |||
} | |||
}, | |||
onResize: function () { | |||
var zoom = window.devicePixelRatio; | |||
this.width = $('body').width() * zoom; | |||
this.height = $('body').height() * zoom; | |||
this.showTilesW = Math.ceil((this.width / scale) / 2) + 3; | |||
this.showTilesH = Math.ceil((this.height / scale) / 2) + 3; | |||
this.renderer.resize(this.width, this.height); | |||
if (window.player) { | |||
this.setPosition({ | |||
x: (window.player.x - (this.width / (scale * 2))) * scale, | |||
y: (window.player.y - (this.height / (scale * 2))) * scale | |||
}, true); | |||
} | |||
if (this.titleScreen) { | |||
this.clean(); | |||
this.buildTitleScreen(); | |||
} | |||
events.emit('onResize'); | |||
}, | |||
getTexture: function (baseTex, cell, size) { | |||
size = size || 8; | |||
var name = baseTex + '_' + cell; | |||
var textureCache = this.textureCache; | |||
var cached = textureCache[name]; | |||
if (!cached) { | |||
var y = ~~(cell / 8); | |||
var x = cell - (y * 8); | |||
cached = new pixi.Texture(this.textures[baseTex], new pixi.Rectangle(x * size, y * size, size, size)); | |||
textureCache[name] = cached; | |||
} | |||
return cached; | |||
}, | |||
clean: function () { | |||
this.stage.removeChild(this.layers.hiders); | |||
this.layers.hiders = new pixi.Container(); | |||
this.layers.hiders.layer = 'hiders'; | |||
this.stage.addChild(this.layers.hiders); | |||
var container = this.layers.tileSprites; | |||
this.stage.removeChild(container); | |||
this.layers.tileSprites = container = new pixi.Container(); | |||
container.layer = 'tiles'; | |||
this.stage.addChild(container); | |||
this.stage.children.sort(function (a, b) { | |||
if (a.layer == 'hiders') | |||
return 1; | |||
else if (b.layer == 'hiders') | |||
return -1; | |||
else if (a.layer == 'tiles') | |||
return -1; | |||
else if (b.layer == 'tiles') | |||
return 1; | |||
else | |||
return 0; | |||
}, this); | |||
}, | |||
onGetMapCustomization: function (msg) { | |||
if (!msg.collide) { | |||
var children = this.layers.tiles.children; | |||
var cLen = children.length; | |||
var x = msg.x * scale; | |||
var y = msg.y * scale; | |||
for (var i = cLen - 1; i >= 0; i--) { | |||
var c = children[i]; | |||
var cx = c.x; | |||
if (c.scale.x < 0) | |||
cx -= scale; | |||
if ((cx == x) && (c.y == y)) { | |||
c.parent.removeChild(c); | |||
break; | |||
} | |||
} | |||
} | |||
var tile = new pixi.Sprite(this.getTexture('sprites', msg.tile)) | |||
tile.alpha = tileOpacity.map(msg.tile); | |||
tile.position.x = msg.x * scale; | |||
tile.position.y = msg.y * scale; | |||
tile.width = scale; | |||
tile.height = scale; | |||
if (Math.random() < 0.5) { | |||
tile.position.x += scale; | |||
tile.scale.x = -scaleMult; | |||
} | |||
this.layers.tiles.addChild(tile); | |||
physics.collisionMap[msg.x][msg.y] = msg.collide; | |||
physics.graph.grid[msg.x][msg.y] = !msg.collide; | |||
}, | |||
buildTile: function (c, i, j) { | |||
var alpha = tileOpacity.map(c); | |||
var canFlip = tileOpacity.canFlip(c); | |||
var tile = new pixi.Sprite(this.getTexture('sprites', c)); | |||
tile.alpha = alpha; | |||
tile.position.x = i * scale; | |||
tile.position.y = j * scale; | |||
tile.width = scale; | |||
tile.height = scale; | |||
if (canFlip) { | |||
if (Math.random() < 0.5) { | |||
tile.position.x += scale; | |||
tile.scale.x = -scaleMult; | |||
} | |||
} | |||
return tile; | |||
}, | |||
onGetMap: function (msg) { | |||
this.titleScreen = false; | |||
physics.init(msg.collisionMap); | |||
var map = this.map = msg.map; | |||
var w = this.w = map.length; | |||
var h = this.h = map[0].length; | |||
for (var i = 0; i < w; i++) { | |||
for (var j = 0; j < h; j++) { | |||
if (!map[i][j].split) | |||
map[i][j] += ''; | |||
map[i][j] = map[i][j].split(','); | |||
} | |||
} | |||
this.clean(); | |||
spritePool.clean(); | |||
this.stage.filters = [new PIXI.filters.VoidFilter()]; | |||
this.stage.filterArea = new PIXI.Rectangle(0, 0, w * scale, h * scale); | |||
this.hiddenRooms = msg.hiddenRooms; | |||
this.sprites = _.get2dArray(w, h, 'array'); | |||
this.stage.children.sort(function (a, b) { | |||
if (a.layer == 'tiles') | |||
return -1; | |||
else if (b.layer == 'tiles') | |||
return 1; | |||
else | |||
return 0; | |||
}, this); | |||
if (this.zoneId != null) | |||
events.emit('onRezone', this.zoneId); | |||
this.zoneId = msg.zoneId; | |||
msg.clientObjects.forEach(function (c) { | |||
c.zoneId = this.zoneId; | |||
events.emit('onGetObject', c); | |||
}, this); | |||
}, | |||
setPosition: function (pos, instant) { | |||
pos.x += 16; | |||
pos.y += 16; | |||
var player = window.player; | |||
if (player) { | |||
var px = player.x; | |||
var py = player.y; | |||
var hiddenRooms = this.hiddenRooms; | |||
var hLen = hiddenRooms.length; | |||
for (var i = 0; i < hLen; i++) { | |||
var h = hiddenRooms[i]; | |||
if (!h.discoverable) | |||
continue; | |||
if ( | |||
( | |||
(px < h.x) || | |||
(px >= h.x + h.width) || | |||
(py < h.y) || | |||
(py >= h.y + h.height) | |||
) || | |||
(!physics.isInPolygon(px, py, h.area)) | |||
) | |||
continue; | |||
h.discovered = true; | |||
} | |||
} | |||
if (instant) { | |||
this.moveTo = null; | |||
this.pos = pos; | |||
this.stage.x = -~~this.pos.x; | |||
this.stage.y = -~~this.pos.y; | |||
} else | |||
this.moveTo = pos; | |||
this.updateSprites(); | |||
}, | |||
isVisible: function (x, y) { | |||
var stage = this.stage; | |||
var sx = -stage.x; | |||
var sy = -stage.y; | |||
var sw = this.width; | |||
var sh = this.height; | |||
return (!((x < sx) || (y < sy) || (x >= sx + sw) || (y >= sy + sh))); | |||
}, | |||
isHidden: function (x, y) { | |||
var hiddenRooms = this.hiddenRooms; | |||
var hLen = hiddenRooms.length; | |||
if (hLen == 0) | |||
return false; | |||
var player = window.player; | |||
var px = player.x; | |||
var py = player.y; | |||
var hidden = false; | |||
for (var i = 0; i < hLen; i++) { | |||
var h = hiddenRooms[i]; | |||
var outsideHider = ( | |||
(x < h.x) || | |||
(x >= h.x + h.width) || | |||
(y < h.y) || | |||
(y >= h.y + h.height) | |||
); | |||
if (outsideHider) | |||
continue; | |||
var inHider = physics.isInPolygon(x, y, h.area); | |||
if (!inHider) | |||
continue; | |||
if (h.discovered) | |||
return false; | |||
outsideHider = ( | |||
(px < h.x) || | |||
(px >= h.x + h.width) || | |||
(py < h.y) || | |||
(py >= h.y + h.height) | |||
); | |||
if (outsideHider) { | |||
hidden = true; | |||
continue; | |||
} | |||
inHider = physics.isInPolygon(px, py, h.area); | |||
if (inHider) | |||
return false; | |||
else | |||
hidden = true; | |||
} | |||
return hidden; | |||
}, | |||
updateSprites: function () { | |||
if (this.titleScreen) | |||
return; | |||
var player = window.player; | |||
if (!player) | |||
return; | |||
var w = this.w; | |||
var h = this.h; | |||
var x = ~~((-this.stage.x / scale) + (this.width / (scale * 2))); | |||
var y = ~~((-this.stage.y / scale) + (this.height / (scale * 2))); | |||
this.lastUpdatePos.x = this.stage.x; | |||
this.lastUpdatePos.y = this.stage.y; | |||
var sprites = this.sprites; | |||
var map = this.map; | |||
var container = this.layers.tileSprites; | |||
var sw = this.showTilesW; | |||
var sh = this.showTilesH; | |||
var lowX = Math.max(0, x - sw + 1); | |||
var lowY = Math.max(0, y - sh + 2); | |||
var highX = Math.min(w, x + sw - 2); | |||
var highY = Math.min(h, y + sh - 2); | |||
var addedSprite = false; | |||
var isHidden = this.isHidden.bind(this); | |||
var newVisible = []; | |||
var newHidden = []; | |||
for (var i = lowX; i < highX; i++) { | |||
var mapRow = map[i]; | |||
var spriteRow = sprites[i]; | |||
for (var j = lowY; j < highY; j++) { | |||
cell = mapRow[j]; | |||
if (!cell) | |||
continue; | |||
var cLen = cell.length; | |||
if (!cLen) | |||
return; | |||
var rendered = spriteRow[j]; | |||
var isHidden = this.isHidden(i, j); | |||
if (rendered.length > 0) { | |||
if (!isHidden) | |||
continue; | |||
else { | |||
newHidden.push({ | |||
x: i, | |||
y: j | |||
}); | |||
var rLen = rendered.length; | |||
for (var k = 0; k < rLen; k++) { | |||
var sprite = rendered[k]; | |||
sprite.visible = false; | |||
spritePool.store(sprite); | |||
} | |||
spriteRow[j] = []; | |||
continue; | |||
} | |||
} else if (isHidden) | |||
continue; | |||
newVisible.push({ | |||
x: i, | |||
y: j | |||
}); | |||
for (var k = 0; k < cLen; k++) { | |||
var c = cell[k]; | |||
if (c == 0) | |||
continue; | |||
c--; | |||
var flipped = ''; | |||
if (tileOpacity.canFlip(c)) { | |||
if (mRandom() < 0.5) | |||
flipped = 'flip'; | |||
} | |||
var tile = spritePool.getSprite(flipped + c); | |||
if (!tile) { | |||
tile = this.buildTile(c, i, j); | |||
container.addChild(tile); | |||
tile.type = c; | |||
tile.sheetNum = tileOpacity.getSheetNum(c); | |||
addedSprite = true; | |||
} else { | |||
tile.position.x = i * scale; | |||
tile.position.y = j * scale; | |||
if (flipped != '') | |||
tile.position.x += scale; | |||
tile.visible = true; | |||
} | |||
tile.z = k; | |||
rendered.push(tile); | |||
} | |||
} | |||
} | |||
lowX = Math.max(0, lowX - 10); | |||
lowY = Math.max(0, lowY - 10); | |||
highX = Math.min(w - 1, highX + 10); | |||
highY = Math.min(h - 1, highY + 10); | |||
for (var i = lowX; i < highX; i++) { | |||
var spriteRow = sprites[i]; | |||
var outside = ((i >= x - sw) && (i < x + sw)); | |||
for (var j = lowY; j < highY; j++) { | |||
if ((outside) && (j >= y - sh) && (j < y + sh)) | |||
continue; | |||
var list = spriteRow[j]; | |||
var lLen = list.length; | |||
for (var k = 0; k < lLen; k++) { | |||
var sprite = list[k]; | |||
sprite.visible = false; | |||
spritePool.store(sprite); | |||
} | |||
spriteRow[j] = []; | |||
} | |||
} | |||
events.emit('onTilesVisible', newVisible, true); | |||
events.emit('onTilesVisible', newHidden, false); | |||
if (addedSprite) { | |||
container.children.sort(function (a, b) { | |||
return (a.z - b.z); | |||
}); | |||
} | |||
}, | |||
update: function () { | |||
var time = +new Date; | |||
if (this.moveTo) { | |||
var deltaX = this.moveTo.x - this.pos.x; | |||
var deltaY = this.moveTo.y - this.pos.y; | |||
if ((deltaX != 0) || (deltaY != 0)) { | |||
var moveSpeed = this.moveSpeed; | |||
var distance = Math.max(Math.abs(deltaX), Math.abs(deltaY)); | |||
var moveSpeedMax = this.moveSpeedMax; | |||
if (distance > 100) | |||
moveSpeedMax *= 1.75; | |||
if (this.moveSpeed < moveSpeedMax) | |||
this.moveSpeed += this.moveSpeedInc; | |||
var elapsed = time - this.lastTick; | |||
moveSpeed *= (elapsed / 16.67); | |||
if (moveSpeed > distance) | |||
moveSpeed = distance; | |||
deltaX = (deltaX / distance) * moveSpeed; | |||
deltaY = (deltaY / distance) * moveSpeed; | |||
this.pos.x = this.pos.x + (deltaX); | |||
this.pos.y = this.pos.y + (deltaY); | |||
} else { | |||
this.moveSpeed = 0; | |||
this.moveTo = null; | |||
} | |||
var stage = this.stage; | |||
stage.x = -~~this.pos.x; | |||
stage.y = -~~this.pos.y; | |||
var halfScale = scale / 2; | |||
if ((Math.abs(stage.x - this.lastUpdatePos.x) > halfScale) || (Math.abs(stage.y - this.lastUpdatePos.y) > halfScale)) | |||
this.updateSprites(); | |||
events.emit('onSceneMove'); | |||
} | |||
this.lastTick = time; | |||
}, | |||
buildContainer: function (obj) { | |||
var container = new pixi.Container; | |||
this.layers[obj.layerName || obj.sheetName].addChild(container); | |||
return container; | |||
}, | |||
buildRectangle: function (obj) { | |||
var graphics = new pixi.Graphics; | |||
var alpha = obj.alpha; | |||
if (alpha != null) | |||
graphics.alpha = alpha; | |||
var fillAlpha = obj.fillAlpha; | |||
if (fillAlpha == null) | |||
fillAlpha = 1; | |||
graphics.beginFill(obj.color || '0x48edff', fillAlpha); | |||
if (obj.strokeColor) | |||
graphics.lineStyle(scaleMult, obj.strokeColor); | |||
graphics.drawRect(0, 0, obj.w, obj.h); | |||
graphics.endFill(); | |||
(obj.parent || this.layers[obj.layerName || obj.sheetName]).addChild(graphics); | |||
graphics.position.x = obj.x; | |||
graphics.position.y = obj.y; | |||
return graphics; | |||
}, | |||
moveRectangle: function (obj) { | |||
obj.sprite.position.x = obj.x; | |||
obj.sprite.position.y = obj.y; | |||
obj.sprite.width = obj.w; | |||
obj.sprite.height = obj.h; | |||
}, | |||
buildObject: function (obj) { | |||
var w = 8; | |||
var h = 8; | |||
if (obj.w) { | |||
w = obj.w / scaleMult; | |||
h = obj.h / scaleMult; | |||
} | |||
var bigSheets = ['bosses', 'bigObjects', 'animBigObjects']; | |||
if ((bigSheets.indexOf(obj.sheetName) > -1) || (obj.sheetName.indexOf('bosses') > -1)) { | |||
obj.layerName = 'mobs'; | |||
w = 24; | |||
h = 24; | |||
obj.w = w * scaleMult; | |||
obj.h = h * scaleMult; | |||
} | |||
var sprite = new pixi.Sprite(this.getTexture(obj.sheetName, obj.cell, w)) | |||
sprite.x = obj.x * scale; | |||
sprite.y = obj.y * scale; | |||
sprite.width = obj.w || scale; | |||
sprite.height = obj.h || scale; | |||
if ((bigSheets.indexOf(obj.sheetName) > -1) || (obj.sheetName.indexOf('bosses') > -1)) { | |||
sprite.x -= scale; | |||
sprite.y -= (scale * 2); | |||
} | |||
if (obj.flipX) { | |||
sprite.scale.x *= -1; | |||
if (bigSheets.indexOf(obj.sheetName) > -1) | |||
sprite.x += (scale * 2); | |||
else | |||
sprite.x += scale; | |||
} | |||
(obj.parent || this.layers[obj.layerName || obj.sheetName] || this.layers.objects).addChild(sprite); | |||
return sprite; | |||
}, | |||
addFilter: function (sprite) { | |||
var thickness = 16; | |||
if (sprite.width > scale) | |||
thickness = 8; | |||
var filter = new shaderOutline(this.renderer.width, this.renderer.height, thickness, '0xffffff'); | |||
if (!sprite.filters) | |||
sprite.filters = [filter]; | |||
else | |||
sprite.filters.push(); | |||
return filter; | |||
}, | |||
removeFilter: function (sprite, filter) { | |||
if (!sprite.filters) | |||
return; | |||
sprite.filters = null; | |||
}, | |||
buildText: function (obj) { | |||
var textSprite = new pixi.Text(obj.text, { | |||
fontFamily: 'bitty', | |||
fontSize: (obj.fontSize || 14), | |||
fill: obj.color || 0xF2F5F5, | |||
stroke: 0x2d2136, | |||
strokeThickness: 4, | |||
align: 'center' | |||
}); | |||
textSprite.x = obj.x - (textSprite.width / 2); | |||
textSprite.y = obj.y; | |||
var parent = obj.parent || this.layers[obj.layerName] | |||
parent.addChild(textSprite); | |||
return textSprite; | |||
}, | |||
buildEmitter: function (config) { | |||
var emitter = particles.buildEmitter(config); | |||
return emitter; | |||
}, | |||
destroyEmitter: function (emitter) { | |||
particles.destroyEmitter(emitter); | |||
}, | |||
setSprite: function (obj) { | |||
var cell = obj.cell; | |||
var y = ~~(cell / 8); | |||
var x = cell - (y * 8); | |||
var baseTex = this.textures[obj.sheetName]; | |||
obj.sprite.texture = this.getTexture(obj.sheetName, obj.cell, obj.sprite.width / scaleMult); | |||
}, | |||
reorder: function (sprite) { | |||
var mobLayer = this.layers.mobs; | |||
var mobs = mobLayer.children; | |||
mobs.sort(function (a, b) { | |||
return (b.y - a.y); | |||
}); | |||
}, | |||
destroyObject: function (obj) { | |||
if (!obj.sprite.parent) | |||
return; | |||
obj.sprite.parent.removeChild(obj.sprite); | |||
}, | |||
render: function () { | |||
if (!this.stage) | |||
return; | |||
effects.render(); | |||
particles.update(); | |||
this.renderer.render(this.stage); | |||
} | |||
}; | |||
>>>>>>> 555-new-dungeon | |||
}); |
@@ -88,7 +88,9 @@ define([ | |||
//Stone Ledges | |||
195, 196, 197, 198, 199, 200, 201, 202, 203, | |||
//Ship Edges | |||
204, 205, 206, 207, 214, 215, 220, 221, 222, 223 | |||
204, 205, 206, 207, 214, 215, 220, 221, 222, 223, | |||
//Gray wall sides and corners | |||
230, 231, 238, 239 | |||
], | |||
objectsNoFlip: [ | |||
//Clotheslines | |||
@@ -1,49 +1,63 @@ | |||
define([ | |||
'howler' | |||
'howler', | |||
'js/misc/physics' | |||
], function ( | |||
howler | |||
howler, | |||
physics | |||
) { | |||
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 () { | |||
unload: function (zoneId) { | |||
this.sounds.forEach(function (s) { | |||
if (s.sound) | |||
if ((s.sound) && (s.zoneId != zoneId)) | |||
s.sound.unload(); | |||
}); | |||
this.sounds = []; | |||
this.sounds.spliceWhere(function (s) { | |||
return (s.zoneId !== zoneId); | |||
}); | |||
}, | |||
update: function (x, y) { | |||
this.sounds.forEach(function (s) { | |||
let dx = Math.abs(s.x - x); | |||
if (dx > 10) { | |||
if (s.sound) | |||
s.sound.volume(0); | |||
return; | |||
} | |||
let dy = Math.abs(s.y - y); | |||
if (dy > 10) { | |||
if (s.sound) | |||
s.sound.volume(0); | |||
return; | |||
} | |||
let volume; | |||
let dist = 10 - Math.max(dx, dy); | |||
dist = (dist * dist) / 100; | |||
let volume = 0.3 * dist; | |||
if (!s.w) { | |||
let dx = Math.abs(s.x - x); | |||
if (dx > 10) { | |||
if (s.sound) | |||
s.sound.volume(0); | |||
return; | |||
} | |||
let dy = Math.abs(s.y - y); | |||
if (dy > 10) { | |||
if (s.sound) | |||
s.sound.volume(0); | |||
return; | |||
} | |||
let dist = 10 - Math.max(dx, dy); | |||
dist = (dist * dist) / 100; | |||
volume = 0.3 * dist; | |||
} else if (physics.isInPolygon(x, y, s.area)) | |||
volume = 0.3; | |||
else { | |||
let distance = physics.distanceToPolygon([x, y], s.area); | |||
if (distance > 10) { | |||
if (s.sound) | |||
s.sound.volume(0); | |||
return; | |||
} | |||
let dist = 10 - distance; | |||
dist = (dist * dist) / 100; | |||
volume = 0.3 * dist; | |||
} | |||
if (!s.sound) { | |||
//eslint-disable-next-line no-undef | |||
@@ -55,16 +69,30 @@ define([ | |||
}); | |||
} | |||
s.sound.volume(volume); | |||
s.sound.volume(volume * s.volume); | |||
}); | |||
}, | |||
addSound: function (file, x, y) { | |||
addSound: function (zoneId, file, volume, x, y, w, h, area) { | |||
if ((!area) && (w)) { | |||
area = [ | |||
[x, y], | |||
[x + w, y], | |||
[x + w, y + h], | |||
[x, y + h] | |||
]; | |||
} | |||
let sound = { | |||
file: file, | |||
x: x, | |||
y: y, | |||
sound: null | |||
w: w, | |||
h: h, | |||
volume: volume, | |||
area: area, | |||
sound: null, | |||
zoneId: zoneId | |||
}; | |||
this.sounds.push(sound); | |||
@@ -52,7 +52,8 @@ define([ | |||
'mail', | |||
'wardrobe', | |||
'passives', | |||
'workbench' | |||
'workbench', | |||
'middleHud' | |||
].forEach(function (u) { | |||
this.build(u); | |||
}, this); | |||
@@ -0,0 +1,30 @@ | |||
define([ | |||
'js/system/events', | |||
'html!ui/templates/middleHud/template', | |||
'css!ui/templates/middleHud/styles' | |||
], function ( | |||
events, | |||
template, | |||
styles | |||
) { | |||
return { | |||
tpl: template, | |||
postRender: function () { | |||
this.onEvent('onGetSelfCasting', this.onGetCasting.bind(this)); | |||
}, | |||
onGetCasting: function (casting) { | |||
var el = this.find('.casting'); | |||
if ((casting == 0) || (casting == 1)) | |||
el.hide(); | |||
else { | |||
el | |||
.show() | |||
.find('.bar') | |||
.width((casting * 100) + '%'); | |||
} | |||
} | |||
}; | |||
}); |
@@ -0,0 +1,32 @@ | |||
@import "../../../css/ui.less"; | |||
.middleHud { | |||
position: absolute; | |||
left: 50%; | |||
top: calc(50% + 60px); | |||
transform: translate(-50%, -50%); | |||
.casting { | |||
display: none; | |||
width: 100px; | |||
height: 20px; | |||
position: relative; | |||
background-color: @grayC; | |||
.bar { | |||
width: 0%; | |||
height: 100%; | |||
background-color: @white; | |||
} | |||
.text { | |||
position: absolute; | |||
left: 0px; | |||
top: 0px; | |||
padding-top: 2px; | |||
width: 100%; | |||
text-align: center; | |||
color: @black; | |||
} | |||
} | |||
} |
@@ -0,0 +1,6 @@ | |||
<div class="middleHud"> | |||
<div class="casting"> | |||
<div class="bar"></div> | |||
<div class="text">casting</div> | |||
</div> | |||
</div> |
@@ -58,10 +58,18 @@ | |||
margin-bottom: 5px; | |||
position: relative; | |||
&:last-child { | |||
&:nth-child(3) { | |||
margin-bottom: 0px; | |||
} | |||
&:last-child { | |||
display: none; | |||
position: absolute; | |||
margin-left: -8px; | |||
margin-top: 13px; | |||
background-color: @grayD; | |||
} | |||
[class^="stat"] { | |||
position: absolute; | |||
left: 0px; | |||
@@ -105,6 +113,10 @@ | |||
.statMana { | |||
background-color: #3fa7dd; | |||
} | |||
.statCasting { | |||
background-color: @purpleA; | |||
} | |||
} | |||
} | |||
} |
@@ -18,6 +18,21 @@ define([ | |||
postRender: function () { | |||
this.onEvent('onSetTarget', this.onSetTarget.bind(this)); | |||
this.onEvent('onDeath', this.onSetTarget.bind(this, null)); | |||
this.onEvent('onGetTargetCasting', this.onGetCasting.bind(this)); | |||
}, | |||
onGetCasting: function (casting) { | |||
var box = this.el.find('.statBox') | |||
.eq(2); | |||
if ((casting == 0) || (casting == 1)) { | |||
box.hide(); | |||
return; | |||
} else | |||
box.show(); | |||
var w = ~~(casting * 100); | |||
box.find('[class^="stat"]').css('width', w + '%'); | |||
}, | |||
onContextMenu: function (e) { | |||
@@ -12,5 +12,9 @@ | |||
<div class="statMana"></div> | |||
<div class="text"></div> | |||
</div> | |||
<div class="statBox"> | |||
<div class="statCasting"></div> | |||
<div class="text">casting</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |
@@ -83,6 +83,7 @@ module.exports = { | |||
} | |||
} | |||
<<<<<<< HEAD | |||
let x = obj.x; | |||
let y = obj.y; | |||
@@ -96,6 +97,58 @@ module.exports = { | |||
let iLen = inRange.length; | |||
for (let i = 0; i < iLen; i++) { | |||
let enemy = inRange[i]; | |||
======= | |||
move: function (obj, x, y, range) { | |||
obj = obj || this.obj; | |||
var aggro = obj.aggro; | |||
if (obj.dead) | |||
return; | |||
var result = { | |||
success: true | |||
}; | |||
obj.fireEvent('beforeAggro', result); | |||
if (!result.success) | |||
return; | |||
//If we're attacking something, don't try and look for more trouble. SAVE THE CPU! | |||
// this only counts for mobs, players can have multiple attackers | |||
var list = aggro.list; | |||
if (obj.isMob) { | |||
var lLen = list.length; | |||
for (var i = 0; i < lLen; i++) { | |||
var l = list[i]; | |||
var lThreat = l.obj.aggro.getHighest(); | |||
if (lThreat) { | |||
l.obj.aggro.list.forEach(function (a) { | |||
a.obj.aggro.unIgnore(lThreat); | |||
}); | |||
} | |||
l.obj.aggro.unIgnore(obj); | |||
if (l.threat > 0) | |||
return; | |||
} | |||
} else { | |||
var lLen = list.length; | |||
for (var i = 0; i < lLen; i++) { | |||
var targetAggro = list[i].obj.aggro; | |||
//Maybe the aggro component has been removed? | |||
if (targetAggro) | |||
targetAggro.unIgnore(obj); | |||
} | |||
} | |||
x = (x == null) ? obj.x : x; | |||
y = (y == null) ? obj.y : y; | |||
//find mobs in range | |||
range = range || aggro.range; | |||
var faction = aggro.faction; | |||
var inRange = aggro.physics.getArea(x - range, y - range, x + range, y + range, (c => (((!c.player) || (!obj.player)) && (!obj.dead) && (c.aggro) && (c.aggro.willAutoAttack(obj))))); | |||
>>>>>>> 555-new-dungeon | |||
//The length could change | |||
let lLen = list.length; | |||
@@ -138,6 +191,7 @@ module.exports = { | |||
return true; | |||
}, | |||
<<<<<<< HEAD | |||
willAutoAttack: function (target) { | |||
if (this.obj === target) | |||
return false; | |||
@@ -145,6 +199,16 @@ module.exports = { | |||
let faction = target.aggro.faction; | |||
if (!faction || !this.faction) | |||
return false; | |||
======= | |||
//Do we have LoS? | |||
if (!aggro.physics.hasLos(x, y, enemy.x, enemy.y)) | |||
continue; | |||
if (enemy.aggro.tryEngage(obj)) | |||
aggro.tryEngage(enemy, 0); | |||
} | |||
}, | |||
>>>>>>> 555-new-dungeon | |||
let rep = this.obj.reputation; | |||
if (!rep) { | |||
@@ -212,6 +276,7 @@ module.exports = { | |||
return true; | |||
}, | |||
<<<<<<< HEAD | |||
getFirstAttacker: function () { | |||
let first = this.list.find(l => ((l.obj.player) && (l.damage > 0))); | |||
if (first) | |||
@@ -222,6 +287,13 @@ module.exports = { | |||
die: function () { | |||
let list = this.list; | |||
let lLen = list.length; | |||
======= | |||
list.push(l); | |||
if (obj.player) | |||
this.move(obj, this.obj.x, this.obj.y, ~~(this.range / 2)); | |||
} | |||
>>>>>>> 555-new-dungeon | |||
for (let i = 0; i < lLen; i++) { | |||
let l = list[i]; | |||
@@ -313,6 +385,7 @@ module.exports = { | |||
} | |||
} | |||
<<<<<<< HEAD | |||
if (highest) | |||
return highest.obj; | |||
@@ -335,6 +408,60 @@ module.exports = { | |||
l.threat -= this.threatDecay; | |||
if (l.threat < 0) | |||
l.threat = 0; | |||
======= | |||
if (highest) | |||
return highest.obj; | |||
else { | |||
//We have aggro but can't reach our target. Don't let the mob run away as if not in combat! | |||
return true; | |||
} | |||
}, | |||
getFurthest: function () { | |||
var furthest = null; | |||
var distance = 0; | |||
var list = this.list; | |||
var lLen = list.length; | |||
var thisObj = this.obj; | |||
var x = thisObj.x; | |||
var y = thisObj.y; | |||
for (var i = 0; i < lLen; i++) { | |||
var l = list[i]; | |||
var obj = l.obj; | |||
if (this.ignoreList.some(o => o == obj)) | |||
continue; | |||
var oDistance = Math.max(Math.abs(x - obj.x), Math.abs(y - obj.y)); | |||
if (oDistance > distance) { | |||
furthest = l; | |||
distance = oDistance; | |||
} | |||
} | |||
return furthest.obj; | |||
}, | |||
getRandom: function () { | |||
var useList = this.list.filter(l => (!this.ignoreList.some(o => (o == l.obj)))); | |||
return useList[~~(Math.random() * useList.length)]; | |||
}, | |||
update: function () { | |||
var list = this.list; | |||
var lLen = list.length; | |||
for (var i = 0; i < lLen; i++) { | |||
var l = list[i]; | |||
if (l.obj.destroyed) { | |||
this.unAggro(l.obj); | |||
i--; | |||
lLen--; | |||
} | |||
>>>>>>> 555-new-dungeon | |||
} | |||
} | |||
} | |||
@@ -5,38 +5,75 @@ module.exports = { | |||
ttl: -1, | |||
<<<<<<< HEAD | |||
init: function (blueprint) { | |||
if (blueprint.ownerId) | |||
this.ownerId = blueprint.ownerId; | |||
======= | |||
ownerName: null, | |||
>>>>>>> 555-new-dungeon | |||
if (blueprint.ttl) | |||
this.ttl = blueprint.ttl; | |||
}, | |||
<<<<<<< HEAD | |||
simplify: function (self) { | |||
return { | |||
type: 'chest', | |||
ownerId: this.ownerId | |||
}; | |||
}, | |||
======= | |||
init: function (blueprint) { | |||
if (blueprint.ownerName != null) | |||
this.ownerName = blueprint.ownerName; | |||
>>>>>>> 555-new-dungeon | |||
update: function () { | |||
if (this.ttl > 0) { | |||
this.ttl--; | |||
<<<<<<< HEAD | |||
if (this.ttl === 0) | |||
this.obj.destroyed = true; | |||
} | |||
}, | |||
======= | |||
simplify: function (self) { | |||
return { | |||
type: 'chest', | |||
ownerName: this.ownerName | |||
}; | |||
}, | |||
update: function () { | |||
if (this.ttl > 0) { | |||
this.ttl--; | |||
if (this.ttl == 0) | |||
this.obj.destroyed = true; | |||
} | |||
}, | |||
>>>>>>> 555-new-dungeon | |||
collisionEnter: function (obj) { | |||
if (!obj.player) | |||
return; | |||
<<<<<<< HEAD | |||
let ownerId = this.ownerId; | |||
if (ownerId !== -1) { | |||
if (ownerId instanceof Array) { | |||
if (ownerId.indexOf(obj.serverId) === -1) | |||
======= | |||
var ownerName = this.ownerName; | |||
if (ownerName) { | |||
if (ownerName instanceof Array) { | |||
if (ownerName.indexOf(obj.name) == -1) | |||
return; | |||
} else if (ownerName != obj.name) | |||
>>>>>>> 555-new-dungeon | |||
return; | |||
} else if (ownerId !== obj.serverId) | |||
return; | |||
@@ -113,8 +113,33 @@ module.exports = { | |||
eLen--; | |||
i--; | |||
} | |||
<<<<<<< HEAD | |||
} | |||
}, | |||
======= | |||
}, | |||
canApplyEffect: function (type) { | |||
if (this.ccResistances[type] == null) | |||
return true; | |||
var ccResistances = this.ccResistances; | |||
if ((100 - ccResistances[type]) >= 50) { | |||
ccResistances[type] += 50; | |||
return true; | |||
} else | |||
return false; | |||
}, | |||
addEffect: function (options, source) { | |||
if ((options.ttl != null) && (options.ttl == 0)) | |||
return; | |||
options.caster = options.caster || source; | |||
if (!this.canApplyEffect(options.type)) | |||
return; | |||
>>>>>>> 555-new-dungeon | |||
canApplyEffect: function (type) { | |||
if (!this.ccResistances[type]) | |||
@@ -684,11 +684,56 @@ module.exports = { | |||
cpnInventory: { | |||
items: extend([], items) | |||
} | |||
<<<<<<< HEAD | |||
======= | |||
}, this); | |||
}, | |||
createBag: function (x, y, items, ownerName) { | |||
var bagCell = 50; | |||
var topQuality = 0; | |||
var iLen = items.length; | |||
for (var i = 0; i < iLen; i++) { | |||
var quality = items[i].quality; | |||
items[i].fromMob = !!this.obj.mob; | |||
if (quality > topQuality) | |||
topQuality = quality; | |||
>>>>>>> 555-new-dungeon | |||
} | |||
}]); | |||
<<<<<<< HEAD | |||
return obj; | |||
}, | |||
======= | |||
if (topQuality == 0) | |||
bagCell = 50; | |||
else if (topQuality == 1) | |||
bagCell = 51; | |||
else if (topQuality == 2) | |||
bagCell = 128; | |||
else if (topQuality == 3) | |||
bagCell = 52; | |||
else | |||
bagCell = 53; | |||
var obj = this.obj.instance.objects.buildObjects([{ | |||
sheetName: 'objects', | |||
cell: bagCell, | |||
x: x, | |||
y: y, | |||
properties: { | |||
cpnChest: { | |||
ownerName: ownerName, | |||
ttl: this.obj.instance.instanced ? -1 : 1710 | |||
}, | |||
cpnInventory: { | |||
items: extend(true, [], items) | |||
} | |||
} | |||
}]); | |||
>>>>>>> 555-new-dungeon | |||
hasSpace: function () { | |||
if (this.inventorySize !== -1) { | |||
@@ -901,11 +946,22 @@ module.exports = { | |||
delete items[i].pos; | |||
} | |||
<<<<<<< HEAD | |||
let blueprint = this.blueprint; | |||
let magicFind = (blueprint.magicFind || 0); | |||
let savedItems = extend([], this.items); | |||
this.items = []; | |||
======= | |||
dropBag: function (ownerName, killSource) { | |||
if (!this.blueprint) | |||
return; | |||
//Only drop loot if this player is in the zone | |||
var playerObject = this.obj.instance.objects.find(o => o.name == ownerName); | |||
if (!playerObject) | |||
return; | |||
>>>>>>> 555-new-dungeon | |||
let dropEvent = { | |||
chanceMultiplier: 1, | |||
@@ -967,8 +1023,13 @@ module.exports = { | |||
playerObject.fireEvent('beforeTargetDeath', this.obj, this.items); | |||
this.obj.instance.eventEmitter.emit('onBeforeDropBag', this.obj, this.items, killSource); | |||
<<<<<<< HEAD | |||
if (this.items.length > 0) | |||
this.createBag(this.obj.x, this.obj.y, this.items, ownerId); | |||
======= | |||
if (this.items.length > 0) | |||
this.createBag(this.obj.x, this.obj.y, this.items, ownerName); | |||
>>>>>>> 555-new-dungeon | |||
this.items = savedItems; | |||
}, | |||
@@ -16,11 +16,17 @@ module.exports = { | |||
maxChaseDistance: 25, | |||
goHome: false, | |||
patrol: null, | |||
patrolTargetNode: 0, | |||
init: function (blueprint) { | |||
this.physics = this.obj.instance.physics; | |||
this.originX = this.obj.x; | |||
this.originY = this.obj.y; | |||
if (blueprint.patrol) | |||
this.patrol = blueprint.patrol; | |||
}, | |||
update: function () { | |||
@@ -63,17 +69,33 @@ module.exports = { | |||
if (obj.actionQueue.length > 0) | |||
return; | |||
//Unless we're going home, don't always move | |||
if ((!this.goHome) && (rnd() < 0.85)) | |||
//Unless we're going home, don't always move | |||
if ((!this.goHome) && (rnd() < 0.85) && (!this.patrol)) | |||
return; | |||
//don't move around if we're not allowed to, unless we're going home | |||
//Don't move around if we're not allowed to, unless we're going home | |||
let walkDistance = this.walkDistance; | |||
if ((!this.goHome) && (walkDistance <= 0)) | |||
return; | |||
let toX = this.originX + ~~(rnd() * (walkDistance * 2)) - walkDistance; | |||
let toY = this.originY + ~~(rnd() * (walkDistance * 2)) - walkDistance; | |||
let toX, toY; | |||
if (!this.patrol) { | |||
toX = this.originX + ~~(rnd() * (walkDistance * 2)) - walkDistance; | |||
toY = this.originY + ~~(rnd() * (walkDistance * 2)) - walkDistance; | |||
} else { | |||
while (true) { | |||
let toNode = this.patrol[this.patrolTargetNode]; | |||
toX = toNode[0]; | |||
toY = toNode[1]; | |||
if ((toX - obj.x == 0) && (toY - obj.y == 0)) { | |||
this.patrolTargetNode++; | |||
if (this.patrolTargetNode >= this.patrol.length) | |||
this.patrolTargetNode = 0; | |||
} else | |||
break; | |||
} | |||
} | |||
if (!this.physics.isCellOpen(toX, toY)) | |||
return; | |||
@@ -0,0 +1,20 @@ | |||
define([ | |||
], function ( | |||
) { | |||
return { | |||
type: 'sound', | |||
sound: null, | |||
volume: 0, | |||
simplify: function () { | |||
return { | |||
type: 'sound', | |||
sound: this.sound, | |||
volume: this.volume | |||
}; | |||
} | |||
}; | |||
}); |
@@ -114,10 +114,12 @@ module.exports = { | |||
builtSpell.animation = null; | |||
} | |||
if ((this.closestRange === -1) || (builtSpell.range < this.closestRange)) | |||
this.closestRange = builtSpell.range; | |||
if ((this.furthestRange === -1) || (builtSpell.range > this.furthestRange)) | |||
this.furthestRange = builtSpell.range; | |||
if (!builtSpell.castOnDeath) { | |||
if ((this.closestRange == -1) || (builtSpell.range < this.closestRange)) | |||
this.closestRange = builtSpell.range; | |||
if ((this.furthestRange == -1) || (builtSpell.range > this.furthestRange)) | |||
this.furthestRange = builtSpell.range; | |||
} | |||
if ((!options.has('id')) && (spellId === -1)) { | |||
spellId = 0; | |||
@@ -226,13 +228,16 @@ module.exports = { | |||
spell: action.spell, | |||
target: action.target | |||
}); | |||
return true; | |||
} exists.target = action.target; | |||
}, | |||
getRandomSpell: function (target) { | |||
let valid = []; | |||
this.spells.forEach(function (s) { | |||
if (s.castOnDeath) | |||
return; | |||
if (s.canCast(target)) | |||
valid.push(s.id); | |||
}); | |||
@@ -363,35 +368,46 @@ module.exports = { | |||
if (!castSuccess.success) | |||
return false; | |||
success = spell.cast(action); | |||
if (spell.targetFurthest) | |||
spell.target = this.obj.aggro.getFurthest(); | |||
else if (spell.targetRandom) | |||
spell.target = this.obj.aggro.getRandom(); | |||
success = spell.castBase(action); | |||
this.stopCasting(spell); | |||
if (success) { | |||
let stats = this.obj.stats.values; | |||
stats.mana -= spell.manaCost; | |||
let cd = { | |||
cd: spell.cdMax | |||
}; | |||
spell.consumeMana(); | |||
spell.setCd(); | |||
} | |||
let isAttack = (spell.type === 'melee'); | |||
if ((Math.random() * 100) < stats[isAttack ? 'attackSpeed' : 'castSpeed']) | |||
cd.cd = 1; | |||
return success; | |||
let stats = this.obj.stats.values; | |||
stats.mana -= spell.manaCost; | |||
let cd = { | |||
cd: spell.cdMax | |||
}; | |||
this.obj.fireEvent('beforeSetSpellCooldown', cd); | |||
let isAttack = (spell.type == 'melee'); | |||
if ((Math.random() * 100) < stats[isAttack ? 'attackSpeed' : 'castSpeed']) | |||
cd.cd = 1; | |||
spell.cd = cd.cd; | |||
this.obj.fireEvent('beforeSetSpellCooldown', cd); | |||
if (this.obj.player) { | |||
let syncer = this.obj.syncer; | |||
syncer.setObject(true, 'stats', 'values', 'mana', this.obj.stats.values.mana); | |||
this.obj.instance.syncer.queue('onGetSpellCooldowns', { | |||
id: this.obj.id, | |||
spell: action.spell, | |||
cd: (spell.cd * 350) | |||
}, [this.obj.serverId]); | |||
} | |||
spell.cd = cd.cd; | |||
if (this.obj.player) { | |||
let syncer = this.obj.syncer; | |||
syncer.setObject(true, 'stats', 'values', 'mana', this.obj.stats.values.mana); | |||
this.obj.instance.syncer.queue('onGetSpellCooldowns', { | |||
id: this.obj.id, | |||
spell: action.spell, | |||
cd: (spell.cd * 350) | |||
}, [this.obj.serverId]); | |||
} | |||
return success; | |||
return true; | |||
}, | |||
getClosestRange: function (spellNum) { | |||
@@ -551,7 +567,33 @@ module.exports = { | |||
} | |||
}, | |||
stopCasting: function (ignore) { | |||
this.spells.forEach(function (s) { | |||
if ((!s.castTimeMax) || (!s.castTime) || (s == ignore)) | |||
return; | |||
s.castTime = 0; | |||
s.currentAction = null; | |||
if (!ignore) | |||
this.obj.syncer.set(false, null, 'casting', 0); | |||
}, this); | |||
}, | |||
events: { | |||
beforeMove: function () { | |||
this.stopCasting(); | |||
}, | |||
beforeDeath: function () { | |||
this.spells.forEach(function (s) { | |||
if (!s.castOnDeath) | |||
return; | |||
s.cast(); | |||
}); | |||
}, | |||
beforeRezone: function () { | |||
this.spells.forEach(function (s) { | |||
if (s.active) { | |||
@@ -544,7 +544,7 @@ module.exports = { | |||
class: 'color-redA', | |||
message: `(level ${this.values.level}) ${this.obj.name} has forever left the shores of the living.` | |||
} | |||
}, -1); | |||
}); | |||
this.syncer.queue('onPermadeath', { | |||
source: killSource.name | |||
@@ -565,7 +565,7 @@ module.exports = { | |||
x: this.obj.x, | |||
y: this.obj.y, | |||
components: [deathAnimation] | |||
}, -1); | |||
}); | |||
} | |||
if (this.obj.inventory) { | |||
@@ -574,10 +574,10 @@ module.exports = { | |||
for (let i = 0; i < aLen; i++) { | |||
let a = aggroList[i]; | |||
if ((!a.threat) || (!a.obj.serverId)) | |||
if ((!a.threat) || (a.obj.serverId == null)) | |||
continue; | |||
this.obj.inventory.dropBag(a.obj.serverId, killSource); | |||
this.obj.inventory.dropBag(a.obj.name, killSource); | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,644 @@ | |||
{ "backgroundcolor":"#32222e", | |||
"height":160, | |||
"infinite":false, | |||
"layers":[ | |||
{ | |||
"draworder":"topdown", | |||
"name":"Level 1", | |||
"objects":[], | |||
"opacity":0.2, | |||
"type":"objectgroup", | |||
"visible":true, | |||
"x":0, | |||
"y":0 | |||
}, | |||
{ | |||
"draworder":"topdown", | |||
"name":"Level 2", | |||
"objects":[ | |||
{ | |||
"height":160, | |||
"id":866, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":160, | |||
"x":280, | |||
"y":1032 | |||
}, | |||
{ | |||
"height":88, | |||
"id":869, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":88, | |||
"x":488, | |||
"y":1192 | |||
}, | |||
{ | |||
"height":88, | |||
"id":870, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":88, | |||
"x":488, | |||
"y":944 | |||
}, | |||
{ | |||
"height":88, | |||
"id":871, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":88, | |||
"x":152, | |||
"y":1192 | |||
}, | |||
{ | |||
"height":88, | |||
"id":872, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":88, | |||
"x":152, | |||
"y":944 | |||
}, | |||
{ | |||
"height":88, | |||
"id":874, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":88, | |||
"x":0, | |||
"y":1064 | |||
}, | |||
{ | |||
"height":64, | |||
"id":877, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":40, | |||
"x":24, | |||
"y":1152 | |||
}, | |||
{ | |||
"height":40, | |||
"id":878, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":128, | |||
"x":24, | |||
"y":1216 | |||
}, | |||
{ | |||
"height":40, | |||
"id":882, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":248, | |||
"x":240, | |||
"y":1216 | |||
}, | |||
{ | |||
"height":40, | |||
"id":883, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":248, | |||
"x":240, | |||
"y":968 | |||
}, | |||
{ | |||
"height":160, | |||
"id":884, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":40, | |||
"x":512, | |||
"y":1032 | |||
}, | |||
{ | |||
"height":96, | |||
"id":885, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":40, | |||
"x":176, | |||
"y":1032 | |||
}, | |||
{ | |||
"height":40, | |||
"id":886, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":64, | |||
"x":216, | |||
"y":1088 | |||
}, | |||
{ | |||
"ellipse":true, | |||
"height":200, | |||
"id":889, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":200, | |||
"x":1288, | |||
"y":112 | |||
}, | |||
{ | |||
"height":48, | |||
"id":896, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":56, | |||
"x":1232, | |||
"y":192 | |||
}, | |||
{ | |||
"ellipse":true, | |||
"height":312, | |||
"id":898, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":312, | |||
"x":1232, | |||
"y":56 | |||
}, | |||
{ | |||
"ellipse":true, | |||
"height":424, | |||
"id":899, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":424, | |||
"x":1176, | |||
"y":0 | |||
}, | |||
{ | |||
"height":160, | |||
"id":900, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":40, | |||
"x":1368, | |||
"y":424 | |||
}, | |||
{ | |||
"height":48, | |||
"id":901, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":96, | |||
"x":552, | |||
"y":1088 | |||
}, | |||
{ | |||
"height":144, | |||
"id":902, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":184, | |||
"x":648, | |||
"y":1040 | |||
}, | |||
{ | |||
"height":0, | |||
"id":907, | |||
"name":"", | |||
"polygon":[ | |||
{ | |||
"x":0, | |||
"y":0 | |||
}, | |||
{ | |||
"x":-24, | |||
"y":48 | |||
}, | |||
{ | |||
"x":-40, | |||
"y":40 | |||
}], | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":0, | |||
"x":1336, | |||
"y":360 | |||
}, | |||
{ | |||
"height":336, | |||
"id":908, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":296, | |||
"x":864, | |||
"y":680 | |||
}, | |||
{ | |||
"height":88, | |||
"id":909, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":136, | |||
"x":704, | |||
"y":872 | |||
}, | |||
{ | |||
"height":144, | |||
"id":910, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":184, | |||
"x":1224, | |||
"y":584 | |||
}, | |||
{ | |||
"height":88, | |||
"id":911, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":136, | |||
"x":704, | |||
"y":736 | |||
}, | |||
{ | |||
"height":128, | |||
"id":912, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":104, | |||
"x":1056, | |||
"y":1040 | |||
}, | |||
{ | |||
"height":24, | |||
"id":913, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":24, | |||
"x":840, | |||
"y":904 | |||
}, | |||
{ | |||
"height":24, | |||
"id":914, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":24, | |||
"x":840, | |||
"y":768 | |||
}, | |||
{ | |||
"height":24, | |||
"id":915, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":24, | |||
"x":1096, | |||
"y":1016 | |||
}, | |||
{ | |||
"height":48, | |||
"id":917, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":24, | |||
"x":784, | |||
"y":992 | |||
}, | |||
{ | |||
"height":24, | |||
"id":918, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":56, | |||
"x":808, | |||
"y":992 | |||
}, | |||
{ | |||
"height":24, | |||
"id":919, | |||
"name":"", | |||
"rotation":0, | |||
"type":"", | |||
"visible":true, | |||
"width":64, | |||
"x":1160, | |||
"y":704 | |||
}], | |||
"opacity":1, | |||
"type":"objectgroup", | |||
"visible":true, | |||
"x":0, | |||
"y":0 | |||
}], | |||
"nextobjectid":920, | |||
"orientation":"orthogonal", | |||
"properties": | |||
{ | |||
"instanced":"0", | |||
"name":"Test Zone", | |||
"spawn":"[{\"maxLevel\":1,\"x\":100,\"y\":186},{\"maxLevel\":999,\"x\":132,\"y\":118}]" | |||
}, | |||
"propertytypes": | |||
{ | |||
"instanced":"string", | |||
"name":"string", | |||
"spawn":"string" | |||
}, | |||
"renderorder":"right-down", | |||
"tiledversion":"1.1.5", | |||
"tileheight":8, | |||
"tilesets":[ | |||
{ | |||
"columns":8, | |||
"firstgid":1, | |||
"image":"..\/..\/..\/client\/images\/walls.png", | |||
"imageheight":256, | |||
"imagewidth":64, | |||
"margin":0, | |||
"name":"walls", | |||
"spacing":0, | |||
"tilecount":256, | |||
"tileheight":8, | |||
"tiles": | |||
{ | |||
"0": | |||
{ | |||
"probability":0.200000002980232 | |||
}, | |||
"2": | |||
{ | |||
"probability":0.600000023841858 | |||
}, | |||
"29": | |||
{ | |||
"probability":0.800000011920929 | |||
}, | |||
"3": | |||
{ | |||
"probability":0.200000002980232 | |||
}, | |||
"30": | |||
{ | |||
"probability":0.200000002980232 | |||
}, | |||
"31": | |||
{ | |||
"probability":0.200000002980232 | |||
}, | |||
"4": | |||
{ | |||
"probability":0.200000002980232 | |||
}, | |||
"50": | |||
{ | |||
"probability":0.400000005960464 | |||
}, | |||
"8": | |||
{ | |||
"probability":0.100000001490116 | |||
} | |||
}, | |||
"tilewidth":8 | |||
}, | |||
{ | |||
"columns":8, | |||
"firstgid":257, | |||
"image":"..\/..\/..\/client\/images\/mobs.png", | |||
"imageheight":88, | |||
"imagewidth":64, | |||
"margin":0, | |||
"name":"mobs", | |||
"spacing":0, | |||
"tilecount":88, | |||
"tileheight":8, | |||
"tileproperties": | |||
{ | |||
"19": | |||
{ | |||
"portal":"midgaard-inn-room_2,1" | |||
} | |||
}, | |||
"tilepropertytypes": | |||
{ | |||
"19": | |||
{ | |||
"portal":"string" | |||
} | |||
}, | |||
"tilewidth":8 | |||
}, | |||
{ | |||
"columns":8, | |||
"firstgid":345, | |||
"image":"..\/..\/..\/client\/images\/tiles.png", | |||
"imageheight":192, | |||
"imagewidth":64, | |||
"margin":0, | |||
"name":"tiles", | |||
"spacing":0, | |||
"tilecount":192, | |||
"tileheight":8, | |||
"tiles": | |||
{ | |||
"0": | |||
{ | |||
"probability":2 | |||
}, | |||
"11": | |||
{ | |||
"probability":4 | |||
}, | |||
"14": | |||
{ | |||
"probability":0.5 | |||
}, | |||
"2": | |||
{ | |||
"probability":4 | |||
}, | |||
"23": | |||
{ | |||
"probability":0.200000002980232 | |||
}, | |||
"24": | |||
{ | |||
"probability":0.200000002980232 | |||
}, | |||
"29": | |||
{ | |||
"probability":0.5 | |||
}, | |||
"3": | |||
{ | |||
"probability":7 | |||
}, | |||
"30": | |||
{ | |||
"probability":0.200000002980232 | |||
}, | |||
"31": | |||
{ | |||
"probability":10 | |||
}, | |||
"38": | |||
{ | |||
"probability":3 | |||
}, | |||
"39": | |||
{ | |||
"probability":3 | |||
}, | |||
"40": | |||
{ | |||
"probability":15 | |||
}, | |||
"41": | |||
{ | |||
"probability":2 | |||
}, | |||
"42": | |||
{ | |||
"probability":26 | |||
}, | |||
"47": | |||
{ | |||
"probability":10 | |||
}, | |||
"5": | |||
{ | |||
"probability":0.00999999977648258 | |||
}, | |||
"54": | |||
{ | |||
"probability":0.5 | |||
}, | |||
"6": | |||
{ | |||
"probability":0.00499999988824129 | |||
}, | |||
"7": | |||
{ | |||
"probability":0.100000001490116 | |||
}, | |||
"8": | |||
{ | |||
"probability":0.5 | |||
}, | |||
"9": | |||
{ | |||
"probability":4 | |||
} | |||
}, | |||
"tilewidth":8 | |||
}, | |||
{ | |||
"columns":8, | |||
"firstgid":537, | |||
"image":"..\/..\/..\/client\/images\/objects.png", | |||
"imageheight":176, | |||
"imagewidth":64, | |||
"margin":0, | |||
"name":"objects", | |||
"spacing":0, | |||
"tilecount":176, | |||
"tileheight":8, | |||
"tiles": | |||
{ | |||
"42": | |||
{ | |||
"probability":5 | |||
} | |||
}, | |||
"tilewidth":8 | |||
}, | |||
{ | |||
"columns":8, | |||
"firstgid":713, | |||
"image":"..\/..\/..\/client\/images\/bigObjects.png", | |||
"imageheight":240, | |||
"imagewidth":192, | |||
"margin":0, | |||
"name":"bigObjects", | |||
"spacing":0, | |||
"tilecount":80, | |||
"tileheight":24, | |||
"tilewidth":24 | |||
}, | |||
{ | |||
"columns":8, | |||
"firstgid":793, | |||
"image":"..\/..\/..\/client\/images\/bosses.png", | |||
"imageheight":240, | |||
"imagewidth":192, | |||
"margin":0, | |||
"name":"bosses", | |||
"spacing":0, | |||
"tilecount":80, | |||
"tileheight":24, | |||
"tilewidth":24 | |||
}], | |||
"tilewidth":8, | |||
"type":"map", | |||
"version":1, | |||
"width":200 | |||
} |
@@ -0,0 +1,258 @@ | |||
var balance = { | |||
mobs: { | |||
violetSerpent: { | |||
level: 5, | |||
meleeDmg: 1, | |||
meleeCd: 5, | |||
slowDmg: 0.1, | |||
slowTtl: 20, | |||
slowCd: 50, | |||
slowChance: 0.85 | |||
}, | |||
scarletSerpent: { | |||
level: 5, | |||
meleeDmg: 1, | |||
meleeCd: 5, | |||
chargeDmg: 1, | |||
chargeCd: 20 | |||
}, | |||
viridianSerpent: { | |||
level: 5, | |||
spitCd: 20, | |||
spitDmg: 1, | |||
spitDotDuration: 10, | |||
spitDotAmount: 1, | |||
poolDuration: 40, | |||
poolDmg: 5 | |||
} | |||
} | |||
}; | |||
module.exports = { | |||
name: 'dungeon', | |||
level: [18, 20], | |||
mobs: { | |||
default: { | |||
faction: 'hostile', | |||
walkDistance: 0, | |||
grantRep: { | |||
gaekatla: 15 | |||
}, | |||
regular: { | |||
hpMult: 4, | |||
dmgMult: 2.2, | |||
drops: { | |||
chance: 45, | |||
rolls: 1, | |||
magicFind: 500 | |||
} | |||
}, | |||
rare: { | |||
hpMult: 7, | |||
dmgMult: 3, | |||
drops: { | |||
chance: 100, | |||
rolls: 1, | |||
magicFind: 2000 | |||
} | |||
} | |||
}, | |||
'violet serpent': { | |||
level: balance.mobs.violetSerpent.level, | |||
spells: [{ | |||
type: 'melee', | |||
element: 'poison', | |||
statMult: balance.mobs.violetSerpent.meleeDmg, | |||
cdMax: balance.mobs.violetSerpent.meleeCd | |||
}, { | |||
statMult: balance.mobs.violetSerpent.slowDmg, | |||
element: 'poison', | |||
cdMax: balance.mobs.violetSerpent.slowCd, | |||
type: 'projectile', | |||
row: 5, | |||
col: 4, | |||
applyEffect: { | |||
type: 'slowed', | |||
chance: balance.mobs.violetSerpent.slowChance, | |||
ttl: balance.mobs.violetSerpent.slowTtl | |||
}, | |||
particles: { | |||
color: { | |||
start: ['a24eff', '7a3ad3'], | |||
end: ['7a3ad3', '533399'] | |||
}, | |||
scale: { | |||
start: { | |||
min: 2, | |||
max: 12 | |||
}, | |||
end: { | |||
min: 0, | |||
max: 6 | |||
} | |||
}, | |||
lifetime: { | |||
min: 2, | |||
max: 4 | |||
}, | |||
alpha: { | |||
start: 0.7, | |||
end: 0 | |||
}, | |||
speed: { | |||
start: { | |||
min: 4, | |||
max: 24 | |||
}, | |||
end: { | |||
min: 0, | |||
max: 12 | |||
} | |||
}, | |||
startRotation: { | |||
min: 0, | |||
max: 360 | |||
}, | |||
rotationSpeed: { | |||
min: 0, | |||
max: 360 | |||
}, | |||
randomScale: true, | |||
randomColor: true, | |||
randomSpeed: true, | |||
chance: 0.55, | |||
spawnType: 'circle', | |||
spawnCircle: { | |||
x: 0, | |||
y: 0, | |||
r: 8 | |||
} | |||
} | |||
}] | |||
}, | |||
'scarlet serpent': { | |||
level: balance.mobs.scarletSerpent.level, | |||
spells: [{ | |||
type: 'melee', | |||
element: 'poison', | |||
statMult: balance.mobs.scarletSerpent.meleeDmg, | |||
cdMax: balance.mobs.scarletSerpent.meleeCd | |||
}, { | |||
type: 'charge', | |||
targetFurthest: true, | |||
stunDuration: 0, | |||
statMult: balance.mobs.scarletSerpent.chargeDmg, | |||
cdMax: balance.mobs.scarletSerpent.chargeCd | |||
}] | |||
}, | |||
'viridian serpent': { | |||
level: balance.mobs.viridianSerpent.level, | |||
spells: [{ | |||
type: 'smokeBomb', | |||
castOnDeath: true, | |||
duration: balance.mobs.viridianSerpent.poolDuration, | |||
cdMult: balance.mobs.viridianSerpent.poolDmg | |||
}, { | |||
statMult: balance.mobs.viridianSerpent.spitDmg, | |||
element: 'poison', | |||
cdMax: balance.mobs.viridianSerpent.spitCd, | |||
type: 'projectile', | |||
row: 5, | |||
col: 4, | |||
applyEffect: { | |||
type: 'lifeDrain', | |||
ttl: balance.mobs.viridianSerpent.spitDotDuration, | |||
amount: balance.mobs.viridianSerpent.spitDotAmount | |||
}, | |||
targetRandom: true, | |||
particles: { | |||
color: { | |||
start: ['a24eff', '7a3ad3'], | |||
end: ['7a3ad3', '533399'] | |||
}, | |||
scale: { | |||
start: { | |||
min: 2, | |||
max: 12 | |||
}, | |||
end: { | |||
min: 0, | |||
max: 6 | |||
} | |||
}, | |||
lifetime: { | |||
min: 2, | |||
max: 4 | |||
}, | |||
alpha: { | |||
start: 0.7, | |||
end: 0 | |||
}, | |||
speed: { | |||
start: { | |||
min: 4, | |||
max: 24 | |||
}, | |||
end: { | |||
min: 0, | |||
max: 12 | |||
} | |||
}, | |||
startRotation: { | |||
min: 0, | |||
max: 360 | |||
}, | |||
rotationSpeed: { | |||
min: 0, | |||
max: 360 | |||
}, | |||
randomScale: true, | |||
randomColor: true, | |||
randomSpeed: true, | |||
chance: 0.55, | |||
spawnType: 'circle', | |||
spawnCircle: { | |||
x: 0, | |||
y: 0, | |||
r: 8 | |||
} | |||
} | |||
}] | |||
} | |||
}, | |||
objects: { | |||
greencandle: { | |||
components: { | |||
cpnLight: { | |||
simplify: function () { | |||
return { | |||
type: 'light', | |||
blueprint: { | |||
color: { | |||
start: ['80f643'], | |||
end: ['4ac441', '51fc9a', 'd07840'] | |||
}, | |||
lifetime: { | |||
min: 2, | |||
max: 6 | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
}; |
@@ -2,5 +2,6 @@ module.exports = [ | |||
'cave', | |||
'estuary', | |||
'sewer', | |||
'fjolarok' | |||
'fjolarok', | |||
'dungeon' | |||
]; |
@@ -1,6 +1,8 @@ | |||
module.exports = { | |||
type: 'projectile', | |||
applyEffect: null, | |||
cdMax: 7, | |||
manaCost: 0, | |||
@@ -120,6 +122,9 @@ module.exports = { | |||
if (!target.stats) | |||
return; | |||
if (this.applyEffect) | |||
target.effects.addEffect(this.applyEffect, this.obj); | |||
target.stats.takeDamage(damage, this.threatMult, this.obj); | |||
} | |||
}; |
@@ -2,6 +2,7 @@ let cpnSmokePatch = { | |||
type: 'smokePatch', | |||
contents: [], | |||
ttl: 0, | |||
applyDamage: function (o, amount) { | |||
o.stats.takeDamage(amount, 1, this.caster); | |||
@@ -29,8 +30,9 @@ let cpnSmokePatch = { | |||
}, | |||
update: function () { | |||
if (this.caster.destroyed) | |||
return; | |||
this.ttl--; | |||
if (this.ttl <= 0) | |||
this.obj.destroyed = true; | |||
let contents = this.contents; | |||
for (let i = 0; i < contents.length; i++) { | |||
@@ -119,15 +121,16 @@ module.exports = { | |||
}; | |||
}, | |||
blueprint: this.particles | |||
} | |||
}, | |||
extraProperties: { | |||
smokePatch: { | |||
caster: obj, | |||
statType: this.statType, | |||
getDamage: this.getDamage.bind(this) | |||
} | |||
} | |||
}, | |||
extraProperties: { | |||
smokePatch: { | |||
caster: obj, | |||
statType: this.statType, | |||
getDamage: this.getDamage.bind(this), | |||
ttl: this.duration | |||
} | |||
} | |||
} | |||
}]); | |||
patches.push(patch); | |||
@@ -6,17 +6,15 @@ module.exports = { | |||
manaCost: 1, | |||
threatMult: 1, | |||
casting: false, | |||
castTime: 0, | |||
castTimeMax: 0, | |||
needLos: false, | |||
pendingAttacks: [], | |||
currentAction: null, | |||
castBase: function () { | |||
if (this.cd > 0) | |||
return false; | |||
else if (this.manaCost > this.obj.stats.values.mana) | |||
return false; | |||
return true; | |||
}, | |||
pendingAttacks: [], | |||
canCast: function (target) { | |||
if (this.cd > 0) | |||
@@ -32,17 +30,76 @@ module.exports = { | |||
let distance = Math.max(Math.abs(target.x - obj.x), Math.abs(target.y - obj.y)); | |||
inRange = (distance <= this.range); | |||
} | |||
return inRange; | |||
}, | |||
castBase: function (action) { | |||
if (this.castTimeMax > 0) { | |||
if ((!this.currentAction) || (this.currentAction.target != action.target)) { | |||
this.currentAction = action; | |||
this.castTime = this.castTimeMax; | |||
this.obj.syncer.set(false, null, 'casting', 0); | |||
} | |||
return false; | |||
} | |||
return this.cast(action); | |||
}, | |||
updateBase: function () { | |||
if (this.castTime > 0) { | |||
this.castTime--; | |||
this.obj.syncer.set(false, null, 'casting', (this.castTimeMax - this.castTime) / this.castTimeMax); | |||
if (!this.castTime) { | |||
if (this.cast(this.currentAction)) { | |||
this.consumeMana(); | |||
this.setCd(); | |||
this.currentAction = null; | |||
} | |||
} else | |||
this.sendBump(null, 0, -1); | |||
return; | |||
} | |||
if (this.cd > 0) | |||
this.cd--; | |||
}, | |||
consumeMana: function () { | |||
let stats = this.obj.stats.values; | |||
stats.mana -= this.manaCost; | |||
if (this.obj.player) | |||
this.obj.syncer.setObject(true, 'stats', 'values', 'mana', stats.mana); | |||
}, | |||
setCd: function () { | |||
let cd = { | |||
cd: this.cdMax | |||
}; | |||
let isAttack = (this.type == 'melee'); | |||
if ((Math.random() * 100) < this.obj.stats.values[isAttack ? 'attackSpeed' : 'castSpeed']) | |||
cd.cd = 1; | |||
this.obj.fireEvent('beforeSetSpellCooldown', cd); | |||
this.cd = cd.cd; | |||
if (this.obj.player) { | |||
this.obj.instance.syncer.queue('onGetSpellCooldowns', { | |||
id: this.obj.id, | |||
spell: this.id, | |||
cd: (this.cd * 350) | |||
}, [this.obj.serverId]); | |||
} | |||
}, | |||
calcDps: function (target, noSync) { | |||
if ((!this.values) || (this.spellType === 'buff')) | |||
if ((!this.values) || (this.spellType == 'buff')) | |||
return; | |||
if ((!this.damage) && (!this.healing)) | |||
@@ -66,12 +123,12 @@ module.exports = { | |||
noCrit: true | |||
}).amount; | |||
let isAttack = (this.type === 'melee'); | |||
let isAttack = (this.type == 'melee'); | |||
let statValues = this.obj.stats.values; | |||
let critChance = isAttack ? statValues.attackCritChance : statValues.spellCritChance; | |||
let critMultiplier = 100 + (isAttack ? statValues.attackCritMultiplier : statValues.spellCritMultiplier); | |||
let critMultiplier = isAttack ? statValues.attackCritMultiplier : statValues.spellCritMultiplier; | |||
let attackSpeed = (statValues.attackSpeed / 100); | |||
attackSpeed += 1; | |||
@@ -84,7 +141,7 @@ module.exports = { | |||
if (this.damage) | |||
this.values.dmg = ~~(dmg * 100) / 100 + '/tick'; | |||
else | |||
else | |||
this.values.heal = ~~(dmg * 100) / 100 + '/tick'; | |||
if (!noSync) | |||
@@ -93,28 +150,27 @@ module.exports = { | |||
}, | |||
sendAnimation: function (blueprint) { | |||
this.obj.instance.syncer.queue('onGetObject', blueprint, -1); | |||
this.obj.instance.syncer.queue('onGetObject', blueprint); | |||
}, | |||
sendBump: function (target) { | |||
let x = this.obj.x; | |||
let y = this.obj.y; | |||
sendBump: function (target, deltaX, deltaY) { | |||
if (target) { | |||
let x = this.obj.x; | |||
let y = this.obj.y; | |||
let tx = target.x; | |||
let ty = target.y; | |||
let tx = target.x; | |||
let ty = target.y; | |||
let deltaX = 0; | |||
let deltaY = 0; | |||
if (tx < x) | |||
deltaX = -1; | |||
else if (tx > x) | |||
deltaX = 1; | |||
if (tx < x) | |||
deltaX = -1; | |||
else if (tx > x) | |||
deltaX = 1; | |||
if (ty < y) | |||
deltaY = -1; | |||
else if (ty > y) | |||
deltaY = 1; | |||
if (ty < y) | |||
deltaY = -1; | |||
else if (ty > y) | |||
deltaY = 1; | |||
} | |||
let components = [{ | |||
type: 'bumpAnimation', | |||
@@ -122,7 +178,8 @@ module.exports = { | |||
deltaY: deltaY | |||
}]; | |||
if (this.animation) { | |||
//During casting we only bump | |||
if ((target) && (this.animation)) { | |||
components.push({ | |||
type: 'animation', | |||
template: this.animation | |||
@@ -132,7 +189,7 @@ module.exports = { | |||
this.obj.instance.syncer.queue('onGetObject', { | |||
id: this.obj.id, | |||
components: components | |||
}, -1); | |||
}); | |||
}, | |||
simplify: function (self) { | |||
@@ -3,7 +3,8 @@ let events = require('../misc/events'); | |||
let spells = { | |||
melee: { | |||
auto: true, | |||
cdMax: 5, | |||
cdMax: 10, | |||
castTimeMax: 0, | |||
useWeaponRange: true, | |||
random: { | |||
damage: [3, 11.4] | |||
@@ -11,7 +12,8 @@ let spells = { | |||
}, | |||
projectile: { | |||
auto: true, | |||
cdMax: 7, | |||
cdMax: 10, | |||
castTimeMax: 0, | |||
manaCost: 0, | |||
range: 9, | |||
random: { | |||
@@ -23,7 +25,8 @@ let spells = { | |||
statType: 'int', | |||
statMult: 1, | |||
element: 'arcane', | |||
cdMax: 14, | |||
cdMax: 8, | |||
castTimeMax: 6, | |||
manaCost: 4, | |||
range: 9, | |||
random: { | |||
@@ -34,7 +37,8 @@ let spells = { | |||
statType: 'int', | |||
statMult: 0.49, | |||
element: 'frost', | |||
cdMax: 12, | |||
cdMax: 9, | |||
castTimeMax: 3, | |||
manaCost: 4, | |||
range: 9, | |||
random: { | |||
@@ -47,6 +51,7 @@ let spells = { | |||
statMult: 0.22, | |||
element: 'fire', | |||
cdMax: 6, | |||
castTimeMax: 0, | |||
manaCost: 5, | |||
random: { | |||
damage: [6, 22.9], | |||
@@ -57,8 +62,8 @@ let spells = { | |||
smite: { | |||
statType: 'int', | |||
statMult: 1, | |||
element: 'holy', | |||
cdMax: 10, | |||
cdMax: 4, | |||
castTimeMax: 6, | |||
range: 9, | |||
manaCost: 4, | |||
random: { | |||
@@ -70,7 +75,8 @@ let spells = { | |||
statType: 'int', | |||
statMult: 0.07, | |||
element: 'holy', | |||
cdMax: 10, | |||
cdMax: 8, | |||
castTimeMax: 2, | |||
manaCost: 8, | |||
range: 9, | |||
radius: 3, | |||
@@ -79,21 +85,13 @@ let spells = { | |||
i_duration: [7, 13] | |||
} | |||
}, | |||
/*'holy vengeance': { | |||
statType: 'int', | |||
statMult: 1, | |||
cdMax: 30, | |||
manaCost: 15, | |||
range: 9, | |||
random: { | |||
i_duration: [30, 50] | |||
} | |||
},*/ | |||
slash: { | |||
statType: 'str', | |||
statMult: 1, | |||
threatMult: 4, | |||
cdMax: 10, | |||
cdMax: 8, | |||
castTimeMax: 2, | |||
manaCost: 4, | |||
useWeaponRange: true, | |||
random: { | |||
@@ -105,6 +103,7 @@ let spells = { | |||
statMult: 0.59, | |||
threatMult: 3, | |||
cdMax: 15, | |||
castTimeMax: 0, | |||
range: 10, | |||
manaCost: 3, | |||
random: { | |||
@@ -112,20 +111,11 @@ let spells = { | |||
i_stunDuration: [6, 10] | |||
} | |||
}, | |||
/*'reflect damage': { | |||
statType: 'str', | |||
statMult: 1, | |||
cdMax: 5, | |||
threatMult: 2, | |||
manaCost: 10, | |||
random: { | |||
i_duration: [4, 8] | |||
} | |||
},*/ | |||
flurry: { | |||
statType: 'dex', | |||
statMult: 0.88, | |||
cdMax: 20, | |||
castTimeMax: 0, | |||
manaCost: 5, | |||
random: { | |||
i_duration: [4, 9] | |||
@@ -136,6 +126,7 @@ let spells = { | |||
statMult: 0.98, | |||
element: 'poison', | |||
cdMax: 5, | |||
castTimeMax: 0, | |||
manaCost: 6, | |||
random: { | |||
damage: [0.25, 0.73], | |||
@@ -143,19 +134,13 @@ let spells = { | |||
i_duration: [7, 13] | |||
} | |||
}, | |||
/*'stealth': { | |||
statType: 'dex', | |||
statMult: 1, | |||
duration: 200, | |||
cdMax: 15, | |||
manaCost: 10 | |||
},*/ | |||
'crystal spikes': { | |||
statType: ['dex', 'int'], | |||
statMult: 1.82, | |||
manaCost: 22, | |||
needLos: true, | |||
cdMax: 20, | |||
cdMax: 16, | |||
castTimeMax: 4, | |||
range: 9, | |||
random: { | |||
damage: [7, 26.5], | |||
@@ -172,6 +157,7 @@ let spells = { | |||
percentage: 0.25 | |||
}, | |||
cdMax: 10, | |||
castTimeMax: 0, | |||
auraRange: 9, | |||
effect: 'regenHp', | |||
random: { | |||
@@ -186,6 +172,7 @@ let spells = { | |||
percentage: 0.25 | |||
}, | |||
cdMax: 10, | |||
castTimeMax: 0, | |||
auraRange: 9, | |||
effect: 'regenMana', | |||
random: { | |||
@@ -200,24 +187,14 @@ let spells = { | |||
percentage: 0.4 | |||
}, | |||
cdMax: 10, | |||
castTimeMax: 0, | |||
auraRange: 9, | |||
effect: 'swiftness', | |||
random: { | |||
chance: [5, 10] | |||
} | |||
} | |||
/*, | |||
'chain lightning': { | |||
statType: 'int', | |||
statMult: 0.454, | |||
element: 'holy', | |||
cdMax: 5, | |||
manaCost: 0, | |||
range: 9, | |||
random: { | |||
damage: [9.3, 18.6] | |||
} | |||
}*/ | |||
}; | |||
module.exports = { | |||
@@ -231,7 +231,8 @@ let types = { | |||
statType: 'str', | |||
statMult: 0.84, | |||
threatMult: 4, | |||
cdMax: 5, | |||
cdMax: 6, | |||
castTimeMax: 0, | |||
useWeaponRange: true, | |||
random: { | |||
damage: [3, 11.4] | |||
@@ -250,6 +251,7 @@ let types = { | |||
statType: 'dex', | |||
statMult: 0.88, | |||
cdMax: 3, | |||
castTimeMax: 0, | |||
useWeaponRange: true, | |||
random: { | |||
damage: [1, 3.8] | |||
@@ -269,6 +271,7 @@ let types = { | |||
statMult: 1, | |||
element: 'holy', | |||
cdMax: 4, | |||
castTimeMax: 0, | |||
manaCost: 0, | |||
range: 6, | |||
random: { | |||
@@ -290,7 +293,8 @@ let types = { | |||
statType: 'str', | |||
statMult: 0.84, | |||
threatMult: 4, | |||
cdMax: 5, | |||
cdMax: 6, | |||
castTimeMax: 0, | |||
useWeaponRange: true, | |||
random: { | |||
damage: [3, 15.4] | |||
@@ -311,6 +315,7 @@ let types = { | |||
element: 'arcane', | |||
auto: true, | |||
cdMax: 7, | |||
castTimeMax: 0, | |||
manaCost: 0, | |||
range: 9, | |||
random: { | |||
@@ -332,6 +337,7 @@ let types = { | |||
statMult: 0.84, | |||
threatMult: 4, | |||
cdMax: 5, | |||
castTimeMax: 0, | |||
useWeaponRange: true, | |||
random: { | |||
damage: [3, 11.4] | |||
@@ -131,6 +131,7 @@ module.exports = { | |||
statType: ['str', 'int'], | |||
statMult: 0.76, | |||
cdMax: 6, | |||
castTimeMax: 0, | |||
useWeaponRange: true, | |||
random: { | |||
damage: [1.5, 5.7] | |||
@@ -148,7 +149,8 @@ module.exports = { | |||
spells['harvest life'] = { | |||
statType: ['str', 'int'], | |||
statMult: 1, | |||
cdMax: 12, | |||
cdMax: 8, | |||
castTimeMax: 4, | |||
manaCost: 5, | |||
range: 1, | |||
random: { | |||
@@ -160,7 +162,8 @@ module.exports = { | |||
spells['summon skeleton'] = { | |||
statType: ['str', 'int'], | |||
statMult: 0.27, | |||
cdMax: 7, | |||
cdMax: 5, | |||
castTimeMax: 2, | |||
manaCost: 5, | |||
range: 9, | |||
random: { | |||
@@ -172,7 +175,8 @@ module.exports = { | |||
spells['blood barrier'] = { | |||
statType: ['str', 'int'], | |||
statMult: 0.1, | |||
cdMax: 20, | |||
cdMax: 15, | |||
castTimeMax: 5, | |||
manaCost: 5, | |||
range: 9, | |||
random: { | |||
@@ -99,7 +99,7 @@ module.exports = { | |||
o = this; | |||
} | |||
let syncTypes = ['portrait']; | |||
let syncTypes = ['portrait', 'area']; | |||
for (let p in o) { | |||
let value = o[p]; | |||
@@ -79,9 +79,12 @@ module.exports = { | |||
obj.height = l.height; | |||
} | |||
if (l.area) | |||
obj.area = l.area; | |||
//Add components (certain ones need to happen first) | |||
//TODO: Clean this part up | |||
let properties = extend({}, l.properties); | |||
let properties = extend(true, {}, l.properties); | |||
['cpnMob'].forEach(function (c) { | |||
let blueprint = properties[c] || null; | |||
if ((blueprint) && (typeof (blueprint) === 'string')) | |||
@@ -337,21 +337,50 @@ module.exports = { | |||
if (blueprint.blocking) | |||
this.collisionMap[blueprint.x][blueprint.y] = 1; | |||
if ((blueprint.properties.cpnNotice) || (blueprint.properties.cpnLightPatch) || (layerName === 'rooms') || (layerName === 'hiddenRooms')) { | |||
if ((blueprint.properties.cpnNotice) || (blueprint.properties.cpnLightPatch) || (layerName === 'rooms') || (layerName == 'hiddenRooms')) { | |||
blueprint.y++; | |||
blueprint.width = cell.width / mapScale; | |||
blueprint.height = cell.height / mapScale; | |||
} else if (cell.width === 24) | |||
blueprint.x++; | |||
if (cell.polyline) { | |||
let lowX = this.size.w; | |||
let lowY = this.size.h; | |||
let highX = 0; | |||
let highY = 0; | |||
blueprint.area = cell.polyline.map(function (v) { | |||
let x = ~~((v.x + cell.x) / mapScale); | |||
let y = ~~((v.y + cell.y) / mapScale); | |||
if (x < lowX) | |||
lowX = x; | |||
if (x > highX) | |||
highX = x; | |||
if (y < lowY) | |||
lowY = y; | |||
if (y > highY) | |||
highY = y; | |||
return [x, y]; | |||
}); | |||
blueprint.x = lowX; | |||
blueprint.y = lowY; | |||
blueprint.width = (highX - lowX); | |||
blueprint.height = (highY - lowY); | |||
} | |||
if (layerName === 'rooms') { | |||
if (blueprint.properties.exit) { | |||
let room = this.rooms.find(function (r) { | |||
return (!( | |||
(blueprint.x + blueprint.width < r.x) || | |||
(blueprint.y + blueprint.height < r.y) || | |||
(blueprint.x >= r.x + r.width) || | |||
(blueprint.y >= r.y + r.height) | |||
(blueprint.y + blueprint.height < r.y) || | |||
(blueprint.x >= r.x + r.width) || | |||
(blueprint.y >= r.y + r.height) | |||
)); | |||
}); | |||
@@ -363,23 +392,30 @@ module.exports = { | |||
blueprint.objects = []; | |||
this.rooms.push(blueprint); | |||
} | |||
} else if (layerName === 'hiddenRooms') | |||
} else if (layerName === 'hiddenRooms') { | |||
blueprint.fog = (cell.properties || {}).fog; | |||
blueprint.discoverable = (cell.properties || {}).discoverable; | |||
this.hiddenRooms.push(blueprint); | |||
else if (!clientObj) { | |||
} else if (!clientObj) { | |||
if (!mapFile.properties.isRandom) | |||
spawners.register(blueprint, blueprint.spawnCd || mapFile.properties.spawnCd); | |||
else { | |||
let room = this.rooms.find(function (r) { | |||
return (!( | |||
(blueprint.x < r.x) || | |||
(blueprint.y < r.y) || | |||
(blueprint.x >= r.x + r.width) || | |||
(blueprint.y >= r.y + r.height) | |||
(blueprint.y < r.y) || | |||
(blueprint.x >= r.x + r.width) || | |||
(blueprint.y >= r.y + r.height) | |||
)); | |||
}); | |||
room.objects.push(blueprint); | |||
} | |||
} else { | |||
if ((cell.width) && (!cell.polyline)) { | |||
blueprint.width = cell.width / mapScale; | |||
blueprint.height = cell.height / mapScale; | |||
} | |||
let obj = objects.buildObjects([blueprint], true).getSimple(true); | |||
this.objBlueprints.push(obj); | |||
} | |||
@@ -49,6 +49,11 @@ module.exports = { | |||
grantRep: blueprint.grantRep, | |||
deathRep: blueprint.deathRep | |||
}); | |||
if (blueprint.patrol) | |||
cpnMob.patrol = blueprint.patrol; | |||
if (cpnMob.patrol) | |||
cpnMob.walkDistance = 1; | |||
let spells = extend([], blueprint.spells); | |||
spells.forEach(function (s) { | |||
@@ -64,7 +69,7 @@ module.exports = { | |||
}); | |||
let attackable = blueprint.attackable; | |||
if (attackable !== false) { | |||
if (!blueprint.has('attackable') || attackable === true) { | |||
mob.addComponent('aggro', { | |||
faction: blueprint.faction | |||
}); | |||
@@ -52,6 +52,7 @@ module.exports = { | |||
} | |||
} | |||
}, | |||
removeRegion: function (obj) { | |||
let oId = obj.id; | |||
@@ -103,12 +104,17 @@ module.exports = { | |||
//If we have fromX and fromY, check if the target cell doesn't contain the same obj (like a notice area) | |||
if ((c.width) && (fromX)) { | |||
if ((fromX < c.x) || (fromY < c.y) || (fromX >= c.x + c.width) || (fromY >= c.y + c.height)) { | |||
if (c.area) { | |||
if ((this.isInPolygon(x, y, c.area)) && (!this.isInPolygon(fromX, fromY, c.area))) { | |||
c.collisionEnter(obj); | |||
obj.collisionEnter(c); | |||
} | |||
} else if ((fromX < c.x) || (fromY < c.y) || (fromX >= c.x + c.width) || (fromY >= c.y + c.height)) { | |||
c.collisionEnter(obj); | |||
obj.collisionEnter(c); | |||
} | |||
} else { | |||
//If a callback returns true, it means we collide | |||
//If a callback returns true, it means we collide | |||
if (c.collisionEnter(obj)) | |||
return; | |||
obj.collisionEnter(c); | |||
@@ -118,6 +124,7 @@ module.exports = { | |||
cell.push(obj); | |||
return true; | |||
}, | |||
removeObject: function (obj, x, y, toX, toY) { | |||
let row = this.cells[x]; | |||
@@ -137,7 +144,12 @@ module.exports = { | |||
if (c.id !== oId) { | |||
//If we have toX and toY, check if the target cell doesn't contain the same obj (like a notice area) | |||
if ((c.width) && (toX)) { | |||
if ((toX < c.x) || (toY < c.y) || (toX >= c.x + c.width) || (toY >= c.y + c.height)) { | |||
if (c.area) { | |||
if ((this.isInPolygon(x, y, c.area)) && (!this.isInPolygon(toX, toY, c.area))) { | |||
c.collisionExit(obj); | |||
obj.collisionExit(c); | |||
} | |||
} else if ((toX < c.x) || (toY < c.y) || (toX >= c.x + c.width) || (toY >= c.y + c.height)) { | |||
c.collisionExit(obj); | |||
obj.collisionExit(c); | |||
} | |||
@@ -502,5 +514,30 @@ module.exports = { | |||
grid[x][y].weight = collides ? 0 : 1; | |||
pathfinder.astar.cleanNode(grid[x][y]); | |||
} | |||
}, | |||
isInPolygon: function (x, y, verts) { | |||
let inside = false; | |||
let vLen = verts.length; | |||
for (let i = 0, j = vLen - 1; i < vLen; j = i++) { | |||
let vi = verts[i]; | |||
let vj = verts[j]; | |||
let xi = vi[0]; | |||
let yi = vi[1]; | |||
let xj = vj[0]; | |||
let yj = vj[1]; | |||
let doesIntersect = ( | |||
((yi > y) != (yj > y)) && | |||
(x < ((((xj - xi) * (y - yi)) / (yj - yi)) + xi)) | |||
); | |||
if (doesIntersect) | |||
inside = !inside; | |||
} | |||
return inside; | |||
} | |||
}; |