Переглянути джерело

merged #1722 and solved package lock conflict

tags/v0.9.0^2
Shaun 3 роки тому
джерело
коміт
00ecad8f64
24 змінених файлів з 557 додано та 5900 видалено
  1. +1
    -0
      src/client/js/components/pather.js
  2. +3
    -2
      src/client/js/components/player.js
  3. +11
    -4
      src/client/js/rendering/renderer.js
  4. +1
    -5
      src/client/js/rendering/tileOpacity.js
  5. +23
    -16
      src/client/js/sound/sound.js
  6. +1
    -1
      src/client/ui/templates/party/styles.less
  7. +6
    -0
      src/server/components/door.js
  8. +22
    -1
      src/server/components/portal.js
  9. +35
    -4
      src/server/config/clientConfig.js
  10. +15
    -7
      src/server/config/maps/cave/map.json
  11. +0
    -23
      src/server/config/maps/fjolarok/chats.js
  12. +0
    -163
      src/server/config/maps/fjolarok/dialogues.js
  13. +394
    -1723
      src/server/config/maps/fjolarok/map.json
  14. +1
    -704
      src/server/config/maps/fjolarok/zone.js
  15. +0
    -4
      src/server/config/maps/mapList.js
  16. +0
    -291
      src/server/config/maps/sewer/events/plagueOfRats.js
  17. +0
    -2461
      src/server/config/maps/sewer/map.json
  18. +0
    -455
      src/server/config/maps/sewer/zone.js
  19. +1
    -1
      src/server/items/generators/quality.js
  20. +1
    -1
      src/server/mods/class-necromancer/index.js
  21. +26
    -20
      src/server/objects/objBase.js
  22. +6
    -6
      src/server/package-lock.json
  23. +4
    -6
      src/server/world/map.js
  24. +6
    -2
      src/server/world/physics.js

+ 1
- 0
src/client/js/components/pather.js Переглянути файл

@@ -27,6 +27,7 @@ define([
lastY: 0,

init: function () {
events.on('onRespawn', this.onDeath.bind(this));
events.on('onDeath', this.onDeath.bind(this));
events.on('onClearQueue', this.onDeath.bind(this));



+ 3
- 2
src/client/js/components/player.js Переглянути файл

@@ -68,8 +68,9 @@ define([
}, instant);
},

onRespawn: function (position) {
this.positionCamera(position.x, position.y, true);
onRespawn: function ({ x, y }) {
this.positionCamera(x, y, true);
sound.update(x, y);
},

destroy: function () {


+ 11
- 4
src/client/js/rendering/renderer.js Переглянути файл

@@ -126,7 +126,7 @@ define([
},

buildSpritesTexture: function () {
const { clientConfig: { atlasTextures } } = globals;
const { clientConfig: { atlasTextureDimensions, atlasTextures } } = globals;

let container = new pixi.Container();

@@ -139,7 +139,7 @@ define([
tile.x = 0;
tile.y = totalHeight;

tileOpacity.atlasTextureDimensions[t] = {
atlasTextureDimensions[t] = {
w: texture.width / 8,
h: texture.height / 8
};
@@ -374,7 +374,7 @@ define([
let foundHiddenLayer = null;

hiddenRooms.forEach(h => {
const { discovered, layer } = h;
const { discovered, layer, interior } = h;
const { x: hx, y: hy, width, height, area } = h;

//Is the tile outside the hider
@@ -383,8 +383,15 @@ define([
x >= hx + width ||
y < hy ||
y >= hy + height
)
) {
//If the hider is an interior, the tile should be hidden if the player is inside the hider
if (interior) {
if (physics.isInPolygon(px, py, area))
foundHiddenLayer = layer;
}

return;
}

//Is the tile inside the hider
if (!physics.isInPolygon(x, y, area))


+ 1
- 5
src/client/js/rendering/tileOpacity.js Переглянути файл

@@ -4,9 +4,6 @@ define([
globals
) {
return {
//Set by renderer
atlasTextureDimensions: {},

getSheetNum: function (tile) {
if (tile < 224)
return 0;
@@ -25,8 +22,7 @@ define([
},

getOffsetAndSheet: function (tile) {
const { clientConfig: { atlasTextures } } = globals;
const { atlasTextureDimensions } = this;
const { clientConfig: { atlasTextureDimensions, atlasTextures } } = globals;

let offset = 0;
let sheetName = null;


+ 23
- 16
src/client/js/sound/sound.js Переглянути файл

@@ -125,8 +125,6 @@ define([
if (this.currentMusic === soundEntry && sound.volume() === musicVolume / 100)
return;

soundEntry.volume = 1;

this.currentMusic = soundEntry;

sound.fade(sound.volume(), (musicVolume / 100), fadeDuration);
@@ -169,7 +167,7 @@ define([
}

//Exponential fall-off
const volume = s.volume * (1 - (Math.pow(distance, 2) / Math.pow(minDistance, 2)));
const volume = s.maxVolume * (1 - (Math.pow(distance, 2) / Math.pow(minDistance, 2)));
this.playSoundHelper(s, volume);
});
},
@@ -178,23 +176,31 @@ define([
const sounds = this.sounds;

const areaMusic = sounds.filter(s => s.music && s.area);
const currentMusic = areaMusic.find(s => physics.isInPolygon(playerX, playerY, s.area));
const defaultMusic = sounds.find(s => s.music && s.defaultMusic);

if (!currentMusic) {
if (defaultMusic)
this.playMusicHelper(defaultMusic);
//All music that should be playing because we're in the correct polygon
const playMusic = areaMusic.filter(s => physics.isInPolygon(playerX, playerY, s.area));

const activeMusic = sounds.filter(s => s.music && s !== defaultMusic);
activeMusic.forEach(s => this.stopSoundHelper(s));
} else {
if (defaultMusic)
this.stopSoundHelper(defaultMusic);
//All music that should stop playing because we're in the incorrect polygon
const stopMusic = areaMusic.filter(s => s.sound && s.sound.playing() && !playMusic.some(m => m === s));

if (currentMusic)
this.playMusicHelper(currentMusic);
//Stop or start defaultMusic, depending on whether anything else was found
const defaultMusic = sounds.filter(a => a.defaultMusic);
if (defaultMusic) {
if (!playMusic.length)
defaultMusic.forEach(m => this.playMusicHelper(m));
else
defaultMusic.forEach(m => this.stopSoundHelper(m));
}

//If there's a music entry in both 'play' and 'stop' that shares a fileName, we'll just ignore it. This happens when you
// move to a building interior, for example. Unfortunately, we can't have different volume settings for these kinds of entries.
// The one that starts playing first will get priority
const filesPlaying = [...playMusic.map(p => p.file), ...stopMusic.map(p => p.file)];
playMusic.spliceWhere(p => filesPlaying.filter(f => f === p.file).length > 1);
stopMusic.spliceWhere(p => filesPlaying.filter(f => f === p.file).length > 1);

stopMusic.forEach(m => this.stopSoundHelper(m));
playMusic.forEach(m => this.playMusicHelper(m));
},

update: function (playerX, playerY) {
@@ -230,6 +236,7 @@ define([
x,
y,
volume,
maxVolume: volume,
area,
music,
defaultMusic


+ 1
- 1
src/client/ui/templates/party/styles.less Переглянути файл

@@ -206,4 +206,4 @@

.mobile .uiParty .list {
max-height: calc(100% - @topPosition - 10px);
}
}

+ 6
- 0
src/server/components/door.js Переглянути файл

@@ -129,6 +129,8 @@ module.exports = {
const message = `The ${key.name} disintegrates on use`;
obj.social.notifySelf({ message });
}

this.obj.instance.syncer.queue('onDoorUnlock', null, [obj.serverId]);
}

if (this.closed) {
@@ -139,6 +141,8 @@ module.exports = {

this.closed = false;
this.enterArea(obj);

this.obj.instance.syncer.queue('onDoorOpen', null, [obj.serverId]);
} else {
thisObj.cell = this.closedSprite;
syncO.cell = this.closedSprite;
@@ -147,6 +151,8 @@ module.exports = {

this.closed = true;
this.enterArea(obj);

this.obj.instance.syncer.queue('onDoorClose', null, [obj.serverId]);
}
},



+ 22
- 1
src/server/components/portal.js Переглянути файл

@@ -17,13 +17,34 @@ module.exports = {
},

collisionEnter: async function (obj) {
if (!obj.player)
const { player, syncer, instance: { physics, syncer: globalSyncer } } = obj;

if (!player)
return;
else if (this.patronLevel) {
if (!roles.isRoleLevel(obj, this.patronLevel, 'enter this area'))
return;
}

if (obj.zoneName === this.toZone) {
physics.removeObject(obj, obj.x, obj.y);

obj.x = this.toPos.x;
obj.y = this.toPos.y;

syncer.set(false, null, 'x', obj.x);
syncer.set(false, null, 'y', obj.y);

physics.addObject(obj, obj.x, obj.y);

globalSyncer.queue('onRespawn', {
x: obj.x,
y: obj.y
}, [obj.serverId]);

return;
}

obj.fireEvent('beforeRezone');

obj.destroyed = true;


+ 35
- 4
src/server/config/clientConfig.js Переглянути файл

@@ -33,11 +33,15 @@ const config = {
'bosses',
'auras'
],
atlasTextureDimensions: {},
atlasTextures: [
'tiles',
'walls',
'objects'
],
blockingTileIndices: [
6, 7, 54, 55, 62, 63, 154, 189, 190, 192, 193, 194, 195, 196, 197
],
tileOpacities: {
default: {
default: 0.4,
@@ -196,8 +200,6 @@ const config = {
module.exports = {
config,

atlasTextureDimensions: {},

init: async function () {
events.emit('onBeforeGetClientConfig', config);

@@ -213,14 +215,43 @@ module.exports = {

//The client needs to know this as well as the map loader
calculateAtlasTextureDimensions: async function () {
for (const tex of config.atlasTextures) {
const { atlasTextures, atlasTextureDimensions } = config;

for (const tex of atlasTextures) {
if (atlasTextureDimensions[tex])
return;

const path = tex.includes('.png') ? `../${tex}` : `../client/images/${tex}.png`;
const dimensions = await imageSize(path);

delete dimensions.type;

this.atlasTextureDimensions[tex] = dimensions;
atlasTextureDimensions[tex] = dimensions;
}
},

getTileIndexInAtlas: async function (spriteSheet, tileIndexInSource) {
const { atlasTextures, atlasTextureDimensions } = config;

//We need to perform this check because once mods start adding sheets to atlasTextures,
// things get out of control. We need to fix this in the future as it will become screwy.
if (Object.keys(atlasTextureDimensions).length !== atlasTextures)
await this.calculateAtlasTextureDimensions();

const indexOfSheet = atlasTextures.indexOf(spriteSheet);

let tileCountBeforeSheet = 0;

for (let i = 0; i < indexOfSheet; i++) {
const sheet = atlasTextures[i];
const { width, height } = atlasTextureDimensions[sheet];

tileCountBeforeSheet += ((width / 8) * (height / 8));
}

const result = tileCountBeforeSheet + tileIndexInSource;

return result;
},

//Used to send to clients


+ 15
- 7
src/server/config/maps/cave/map.json Переглянути файл

@@ -1,4 +1,12 @@
{ "backgroundcolor":"#32222e",
"compressionlevel":-1,
"editorsettings":
{
"export":
{
"target":"."
}
},
"height":200,
"infinite":false,
"layers":[
@@ -2339,7 +2347,7 @@
{
"name":"cpnPortal",
"type":"string",
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":86}}"
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":50}}"
}],
"rotation":0,
"type":"",
@@ -2375,7 +2383,7 @@
{
"name":"cpnPortal",
"type":"string",
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":86}}"
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":50}}"
}],
"rotation":0,
"type":"",
@@ -2393,7 +2401,7 @@
{
"name":"cpnPortal",
"type":"string",
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":86}}"
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":50}}"
}],
"rotation":0,
"type":"",
@@ -2411,7 +2419,7 @@
{
"name":"cpnPortal",
"type":"string",
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":86}}"
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":50}}"
}],
"rotation":0,
"type":"",
@@ -2429,7 +2437,7 @@
{
"name":"cpnPortal",
"type":"string",
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":86}}"
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":50}}"
}],
"rotation":0,
"type":"",
@@ -2465,7 +2473,7 @@
{
"name":"cpnPortal",
"type":"string",
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":86}}"
"value":"{\"zone\":\"fjolarok\",\"pos\":{\"x\":71,\"y\":50}}"
}],
"rotation":0,
"type":"",
@@ -2500,7 +2508,7 @@
"value":"[{\"x\":16,\"y\":136}, {\"source\": \"radulos\", \"x\": 163, \"y\": 35}]"
}],
"renderorder":"right-down",
"tiledversion":"1.2.5",
"tiledversion":"1.3.3",
"tileheight":8,
"tilesets":[
{


+ 0
- 23
src/server/config/maps/fjolarok/chats.js Переглянути файл

@@ -1,27 +1,4 @@
module.exports = {
estrid: [{
msg: '*polishes some vials*'
}, {
msg: 'Where did I put that flask?'
}, {
msg: '*coughs*'
}, {
msg: 'Hm...'
}],
priest: [{
msg: 'peace be with you'
}, {
msg: 'walk in the light'
}],
cow: [{
msg: '*moos*'
}],
goat: [{
msg: '*bleats*'
}],
pig: [{
msg: '*oinks*'
}],
hermit: [{
msg: '*strokes his beard*'
}, {


+ 0
- 163
src/server/config/maps/fjolarok/dialogues.js Переглянути файл

@@ -106,168 +106,5 @@ module.exports = {
targetName: 'hermit'
}]
}
},
estrid: {
1: {
msg: [{
msg: 'Is there anything I can help you with today?',
options: [1.1, 1.3, 1.4, 1.5]
}],
options: {
1.1: {
msg: 'How long have you been working here?',
goto: 2
},
1.3: {
msg: 'I\'d like to browse your wares.',
goto: 'tradeBuy'
},
1.4: {
msg: 'I have some items to sell',
goto: 'tradeSell'
},
1.5: {
msg: 'I want to buy something back',
goto: 'tradeBuyback'
}
}
},
2: {
msg: 'I haven\'t been working here long, but I was born and raised here by my mother. She ran the shop before me.',
options: {
2.1: {
msg: 'Where is your mother now?',
goto: '2-1'
},
2.2: {
msg: 'I\'d like to ask something else.',
goto: 1
}
}
},
'2-1': {
msg: 'A few months ago, she...took ill. She\'s been bedridden upstairs ever since.',
options: {
'2-1.1': {
msg: 'I\'d like to ask something else.',
goto: 1
}
}
},
tradeBuy: {
cpn: 'trade',
method: 'startBuy',
args: [{
targetName: 'estrid'
}]
},
tradeSell: {
cpn: 'trade',
method: 'startSell',
args: [{
targetName: 'estrid'
}]
},
tradeBuyback: {
cpn: 'trade',
method: 'startBuyback',
args: [{
targetName: 'estrid'
}]
}
},
vikar: {
1: {
msg: [{
msg: 'How may I help you today?',
options: []
}]
}
},
asvald: {
1: {
msg: [{
msg: 'Is there anything I can help you with today?',
options: [1.1, 1.2, 1.3]
}],
options: {
1.1: {
msg: 'I would like to buy some runes',
goto: 'tradeBuy'
},
1.2: {
msg: 'I have some items I would like to sell',
goto: 'tradeSell'
},
1.3: {
msg: 'Could I see the items I sold to you?',
goto: 'tradeBuyback'
}
}
},
tradeBuy: {
cpn: 'trade',
method: 'startBuy',
args: [{
targetName: 'asvald'
}]
},
tradeSell: {
cpn: 'trade',
method: 'startSell',
args: [{
targetName: 'asvald'
}]
},
tradeBuyback: {
cpn: 'trade',
method: 'startBuyback',
args: [{
targetName: 'asvald'
}]
}
},
priest: {
1: {
msg: [{
msg: 'Is there anything I can help you with today?',
options: [1.1, 1.2, 1.3]
}],
options: {
1.1: {
msg: 'I\'d like to browse your wares.',
goto: 'tradeBuy'
},
1.2: {
msg: 'I have some items to sell',
goto: 'tradeSell'
},
1.3: {
msg: 'I want to buy something back',
goto: 'tradeBuyback'
}
}
},
tradeBuy: {
cpn: 'trade',
method: 'startBuy',
args: [{
targetName: 'priest'
}]
},
tradeSell: {
cpn: 'trade',
method: 'startSell',
args: [{
targetName: 'priest'
}]
},
tradeBuyback: {
cpn: 'trade',
method: 'startBuyback',
args: [{
targetName: 'priest'
}]
}
}
};

+ 394
- 1723
src/server/config/maps/fjolarok/map.json
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 1
- 704
src/server/config/maps/fjolarok/zone.js Переглянути файл

@@ -18,506 +18,12 @@ module.exports = {
type: 'fish',
quantity: [6, 12]
},
shopestrid: {
properties: {
cpnNotice: {
actions: {
enter: {
cpn: 'dialogue',
method: 'talk',
args: [{
targetName: 'estrid'
}]
},
exit: {
cpn: 'dialogue',
method: 'stopTalk'
}
}
}
}
},
shophermit: {
properties: {
cpnNotice: {
actions: {
enter: {
cpn: 'dialogue',
method: 'talk',
args: [{
targetName: 'hermit'
}]
},
exit: {
cpn: 'dialogue',
method: 'stopTalk'
}
}
}
}
},
shopvikar: {
properties: {
cpnNotice: {
actions: {
enter: {
cpn: 'dialogue',
method: 'talk',
args: [{
targetName: 'vikar'
}]
},
exit: {
cpn: 'dialogue',
method: 'stopTalk'
}
}
}
}
},
shopasvald: {
properties: {
cpnNotice: {
actions: {
enter: {
cpn: 'dialogue',
method: 'talk',
args: [{
targetName: 'asvald'
}]
},
exit: {
cpn: 'dialogue',
method: 'stopTalk'
}
}
}
}
},
shoppriest: {
properties: {
cpnNotice: {
actions: {
enter: {
cpn: 'dialogue',
method: 'talk',
args: [{
targetName: 'priest'
}]
},
exit: {
cpn: 'dialogue',
method: 'stopTalk'
}
}
}
}
},
gas: {
components: {
cpnParticles: {
simplify: function () {
return {
type: 'particles',
blueprint: {
color: {
start: ['c0c3cf', '80f643'],
end: ['386646', '69696e']
},
scale: {
start: {
min: 18,
max: 64
},
end: {
min: 8,
max: 24
}
},
speed: {
start: {
min: 2,
max: 6
},
end: {
min: 0,
max: 4
}
},
lifetime: {
min: 4,
max: 24
},
alpha: {
start: 0.05,
end: 0
},
randomScale: true,
randomSpeed: true,
chance: 0.02,
randomColor: true,
spawnType: 'rect',
blendMode: 'screen',
spawnRect: {
x: -80,
y: -80,
w: 160,
h: 160
}
}
};
}
}
}
},
greencandle: {
components: {
cpnLight: {
simplify: function () {
return {
type: 'light',
blueprint: {
color: {
start: ['80f643'],
end: ['4ac441', '51fc9a', 'd07840']
},
lifetime: {
min: 2,
max: 6
}
}
};
}
}
}
},
fountain: {
components: {
cpnParticles: {
simplify: function () {
return {
type: 'particles',
blueprint: {
color: {
start: ['48edff', '3fa7dd'],
end: ['3a71ba', '42548d']
},
scale: {
start: {
min: 2,
max: 10
},
end: {
min: 0,
max: 2
}
},
speed: {
start: {
min: 4,
max: 16
},
end: {
min: 2,
max: 8
}
},
lifetime: {
min: 2,
max: 5
},
randomScale: true,
randomSpeed: true,
chance: 0.8,
randomColor: true,
spawnType: 'rect',
spawnRect: {
x: -10,
y: -21,
w: 20,
h: 8
}
}
};
}
}
}
},
alchgreenpot: {
components: {
cpnParticles: {
simplify: function () {
return {
type: 'particles',
blueprint: {
color: {
start: ['80f643', '80f643'],
end: ['4ac441', '4ac441']
},
scale: {
start: {
min: 2,
max: 10
},
end: {
min: 0,
max: 2
}
},
speed: {
start: {
min: 4,
max: 16
},
end: {
min: 2,
max: 8
}
},
lifetime: {
min: 1,
max: 4
},
randomScale: true,
randomSpeed: true,
chance: 0.1,
randomColor: true,
spawnType: 'rect',
spawnRect: {
x: -15,
y: -20,
w: 30,
h: 8
}
}
};
}
}
}
},
alchredpot: {
components: {
cpnParticles: {
simplify: function () {
return {
type: 'particles',
blueprint: {
color: {
start: ['ff4252', 'ff4252'],
end: ['a82841', 'a82841']
},
scale: {
start: {
min: 2,
max: 10
},
end: {
min: 0,
max: 2
}
},
speed: {
start: {
min: 4,
max: 16
},
end: {
min: 2,
max: 8
}
},
lifetime: {
min: 1,
max: 4
},
randomScale: true,
randomSpeed: true,
chance: 0.2,
randomColor: true,
spawnType: 'rect',
spawnRect: {
x: -15,
y: -28,
w: 30,
h: 8
}
}
};
}
}
}
},
'alchemy workbench': {
components: {
cpnParticles: {
simplify: function () {
return {
type: 'particles',
blueprint: {
color: {
start: ['ff4252', 'ff4252'],
end: ['a82841', 'a82841']
},
scale: {
start: {
min: 2,
max: 10
},
end: {
min: 0,
max: 2
}
},
speed: {
start: {
min: 4,
max: 16
},
end: {
min: 2,
max: 8
}
},
lifetime: {
min: 1,
max: 4
},
randomScale: true,
randomSpeed: true,
chance: 0.2,
randomColor: true,
spawnType: 'rect',
spawnRect: {
x: -15,
y: -28,
w: 30,
h: 8
}
}
};
}
},
cpnWorkbench: {
type: 'alchemy'
}
}
},
etchbench: {
components: {
cpnParticles: {
simplify: function () {
return {
type: 'particles',
blueprint: {
color: {
start: ['ff4252', 'ff4252'],
end: ['a82841', 'a82841']
},
scale: {
start: {
min: 2,
max: 10
},
end: {
min: 0,
max: 2
}
},
speed: {
start: {
min: 4,
max: 16
},
end: {
min: 2,
max: 8
}
},
lifetime: {
min: 1,
max: 4
},
randomScale: true,
randomSpeed: true,
chance: 0.2,
randomColor: true,
spawnType: 'rect',
spawnRect: {
x: -15,
y: -28,
w: 30,
h: 8
}
}
};
}
},
cpnWorkbench: {
type: 'etching'
}
}
},
fireplace: {
components: {
cpnWorkbench: {
type: 'cooking'
}
}
},
'enchanting shrine': {
components: {
cpnParticles: {
simplify: function () {
return {
type: 'particles',
blueprint: {
color: {
start: ['48edff', 'fc66f7'],
end: ['393268', '42548d']
},
scale: {
start: {
min: 2,
max: 10
},
end: {
min: 0,
max: 2
}
},
speed: {
start: {
min: 4,
max: 16
},
end: {
min: 2,
max: 8
}
},
lifetime: {
min: 1,
max: 4
},
randomScale: true,
randomSpeed: true,
chance: 0.2,
randomColor: true,
spawnType: 'rect',
spawnRect: {
x: -15,
y: -28,
w: 30,
h: 8
}
}
};
}
},
cpnWorkbench: {
type: 'enchanting'
}
}
}
},
mobs: {
@@ -531,6 +37,7 @@ module.exports = {
},
'crazed seagull': {
level: 1,
spawnCd: 50,

rare: {
count: 0
@@ -645,15 +152,6 @@ module.exports = {
name: 'The Pincer King'
}
},
'mud crab': {
level: 9
},
frog: {
level: 8,
rare: {
name: 'The Muck Prince'
}
},
eagle: {
level: 10,
regular: {
@@ -727,147 +225,6 @@ module.exports = {
}
}
},
guard: {
level: 20,
attackable: false,

walkDistance: 0,

rare: {
count: 0
}
},
estrid: {
level: 15,
attackable: false,
walkDistance: 5,

rare: {
count: 0
},

properties: {
cpnTrade: {
items: {
min: 0,
max: 0,
extra: [{
name: 'Empty Vial',
material: true,
sprite: [0, 9],
worth: 10,
infinite: true
}]
},
faction: {
id: 'fjolgard',
tier: 5
},
markup: {
buy: 0.25,
sell: 2.5
}
}
}
},
vikar: {
level: 15,
walkDistance: 0,
attackable: false,
rare: {
count: 0
}
},
luta: {
level: 15,
walkDistance: 0,
attackable: false,
rare: {
count: 0
}
},
asvald: {
level: 15,
walkDistance: 0,
attackable: false,
rare: {
count: 0
},

properties: {
cpnTrade: {
items: {
min: 0,
max: 0,
extra: [{
generate: true,
spell: true,
quality: 0,
infinite: true,
spellName: 'magic missile',
worth: 3
}, {
generate: true,
spell: true,
quality: 0,
infinite: true,
spellName: 'ice spear',
worth: 3
}, {
generate: true,
spell: true,
quality: 0,
infinite: true,
spellName: 'smite',
worth: 3
}, {
generate: true,
spell: true,
quality: 0,
infinite: true,
spellName: 'consecrate',
worth: 3
}, {
generate: true,
spell: true,
quality: 0,
infinite: true,
spellName: 'slash',
worth: 3
}, {
generate: true,
spell: true,
quality: 0,
infinite: true,
spellName: 'charge',
worth: 3
}, {
generate: true,
spell: true,
quality: 0,
infinite: true,
spellName: 'flurry',
worth: 3
}, {
generate: true,
spell: true,
quality: 0,
infinite: true,
spellName: 'smokebomb',
worth: 3
}]
},
faction: {
id: 'fjolgard',
tier: 5
},
markup: {
buy: 0.25,
sell: 10
}
}
}
},
rodriguez: {
attackable: false,
level: 10,
@@ -896,66 +253,6 @@ module.exports = {
count: 0
}
},
priest: {
level: 20,
attackable: false,
walkDistance: 0,
rare: {
count: 0
},

properties: {
cpnTrade: {
items: {
min: 5,
max: 10,
extra: [{
type: 'skin',
skinId: 'gaekatlan-druid',
worth: 100,
factions: [{
id: 'gaekatla',
tier: 7
}]
}, {
worth: 100,
infinite: true,
generate: true,
name: 'Cowl of Obscurity',
level: [4, 13],
quality: 4,
noSpell: true,
slot: 'head',
sprite: [2, 0],
spritesheet: '../../../images/legendaryItems.png',
type: 'Silk Cowl',
description: 'Imbued with the powers of Gaekatla herself.',
stats: ['hpMax', 'hpMax', 'int', 'int'],
effects: [{
type: 'healOnCrit',
rolls: {
i_chance: [20, 60],
i_percentage: [3, 7]
}
}],
factions: [{
id: 'gaekatla',
tier: 7
}]
}]
},
faction: {
id: 'gaekatla',
tier: 5
},
markup: {
buy: 0.25,
sell: 10
}
}
}
},

sundfehr: {
level: 9,
walkDistance: 0,


+ 0
- 4
src/server/config/maps/mapList.js Переглянути файл

@@ -5,10 +5,6 @@ let config = [
name: 'cave',
path: 'config/maps'
},
{
name: 'sewer',
path: 'config/maps'
},
{
name: 'fjolarok',
path: 'config/maps'


+ 0
- 291
src/server/config/maps/sewer/events/plagueOfRats.js Переглянути файл

@@ -1,291 +0,0 @@
const { mobs: { rat: { level, faction, grantRep, regular: { drops } } } } = require('../zone');
const rewardGenerator = require('../../../../misc/rewardGenerator');

const rewardConfig = {
regularKill: [{
name: 'Iron Bar',
sprite: [0, 0],
quality: 0,
quantity: 5,
chance: 10
}, {
name: 'Cloth Scrap',
sprite: [0, 1],
quality: 0,
quantity: 5,
chance: 10
}, {
name: 'Leather Scrap',
sprite: [0, 7],
quality: 0,
quantity: 5,
chance: 10
}, {
name: 'Muddy Runestone',
material: true,
quality: 0,
sprite: [6, 0],
spritesheet: 'images/materials.png',
chance: 1
}, {
name: 'Epic Essence',
material: true,
sprite: [0, 5],
quality: 3,
chance: 1
}, {
name: 'Rat Claw',
material: true,
sprite: [3, 0],
spritesheet: 'images/materials.png',
chance: 3
}]
};

const descriptionStrings = {
leadup: 'A bandit alchemist has been spotted in the sewer tunnels.',
active: 'Rats are swarming towards the city.',
success: 'Success: The rat invasion has been averted.',
failure: 'Failure: The rats have made it to the city.',
escapeCounter: 'Escapees: $ratEscapees$'
};

const config = {
cron: '0 */3 * * *',
//cron: '* * * * *',
idFirstSpawnPhase: 6,
idFailPhase: 19,
maxEscapees: 5,
repeats: [5, 5, 3],
//repeats: [1, 1, 1],
rewardItemsPerKill: 3
};

const ratTargetPos = {
x: 97,
y: 87
};

const rat = {
name: 'Bloodthirsty Rat',
cell: 24,
level,
faction,
grantRep,
drops,
hpMult: 3,
pos: {
x: 61,
y: 62
},
originX: ratTargetPos.x,
originY: ratTargetPos.y,
maxChaseDistance: 1000,
spells: [{
type: 'smokeBomb',
radius: 1,
duration: 20,
range: 2,
selfCast: 1,
statMult: 1,
damage: 0.125,
element: 'poison',
cdMax: 5,
particles: {
scale: {
start: {
min: 10,
max: 25
},
end: {
min: 10,
max: 0
}
},
opacity: {
start: 0.3,
end: 0
},
lifetime: {
min: 1,
max: 2
},
speed: {
start: 3,
end: 0
},
color: {
start: ['db5538', '4ac441'],
end: ['953f36', '386646']
},
chance: 0.125,
randomColor: true,
randomScale: true,
blendMode: 'screen',
spawnType: 'rect',
spawnRect: {
x: -10,
y: -10,
w: 20,
h: 20
}
}
}],
events: {
afterMove: function () {
const { obj: { x, y } } = this;
if (x !== ratTargetPos.x || y !== ratTargetPos.y)
return;

const eventManager = this.obj.instance.events;
const eventName = this.obj.event.config.name;

eventManager.incrementEventVariable(eventName, 'ratEscapees', 1);

const { active, escapeCounter } = descriptionStrings;
const newDesc = `${active}<br /><br />${escapeCounter}`;

eventManager.setEventDescription(eventName, newDesc);

this.obj.destroyed = true;

const totalEscapees = this.obj.event.variables.ratEscapees;
if (totalEscapees >= config.maxEscapees) {
const event = this.obj.event;
event.currentPhase.end = true;
event.nextPhase = config.idFailPhase;
}
},

afterDeath: function ({ source: { name } }) {
const eventManager = this.obj.instance.events;
const eventName = this.obj.event.config.name;

const itemCount = config.rewardItemsPerKill;
const rewards = rewardGenerator(itemCount, rewardConfig.regularKill);

eventManager.addParticipantRewards(eventName, name, rewards);
}
}
};

module.exports = {
name: 'Plague of Rats',
description: descriptionStrings.leadup,
distance: -1,
cron: config.cron,

phases: [{
type: 'spawnMob',
auto: true,
mobs: [{
id: 'banditAlchemist',
name: 'Bandit Alchemist',
attackable: false,
hpMult: 1,
cell: 79,
level: 15,
pos: {
x: 117,
y: 62
}
}]
}, {
type: 'moveMob',
id: 'banditAlchemist',
pos: {
x: 64,
y: 63
}
}, {
type: 'eventChain',
config: [{
type: 'mobTalk',
id: 'banditAlchemist',
text: 'I think I cracked it! The serum should finally be complete.',
delay: 15
}, {
type: 'mobTalk',
id: 'banditAlchemist',
text: 'One taste of this and the rats\' hunger for blood will be instatiable.',
delay: 15
}, {
type: 'mobTalk',
id: 'banditAlchemist',
text: '*pours a bubbling liquid into a rat nest*',
delay: 15
}, {
type: 'mobTalk',
id: 'banditAlchemist',
text: 'Let\'s see how Fjolgard handles a rat infestation of the bloodthirsty variety.',
delay: 15
}, {
type: 'mobTalk',
id: 'banditAlchemist',
text: '*laughs*',
delay: 15
}]
}, {
type: 'moveMob',
id: 'banditAlchemist',
pos: {
x: 117,
y: 63
},
auto: true
}, {
type: 'despawnMob',
id: 'banditAlchemist'
}, {
type: 'setDescription',
desc: descriptionStrings.active,
auto: true
}, {
type: 'spawnMob',
mobs: [rat],
auto: true
}, {
type: 'wait',
ttl: 15
}, {
type: 'goto',
gotoPhaseIndex: config.idFirstSpawnPhase,
repeats: config.repeats[0]
}, {
type: 'spawnMob',
mobs: [rat],
auto: true
}, {
type: 'wait',
ttl: 7
}, {
type: 'goto',
gotoPhaseIndex: config.idFirstSpawnPhase + 3,
repeats: config.repeats[1]
}, {
type: 'spawnMob',
mobs: [rat],
auto: true
}, {
type: 'wait',
ttl: 3
}, {
type: 'goto',
gotoPhaseIndex: config.idFirstSpawnPhase + 6,
repeats: config.repeats[2]
}, {
type: 'killAllMobs'
}, {
type: 'setDescription',
desc: descriptionStrings.success,
ttl: 100
}, {
type: 'giveRewards'
}, {
type: 'end'
}, {
type: 'setDescription',
desc: descriptionStrings.failure,
ttl: 100
}]
};

+ 0
- 2461
src/server/config/maps/sewer/map.json
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 0
- 455
src/server/config/maps/sewer/zone.js Переглянути файл

@@ -1,455 +0,0 @@
const balance = {
rat: {
clawChance: 3
},
giantRat: {
clawChance: 5
},
enragedRat: {
clawChance: 80
},
stinktooth: {
runestoneChance: 10,
recipeChance: 3,
shankChance: 0.2
},
bandit: {
keyChance: 1
},
direRat: {
clawChance: 7
},
bera: {
recipeChance: 3,
keyChance: 3
}
};

module.exports = {
name: 'The Fjolgard Sewer',
level: [11, 13],

resources: {
Stinkcap: {
type: 'herb',
max: 1
}
},

mobs: {
default: {
faction: 'fjolgard',
deathRep: -5
},

rat: {
faction: 'fjolgard',
grantRep: {
fjolgard: 6
},
level: 11,

regular: {
drops: {
rolls: 1,
noRandom: true,
alsoRandom: true,
blueprints: [{
chance: balance.rat.clawChance,
name: 'Rat Claw',
material: true,
sprite: [3, 0],
spritesheet: 'images/materials.png'
}]
}
},

rare: {
name: 'Enraged Rat',
cell: 24,

drops: {
rolls: 1,
noRandom: true,
alsoRandom: true,
blueprints: [{
chance: balance.enragedRat.clawChance,
name: 'Rat Claw',
material: true,
sprite: [3, 0],
spritesheet: 'images/materials.png'
}]
}
}
},

'giant rat': {
faction: 'fjolgard',
grantRep: {
fjolgard: 6
},
level: 12,

regular: {
hpMult: 2,
dmgMult: 1.2,

drops: {
rolls: 1,
noRandom: true,
alsoRandom: true,
blueprints: [{
chance: balance.giantRat.clawChance,
name: 'Rat Claw',
material: true,
sprite: [3, 0],
spritesheet: 'images/materials.png'
}]
}
},

rare: {
count: 0
}
},

stinktooth: {
faction: 'hostile',
grantRep: {
fjolgard: 15
},
level: 13,
spawnCd: 1714,

regular: {
hpMult: 10,
dmgMult: 3,

drops: {
rolls: 3,
chance: 100,
noRandom: true,
alsoRandom: true,
magicFind: [2000, 125],
blueprints: [{
chance: balance.stinktooth.shankChance,
name: 'Putrid Shank',
level: 13,
quality: 4,
slot: 'oneHanded',
type: 'Dagger',
spritesheet: '../../../images/legendaryItems.png',
sprite: [0, 1],
implicitStat: {
stat: 'lifeOnHit',
value: [5, 20]
},
effects: [{
type: 'castSpellOnHit',
rolls: {
i_chance: [5, 20],
spell: 'smokeBomb'
}
}]
}, {
chance: balance.stinktooth.recipeChance,
type: 'recipe',
name: 'Recipe: Rune of Whirlwind',
profession: 'etching',
teaches: 'runeWhirlwind'
}, {
chance: balance.stinktooth.runestoneChance,
name: 'Muddy Runestone',
material: true,
sprite: [6, 0],
spritesheet: 'images/materials.png'
}]
}
},

rare: {
count: 0
},

spells: [{
type: 'melee',
statMult: 1,
damage: 0.08
}, {
type: 'whirlwind',
range: 2,
damage: 0.2,
cdMax: 40
}, {
type: 'summonSkeleton',
killMinionsOnDeath: false,
killMinionsBeforeSummon: false,
minionsDieOnAggroClear: true,
needLos: false,
sheetName: 'mobs',
cdMax: 60,
positions: [[30, 30], [40, 30], [30, 40], [40, 40]],
summonTemplates: [{
name: 'Biter Rat',
cell: 16,
hpPercent: 20,
dmgPercent: 0.1,
basicSpell: 'melee'
}, {
name: 'Spitter Rat',
cell: 24,
hpPercent: 10,
dmgPercent: 0.175,
basicSpell: 'projectile'
}]
}, {
type: 'charge',
castOnEnd: 1,
cdMax: 50,
targetRandom: true,
damage: 0.3
}, {
type: 'fireblast',
range: 2,
damage: 0.001,
pushback: 2,
procCast: true
}]
},

bandit: {
faction: 'hostile',
grantRep: {
fjolgard: 18
},
level: 11,

regular: {
drops: {
noRandom: true,
alsoRandom: true,
blueprints: [{
chance: balance.bandit.keyChance,
type: 'key',
noSalvage: true,
name: 'Rusted Key',
keyId: 'rustedSewer',
singleUse: true,
sprite: [12, 1],
quantity: 1
}]
}
},

rare: {
name: 'Cutthroat'
}
},

'dire rat': {
level: 13,
walkDistance: 0,
faction: 'hostile',
noQuest: true,
grantRep: {
fjolgard: 22
},

regular: {
hpMult: 5,
dmgMult: 1.2,

drops: {
rolls: 1,
noRandom: true,
alsoRandom: true,
blueprints: [{
chance: balance.direRat.clawChance,
name: 'Rat Claw',
material: true,
sprite: [3, 0],
spritesheet: 'images/materials.png'
}]
}
},

rare: {
count: 0
}
},

'bera the blade': {
faction: 'hostile',
grantRep: {
fjolgard: 25
},
level: 14,
walkDistance: 0,

regular: {
hpMult: 3,
dmgMult: 1.5,

drops: {
rolls: 1,
noRandom: true,
alsoRandom: true,
blueprints: [{
chance: balance.bera.recipeChance,
type: 'recipe',
name: 'Recipe: Rune of Ambush',
profession: 'etching',
teaches: 'runeAmbush'
}, {
chance: balance.bera.keyChance,
type: 'key',
noSalvage: true,
name: 'Rusted Key',
keyId: 'rustedSewer',
singleUse: true,
sprite: [12, 1],
quantity: 1
}]
}
},

rare: {
count: 0
}
}
},
objects: {
'mudfish school': {
max: 9,
type: 'fish',
quantity: [6, 12]
},

sewerdoor: {
properties: {
cpnDoor: {
autoClose: 171,
locked: true,
key: 'rustedSewer',
destroyKey: true
}
}
},

bubbles: {
components: {
cpnParticles: {
simplify: function () {
return {
type: 'particles',
blueprint: {
color: {
start: ['51fc9a', '80f643'],
end: ['386646', '44cb95']
},
scale: {
start: {
min: 2,
max: 8
},
end: {
min: 2,
max: 4
}
},
speed: {
start: {
min: 2,
max: 6
},
end: {
min: 0,
max: 4
}
},
lifetime: {
min: 1,
max: 3
},
alpha: {
start: 0.5,
end: 0
},
randomScale: true,
randomSpeed: true,
chance: 0.2,
randomColor: true,
spawnType: 'rect',
blendMode: 'screen',
spawnRect: {
x: -40,
y: -40,
w: 80,
h: 80
}
}
};
}
}
}
},

gas: {
components: {
cpnParticles: {
simplify: function () {
return {
type: 'particles',
blueprint: {
color: {
start: ['c0c3cf', '80f643'],
end: ['386646', '69696e']
},
scale: {
start: {
min: 18,
max: 64
},
end: {
min: 8,
max: 24
}
},
speed: {
start: {
min: 2,
max: 6
},
end: {
min: 0,
max: 4
}
},
lifetime: {
min: 4,
max: 24
},
alpha: {
start: 0.05,
end: 0
},
randomScale: true,
randomSpeed: true,
chance: 0.02,
randomColor: true,
spawnType: 'rect',
blendMode: 'screen',
spawnRect: {
x: -80,
y: -80,
w: 160,
h: 160
}
}
};
}
}
}
}
}
};

+ 1
- 1
src/server/items/generators/quality.js Переглянути файл

@@ -1,6 +1,6 @@
module.exports = {
qualities: [
2000,
0,
350,
80,
17,


+ 1
- 1
src/server/mods/class-necromancer/index.js Переглянути файл

@@ -18,7 +18,7 @@ module.exports = {
},

onAfterGetZone: function (zone, config) {
if (zone !== 'fjolarok')
if (zone !== 'fjolgard')
return;

let newRunes = [{


+ 26
- 20
src/server/objects/objBase.js Переглянути файл

@@ -275,10 +275,12 @@ module.exports = {
},

performMove: function (action) {
let data = action.data;
let physics = this.instance.physics;
const { x: xOld, y: yOld, syncer, aggro, mob, instance: { physics } } = this;

if (!action.force) {
const { maxDistance = 1, force, data } = action;
const { x: xNew, y: yNew } = data;

if (!force) {
if (physics.isTileBlocking(data.x, data.y))
return true;

@@ -290,10 +292,8 @@ module.exports = {
return true;
}

let maxDistance = action.maxDistance || 1;

let deltaX = Math.abs(this.x - data.x);
let deltaY = Math.abs(this.y - data.y);
let deltaX = Math.abs(xOld - xNew);
let deltaY = Math.abs(yOld - yNew);
if (
(
(deltaX > maxDistance) ||
@@ -308,27 +308,33 @@ module.exports = {
}

//Don't allow mob overlap during combat
if ((this.mob) && (this.mob.target)) {
if (physics.addObject(this, data.x, data.y)) {
physics.removeObject(this, this.x, this.y);
if (mob && mob.target) {
this.x = xNew;
this.y = yNew;

if (physics.addObject(this, xNew, yNew))
physics.removeObject(this, xOld, yOld);
else {
this.x = xOld;
this.y = yOld;

this.x = data.x;
this.y = data.y;
} else
return false;
}
} else {
physics.removeObject(this, this.x, this.y, data.x, data.y);
physics.addObject(this, data.x, data.y, this.x, this.y);
this.x = data.x;
this.y = data.y;
physics.removeObject(this, xOld, yOld, xNew, yNew);

this.x = xNew;
this.y = yNew;

physics.addObject(this, xNew, yNew, xOld, yOld);
}

let syncer = this.syncer;
//We can't use xNew and yNew because addObject could have changed the position (like entering a building interior with stairs)
syncer.o.x = this.x;
syncer.o.y = this.y;

if (this.aggro)
this.aggro.move();
if (aggro)
aggro.move();

this.fireEvent('afterMove');



+ 6
- 6
src/server/package-lock.json Переглянути файл

@@ -796,9 +796,9 @@
}
},
"engine.io-client": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.0.tgz",
"integrity": "sha512-12wPRfMrugVw/DNyJk34GQ5vIVArEcVMXWugQGGuw2XxUSztFNmJggZmv8IZlLyEdnpO1QB9LkcjeWewO2vxtA==",
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.1.tgz",
"integrity": "sha512-oVu9kBkGbcggulyVF0kz6BV3ganqUeqXvD79WOFKa+11oK692w1NyFkuEj4xrkFRpZhn92QOqTk4RQq5LiBXbQ==",
"requires": {
"component-emitter": "~1.3.0",
"component-inherit": "0.0.3",
@@ -3020,9 +3020,9 @@
}
},
"ws": {
"version": "7.4.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.3.tgz",
"integrity": "sha512-hr6vCR76GsossIRsr8OLR9acVVm1jyfEWvhbNjtgPOrfvAlKzvyeg/P6r8RuDjRyrcQoPQT7K0DGEPc7Ae6jzA=="
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
},
"xmlhttprequest-ssl": {
"version": "1.5.5",


+ 4
- 6
src/server/world/map.js Переглянути файл

@@ -300,7 +300,7 @@ module.exports = {
},

getOffsetCellPos: function (sheetName, cell) {
const { atlasTextureDimensions, config: { atlasTextures } } = clientConfig;
const { config: { atlasTextureDimensions, atlasTextures } } = clientConfig;
const indexInAtlas = atlasTextures.indexOf(sheetName);

let offset = 0;
@@ -378,11 +378,8 @@ module.exports = {

if (layerName.indexOf('walls') > -1)
this.collisionMap[x][y] = 1;
else if (layerName === 'tiles' && sheetName === 'tiles') {
//Check for water and water-like tiles
if ([6, 7, 54, 55, 62, 63, 154, 189, 190, 192, 193, 194, 195, 196, 197].includes(offsetCell))
this.collisionMap[x][y] = 1;
}
else if (clientConfig.config.blockingTileIndices.includes(offsetCell))
this.collisionMap[x][y] = 1;
},

object: function (layerName, cell) {
@@ -459,6 +456,7 @@ module.exports = {
}
} else if (layerName === 'hiddenRooms') {
blueprint.fog = (cell.properties || {}).fog;
blueprint.interior = (cell.properties || {}).interior;
blueprint.discoverable = (cell.properties || {}).discoverable;
blueprint.layer = ~~((cell.properties || {}).layer || 0);



+ 6
- 2
src/server/world/physics.js Переглянути файл

@@ -114,14 +114,18 @@ module.exports = {
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);
}
}

cell.push(obj);
//Perhaps a collisionEvent caused us to move somewhere else, in which case, we don't push to the cell
// as we assume that the collisionEvent handled it for us
if (obj.x === x && obj.y === y)
cell.push(obj);
return true;
},



Завантаження…
Відмінити
Зберегти