浏览代码

Merge branch 'staging' into 'master'

Staging

Closes #161, #159, #158, #40, #132, #156, #153, #134, #148, #115, #151, #137, #116, #146, #147, #144, #135, #133, #131, #127, #130, #126, #124, #123, #118, and #119

See merge request !118
tags/v0.1.3^0
Big Bad Waffle 7 年前
父节点
当前提交
98c1f1579f
共有 78 个文件被更改,包括 1399 次插入913 次删除
  1. +1
    -1
      src/client/css/colors.less
  2. +1
    -1
      src/client/css/main.less
  3. 二进制
     
  4. 二进制
     
  5. +0
    -303
      src/client/js/canvas.js
  6. +1
    -1
      src/client/js/components/animation.js
  7. +1
    -1
      src/client/js/components/attackAnimation.js
  8. +1
    -1
      src/client/js/components/chatter.js
  9. +30
    -11
      src/client/js/components/chest.js
  10. +1
    -1
      src/client/js/components/effects.js
  11. +1
    -1
      src/client/js/components/flash.js
  12. +1
    -38
      src/client/js/components/light.js
  13. +1
    -1
      src/client/js/components/mouseMover.js
  14. +4
    -2
      src/client/js/components/moveAnimation.js
  15. +1
    -1
      src/client/js/components/particles.js
  16. +1
    -1
      src/client/js/components/pather.js
  17. +1
    -1
      src/client/js/components/player.js
  18. +2
    -4
      src/client/js/components/projectile.js
  19. +5
    -5
      src/client/js/components/spellbook.js
  20. +1
    -1
      src/client/js/components/stats.js
  21. +5
    -1
      src/client/js/input.js
  22. +1
    -1
      src/client/js/main.js
  23. +1
    -1
      src/client/js/objects/objBase.js
  24. +10
    -4
      src/client/js/objects/objects.js
  25. +2
    -49
      src/client/js/rendering/effects.js
  26. +1
    -1
      src/client/js/rendering/numbers.js
  27. +212
    -149
      src/client/js/rendering/renderer.js
  28. +36
    -0
      src/client/js/rendering/spritePool.js
  29. +0
    -111
      src/client/js/rendering/spriteShader.js
  30. +9
    -0
      src/client/js/rendering/tileOpacity.js
  31. +3
    -1
      src/client/ui/templates/characters/styles.less
  32. +3
    -1
      src/client/ui/templates/createCharacter/styles.less
  33. +13
    -0
      src/client/ui/templates/equipment/styles.less
  34. +1
    -1
      src/client/ui/templates/help/template.html
  35. +1
    -0
      src/client/ui/templates/hud/styles.less
  36. +4
    -30
      src/client/ui/templates/inventory/inventory.js
  37. +16
    -0
      src/client/ui/templates/inventory/styles.less
  38. +6
    -2
      src/client/ui/templates/login/login.js
  39. +83
    -52
      src/client/ui/templates/login/styles.less
  40. +8
    -16
      src/client/ui/templates/login/template.html
  41. +6
    -0
      src/client/ui/templates/messages/styles.less
  42. +1
    -1
      src/client/ui/templates/options/options.js
  43. +2
    -2
      src/client/ui/templates/party/styles.less
  44. +6
    -0
      src/client/ui/templates/reputation/styles.less
  45. +13
    -0
      src/client/ui/templates/smithing/styles.less
  46. +7
    -1
      src/client/ui/templates/trade/trade.js
  47. +33
    -9
      src/server/components/auth.js
  48. +1
    -1
      src/server/components/extensions/factionVendor.js
  49. +80
    -0
      src/server/components/follower.js
  50. +41
    -10
      src/server/components/inventory.js
  51. +2
    -2
      src/server/components/mob.js
  52. +19
    -3
      src/server/components/notice.js
  53. +11
    -6
      src/server/components/player.js
  54. +2
    -0
      src/server/components/spellbook.js
  55. +32
    -19
      src/server/components/stats.js
  56. +2
    -2
      src/server/components/trade.js
  57. +1
    -0
      src/server/config/classes.js
  58. +23
    -3
      src/server/config/factions/gaekatla.js
  59. +1
    -6
      src/server/config/maps/city/map.json
  60. +1
    -1
      src/server/config/maps/city/zone.js
  61. +387
    -0
      src/server/config/maps/fjolarok/map.json
  62. 二进制
     
  63. +0
    -1
      src/server/config/maps/mapList.js
  64. +1
    -0
      src/server/config/maps/test/map.json
  65. +160
    -9
      src/server/config/maps/tutorial/map.json
  66. +24
    -0
      src/server/config/maps/tutorial/zone.js
  67. +14
    -4
      src/server/config/spells/spellCharge.js
  68. +5
    -0
      src/server/config/spells/spellMelee.js
  69. +5
    -0
      src/server/items/generators/spellbook.js
  70. +1
    -1
      src/server/misc/mods.js
  71. +1
    -0
      src/server/misc/profanities.js
  72. +1
    -0
      src/server/package.json
  73. +1
    -1
      src/server/startup.js
  74. +2
    -2
      src/server/world/atlas.js
  75. +28
    -30
      src/server/world/instancer.js
  76. +11
    -1
      src/server/world/map.js
  77. +4
    -2
      src/server/world/randomMap.js
  78. +1
    -1
      src/server/world/resourceSpawner.js

+ 1
- 1
src/client/css/colors.less 查看文件

@@ -14,8 +14,8 @@
@red: #d43346;
@blue: #3fa7dd;
@green: #80f643;

@greenB: #4ac441;
@greenC: #386646;

@blackA: #505360;
@blackB: #3c3f4c;


+ 1
- 1
src/client/css/main.less 查看文件

@@ -67,4 +67,4 @@ body {
-webkit-border-radius: 10px;
border-radius: 0px;
background: @lightGray;
}
}

二进制
查看文件


二进制
查看文件


+ 0
- 303
src/client/js/canvas.js 查看文件

@@ -1,303 +0,0 @@
define([
'js/system/events',
'js/resources',
'js/rendering/tileOpacity',
'js/misc/physics',
'js/spriteBuilder'
], function(
events,
resources,
tileOpacity,
physics,
spriteBuilder
) {
return {
map: null,
mapSprite: null,

//TEST: Remove
visMap: null,

pos: {
x: 0,
y: 0
},
moveTo: null,
moveSpeed: 0,
moveSpeedMax: 1.5,
moveSpeedInc: 0.5,
moveSpeedFlatten: 16,

size: {
x: 0,
y: 0,
},
layers: {},

tileSize: {
w: 32,
h: 32
},

zoneId: null,

player: null,

init: function() {
events.on('onGetMap', this.onGetMap.bind(this));

var canvas = $('.canvasContainer canvas');

canvas.each(function(i, c) {
c = $(c);

if (!c.attr('layer'))
return;

this.layers[c.attr('layer')] = {
canvas: c,
ctx: c[0].getContext('2d')
};

c[0].width = this.size.x = $('body').width();
c[0].height = this.size.y = $('body').height();
c.css('z-index', i + 1);
}.bind(this));

this.layers.particles.ctx.globalCompositeOperation = 'lighter';

$('.canvasContainer')
.width(this.size.x)
.height(this.size.y);
},
onGetMap: function(msg) {
$('.canvasContainer')
.removeClass('visible');

setTimeout(function() {
$('.canvasContainer').addClass('visible');
}, 1000);
if (this.zoneId != null) {
events.emit('onRezone', this.zoneId);
}

this.zoneId = msg.zoneId;

$('.canvasContainer').addClass('visible');

this.map = msg.map;
this.visMap = msg.visMap;

physics.init(msg.collisionMap);

msg.clientObjects.forEach(function(c) {
c.zoneId = this.zoneId;
events.emit('onGetObject', c);
}, this);

this.mapSprite = spriteBuilder.buildSprite(
['tiles', 'walls', 'objects'], [this.map['tiles'], this.map['walls'], this.map['objects']], [0.55, 0.85, 0.85]
);
},
fadeOut: function() {
$('.canvasContainer')
.removeClass('visible');

setTimeout(function() {
$('.canvasContainer').addClass('visible');
}, 1000);
},
setPosition: function(pos, instant) {
if (instant) {
this.fadeOut();

this.moveTo = null;
this.pos = pos;
return;
}

this.moveTo = pos;
},
clear: function(filter) {
for (var l in this.layers) {
var ctx = this.layers[l].ctx;

ctx.save();

ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, this.size.x, this.size.y);

ctx.restore();
}
},
begin: function() {
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));
if (moveSpeed > distance)
moveSpeed = distance;

if (distance > this.moveSpeedFlatten) {
var maxSpeed = this.moveSpeedMax;
if (distance > 64) {
maxSpeed += (distance - 64) / 1000;
}
if (this.moveSpeed < maxSpeed)
this.moveSpeed += this.moveSpeedInc;
}

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

for (var l in this.layers) {
var ctx = this.layers[l].ctx;

ctx.save();
ctx.translate(-~~this.pos.x, -~~this.pos.y);
}
},
end: function() {
for (var l in this.layers) {
var ctx = this.layers[l].ctx;

ctx.restore();
}
},

renderMap: function() {
if (!this.player)
return;

this.layers['tiles'].ctx.drawImage(
this.mapSprite,
this.pos.x,
this.pos.y,
this.size.x,
this.size.y,
this.pos.x,
this.pos.y,
this.size.x,
this.size.y
);
},
renderObject: function(obj) {
if (!this.player)
return;

var x = obj.x;
var y = obj.y;

var pX = this.player.x;
var pY = this.player.y;

var dx = Math.abs(x - pX);
var dy = Math.abs(y - pY);

var dxMax = (this.size.x / 64) + 4;
var dyMax = (this.size.y / 64) + 4;

if ((dx > dxMax) || (dy > dyMax))
return;

var sprite = resources.sprites[obj.sheetName].image;
var ctx = this.layers[obj.layerName || obj.sheetName].ctx;

var tileY = ~~(obj.cell / 8);
var tileX = obj.cell - (tileY * 8);

var offsetX = obj.offsetX || 0;
var offsetY = obj.offsetY || 0;

var alpha = 1;
if (obj.alpha != null)
alpha = obj.alpha;

ctx.globalAlpha = alpha;

var size = obj.size || 32;

if (obj.flipX) {
ctx.save();
ctx.scale(-1, 1);
ctx.drawImage(
sprite,
tileX * 32,
tileY * 32,
32,
32,
-(x * 32) - (~~(offsetX / 4) * 4),
(y * 32) + (~~(offsetY / 4) * 4),
-32,
32
);
ctx.restore();
}
else if (obj.flipY) {
ctx.save();
ctx.scale(1, -1);
ctx.drawImage(
sprite,
tileX * 32,
tileY * 32,
32,
32,
(x * 32) - (~~(offsetX / 4) * 4),
-(y * 32) + (~~(offsetY / 4) * 4),
32,
-32
);
ctx.restore();
} else
ctx.drawImage(sprite, tileX * size, tileY * size, size, size, (x * 32) + (~~(offsetX / 4) * 4), (y * 32) + (~~(offsetY / 4) * 4), size, size);
},
renderRect: function(layer, x, y, color) {
if (!this.player)
return;

var pX = this.player.x;
var pY = this.player.y;

var dx = Math.abs(x - pX);
var dy = Math.abs(y - pY);

var dxMax = (this.size.x / 64) + 4;
var dyMax = (this.size.y / 64) + 4;

if ((dx > dxMax) || (dy > dyMax))
return;

var ctx = this.layers[layer].ctx;
ctx.fillStyle = color;
ctx.fillRect(x * 32, y * 32, 32, 32);
},
renderText: function(layer, text, x, y) {
var ctx = this.layers[layer].ctx;
ctx.fillStyle = 'white';

ctx.fillText(text, x, y);
},
renderOutlineText: function(layer, text, x, y, centerX) {
var ctx = this.layers[layer].ctx;
ctx.lineWidth = 2;

if (centerX)
x -= (ctx.measureText(text).width / 2);

ctx.strokeText(text, x, y);
ctx.fillText(text, x, y);
}
};
});

+ 1
- 1
src/client/js/components/animation.js 查看文件

@@ -1,5 +1,5 @@
define([
'js/renderer'
'js/rendering/renderer'
], function(
renderer
) {


+ 1
- 1
src/client/js/components/attackAnimation.js 查看文件

@@ -1,6 +1,6 @@
define([
'js/rendering/effects',
'js/renderer'
'js/rendering/renderer'
], function(
effects,
renderer


+ 1
- 1
src/client/js/components/chatter.js 查看文件

@@ -1,5 +1,5 @@
define([
'js/renderer'
'js/rendering/renderer'
], function(
renderer
) {


+ 30
- 11
src/client/js/components/chest.js 查看文件

@@ -4,19 +4,29 @@ define([

) {
var colors = [
'f2f5f5',
'929398',
'3fa7dd',
'faac45',
'a24eff',
'ff6942'
'ffeb38'
];

var chances = [
0.0075,
0.02,
0.05,
0.1,
0.17
0.04,
0.08,
0.095
];

var indices = {
'50': 0,
'51': 1,
'128': 2,
'52': 3,
'53': 4
};

return {
type: 'chest',

@@ -35,23 +45,32 @@ define([
}
}

var color = colors[this.obj.cell - 50];
var index = indices[this.obj.cell];

var color = colors[index];

this.obj.addComponent('particles', {
chance: chances[this.obj.cell - 50],
chance: chances[index],
blueprint: {
color: {
start: colors[this.obj.cell - 50]
start: colors[index]
},
alpha: {
start: 0.75,
end: 0.2
},
lifetime: {
start: 1,
end: 4
min: 1,
max: 4
},
chance: chances[this.obj.cell - 50]
chance: chances[index],
spawnType: 'rect',
spawnRect: {
x: -4,
y: -4,
w: 8,
h: 8
}
}
});
},


+ 1
- 1
src/client/js/components/effects.js 查看文件

@@ -1,5 +1,5 @@
define([
'js/renderer'
'js/rendering/renderer'
], function(
renderer
) {


+ 1
- 1
src/client/js/components/flash.js 查看文件

@@ -1,5 +1,5 @@
define([
'js/renderer'
'js/rendering/renderer'
], function(
renderer
) {


+ 1
- 38
src/client/js/components/light.js 查看文件

@@ -1,9 +1,7 @@
define([
'js/canvas',
'js/rendering/effects',
'js/renderer'
'js/rendering/renderer'
], function(
canvas,
effects,
renderer
) {
@@ -85,41 +83,6 @@ define([

},

render: function() {
return;
if (this.lightCd > 0) {
this.lightCd--;
} else {
this.lightCd = 5;
}

ctx = canvas.layers.particles.ctx;
var color = 'rgba(255, 255, 125, $O$)';

var x = this.obj.x;
var y = this.obj.y;

var range = this.range;
var halfRange = (range - 1) / 2;

for (var i = 0; i < range; i++) {
for (var j = 0; j < range; j++) {
var o = range - (Math.abs(halfRange - i) + Math.abs(halfRange - j));
o /= 6;

var n = i + '|' + j;

if (this.lightCd == 0) {
if (Math.random() < 0.5)
this.lightO[n] = (Math.random() * (o * o));
}

o = o * (0.4 + this.lightO[n]);
canvas.renderRect('effects', (x + i - halfRange), (y + j - halfRange), color.replace('$O$', o));
}
}
},

destroy: function() {
var keys = Object.keys(this.emitters);
for (var i = 0; i < keys.length; i++) {


+ 1
- 1
src/client/js/components/mouseMover.js 查看文件

@@ -1,6 +1,6 @@
define([
'js/system/events',
'js/renderer',
'js/rendering/renderer',
'js/system/client',
'js/input',
'js/objects/objects'


+ 4
- 2
src/client/js/components/moveAnimation.js 查看文件

@@ -1,7 +1,7 @@
define([
'js/rendering/renderer'
], function(
renderer
) {
return {
type: 'moveAnimation',
@@ -114,6 +114,8 @@ define([

this.obj.setSpritePosition();
}

renderer.updateSprites();
}
};
});

+ 1
- 1
src/client/js/components/particles.js 查看文件

@@ -1,5 +1,5 @@
define([
'js/renderer'
'js/rendering/renderer'
], function(
renderer
) {


+ 1
- 1
src/client/js/components/pather.js 查看文件

@@ -1,5 +1,5 @@
define([
'js/renderer',
'js/rendering/renderer',
'js/system/events'
], function(
renderer,


+ 1
- 1
src/client/js/components/player.js 查看文件

@@ -1,5 +1,5 @@
define([
'js/renderer',
'js/rendering/renderer',
'js/system/events'
], function(
renderer,


+ 2
- 4
src/client/js/components/projectile.js 查看文件

@@ -1,9 +1,7 @@
define([
'js/rendering/effects',
'js/canvas'
'js/rendering/effects'
], function(
effects,
canvas
effects
) {
var scale = 40;



+ 5
- 5
src/client/js/components/spellbook.js 查看文件

@@ -1,6 +1,6 @@
define([
'js/system/client',
'js/renderer',
'js/rendering/renderer',
'js/system/events'
], function(
client,
@@ -80,7 +80,7 @@ define([
this.spells.splice(existIndex, 1, s);
return;
}
if (this.spells.length - 1 >= s.id)
this.spells.splice(s.id, 0, s);
else
@@ -141,7 +141,7 @@ define([
},

tabTarget: function() {
this.onMouseDown(null, objects.getClosest(window.player.x, window.player.y, 10, this.target));
this.onMouseDown(null, objects.getClosest(window.player.x, window.player.y, 10, this.shiftDown, this.target));
},

build: function(destroy) {
@@ -151,7 +151,7 @@ define([
data: {
instanceModule: 'customMap',
method: 'customize',
data: {
data: {
tile: 189,
direction: this.obj.keyboardMover.direction,
destroy: destroy
@@ -288,4 +288,4 @@ define([
this.targetSprite.y = this.target.y * scale;
}
};
});
});

+ 1
- 1
src/client/js/components/stats.js 查看文件

@@ -1,6 +1,6 @@
define([
'js/system/events',
'js/renderer'
'js/rendering/renderer'
], function(
events,
renderer


+ 5
- 1
src/client/js/input.js 查看文件

@@ -1,6 +1,6 @@
define([
'js/system/events',
'js/renderer'
'js/rendering/renderer'
], function(
events,
renderer
@@ -54,6 +54,10 @@ define([
},

resetKeys: function() {
for (var k in this.keys) {
events.emit('onKeyUp', k);
}

this.keys = {};
},



+ 1
- 1
src/client/js/main.js 查看文件

@@ -1,7 +1,7 @@
define([
'js/system/client',
'ui/factory',
'js/renderer',
'js/rendering/renderer',
'js/objects/objects',
'js/rendering/effects',
'js/rendering/numbers',


+ 1
- 1
src/client/js/objects/objBase.js 查看文件

@@ -1,6 +1,6 @@
define([
'js/components/components',
'js/renderer',
'js/rendering/renderer',
'js/system/events'
], function(
components,


+ 10
- 4
src/client/js/objects/objects.js 查看文件

@@ -1,7 +1,7 @@
define([
'js/objects/objBase',
'js/system/events',
'js/renderer'
'js/rendering/renderer'
], function(
objBase,
events,
@@ -46,7 +46,7 @@ define([
events.emit('onMobHover', mob);
},

getClosest: function(x, y, maxDistance, fromMob, callback) {
getClosest: function(x, y, maxDistance, reverse, fromMob, callback) {
var objects = this.objects;
var oLen = objects.length;

@@ -79,7 +79,13 @@ define([
return (l.id == fromMob.id);
});

return list[(fromIndex + 1) % list.length];
if (reverse) {
fromIndex = (fromIndex === 0 ? list.length : fromIndex) - 1;
} else {
fromIndex = (fromIndex + 1) % list.length;
}
return list[fromIndex];
},

onRezone: function(oldZone) {
@@ -341,4 +347,4 @@ define([
}
}
};
});
});

+ 2
- 49
src/client/js/rendering/effects.js 查看文件

@@ -1,7 +1,7 @@
define([
'js/canvas'
], function(
canvas
) {
return {
list: [],
@@ -45,53 +45,6 @@ define([

l.renderManual();
}

//this.renderParticles(this.particles);
},
renderParticles: function(particles) {
var particles = particles;
var pLen = particles.length;

var ctx = canvas.layers.particles.ctx;

for (var i = 0; i < pLen; i++) {
var p = particles[i];

p.ttl--;
if (p.ttl == 0) {
particles.splice(i, 1);
i--;
pLen--;
continue;
}

p.x += p.dx;
p.y += p.dy;

var size = p.size;
var half = size / 2;

var o = (p.ttl / p.ttlMax) * p.a;

var x = ~~((p.x - half) / 4) * 4;
var y = ~~((p.y - half) / 4) * 4;

size = ~~(size / 4) * 4;

if (p.grow)
p.size += p.grow;
else if (p.shrink)
p.size -= p.shrink;

if (p.stroke) {
ctx.lineWidth = p.stroke;
ctx.strokeStyle = 'rgba(' + p.r + ', ' + p.g + ', ' + p.b + ', ' + o + ')';
ctx.strokeRect(x, y, size, size);
} else {
ctx.fillStyle = 'rgba(' + p.r + ', ' + p.g + ', ' + p.b + ', ' + o + ')';
ctx.fillRect(x, y, size, size);
}
}
}
};
});

+ 1
- 1
src/client/js/rendering/numbers.js 查看文件

@@ -1,7 +1,7 @@
define([
'js/system/events',
'js/objects/objects',
'js/renderer'
'js/rendering/renderer'
], function(
events,
objects,


src/client/js/renderer.js → src/client/js/rendering/renderer.js 查看文件

@@ -5,7 +5,8 @@ define([
'js/rendering/effects',
'js/rendering/tileOpacity',
'js/rendering/particles',
'js/rendering/shaders/outline'
'js/rendering/shaders/outline',
'js/rendering/spritePool'
], function(
resources,
events,
@@ -13,7 +14,8 @@ define([
effects,
tileOpacity,
particles,
shaderOutline
shaderOutline,
spritePool
) {
var scale = 40;
var scaleMult = 5;
@@ -32,18 +34,14 @@ define([
hiders: null
},

chunkSize: 30,

titleScreen: false,

pad: {
x: 10,
y: 10
},

width: 0,
height: 0,

showTilesW: 0,
showTilesH: 0,

pos: {
x: 0,
y: 0
@@ -52,15 +50,23 @@ define([
moveSpeed: 0,
moveSpeedMax: 1.50,
moveSpeedInc: 0.5,
moveSpeedFlatten: 16,

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;
@@ -72,8 +78,8 @@ define([
this.width = $('body').width();
this.height = $('body').height();

this.pad.x = ~~((this.width / 2) / 32);
this.pad.y = ~~((this.height / 2) / 32);
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
@@ -89,7 +95,7 @@ define([
var layers = this.layers;
Object.keys(layers).forEach(function(l) {
if (l == 'tileSprites') {
layers[l] = new pixi.particles.ParticleContainer(2500);
layers[l] = new pixi.Container();
layers[l].layer = 'tiles';
} else
layers[l] = new pixi.Container();
@@ -148,14 +154,43 @@ define([

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 (Math.random() < 0.4)
tile = 6;
var tile = new pixi.Sprite(this.getTexture('sprites', tile));
if (j < 7)
tile = 5;
//else if (j > 26)
// tile = 3;
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();

var alpha = Math.sin((i % 4) + Math.cos(j % 8));
if (tile == 5)
alpha /= 2;
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.1, alpha), 0.8);

if (Math.random() < 0.35) {
tile = {
'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;
@@ -186,6 +221,9 @@ define([
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({
@@ -224,7 +262,7 @@ define([
var container = this.layers.tileSprites;
this.stage.removeChild(container);

this.layers.tileSprites = container = new pixi.particles.ParticleContainer(2500);
this.layers.tileSprites = container = new pixi.Container();
container.layer = 'tiles';
this.stage.addChild(container);

@@ -279,18 +317,18 @@ define([
var alpha = tileOpacity.map(c);
var canFlip = tileOpacity.canFlip(c);

var tile = new pixi.Sprite(this.getTexture('sprites', c + (0 * 160)));
var tile = new pixi.Sprite(this.getTexture('sprites', c));

tile.alpha = alpha;
tile.position.x = i * 8;
tile.position.y = j * 8;
tile.width = 8;
tile.height = 8;
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 += 8;
tile.scale.x = -1;
tile.position.x += scale;
tile.scale.x = -scaleMult;
}
}

@@ -301,10 +339,37 @@ define([
this.titleScreen = false;
physics.init(msg.collisionMap);

var map = msg.map;
var map = this.map = msg.map;
var w = this.w = map.length;
var h = this.h = map[0].length;

this.clean();
spritePool.clean();

this.buildHiddenRooms(msg);

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

buildHiddenRooms: function(msg) {
var hiddenWalls = msg.hiddenWalls;
var hiddenTiles = msg.hiddenTiles;

@@ -312,7 +377,6 @@ define([
this.hiddenRooms.forEach(function(h) {
h.container = new pixi.Container();
this.layers.hiders.addChild(h.container);

this.buildRectangle({
x: h.x * scale,
y: h.y * scale,
@@ -321,72 +385,98 @@ define([
color: 0x2d2136,
parent: h.container
});

for (var i = h.x; i < h.x + h.width; i++) {
for (var j = h.y; j < h.y + h.height; j++) {
var cell = hiddenTiles[i][j];
if (cell != 0) {
var tile = this.buildTile(cell - 1, i, j);
[hiddenTiles, hiddenWalls].forEach(function(k) {
var cell = k[i][j];
if (cell == 0)
return;

tile.position.x *= scaleMult;
tile.position.y *= scaleMult;
var tile = this.buildTile(cell - 1, i, j);
tile.width = scale;
tile.height = scale;

h.container.addChild(tile);
}
}, this);
}
}
}, this);
},
hideHiders: function() {
var player = window.player;
if (!player)
return;

cell = hiddenWalls[i][j];
if (cell == 0)
continue;
var x = player.x;
var y = player.y;

var hiddenRooms = this.hiddenRooms;
var hLen = hiddenRooms.length;
for (var i = 0; i < hLen; i++) {
var h = hiddenRooms[i];
h.container.visible = (
(x < h.x) ||
(x >= h.x + h.width) ||
(y < h.y) ||
(y >= h.y + h.height)
);
}
},

var tile = this.buildTile(cell - 1, i, j);
setPosition: function(pos, instant) {
pos.x += 16;
pos.y += 16;

tile.position.x *= scaleMult;
tile.position.y *= scaleMult;
tile.width = scale;
tile.height = scale;
this.hideHiders();

h.container.addChild(tile);
}
}
}, this);
if (instant) {
this.moveTo = null;
this.pos = pos;
this.stage.x = -~~this.pos.x;
this.stage.y = -~~this.pos.y;
} else
this.moveTo = pos;

var padding = msg.padding ? JSON.parse(msg.padding) : {};
this.updateSprites();
},

this.clean();
var container = new pixi.particles.ParticleContainer(270000);
updateSprites: function() {
var player = window.player;
if (!player)
return;

var isPadX = false;
var isPadY = false;
var padX = 0;
var padY = 0;
var w = this.w;
var h = this.h;

if (!msg.padding) {
padX = 0;
padY = 0;
}
var x = ~~((-this.stage.x / scale) + (this.width / (scale * 2)));
var y = ~~((-this.stage.y / scale) + (this.height / (scale * 2)));

var chunkSize = this.chunkSize;
this.lastUpdatePos.x = this.stage.x;
this.lastUpdatePos.y = this.stage.y;

for (var i = -padX; i < w + padX; i++) {
if ((i < 0) || (i >= w))
isPadX = true;
else
isPadX = false;
var sprites = this.sprites;
var map = this.map;
var container = this.layers.tileSprites;

var sw = this.showTilesW;
var sh = this.showTilesH;

for (var j = -padY; j < h + padY; j++) {
if ((j < 0) || (j >= h))
isPadY = true;
else
isPadY = false;
var lowX = Math.max(0, x - sw) + 2;
var lowY = Math.max(0, y - sh) + 2;
var highX = Math.min(w - 1, x + sw) - 2;
var highY = Math.min(h - 1, y + sh) - 2;

var cell = null;
var addedSprite = false;

for (var i = lowX; i < highX; i++) {
for (var j = lowY; j < highY; j++) {
cell = map[i][j];
if (!cell)
continue;
if (!cell.split)

var rendered = sprites[i][j];
if (rendered.length > 0)
continue;
else if (!cell.split)
cell += '';
cell = cell.split(',');
for (var k = 0; k < cell.length; k++) {
@@ -396,91 +486,59 @@ define([

c--;

var tile = this.buildTile(c, i, j);
var flipped = '';
if (tileOpacity.canFlip(c)) {
if (Math.random() < 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;
}

container.addChild(tile);
rendered.push(tile);
}
}
}

var renderTexture = pixi.RenderTexture.create(w * 8, h * 8);
this.renderer.render(container, renderTexture);

var cw = w / this.chunkSize;
var ch = h / this.chunkSize;

for (var i = 0; i < cw; i++) {
var tw = Math.min(this.chunkSize, w - (i * chunkSize));

for (var j = 0; j < ch; j++) {
var th = Math.min(this.chunkSize, h - (j * chunkSize));
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);

var texture = new pixi.Texture(renderTexture, new pixi.Rectangle(i * this.chunkSize * 8, j * this.chunkSize * 8, tw * 8, th * 8));

var sprite = new pixi.Sprite(texture);
sprite.position.x = i * this.chunkSize * scale;
sprite.position.y = j * this.chunkSize * scale;
sprite.width = tw * scale;
sprite.height = th * scale;
for (var i = lowX; i < highX; 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;

this.layers.tileSprites.addChild(sprite);
var list = sprites[i][j];
var lLen = list.length;
for (var k = 0; k < lLen; k++) {
var sprite = list[k];
sprite.visible = false;
spritePool.store(sprite);
}
sprites[i][j] = [];
}
}

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;

this.hideHiders();

if (instant) {
this.moveTo = null;
this.pos = pos;
this.stage.x = -~~this.pos.x;
this.stage.y = -~~this.pos.y;
return;
}

this.moveTo = pos;
},

hideHiders: function() {
var player = window.player;
if (!player)
return;

var x = player.x;
var y = player.y;

var hiddenRooms = this.hiddenRooms;
var hLen = hiddenRooms.length;
for (var i = 0; i < hLen; i++) {
var h = hiddenRooms[i];
h.container.visible = (
(x < h.x) ||
(x >= h.x + h.width) ||
(y < h.y) ||
(y >= h.y + h.height)
);
//Reorder
if (addedSprite) {
container.children.sort(function(a, b) {
return (a.sheetNum - b.sheetNum);
});
}
},

@@ -517,8 +575,13 @@ define([
this.moveTo = null;
}

this.stage.x = -~~this.pos.x;
this.stage.y = -~~this.pos.y;
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');
}

+ 36
- 0
src/client/js/rendering/spritePool.js 查看文件

@@ -0,0 +1,36 @@
define([
], function(
) {
return {
pool: {},

clean: function() {
this.pool = {};
},

getSprite: function(type) {
var list = this.pool[type];
if (!list)
return null;
else if (list.length == 0)
return null;
else
return list.pop();
},

store: function(sprite) {
var pool = this.pool;
var type = sprite.type;
if (sprite.scale.x < 0)
type = 'flip' + type;
var list = pool[type];
if (!list) {
list = pool[type] = [];
}

list.push(sprite);
}
};
});

+ 0
- 111
src/client/js/rendering/spriteShader.js 查看文件

@@ -1,111 +0,0 @@
define([
'js/resources'
], function(
resources
) {
var canvas = $('<canvas></canvas>').appendTo('body').hide();

return {
outline: function(imgName, offsetX, offsetY, imgW, imgH, ur, ug, ub, ua) {
var img = resources.sprites[imgName].image;

canvas[0].width = imgW;
canvas[0].height = imgH;

var ctx = canvas[0].getContext('2d');
ctx.drawImage(img, offsetX, offsetY, imgW, imgH, 2, 2, imgW, imgH);

var imgData = ctx.getImageData(0, 0, imgW, imgH);
var pixels = imgData.data;

var secondData = ctx.getImageData(0, 0, imgW, imgH);
var secondPixels = secondData.data;

var newData = ctx.createImageData(imgW * 4, imgH * 4);
var newPixels = newData.data;

var fillPixels = function(x, y, r, g, b, a) {
var index = ((y * imgW * 4) + x) * 4;

for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
var newIndex = index + (i * 4) + (j * (imgW * 4 * 4));
newPixels[newIndex] = r;
newPixels[newIndex + 1] = g;
newPixels[newIndex + 2] = b;
newPixels[newIndex + 3] = a;
}
}
}

for (var i = 0; i < imgW; i++) {
for (var j = 0; j < imgW; j++) {
var index = ((j * imgW) + i) * 4;

var transparent = (pixels[index + 3] == 0);
if (transparent) {
var touchPixel = false;
if (i > 0)
touchPixel = (pixels[index - 1] > 0);
if ((!touchPixel) && (j > 0))
touchPixel = (pixels[index - (imgW * 4) + 3] > 0);
if ((!touchPixel) && (i < imgW - 1))
touchPixel = (pixels[index + 7] > 0);
if ((!touchPixel) && (j < imgH - 1))
touchPixel = (pixels[index + (imgW * 4) + 3] > 0);

if (touchPixel) {
secondPixels[index] = 0;
secondPixels[index + 1] = 0;
secondPixels[index + 2] = 0;
secondPixels[index + 3] = 255;
}
}
}
}

for (var i = 0; i < imgW; i++) {
for (var j = 0; j < imgW; j++) {
var index = ((j * imgW) + i) * 4;

var transparent = (secondPixels[index + 3] == 0);
if (transparent) {
var touchPixel = false;
if (i > 0)
touchPixel = (secondPixels[index - 1] > 0)
if ((!touchPixel) && (j > 0))
touchPixel = (secondPixels[index - (imgW * 4) + 3] > 0)
if ((!touchPixel) && (i < imgW - 1))
touchPixel = (secondPixels[index + 7] > 0)
if ((!touchPixel) && (j < imgH - 1))
touchPixel = (secondPixels[index + (imgW * 4) + 3] > 0)

if (touchPixel)
fillPixels(i * 4, j * 4, ur, ug, ub, ua);

continue;
}

var r = secondPixels[index];
var g = secondPixels[index + 1];
var b = secondPixels[index + 2];
var a = secondPixels[index + 3];
if ((r + g + b == 0) && (a == 255)) {
a = 0;
}

fillPixels(i * 4, j * 4, r, g, b, a);
}
}

canvas[0].width = imgW * 4;
canvas[0].height = imgH * 4;

ctx.putImageData(newData, 0, 0);

var url = canvas[0].toDataURL();

return url;
}
};
});

+ 9
- 0
src/client/js/rendering/tileOpacity.js 查看文件

@@ -85,6 +85,15 @@ define([
120, 122 //Wall-mounted plants
],

getSheetNum: function(tile) {
if (tile < 192)
return 0;
else if (tile < 384)
return 1;
else
return 2;
},

map: function(tile) {
var sheetNum;



+ 3
- 1
src/client/ui/templates/characters/styles.less 查看文件

@@ -67,8 +67,10 @@
.sprite {
width: 32px;
height: 32px;
zoom: 4;
transform: scale(4);
transform-origin: 0% 0%;
image-rendering: pixelated;
image-rendering: optimizeSpeed;
display: none;
}
}


+ 3
- 1
src/client/ui/templates/createCharacter/styles.less 查看文件

@@ -68,7 +68,9 @@
.sprite {
width: 32px;
height: 32px;
zoom: 4;
transform: scale(4);
transform-origin: 0% 0%;
image-rendering: optimizeSpeed;
image-rendering: pixelated;
background: url('../../../images/charas.png') -64px 0px;
}


+ 13
- 0
src/client/ui/templates/equipment/styles.less 查看文件

@@ -103,6 +103,7 @@
&:hover {
.icon {
filter: brightness(160%);
-moz-filter: brightness(160%);
}

&.empty {
@@ -130,6 +131,12 @@
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);

-moz-filter:
drop-shadow(0px -2px 0px @blackD)
drop-shadow(0px 2px 0px @blackD)
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);

&.blueText > font {
color: @blue;
}
@@ -191,6 +198,12 @@
drop-shadow(0px 2px 0px @blackD)
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);

-moz-filter:
drop-shadow(0px -2px 0px @blackD)
drop-shadow(0px 2px 0px @blackD)
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);
}
}
}


+ 1
- 1
src/client/ui/templates/help/template.html 查看文件

@@ -4,7 +4,7 @@
<div class="row"><span class="topic">Combat: </span><br />Hover on an enemy and press 1 to enable auto-attack</div>
<div class="row"><span class="topic">Chat: </span><br />Press Enter to open the chat window</div>
<div class="row"><span class="topic">Inventory: </span><br />Press i to open your inventory</div>
<div class="row"><span class="topic">Equipment: </span><br />Click on an item in your inventory to equip it</div>
<div class="row"><span class="topic">Equipment: </span><br />Right click an item in your inventory to equip it or press j for the equipment panel</div>
<div class="row"><span class="topic">Stats: </span><br />Wizards and Clerics need Int to deal more damage. Thieves need Dex and Warriors need Str</div>
<div class="row"><span class="topic">Show Nameplates: </span><br />V</div>
<div class="row"><span class="topic">Who's Online: </span><br />O</div>

+ 1
- 0
src/client/ui/templates/hud/styles.less 查看文件

@@ -52,6 +52,7 @@
text-align: center;
color: @white;
padding: 2px 0px;
line-height: 16px;

text-shadow:
2px 0px #2d2136,


+ 4
- 30
src/client/ui/templates/inventory/inventory.js 查看文件

@@ -5,8 +5,7 @@ define([
'css!ui/templates/inventory/styles',
'html!ui/templates/inventory/templateItem',
'html!ui/templates/inventory/templateTooltip',
'js/input',
'js/rendering/spriteShader'
'js/input'
], function(
events,
client,
@@ -14,8 +13,7 @@ define([
styles,
tplItem,
tplTooltip,
input,
spriteShader
input
) {
var qualityColors = [{
r: 252,
@@ -372,30 +370,6 @@ define([
onGetItems: function(items) {
this.items = items;

this.items.forEach(function(item) {
var prefix = -1;
['quest', 'material', 'ability'].forEach(function(p, i) {
if (item[p])
prefix += 1 + i;
});
if (prefix == -1)
prefix = 3 + item.slot + item.type;

item.sortName = prefix + item.name + item.level + item.id;

if ((item == this.hoverItem))
this.onHover(null, item);
}, this);

this.items.sort(function(a, b) {
if (a.sortName < b.sortName)
return -1;
else if (a.sortName > b.sortName)
return 1;
else
return 0;
});

if (this.shown)
this.build();
},
@@ -444,9 +418,9 @@ define([
performItemAction: function(item, action) {
if (!item)
return;
else if ((action == 'equip') && ((item.material) || (item.quast) || (item.level > window.player.stats.values.level)))
else if ((action == 'equip') && ((item.material) || (item.quest) || (item.level > window.player.stats.values.level)))
return;
if (item.factions) {
if ((item.factions) && (action == 'equip')) {
if (item.factions.some(function(f) {
return f.noEquip;
}))


+ 16
- 0
src/client/ui/templates/inventory/styles.less 查看文件

@@ -57,6 +57,13 @@
drop-shadow(0px 4px 0px @blackD)
drop-shadow(4px 0px 0px @blackD)
drop-shadow(-4px 0px 0px @blackD);

-moz-filter:
brightness(100%)
drop-shadow(0px -4px 0px @blackD)
drop-shadow(0px 4px 0px @blackD)
drop-shadow(4px 0px 0px @blackD)
drop-shadow(-4px 0px 0px @blackD);
}
}

@@ -70,6 +77,13 @@
drop-shadow(0px 2px 0px @blackD)
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);

-moz-filter:
drop-shadow(0px -2px 0px @blackD)
drop-shadow(0px 2px 0px @blackD)
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);

}

.icon {
@@ -95,6 +109,8 @@
&:hover {
.icon {
filter: brightness(160%);

-moz-filter: brightness(160%);
}
}
}


+ 6
- 2
src/client/ui/templates/login/login.js 查看文件

@@ -4,7 +4,7 @@ define([
'ui/factory',
'html!ui/templates/login/template',
'css!ui/templates/login/styles',
'js/renderer'
'js/rendering/renderer'
], function(
events,
client,
@@ -22,7 +22,10 @@ define([
this.on('.btnLogin', 'click', this.onLoginClick.bind(this));
this.on('.btnRegister', 'click', this.onRegisterClick.bind(this));

this.find('.right .buttons .button').on('click', this.redirect.bind(this));
this.find('.extra, .version')
.appendTo($('<div class="uiLoginExtra"></div>>').appendTo('.ui-container'));

$('.uiLoginExtra').find('.button').on('click', this.redirect.bind(this));

this.find('input')
.on('keyup', this.onKeyDown.bind(this))
@@ -63,6 +66,7 @@ define([
if (!res) {
uiFactory.build('characters', {});

$('.uiLoginExtra').remove();
this.el.remove();
} else
this.el.find('.message').html(res);


+ 83
- 52
src/client/ui/templates/login/styles.less 查看文件

@@ -7,18 +7,18 @@
@logoWidth: 559px;
@logoHeight: 200px;

@boxHeight: 370px;
@boxHeight: 169px;

@messageHeight: @boxPadding;

@totalWidth: (@leftWidth + @rightWidth + (@boxPadding * 2));
@totalWidth: @rightWidth;
@totalHeight: (@logoHeight + @boxHeight + (@boxPadding * 3) + @messageHeight);

.uiLogin {
display: none;
width: @totalWidth;
height: @totalHeight;
margin-top: -30px;
margin-top: -80px;

.logo {
width: 562px;
@@ -27,25 +27,38 @@
margin-bottom: (@boxPadding * 3);
}

.left, .right, .news {
.right {
height: @boxHeight;
float: left;
background-color: #3a3b4a;
}

.left {
width: @leftWidth;
padding: @boxPadding;
}

.right {
width: @rightWidth;
padding: @boxPadding;
margin-left: (@boxPadding * 2);

.textbox, input:-webkit-autofill {
.label, input {
float: left;
}

.label {
width: 30%;
padding-top: 10px;
color: @green;
}

input {
width: 70%;
}

input, .textbox, input:-webkit-autofill {
box-shadow: 0 0 0px 1000px darken(@gray, 15%) inset;
color: @white;
-webkit-text-fill-color: @white;
margin-bottom: @boxPadding;
}

/* We duplicate this for firefox which doesn't like the webkit selector */
input, .textbox {
box-shadow: 0 0 0px 1000px darken(@gray, 15%) inset;
width: 100%;
color: @white;
-webkit-text-fill-color: @white;
margin-bottom: @boxPadding;
@@ -53,11 +66,26 @@

.message {
height: @messageHeight;
width: 100%;
margin-top: @boxPadding;
width: 200%;
margin-left: -50%;
margin-top: 36px;
float: left;
text-align: center;
color: @redA;
color: @orange;

filter:
brightness(100%)
drop-shadow(0px -4px 0px @blackD)
drop-shadow(0px 4px 0px @blackD)
drop-shadow(4px 0px 0px @blackD)
drop-shadow(-4px 0px 0px @blackD);

-moz-filter:
brightness(100%)
drop-shadow(0px -4px 0px @blackD)
drop-shadow(0px 4px 0px @blackD)
drop-shadow(4px 0px 0px @blackD)
drop-shadow(-4px 0px 0px @blackD);
}

.top-buttons {
@@ -80,52 +108,55 @@
}
}
}
}

.buttons {
width: 100%;
height: 35px;
margin-top: 80px;

.button {
width: 100%;
margin-bottom: calc(@boxPadding / 2);
background-color: @blueC;
color: @white;

&:hover {
background-color: @blueB;
}
}
}
.spacer-h {
height: 61px;
}
}

.news {
width: @leftWidth;
padding: @boxPadding;
.uiLoginExtra {
.extra {
position: absolute;
left: 10px;
bottom: 10px;

.heading {
background-color: @grayD;
.button {
padding-left: 10px;
padding-right: 10px;
width: 100%;
margin-bottom: 10px;
background-color: @blueD;
color: @white;
margin-bottom: 8px;
text-align: center;
height: 35px;
padding-top: 9px;
}

.list {
overflow-y: auto;
padding: 16px;
&:last-child {
margin-bottom: 0px;
}

.item {
text-align: justify;
color: @grayB;
margin-bottom: 22px;
&:hover {
background-color: @blueC;
}
}
}

.spacer-h {
height: 61px;
.version {
position: absolute;
right: 10px;
bottom: 10px;
color: @yellow;

filter:
brightness(100%)
drop-shadow(0px -4px 0px @blackD)
drop-shadow(0px 4px 0px @blackD)
drop-shadow(4px 0px 0px @blackD)
drop-shadow(-4px 0px 0px @blackD);

-moz-filter:
brightness(100%)
drop-shadow(0px -4px 0px @blackD)
drop-shadow(0px 4px 0px @blackD)
drop-shadow(4px 0px 0px @blackD)
drop-shadow(-4px 0px 0px @blackD);
}
}

+ 8
- 16
src/client/ui/templates/login/template.html 查看文件

@@ -1,28 +1,20 @@
<div class="uiLogin">
<img class="logo" src="images/logo_4.png" alt="">
<div class="news">
<div class="heading">what's new</div>
<div class="list">
<div class="item">Faction Quartermasters</div>
<div class="item">New Unlockable Skin</div>
<div class="item">New Map: City Sewer</div>
<div class="item">Factions and Reputations</div>
<div class="item">You can now filter the chat window</div>
<div class="item">Prophecies. When creating a new character you can choose which prophecies to apply. This includes a permadeath prophecy called 'hardcore'.</div>
</div>
</div>
<div class="right">
<div class="label">username</div>
<input type="text" class="el textbox txtUsername" placeholder="username">
<div class="label">password</div>
<input type="password" class="el textbox txtPassword" placeholder="password">
<div class="top-buttons">
<div class="el button btnRegister">register</div>
<div class="el button btnLogin">login</div>
</div>
<div class="message"></div>
<div class="buttons">
<div class="el button btnPatreon" location="http://patreon.com/bigbadwaffle">Pledge on Patreon</div>
<div class="el button btnPaypal" location="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=BR2CC82WUAVEA">Donate on Paypal</div>
<div class="el button btnWiki" location="http://isleward.gamepedia.com/Isleward_Wiki">Access the Wiki</div>
</div>
</div>
<div class="extra">
<div class="el button btnPatreon" location="http://patreon.com/bigbadwaffle">Pledge on Patreon</div>
<div class="el button btnPaypal" location="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=BR2CC82WUAVEA">Donate on Paypal</div>
<div class="el button btnWiki" location="http://isleward.gamepedia.com/Isleward_Wiki">Access the Wiki</div>
</div>
<div class="version">v0.1.3</div>
</div>

+ 6
- 0
src/client/ui/templates/messages/styles.less 查看文件

@@ -88,6 +88,12 @@
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);

-moz-filter:
drop-shadow(0px -2px 0px @blackD)
drop-shadow(0px 2px 0px @blackD)
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);

word-wrap: break-word;
line-height: 18px;



+ 1
- 1
src/client/ui/templates/options/options.js 查看文件

@@ -2,7 +2,7 @@ define([
'js/system/events',
'html!ui/templates/options/template',
'css!ui/templates/options/styles',
'js/renderer',
'js/rendering/renderer',
'ui/factory',
'js/objects/objects',
'js/system/client'


+ 2
- 2
src/client/ui/templates/party/styles.less 查看文件

@@ -94,8 +94,8 @@
.invite {
position: absolute;

right: 16px;
bottom: 112px;
right: 10px;
bottom: 164px;

background-color: @gray;
border: 4px solid @lightGray;


+ 6
- 0
src/client/ui/templates/reputation/styles.less 查看文件

@@ -101,6 +101,12 @@
drop-shadow(0px 2px 0px @blackD)
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);

-moz-filter:
drop-shadow(0px -2px 0px @blackD)
drop-shadow(0px 2px 0px @blackD)
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);
}
}
}

+ 13
- 0
src/client/ui/templates/smithing/styles.less 查看文件

@@ -89,6 +89,12 @@
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);

-moz-filter:
drop-shadow(0px -2px 0px @blackD)
drop-shadow(0px 2px 0px @blackD)
drop-shadow(2px 0px 0px @blackD)
drop-shadow(-2px 0px 0px @blackD);

&.red {
color: @red;
}
@@ -106,6 +112,13 @@
drop-shadow(0px 4px 0px @blackD)
drop-shadow(4px 0px 0px @blackD)
drop-shadow(-4px 0px 0px @blackD);

-moz-filter:
brightness(100%)
drop-shadow(0px -4px 0px @blackD)
drop-shadow(0px 4px 0px @blackD)
drop-shadow(4px 0px 0px @blackD)
drop-shadow(-4px 0px 0px @blackD);
}
}
}


+ 7
- 1
src/client/ui/templates/trade/trade.js 查看文件

@@ -101,7 +101,13 @@ define([
itemEl.find('.quantity').html('EQ');

if (action == 'buy') {
if (item.worth > window.player.trade.gold)
var noAfford = (item.worth > window.player.trade.gold);
if ((!noAfford) && (item.factions)) {
noAfford = item.factions.some(function(f) {
return f.noEquip;
});
}
if (noAfford)
$('<div class="no-afford"></div>').appendTo(itemEl);
}



+ 33
- 9
src/server/components/auth.js 查看文件

@@ -1,4 +1,5 @@
define([
'bcrypt-nodejs',
'security/io',
'misc/messages',
'security/connections',
@@ -6,6 +7,7 @@ define([
'config/skins',
'misc/profanities'
], function(
bcrypt,
io,
messages,
connections,
@@ -220,23 +222,42 @@ define([
io.get({
ent: credentials.username,
field: 'login',
callback: this.onLogin.bind(this, msg)
callback: this.onHashCompare.bind(this, msg)
});
},
onLogin: function(msg, result) {
onHashCompare: function(msg, storedPassword) {
var credentials = msg.data;

if (!result)
bcrypt.compare(credentials.password, storedPassword, this.onLogin.bind(this, msg, storedPassword));
},
onLogin: function(msg, storedPassword, err, compareResult) {
if (!storedPassword)
msg.callback(messages.login.incorrect);
else {
if (result == credentials.password) {
this.username = credentials.username;
connections.logOut(this.obj);
msg.callback();
if (compareResult) { //If stored password matches the hashed password entered by the user, log them in directly
this.onLoginVerified(msg);
} else if (msg.data.password == storedPassword) { //If the stored password matches a plaintext password entered by the user; In that case the password gets hashed for the future
this.onUnhashedLogin(msg);
} else
msg.callback(messages.login.incorrect);
}
},
onUnhashedLogin: function(msg) {
bcrypt.hash(msg.data.password, null, null, this.onPasswordHashed.bind(this, msg));
},
onPasswordHashed: function(msg, err, hashedPassword) {
io.set({
ent: msg.data.username,
field: 'login',
value: hashedPassword,
callback: this.onLoginVerified.bind(this, msg)
});
},
onLoginVerified: function(msg) {
this.username = msg.data.username;
connections.logOut(this.obj);
msg.callback();
},

register: function(msg) {
var credentials = msg.data;
@@ -273,10 +294,13 @@ define([

var credentials = msg.data;

bcrypt.hash(credentials.password, null, null, this.onHashGenerated.bind(this, msg));
},
onHashGenerated: function(msg, err, hashedPassword) {
io.set({
ent: credentials.username,
ent: msg.data.username,
field: 'login',
value: credentials.password,
value: hashedPassword,
callback: this.onRegister.bind(this, msg)
});
},


+ 1
- 1
src/server/components/extensions/factionVendor.js 查看文件

@@ -148,7 +148,7 @@ define([
item = this.findBuyback(itemId, requestedBy.name);
var result = true;
if (item.faction)
if (item.factions)
result = requestedBy.reputation.canEquipItem(item);

if (!result) {


+ 80
- 0
src/server/components/follower.js 查看文件

@@ -0,0 +1,80 @@
define([
], function(
) {
return {
type: 'follower',

master: null,

lifetime: -1,

fGetHighest: {
inCombat: null,
outOfCombat: null
},

bindEvents: function() {
this.lifetime = 100;

this.fGetHighest.inCombat = this.master.aggro.getHighest.bind(this.master.aggro);
this.fGetHighest.outOfCombat = this.returnNoAggro.bind(this);
},

returnNoAggro: function() {
var master = this.master;
var obj = this.obj;
var mob = obj.mob;

mob.originX = master.x + ~~((Math.random() * 2) * 2) - 1;
mob.originY = master.y + ~~((Math.random() * 2) * 2) - 1;

return null;
},

despawn: function() {
var obj = this.obj;

obj.destroyed = true;
this.obj.instance.syncer.queue('onGetObject', {
x: obj.x,
y: obj.y,
components: [{
type: 'attackAnimation',
row: 0,
col: 4
}]
});
},

update: function() {
this.lifetime--;
if (this.lifetime <= 0) {
this.despawn();
return;
}

var obj = this.obj;
var master = this.master;

if (master.destroyed) {
this.despawn();
return;
}

var doMove = (
(Math.abs(obj.x - master.x) >= 10) ||
(Math.abs(obj.y - master.y) >= 10)
);

if (doMove) {
if (obj.aggro.getHighest == this.fGetHighest.inCombat)
obj.mob.target = obj;
}


obj.aggro.getHighest = doMove ? this.fGetHighest.outOfCombat : this.fGetHighest.inCombat;
}
};
});

+ 41
- 10
src/server/components/inventory.js 查看文件

@@ -33,17 +33,18 @@ define([
for (var i = 0; i < iLen; i++) {
var item = items[i];

//Hacks for old items
if ((item.spell) && (!item.spell.rolls))
continue;

if (item.effects) {
item.effects.forEach(function(e) {
var faction = require('config/factions/' + e.factionId);
var statGenerator = faction.uniqueStat;
statGenerator.generate(item);
});
else if ((item.spell) && (item.type == 'Spear')) {
item.spell.properties = item.spell.properties || {};
item.spell.properties.range = item.range;
}
}

this.hookItemEvents(items);

for (var i = 0; i < iLen; i++) {
this.getItem(items[i], true);
}

@@ -55,9 +56,10 @@ define([
spellName: 'arcane barrier'
}));*/

/*for (var i = 0; i < 10; i++) {
/*for (var i = 0; i < 1; i++) {
var item = generator.generate({
slot: 'twoHanded',
type: 'Spear',
quality: 4,
level: 1
});
@@ -71,6 +73,27 @@ define([
this.blueprint = blueprint;
},

transfer: function() {
this.hookItemEvents();
},

hookItemEvents: function(items) {
var items = items || this.items;
var iLen = items.length;
for (var i = 0; i < iLen; i++) {
var item = items[i];

if (item.effects) {
item.effects.forEach(function(e) {
var faction = require('config/factions/' + e.factionId);
var statGenerator = faction.uniqueStat;
statGenerator.generate(item);
});
}
}

},

//Client Actions

enchantItem: function(msg) {
@@ -341,8 +364,10 @@ define([

if (topQuality == 0)
bagCell = 50;
else if (topQuality < 3)
else if (topQuality == 1)
bagCell = 51;
else if (topQuality == 2)
bagCell = 128;
else if (topQuality == 3)
bagCell = 52;
else
@@ -365,7 +390,7 @@ define([

return obj;
},
getItem: function(item, hideMessage) {
//We need to know if a mob dropped it for quest purposes
var fromMob = item.fromMob;
@@ -565,6 +590,9 @@ define([
var blueprints = blueprint.blueprints;
for (var i = 0; i < blueprints.length; i++) {
var drop = blueprints[i];
if ((drop.maxLevel) && (drop.maxLevel < killSource.stats.values.level))
continue;

drop.level = drop.level || level;
drop.magicFind = magicFind;

@@ -672,6 +700,9 @@ define([
var iLen = items.length;
for (var i = 0; i < iLen; i++) {
var item = items[i];
if (!item.eq)
continue;

var effects = item.effects;
if (!effects)
continue;


+ 2
- 2
src/server/components/mob.js 查看文件

@@ -31,7 +31,7 @@ define([
if (this.obj.aggro)
target = this.obj.aggro.getHighest();
var goHome = false;
if (target) {
if ((target) && (target != this.obj)) {
this.fight(target);
return;
} else if (this.target) {
@@ -47,7 +47,7 @@ define([
return;

var walkDistance = this.walkDistance;
if (walkDistance <= 0)
if ((!goHome) && (walkDistance <= 0))
return;

var obj = this.obj;


+ 19
- 3
src/server/components/notice.js 查看文件

@@ -11,10 +11,13 @@ define([

syncer: null,

maxLevel: 0,

init: function(blueprint) {
this.msg = blueprint.msg;
this.actions = blueprint.actions || {};
this.announce = blueprint.announce;
this.maxLevel = blueprint.maxLevel || 0;

this.syncer = this.obj.instance.syncer;
},
@@ -43,6 +46,8 @@ define([
collisionEnter: function(obj) {
if (!obj.player)
return;
else if ((this.maxLevel) && (obj.stats.values.level > this.maxLevel))
return;

this.callAction(obj, 'enter');

@@ -64,9 +69,13 @@ define([
}, [obj.serverId]);
},

collisionExit: function(obj) {
if (!obj.player)
return;
collisionExit: function(obj, force) {
if (!force) {
if (!obj.player)
return;
else if ((this.maxLevel) && (obj.stats.values.level > this.maxLevel))
return;
}

this.callAction(obj, 'exit');

@@ -76,6 +85,13 @@ define([
this.syncer.queue('onRemoveDialogue', {
src: this.obj.id
}, [obj.serverId]);
},

events: {
onCellPlayerLevelUp: function(obj) {
if ((this.maxLevel) && (obj.stats.values.level > this.maxLevel))
this.collisionExit(obj, true);
}
}
};
});

+ 11
- 6
src/server/components/player.js 查看文件

@@ -32,7 +32,7 @@ define([
previewSpritesheet: character.previewSpritesheet,
name: character.name,
class: character.class,
zoneName: character.zoneName || 'tutorial-cove',
zoneName: character.zoneName || 'tutorial',
x: character.x,
y: character.y,
account: character.account,
@@ -75,14 +75,15 @@ define([
items: character.stash
});
obj.addComponent('effects', blueprintEffects);
obj.addComponent('equipment', character.components.find(c => c.type == 'equipment'));
obj.addComponent('inventory', character.components.find(c => c.type == 'inventory'));
obj.addComponent('quests', character.components.find(c => c.type == 'quests'));

var prophecies = character.components.find(c => c.type == 'prophecies');
if (prophecies)
obj.addComponent('prophecies', prophecies);

obj.addComponent('equipment', character.components.find(c => c.type == 'equipment'));
obj.addComponent('inventory', character.components.find(c => c.type == 'inventory'));
obj.addComponent('quests', character.components.find(c => c.type == 'quests'));

var blueprintEffects = character.components.find(c => c.type == 'effects') || {};
if (blueprintEffects.effects) {
//Calculate ttl of effects
@@ -149,8 +150,12 @@ define([
physics.removeObject(this.obj, this.obj.x, this.obj.y);

if (!permadeath) {
this.obj.x = this.obj.spawn.x;
this.obj.y = this.obj.spawn.y;
var level = this.obj.stats.values.level;
var spawns = this.obj.spawn;
var spawnPos = ((spawns.find(s => ((s.maxLevel) && (s.maxLevel >= level)))) || (spawns[0]));

this.obj.x = spawnPos.x;
this.obj.y = spawnPos.y;

var syncer = this.obj.syncer;
syncer.o.x = this.obj.x;


+ 2
- 0
src/server/components/spellbook.js 查看文件

@@ -135,6 +135,8 @@ define([
this.spells.splice(spellId, 0, builtSpell);

builtSpell.calcDps(null, true);
if (builtSpell.init)
builtSpell.init();

if (this.obj.player)
this.obj.syncer.setArray(true, 'spellbook', 'getSpells', builtSpell.simplify());


+ 32
- 19
src/server/components/stats.js 查看文件

@@ -156,45 +156,54 @@ define([
},

getXp: function(amount) {
amount = ~~(amount * (1 + (this.values.xpIncrease / 100)));
var obj = this.obj;
var values = this.values;

amount = ~~(amount * (1 + (values.xpIncrease / 100)));

this.values.xpTotal = ~~(this.values.xpTotal + amount);
this.values.xp = ~~(this.values.xp + amount);
values.xpTotal = ~~(values.xpTotal + amount);
values.xp = ~~(values.xp + amount);

this.syncer.queue('onGetDamage', {
id: this.obj.id,
id: obj.id,
event: true,
text: '+' + amount + ' xp'
});

var syncO = {};

var didLevelUp = false;
while (this.values.xp >= this.values.xpMax) {

while (values.xp >= values.xpMax) {
didLevelUp = true;
this.values.xp -= this.values.xpMax;
this.values.level++;
values.xp -= values.xpMax;
values.level++;

this.values.hpMax += 40;
values.hpMax += 40;

this.syncer.queue('onGetDamage', {
id: this.obj.id,
id: obj.id,
event: true,
text: 'level up'
});

this.obj.syncer.setObject(true, 'stats', 'values', 'level', this.values.level);
this.obj.syncer.setObject(true, 'stats', 'values', 'hpMax', this.values.hpMax);
obj.syncer.setObject(true, 'stats', 'values', 'level', values.level);
obj.syncer.setObject(true, 'stats', 'values', 'hpMax', values.hpMax);

syncO.level = this.values.level;
syncO.level = values.level;

this.calcXpMax();
}

if (didLevelUp)
this.obj.auth.doSave();
if (didLevelUp) {
var cellContents = obj.instance.physics.getCell(obj.x, obj.y);
cellContents.forEach(function(c) {
c.fireEvent('onCellPlayerLevelUp', obj);
});

obj.auth.doSave();
}

this.obj.syncer.setObject(true, 'stats', 'values', 'xp', this.values.xp);
obj.syncer.setObject(true, 'stats', 'values', 'xp', this.values.xp);

process.send({
method: 'object',
@@ -237,13 +246,13 @@ define([
var amount = level * 10 * mult;
if (Math.abs(levelDelta) <= 10)
amount = ~~(((sourceLevel + levelDelta) * 10) * Math.pow(1 - (Math.abs(levelDelta) / 10), 2) * mult);
else
else
amount = 0;

a.obj.stats.getXp(amount, this.obj);
}
a.obj.fireEvent('afterKillMob', target);
}

@@ -315,6 +324,10 @@ define([
if (death.success) {
var deathEvent = {};

var killSource = source;
if (source.follower)
killSource = source.follower.master;

if (source.player)
source.stats.kill(this.obj);
else


+ 2
- 2
src/server/components/trade.js 查看文件

@@ -66,7 +66,7 @@ define([
if ((target != null) && (target.id == null))
target = this.obj.instance.objects.objects.find(o => o.id == target);
else if (targetName != null)
target = this.obj.instance.objects.objects.find(o => o.name.toLowerCase() == targetName);
target = this.obj.instance.objects.objects.find(o => ((o.name) && (o.name.toLowerCase() == targetName)));

this.target = null;

@@ -230,7 +230,7 @@ define([
if ((target != null) && (target.id == null))
target = this.obj.instance.objects.objects.find(o => o.id == target);
else if (targetName != null)
target = this.obj.instance.objects.objects.find(o => o.name.toLowerCase() == targetName);
target = this.obj.instance.objects.objects.find(o => ((o.name) && (o.name.toLowerCase() == targetName)));

this.target = null;



+ 1
- 0
src/server/config/classes.js 查看文件

@@ -49,5 +49,6 @@ define([
};

events.emit('onBeforeGetClasses', classes);

return classes;
});

+ 23
- 3
src/server/config/factions/gaekatla.js 查看文件

@@ -37,6 +37,11 @@ define([

item.effects.push(result);
}
//This is a hack for items that were never generated properly
else if (!result.chance) {
result.chance = chanceRoll;
result.text = chanceRoll + '% chance on kill to summon a critter to assist you in battle';
}

if (!result.events)
result.events = {};
@@ -53,7 +58,7 @@ define([
var effect = item.effects.find(e => (e.factionId == 'gaekatla'));

var roll = Math.random() * 100;
if (roll >= this.chance)
if (roll >= effect.chance)
return;

//Spawn a mob
@@ -64,12 +69,20 @@ define([
y: mob.y,
cell: 34,
sheetName: 'mobs',
name: 'Squiggle'
name: 'Squiggle',
properties: {
cpnFollower: {}
},
extraProperties: {
follower: {
master: this
}
}
}
});

mobBuilder.build(mob, {
level: 5,
level: item.level,
faction: this.aggro.faction,
walkDistance: 2,
regular: {
@@ -77,7 +90,14 @@ define([
hpMult: 1,
dmgMult: 1
},
spells: [{
type: 'melee',
damage: 1,
statMult: 0.1
}]
}, false, 'regular');

mob.follower.bindEvents();
}
}
},


+ 1
- 6
src/server/config/maps/city/map.json
文件差异内容过多而无法显示
查看文件


+ 1
- 1
src/server/config/maps/city/zone.js 查看文件

@@ -111,7 +111,7 @@ module.exports = {
},
faction: {
id: 'gaekatla',
tier: 6
tier: 5
},
markup: {
buy: 0.25,


+ 387
- 0
src/server/config/maps/fjolarok/map.json
文件差异内容过多而无法显示
查看文件


二进制
查看文件


+ 0
- 1
src/server/config/maps/mapList.js 查看文件

@@ -4,7 +4,6 @@ define([

) {
return [
'tutorial-cove',
'tutorial',
'estuary',
'city',


+ 1
- 0
src/server/config/maps/test/map.json
文件差异内容过多而无法显示
查看文件


+ 160
- 9
src/server/config/maps/tutorial/map.json 查看文件

@@ -140,8 +140,8 @@
"type":"",
"visible":true,
"width":8,
"x":688,
"y":712
"x":672,
"y":672
},
{
"gid":229,
@@ -556,8 +556,8 @@
"type":"",
"visible":true,
"width":8,
"x":648,
"y":536
"x":592,
"y":544
},
{
"gid":229,
@@ -732,8 +732,8 @@
"type":"",
"visible":true,
"width":8,
"x":656,
"y":632
"x":672,
"y":504
},
{
"gid":233,
@@ -766,6 +766,38 @@
"width":8,
"x":400,
"y":320
},
{
"gid":229,
"height":8,
"id":626,
"name":"Seagull",
"properties":
{

},
"rotation":0,
"type":"",
"visible":true,
"width":8,
"x":616,
"y":688
},
{
"gid":229,
"height":8,
"id":635,
"name":"Crazed Seagull",
"properties":
{

},
"rotation":0,
"type":"",
"visible":true,
"width":8,
"x":616,
"y":808
}],
"opacity":1,
"properties":
@@ -1001,6 +1033,126 @@
"width":24,
"x":632,
"y":400
},
{
"height":112,
"id":627,
"name":"",
"properties":
{
"cpnNotice":"{\"maxLevel\": 1, \"msg\": \"You open your eyes and cough. Saltwater burns your throat. You remember the storm, and the crash that left your ship in pieces.<br \/><br \/>You realize you need to find shelter. Use <font class='color-green'>wasd<\/font> or the <ont class='color-green'>arrow keys<\/font> to move.\"}"
},
"rotation":0,
"type":"",
"visible":true,
"width":120,
"x":384,
"y":824
},
{
"height":32,
"id":628,
"name":"",
"properties":
{
"cpnNotice":"{\"maxLevel\": 1, \"msg\": \"You take a few steps, still weak from the ordeal. Through the glare of the sun, you see a creature to the north-east.<br \/><br \/>Press <font class='color-green'>v<\/font> to toggle nameplates.\"}"
},
"rotation":0,
"type":"",
"visible":true,
"width":48,
"x":520,
"y":824
},
{
"height":80,
"id":629,
"name":"",
"properties":
{
"cpnNotice":"{\"maxLevel\": 1, \"msg\": \"You take a few steps, still weak from the ordeal. Through the glare of the sun, you see a creature to the north-east.<br \/><br \/>Press <font class='color-green'>v<\/font> to toggle nameplates.\"}"
},
"rotation":0,
"type":"",
"visible":true,
"width":136,
"x":504,
"y":856
},
{
"height":40,
"id":630,
"name":"",
"properties":
{
"cpnNotice":"{\"maxLevel\": 1, \"msg\": \"The seagull's eyes are bloodshot and in its beak you see a glinting locket. It stole your family heirloom!<br \/><br \/>Click on it to target it then press <font class='color-green'>1<\/font> to toggle auto-attack. Remember to stand close if you are a warrior or thief.\"}"
},
"rotation":0,
"type":"",
"visible":true,
"width":8,
"x":568,
"y":800
},
{
"height":8,
"id":631,
"name":"",
"properties":
{
"cpnNotice":"{\"maxLevel\": 1, \"msg\": \"You take a few steps, still weak from the ordeal. Through the glare of the sun, you see a creature to the north-east.<br \/><br \/>Press <font class='color-green'>v<\/font> to toggle nameplates.\"}"
},
"rotation":0,
"type":"",
"visible":true,
"width":8,
"x":568,
"y":848
},
{
"height":40,
"id":632,
"name":"",
"properties":
{
"cpnNotice":"{\"maxLevel\": 2, \"msg\": \"You can loot items by standing on them then open your inventory with <font class='color-green'>i<\/font>.<br \/><br \/>To equip an item, simply right click the item in your inventory.\"}"
},
"rotation":0,
"type":"",
"visible":true,
"width":144,
"x":568,
"y":760
},
{
"height":32,
"id":633,
"name":"",
"properties":
{
"cpnNotice":"{\"maxLevel\": 2, \"msg\": \"Far to the north, you see a small shack. Civilization!<br \/><br \/>You can read more help by pressing <font class='color-green'>h<\/font>.\"}"
},
"rotation":0,
"type":"",
"visible":true,
"width":144,
"x":592,
"y":728
},
{
"height":56,
"id":634,
"name":"",
"properties":
{
"cpnNotice":"{\"maxLevel\": 1, \"msg\": \"The seagull's eyes are bloodshot and in its beak you see a glinting locket. It stole your family heirloom!<br \/><br \/>Click on it to target it then press <font class='color-green'>1<\/font> to toggle auto-attack. Remember to stand close if you are a warrior or thief.\"}"
},
"rotation":0,
"type":"",
"visible":true,
"width":112,
"x":576,
"y":800
}],
"opacity":1,
"type":"objectgroup",
@@ -1261,14 +1413,13 @@
"x":0,
"y":0
}],
"nextobjectid":617,
"nextobjectid":636,
"orientation":"orthogonal",
"properties":
{
"instanced":"0",
"name":"Test Zone",
"padding":"{\"tiles\":[[6,10],[7,5]]}",
"spawn":"{\"x\":72,\"y\":86}"
"spawn":"[{\"maxLevel\":1,\"x\":60,\"y\":116},{\"maxLevel\":2,\"x\":89,\"y\":48}]"
},
"renderorder":"right-down",
"tileheight":8,


+ 24
- 0
src/server/config/maps/tutorial/zone.js 查看文件

@@ -96,6 +96,30 @@ module.exports = {
}
}
},
'crazed seagull': {
level: 1,

rare: {
count: 0
},

regular: {
drops: {
chance: 100,
rolls: 1,
noRandom: true,
blueprints: [{
maxLevel: 2,
name: 'Family Heirloom',
quality: 2,
slot: 'neck',
type: 'Pendant',
noSalvage: true,
stats: ['hpMax', 'regenHp', 'regenMana']
}]
}
}
},
seagull: {
level: 2,
regular: {


+ 14
- 4
src/server/config/spells/spellCharge.js 查看文件

@@ -20,8 +20,11 @@ define([
var obj = this.obj;
var target = action.target;

var dx = target.x - obj.x;
var dy = target.y - obj.y;
var x = obj.x;
var y = obj.y;

var dx = target.x - x;
var dy = target.y - y;

//We need to stop just short of the target
var offsetX = 0;
@@ -39,8 +42,8 @@ define([

var physics = obj.instance.physics;
//Check where we should land
if (physics.isTileBlocking(targetPos.x - offsetX, targetPos.y - offsetY)) {
if (physics.isTileBlocking(targetPos.x - offsetX, targetPos.y)) {
if (!this.isTileValid(physics, x, y, targetPos.x - offsetX, targetPos.y - offsetY)) {
if (!this.isTileValid(physics, x, y, targetPos.x - offsetX, targetPos.y)) {
targetPos.y -= offsetY;
} else {
targetPos.x -= offsetX;
@@ -113,6 +116,13 @@ define([

var damage = this.getDamage(target);
target.stats.takeDamage(damage, this.threatMult, obj);
},

isTileValid: function(physics, fromX, fromY, toX, toY) {
if (physics.isTileBlocking(toX, toY))
return false;
else
return physics.hasLos(fromX, fromY, toX, toY);
}
};
});

+ 5
- 0
src/server/config/spells/spellMelee.js 查看文件

@@ -16,6 +16,11 @@ define([
col: 4,
row: 1,

init: function() {
if (this.range > 1)
this.needLos = true;
},

cast: function(action) {
var target = action.target;



+ 5
- 0
src/server/items/generators/spellbook.js 查看文件

@@ -84,6 +84,11 @@ define([
}
}

if (item.range) {
item.spell.properties = item.spell.properties || {};
item.spell.properties.range = item.range;
}

var perfection = ~~(propertyPerfection.reduce((p, n) => p += n, 0) / propertyPerfection.length * 4);
if (!item.slot)
item.quality = perfection;


+ 1
- 1
src/server/misc/mods.js 查看文件

@@ -33,6 +33,6 @@ define([
mod.init();
}
}, this);
}
}
};
});

+ 1
- 0
src/server/misc/profanities.js 查看文件

@@ -220,6 +220,7 @@ define([

return {
isClean: function(text) {
text = text.toLowerCase();
var cb = text.indexOf.bind(text);

for (var i = 0; i < cLen; i++) {


+ 1
- 0
src/server/package.json 查看文件

@@ -3,6 +3,7 @@
"version": "0.0.2",
"description": "isleward",
"dependencies": {
"bcrypt-nodejs": "0.0.3",
"express": "^4.13.1",
"extend": "^3.0.0",
"less-middleware": "^2.0.1",


+ 1
- 1
src/server/startup.js 查看文件

@@ -25,6 +25,7 @@ define([
global.gc();
}, 60000);
mods.init();
globals.init();
components.init(this.onComponentsReady.bind(this));
},
@@ -32,7 +33,6 @@ define([
server.init(this.onServerReady.bind(this));
},
onServerReady: function() {
mods.init();
atlas.init();
leaderboard.init();
}


+ 2
- 2
src/server/world/atlas.js 查看文件

@@ -27,7 +27,7 @@ define([
instanceId = -1;

if (!thread) {
thread = this.getThreadFromName('tutorial-cove');
thread = this.getThreadFromName('tutorial');
obj.zoneName = thread.name;
}

@@ -172,7 +172,7 @@ define([
var thread = this.getThreadFromName(obj.zoneName);

if (!thread) {
thread = this.getThreadFromName('tutorial-cove');
thread = this.getThreadFromName('tutorial');
obj.zoneName = thread.name;
serverObj.zoneName = thread.name;
}


+ 28
- 30
src/server/world/instancer.js 查看文件

@@ -124,15 +124,14 @@ define([
msg.keepPos = false;
}

var spawnPos = map.getSpawnPos(obj);

if ((!msg.keepPos) || (obj.x == null)) {
obj.x = map.spawn.x;
obj.y = map.spawn.y;
obj.x = spawnPos.x;
obj.y = spawnPos.y;
}

obj.spawn = {
x: map.spawn.x,
y: map.spawn.y
};
obj.spawn = map.spawn;

syncer.queue('onGetMap', map.clientMap, [obj.serverId]);

@@ -140,13 +139,11 @@ define([
objects.addObject(obj, this.onAddObject.bind(this));
else {
var o = objects.transferObject(obj);
if (o.zoneName != 'tutorial-cove')
questBuilder.obtain(o);
questBuilder.obtain(o);
}
},
onAddObject: function(obj) {
if (obj.zoneName != 'tutorial-cove')
questBuilder.obtain(obj);
questBuilder.obtain(obj);
},
updateObject: function(msg) {
var obj = objects.find(o => o.serverId == msg.id);
@@ -314,25 +311,23 @@ define([
msg.keepPos = false;
}

var spawnPos = map.getSpawnPos(obj);

if ((!msg.keepPos) || (obj.x == null)) {
obj.x = map.spawn.x;
obj.y = map.spawn.y;
obj.x = spawnPos.x;
obj.y = spawnPos.y;
}

obj.spawn = {
x: map.spawn.x,
y: map.spawn.y
};
obj.spawn = map.spawn;

if (exists) {
//Keep track of what the connection id is (sent from the server)
obj.serverId = obj.id;
delete obj.id;

obj.spawn = {
x: exists.map.spawn.x,
y: exists.map.spawn.y
};
var spawnPos = exists.map.getSpawnPos(obj);

obj.spawn = exists.map.spawn;

exists.syncer.queue('onGetMap', exists.map.clientMap, [obj.serverId]);

@@ -355,14 +350,14 @@ define([
},
onAddObject: function(keepPos, obj) {
if (!keepPos) {
obj.x = obj.instance.map.spawn.x;
obj.y = obj.instance.map.spawn.y;
var spawnPos = obj.instance.map.getSpawnPos(obj);

obj.x = spawnPos.x;
obj.y = spawnPos.y;
}

obj.instance.spawners.scale(obj.stats.values.level);

if (obj.zoneName != 'tutorial-cove')
obj.instance.questBuilder.obtain(obj);
obj.instance.questBuilder.obtain(obj);
},
updateObject: function(msg) {
var id = msg.id;
@@ -462,7 +457,8 @@ define([
questBuilder: extend(true, {}, questBuilder),
map: {
spawn: extend(true, {}, map.spawn),
clientMap: extend(true, {}, map.clientMap)
clientMap: extend(true, {}, map.clientMap),
getSpawnPos: map.getSpawnPos.bind(map)
}
};

@@ -500,11 +496,13 @@ define([
obj = instance.objects.addObject(objToAdd, this.onAddObject.bind(this, false));
else {
obj = instance.objects.transferObject(objToAdd);
obj.x = instance.map.spawn.x;
obj.y = instance.map.spawn.y;
if (obj.zoneName != 'tutorial-cove')
instance.questBuilder.obtain(obj);

var spawnPos = instance.map.getSpawnPos(obj);

obj.x = spawnPos.x;
obj.y = spawnPos.y;
instance.questBuilder.obtain(obj);
obj.instance.spawners.scale(obj.stats.values.level);
}



+ 11
- 1
src/server/world/map.js 查看文件

@@ -95,8 +95,11 @@ define([
if (this.instanced)
this.instanced = (this.instanced == '1');

if (mapFile.properties.spawn)
if (mapFile.properties.spawn) {
this.spawn = JSON.parse(mapFile.properties.spawn);
if (!this.spawn.push)
this.spawn = [ this.spawn ];
}
},
create: function() {
this.getMapFile();
@@ -361,6 +364,13 @@ define([
this.objBlueprints.push(obj);
}
}
},

getSpawnPos: function(obj) {
var stats = obj.components.find(c => (c.type == 'stats'));
var level = stats.values.level;

return ((this.spawn.find(s => ((s.maxLevel) && (s.maxLevel >= level)))) || (this.spawn[0]));
}
}



+ 4
- 2
src/server/world/randomMap.js 查看文件

@@ -200,8 +200,10 @@ define([
clientMap.collisionMap = _.get2dArray(w, h);

var startTemplate = startRoom.template;
map.spawn.x = startRoom.x + ~~(startTemplate.width / 2);
map.spawn.y = startRoom.y + ~~(startTemplate.height / 2);
map.spawn = [{
x: startRoom.x + ~~(startTemplate.width / 2),
y: startRoom.y + ~~(startTemplate.height / 2)
}];

this.drawRoom(instance, startRoom);



+ 1
- 1
src/server/world/resourceSpawner.js 查看文件

@@ -46,7 +46,7 @@ define([
var w = this.physics.width;
var h = this.physics.height;

var spawn = this.map.spawn;
var spawn = this.map.spawn[0];
var x = null;
var y = null;



正在加载...
取消
保存