Bläddra i källkod

first batch of conflict fixes

tags/v0.3.0
Big Bad Waffle 5 år sedan
förälder
incheckning
29d8839704
52 ändrade filer med 5565 tillägg och 292 borttagningar
  1. Binär
     
  2. Binär
     
  3. Binär
     
  4. Binär
     
  5. Binär
     
  6. Binär
     
  7. +2
    -1
      src/client/js/components/components.js
  8. +4
    -4
      src/client/js/components/explosion.js
  9. +7
    -0
      src/client/js/components/light.js
  10. +10
    -0
      src/client/js/components/lightPatch.js
  11. +1
    -0
      src/client/js/components/particles.js
  12. +10
    -0
      src/client/js/components/projectile.js
  13. +17
    -0
      src/client/js/components/sound.js
  14. +44
    -0
      src/client/js/misc/distanceToPolygon.js
  15. +44
    -8
      src/client/js/misc/physics.js
  16. +17
    -2
      src/client/js/objects/objBase.js
  17. +88
    -17
      src/client/js/objects/objects.js
  18. +30
    -2
      src/client/js/rendering/particles.js
  19. +866
    -0
      src/client/js/rendering/renderer.js
  20. +3
    -1
      src/client/js/rendering/tileOpacity.js
  21. +58
    -30
      src/client/js/sound/sound.js
  22. +2
    -1
      src/client/ui/factory.js
  23. +30
    -0
      src/client/ui/templates/middleHud/middleHud.js
  24. +32
    -0
      src/client/ui/templates/middleHud/styles.less
  25. +6
    -0
      src/client/ui/templates/middleHud/template.html
  26. +13
    -1
      src/client/ui/templates/target/styles.less
  27. +15
    -0
      src/client/ui/templates/target/target.js
  28. +5
    -1
      src/client/ui/templates/target/template.html
  29. +127
    -0
      src/server/components/aggro.js
  30. +37
    -0
      src/server/components/chest.js
  31. +25
    -0
      src/server/components/effects.js
  32. +61
    -0
      src/server/components/inventory.js
  33. +27
    -5
      src/server/components/mob.js
  34. +20
    -0
      src/server/components/sound.js
  35. +68
    -26
      src/server/components/spellbook.js
  36. +4
    -4
      src/server/components/stats.js
  37. +644
    -0
      src/server/config/maps/dungeon.json
  38. +2493
    -0
      src/server/config/maps/dungeon/map.json
  39. +258
    -0
      src/server/config/maps/dungeon/zone.js
  40. +251
    -77
      src/server/config/maps/fjolarok/map.json
  41. +2
    -1
      src/server/config/maps/mapList.js
  42. +5
    -0
      src/server/config/spells/spellProjectile.js
  43. +14
    -11
      src/server/config/spells/spellSmokeBomb.js
  44. +89
    -32
      src/server/config/spells/spellTemplate.js
  45. +25
    -48
      src/server/config/spellsConfig.js
  46. +8
    -2
      src/server/items/config/types.js
  47. +7
    -3
      src/server/mods/class-necromancer/index.js
  48. +1
    -1
      src/server/objects/objBase.js
  49. +4
    -1
      src/server/objects/objects.js
  50. +45
    -9
      src/server/world/map.js
  51. +6
    -1
      src/server/world/mobBuilder.js
  52. +40
    -3
      src/server/world/physics.js

Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


Binär
Visa fil


+ 2
- 1
src/client/js/components/components.js Visa fil

@@ -32,7 +32,8 @@ let components = [
'reputation',
'serverActions',
'social',
'passives'
'passives',
'sound'
].map(function (c) {
return 'js/components/' + c;
});


+ 4
- 4
src/client/js/components/explosion.js Visa fil

@@ -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) {


+ 7
- 0
src/client/js/components/light.js Visa fil

@@ -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++) {


+ 10
- 0
src/client/js/components/lightPatch.js Visa fil

@@ -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);


+ 1
- 0
src/client/js/components/particles.js Visa fil

@@ -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);
},


+ 10
- 0
src/client/js/components/projectile.js Visa fil

@@ -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;


+ 17
- 0
src/client/js/components/sound.js Visa fil

@@ -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);
}
};
});

+ 44
- 0
src/client/js/misc/distanceToPolygon.js Visa fil

@@ -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;
}
};
});

+ 44
- 8
src/client/js/misc/physics.js Visa fil

@@ -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
}
};
});

+ 17
- 2
src/client/js/objects/objBase.js Visa fil

@@ -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);


+ 88
- 17
src/client/js/objects/objects.js Visa fil

@@ -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);
}
}
};
});

+ 30
- 2
src/client/js/rendering/particles.js Visa fil

@@ -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);
}


+ 866
- 0
src/client/js/rendering/renderer.js Visa fil

@@ -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
});

+ 3
- 1
src/client/js/rendering/tileOpacity.js Visa fil

@@ -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


+ 58
- 30
src/client/js/sound/sound.js Visa fil

@@ -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);


+ 2
- 1
src/client/ui/factory.js Visa fil

@@ -52,7 +52,8 @@ define([
'mail',
'wardrobe',
'passives',
'workbench'
'workbench',
'middleHud'
].forEach(function (u) {
this.build(u);
}, this);


+ 30
- 0
src/client/ui/templates/middleHud/middleHud.js Visa fil

@@ -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) + '%');
}
}
};
});

+ 32
- 0
src/client/ui/templates/middleHud/styles.less Visa fil

@@ -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;
}
}
}

+ 6
- 0
src/client/ui/templates/middleHud/template.html Visa fil

@@ -0,0 +1,6 @@
<div class="middleHud">
<div class="casting">
<div class="bar"></div>
<div class="text">casting</div>
</div>
</div>

+ 13
- 1
src/client/ui/templates/target/styles.less Visa fil

@@ -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;
}
}
}
}

+ 15
- 0
src/client/ui/templates/target/target.js Visa fil

@@ -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) {


+ 5
- 1
src/client/ui/templates/target/template.html Visa fil

@@ -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>

+ 127
- 0
src/server/components/aggro.js Visa fil

@@ -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
}
}
}


+ 37
- 0
src/server/components/chest.js Visa fil

@@ -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;


+ 25
- 0
src/server/components/effects.js Visa fil

@@ -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])


+ 61
- 0
src/server/components/inventory.js Visa fil

@@ -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;
},


+ 27
- 5
src/server/components/mob.js Visa fil

@@ -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;


+ 20
- 0
src/server/components/sound.js Visa fil

@@ -0,0 +1,20 @@
define([

], function (

) {
return {
type: 'sound',

sound: null,
volume: 0,

simplify: function () {
return {
type: 'sound',
sound: this.sound,
volume: this.volume
};
}
};
});

+ 68
- 26
src/server/components/spellbook.js Visa fil

@@ -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) {


+ 4
- 4
src/server/components/stats.js Visa fil

@@ -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);
}
}
}


+ 644
- 0
src/server/config/maps/dungeon.json Visa fil

@@ -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
}

+ 2493
- 0
src/server/config/maps/dungeon/map.json
Filskillnaden har hållits tillbaka eftersom den är för stor
Visa fil


+ 258
- 0
src/server/config/maps/dungeon/zone.js Visa fil

@@ -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
}
}
}
}
}
}
}
}
};

+ 251
- 77
src/server/config/maps/fjolarok/map.json
Filskillnaden har hållits tillbaka eftersom den är för stor
Visa fil


+ 2
- 1
src/server/config/maps/mapList.js Visa fil

@@ -2,5 +2,6 @@ module.exports = [
'cave',
'estuary',
'sewer',
'fjolarok'
'fjolarok',
'dungeon'
];

+ 5
- 0
src/server/config/spells/spellProjectile.js Visa fil

@@ -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);
}
};

+ 14
- 11
src/server/config/spells/spellSmokeBomb.js Visa fil

@@ -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);


+ 89
- 32
src/server/config/spells/spellTemplate.js Visa fil

@@ -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) {


+ 25
- 48
src/server/config/spellsConfig.js Visa fil

@@ -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 = {


+ 8
- 2
src/server/items/config/types.js Visa fil

@@ -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]


+ 7
- 3
src/server/mods/class-necromancer/index.js Visa fil

@@ -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: {


+ 1
- 1
src/server/objects/objBase.js Visa fil

@@ -99,7 +99,7 @@ module.exports = {
o = this;
}

let syncTypes = ['portrait'];
let syncTypes = ['portrait', 'area'];

for (let p in o) {
let value = o[p];


+ 4
- 1
src/server/objects/objects.js Visa fil

@@ -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'))


+ 45
- 9
src/server/world/map.js Visa fil

@@ -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);
}


+ 6
- 1
src/server/world/mobBuilder.js Visa fil

@@ -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
});


+ 40
- 3
src/server/world/physics.js Visa fil

@@ -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;
}
};

Laddar…
Avbryt
Spara