@@ -4,7 +4,6 @@ package-lock.json | |||
storage.db | |||
*.sublime-project | |||
*.sublime-workspace | |||
*.css | |||
src/server/mods/iwd-* | |||
!helpers/item-tooltip/styles.css | |||
!helpers/passives/**/*.css | |||
@@ -11,7 +11,7 @@ COPY . . | |||
WORKDIR /usr/src/isleward/src/server/ | |||
# Install only production npm modules specified in package.json | |||
RUN npm install --only=production | |||
RUN npm ci --only=production | |||
# Expose container's port 4000 | |||
EXPOSE 4000 | |||
@@ -0,0 +1 @@ | |||
body,html{position:fixed;overflow:hidden;overscroll-behavior:none}body{margin:0px;width:100vw;height:100vh;background-color:#2d2136}.ui-container{width:100%;height:100%;position:absolute;left:0px;top:0px;z-index:20;overflow:hidden;display:flex;justify-content:center;align-items:center}.ui-container>.right{position:absolute;right:10px;top:94px}.ui-container.mobile .uiTooltipInfo{display:none !important}.ui-container.hideMonetization .monetization{display:none}.mobile.ui-container>.right{top:10px;right:158px;z-index:2;display:flex;flex-direction:row-reverse}*{box-sizing:border-box;font-family:bitty;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.canvas-container{position:relative;float:left}.canvas-container.visible{opacity:1;transition:1s}.canvas-container canvas{left:0px;top:0px;width:100vw}.disabled{opacity:.4 !important;pointer-events:none !important}[class^="ui"] input,[class^="ui"] textarea{-webkit-user-select:text;-khtml-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}[class^="ui"] .el{height:35px;text-align:center;padding:0px 0px 0px 0px;background-color:transparent}[class^="ui"] .textbox{border:none;outline:none;font-size:16px}[class^="ui"] div.textbox{padding-top:6px}[class^="ui"] .btn{cursor:pointer;display:flex;justify-content:center;align-items:center}[class^="ui"] .btn:hover{background-color:#473456}[class^="ui"] .spacer-h{width:100%}[class^="ui"].modal .btnClose{position:absolute;background-color:#505360;color:#ff6942;cursor:pointer;height:31px;width:31px;text-align:center;right:0px;top:0px;padding-top:0px;display:flex;justify-content:center;align-items:center}[class^="ui"].modal .btnClose:hover{background-color:#676b7c}::-webkit-scrollbar{width:16px}::-webkit-scrollbar-track{background-color:#3c3f4c;-webkit-border-radius:0px;border-radius:0px}::-webkit-scrollbar-thumb{-webkit-border-radius:10px;border-radius:0px;background:#929398}:root{scrollbar-color:#929398 #3c3f4c !important;scrollbar-width:thin !important;--color-element-default:#f2f5f5;--color-element-arcane:#fc66f7;--color-element-frost:#48edff;--color-element-fire:#ff4252;--color-element-holy:#ffeb38;--color-element-poison:#51fc9a}.q0{color:#f2f5f5}.q1{color:#4ac441}.q2{color:#3fa7dd}.q3{color:#a24eff}.q4{color:#ff6942}.color-red{color:#d43346 !important}.color-redA{color:#ff4252 !important}.color-blueA{color:#48edff !important}.color-blueB{color:#3fa7dd !important}.color-greenB{color:#4ac441 !important}.color-yellowB{color:#faac45 !important}.color-green{color:#80f643 !important}.color-brownC{color:#b15a30 !important}.color-brownD{color:#763b3b !important}.color-grayA{color:#f2f5f5 !important}.color-grayB{color:#c0c3cf !important}.color-grayC{color:#929398 !important}.color-grayD{color:#69696e !important}.color-pinkA{color:#fc66f7 !important}.color-pinkB{color:#de43ae !important}.color-purpleA{color:#a24eff !important}.color-tealB{color:#51fc9a !important}[class^="ui"] .renderItem{width:72px;height:72px;float:left;position:relative;cursor:pointer;box-sizing:border-box;margin:4px;background-color:#312136}[class^="ui"] .renderItem.hover{background-color:rgba(72,237,255,0.1)}[class^="ui"] .renderItem.dragging{position:absolute;opacity:.5;pointer-events:none;background-color:transparent}[class^="ui"] .renderItem.dragging .icon{filter:brightness(100%) drop-shadow(0 -4px 0 #312136) drop-shadow(0 4px 0 #312136) drop-shadow(4px 0 0 #312136) drop-shadow(-4px 0 0 #312136);-moz-filter:brightness(100%) drop-shadow(0 -4px 0 #312136) drop-shadow(0 4px 0 #312136) drop-shadow(4px 0 0 #312136) drop-shadow(-4px 0 0 #312136)}[class^="ui"] .renderItem .quantity{left:6px;bottom:3px;position:absolute;color:#f2f5f5;filter:drop-shadow(0 -2px 0 #312136) drop-shadow(0 2px 0 #312136) drop-shadow(2px 0 0 #312136) drop-shadow(-2px 0 0 #312136);-moz-filter:drop-shadow(0 -2px 0 #312136) drop-shadow(0 2px 0 #312136) drop-shadow(2px 0 0 #312136) drop-shadow(-2px 0 0 #312136)}[class^="ui"] .renderItem .icon{width:64px;height:64px;position:absolute;left:4px;top:4px}[class^="ui"] .renderItem.eq .quantity{color:#ffeb38}[class^="ui"] .renderItem.new .quantity{color:#80f643}[class^="ui"] .renderItem:hover .icon{filter:brightness(160%);-moz-filter:brightness(160%)}.hasBorderShadow{box-shadow:0 -2px 0 #2d2136,0 2px 0 #2d2136,2px 0 0 #2d2136,-2px 0 0 #2d2136} |
@@ -3,7 +3,7 @@ require.config({ | |||
waitSeconds: 120, | |||
paths: { | |||
socket: 'https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.slim', | |||
jquery: 'https://code.jquery.com/jquery-3.4.1.slim.min', | |||
jquery: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.slim.min', | |||
text: 'https://cdnjs.cloudflare.com/ajax/libs/require-text/2.0.12/text.min', | |||
html: 'plugins/html', | |||
css: 'https://cdnjs.cloudflare.com/ajax/libs/require-css/0.1.10/css.min', | |||
@@ -52,6 +52,8 @@ define([ | |||
if (this.noSprite) | |||
this.obj.sheetName = null; | |||
this.sprite.visible = this.obj.isVisible; | |||
}, | |||
renderManual: function () { | |||
@@ -66,7 +68,7 @@ define([ | |||
if (this.destroyObject) | |||
this.obj.destroyed = true; | |||
else { | |||
if (this.obj.sprite && this.hideSprite) | |||
if (this.obj.isVisible && this.obj.sprite) | |||
this.obj.sprite.visible = true; | |||
this.destroyed = true; | |||
@@ -67,8 +67,8 @@ define([ | |||
return; | |||
t.eventList = {}; | |||
t.hookEvent = hookEvent.bind(t); | |||
t.unhookEvents = unhookEvents.bind(t); | |||
t.hookEvent = hookEvent; | |||
t.unhookEvents = unhookEvents; | |||
templates[t.type] = t; | |||
}); | |||
@@ -113,7 +113,9 @@ define([ | |||
}); | |||
e.sprite.alpha = useAlpha; | |||
}, this); | |||
e.sprite.visible = this.obj.isVisible; | |||
}); | |||
}, | |||
setVisible: function (visible) { | |||
@@ -65,6 +65,9 @@ define([ | |||
}, | |||
explode: function (blueprint) { | |||
if (!this.obj.isVisible) | |||
return; | |||
let particles = this.obj.addComponent('particles', this.blueprint); | |||
particles.emitter.update(0.2); | |||
@@ -76,6 +76,8 @@ define([ | |||
}); | |||
} | |||
} | |||
this.setVisible(this.obj.isVisible); | |||
}, | |||
update: function () { | |||
@@ -79,6 +79,8 @@ define([ | |||
ray.blendMode = PIXI.BLEND_MODES.ADD; | |||
} | |||
} | |||
this.setVisible(this.obj.isVisible); | |||
}, | |||
update: function () { | |||
@@ -17,6 +17,8 @@ define([ | |||
this.blueprint.obj = this.obj; | |||
this.emitter = renderer.buildEmitter(this.blueprint); | |||
this.setVisible(this.obj.isVisible); | |||
}, | |||
setVisible: function (visible) { | |||
@@ -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)); | |||
@@ -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 () { | |||
@@ -226,7 +226,7 @@ define([ | |||
if (!target) | |||
return; | |||
if (this.target.destroyed || this.target.nonSelectable) { | |||
if (this.target.destroyed || this.target.nonSelectable || !this.target.isVisible) { | |||
this.target = null; | |||
this.targetSprite.visible = false; | |||
} | |||
@@ -108,6 +108,28 @@ define([ | |||
stats.updateHpSprite(); | |||
}, | |||
updateVisibility: function () { | |||
const { x, y, hidden, isVisible } = this; | |||
const vis = ( | |||
!hidden && | |||
( | |||
this.self || | |||
( | |||
renderer.sprites[x] && | |||
renderer.sprites[x][y].length > 0 && | |||
!renderer.isHidden(x, y) | |||
) | |||
) | |||
); | |||
if (vis === isVisible) | |||
return; | |||
this.isVisible = vis; | |||
this.setVisible(vis); | |||
}, | |||
setVisible: function (visible) { | |||
if (this.sprite) | |||
this.sprite.visible = visible; | |||
@@ -115,6 +137,11 @@ define([ | |||
if (this.nameSprite) | |||
this.nameSprite.visible = (visible && config.showNames); | |||
if (!visible && this.stats && this.stats.hpSprite && this.stats.hpSprite.visible) { | |||
this.stats.hpSprite.visible = false; | |||
this.stats.hpSpriteInner.visible = false; | |||
} | |||
this.components.forEach(c => { | |||
if (c.setVisible) | |||
c.setVisible(visible); | |||
@@ -50,7 +50,7 @@ define([ | |||
getClosest: function (x, y, maxDistance, reverse, fromMob) { | |||
let objects = this.objects; | |||
let list = objects.filter(function (o) { | |||
let list = objects.filter(o => { | |||
if ((!o.stats) || (o.nonSelectable) || (o === window.player) || (!o.sprite.visible)) | |||
return false; | |||
@@ -65,7 +65,7 @@ define([ | |||
if (list.length === 0) | |||
return null; | |||
list.sort(function (a, b) { | |||
list.sort((a, b) => { | |||
let aDistance = Math.max(Math.abs(x - a.x), Math.abs(y - a.y)); | |||
let bDistance = Math.max(Math.abs(x - b.x), Math.abs(y - b.y)); | |||
@@ -77,9 +77,7 @@ define([ | |||
if (!fromMob) | |||
return list[0]; | |||
let fromIndex = list.findIndex(function (l) { | |||
return (l.id === fromMob.id); | |||
}); | |||
let fromIndex = list.findIndex(l => l.id === fromMob.id); | |||
if (reverse) | |||
fromIndex = (fromIndex === 0 ? list.length : fromIndex) - 1; | |||
@@ -136,38 +134,36 @@ define([ | |||
obj[p] = value; | |||
} | |||
components.forEach(function (c) { | |||
if (obj.sheetName) | |||
obj.sprite = renderer.buildObject(obj); | |||
if ((obj.name) && (obj.sprite)) { | |||
obj.nameSprite = renderer.buildText({ | |||
layerName: 'effects', | |||
text: obj.name, | |||
x: (obj.x * scale) + (scale / 2), | |||
y: (obj.y * scale) + scale | |||
}); | |||
} | |||
//We need to set visibility before components kick in as they sometimes need access to isVisible | |||
obj.updateVisibility(); | |||
components.forEach(c => { | |||
//Map ids to objects | |||
let keys = Object.keys(c).filter(function (k) { | |||
return ((k.indexOf('id') === 0) && (k.length > 2)); | |||
let keys = Object.keys(c).filter(k => { | |||
return (k.indexOf('id') === 0 && k.length > 2); | |||
}); | |||
keys.forEach(function (k) { | |||
keys.forEach(k => { | |||
let value = c[k]; | |||
let newKey = k.substr(2, k.length).toLowerCase(); | |||
c[newKey] = this.objects.find(function (o) { | |||
return (o.id === value); | |||
}); | |||
c[newKey] = this.objects.find(o => o.id === value); | |||
delete c[k]; | |||
}, this); | |||
}); | |||
obj.addComponent(c.type, c); | |||
}, this); | |||
if (obj.sheetName) { | |||
obj.sprite = renderer.buildObject(obj); | |||
if (template.hidden) { | |||
obj.sprite.visible = false; | |||
if (obj.nameSprite) | |||
obj.nameSprite.visible = false; | |||
if ((obj.stats) && (obj.stats.hpSprite)) { | |||
obj.stats.hpSprite.visible = false; | |||
obj.stats.hpSpriteInner.visible = false; | |||
} | |||
} | |||
} | |||
this.objects.push(obj); | |||
}); | |||
if (obj.self) { | |||
events.emit('onGetPlayer', obj); | |||
@@ -181,27 +177,7 @@ define([ | |||
}, true); | |||
} | |||
if ((obj.name) && (obj.sprite)) { | |||
obj.nameSprite = renderer.buildText({ | |||
layerName: 'effects', | |||
text: obj.name, | |||
x: (obj.x * scale) + (scale / 2), | |||
y: (obj.y * scale) + scale | |||
}); | |||
} | |||
if (renderer.sprites) { | |||
let isVisible = ( | |||
obj.self || | |||
( | |||
renderer.sprites[obj.x] && | |||
renderer.sprites[obj.x][obj.y].length > 0 && | |||
!renderer.isHidden(obj.x, obj.y) | |||
) | |||
); | |||
obj.setVisible(isVisible); | |||
} | |||
this.objects.push(obj); | |||
return obj; | |||
}, | |||
@@ -209,28 +185,26 @@ define([ | |||
updateObject: function (obj, template) { | |||
let components = template.components || []; | |||
components.forEach(function (c) { | |||
components.forEach(c => { | |||
//Map ids to objects | |||
let keys = Object.keys(c).filter(function (k) { | |||
return ((k.indexOf('id') === 0) && (k.length > 2)); | |||
let keys = Object.keys(c).filter(k => { | |||
return (k.indexOf('id') === 0 && k.length > 2); | |||
}); | |||
keys.forEach(function (k) { | |||
keys.forEach(k => { | |||
let value = c[k]; | |||
let newKey = k.substr(2, k.length).toLowerCase(); | |||
c[newKey] = this.objects.find(function (o) { | |||
return (o.id === value); | |||
}); | |||
c[newKey] = this.objects.find(o => o.id === value); | |||
delete c[k]; | |||
}, this); | |||
}); | |||
obj.addComponent(c.type, c); | |||
}, this); | |||
}); | |||
delete template.components; | |||
if (template.removeComponents) { | |||
template.removeComponents.forEach(function (r) { | |||
template.removeComponents.forEach(r => { | |||
obj.removeComponent(r); | |||
}); | |||
delete template.removeComponents; | |||
@@ -265,22 +239,6 @@ define([ | |||
if (((template.sheetName) || (template.cell)) && (sprite)) | |||
renderer.setSprite(obj); | |||
if (sprite) { | |||
if (template.hidden !== null) { | |||
sprite.visible = !template.hidden; | |||
if (obj.nameSprite) | |||
obj.nameSprite.visible = config.showNames; | |||
if ((obj.stats) && (obj.stats.hpSprite)) { | |||
obj.stats.hpSprite.visible = !template.hidden; | |||
obj.stats.hpSpriteInner.visible = !template.hidden; | |||
} | |||
} | |||
} | |||
if ((template.x !== 0) || (template.y !== 0)) { | |||
if (obj.stats) | |||
obj.stats.updateHpSprite(); | |||
} | |||
if ((!obj.sprite) && (template.sheetName)) | |||
obj.sprite = renderer.buildObject(obj); | |||
@@ -292,27 +250,15 @@ define([ | |||
x: (obj.x * scale) + (scale / 2), | |||
y: (obj.y * scale) + scale | |||
}); | |||
obj.nameSprite.visible = config.showNames; | |||
} | |||
if (obj.sprite) { | |||
let ix = ~~obj.x; | |||
let iy = ~~obj.y; | |||
let isVisible = ( | |||
!!obj.player || | |||
( | |||
!obj.hidden && | |||
renderer.sprites[ix] && | |||
renderer.sprites[ix][iy] && | |||
renderer.sprites[ix][iy].length > 0 && | |||
!renderer.isHidden(obj.x, obj.y) | |||
) | |||
); | |||
obj.setVisible(isVisible); | |||
} | |||
if ((template.x !== 0) || (template.y !== 0)) { | |||
obj.updateVisibility(); | |||
obj.setSpritePosition(); | |||
obj.setSpritePosition(); | |||
if (obj.stats) | |||
obj.stats.updateHpSprite(); | |||
} | |||
}, | |||
update: function () { | |||
@@ -340,13 +286,13 @@ define([ | |||
for (let i = 0; i < oLen; i++) { | |||
let o = objects[i]; | |||
let onPos = tiles.some(function (t) { | |||
let onPos = tiles.some(t => { | |||
return (!(t.x !== o.x || t.y !== o.y)); | |||
}); | |||
if (!onPos) | |||
continue; | |||
o.setVisible(visible); | |||
o.updateVisibility(); | |||
} | |||
}, | |||
@@ -36,7 +36,7 @@ define([ | |||
let target = objects.objects.find(function (o) { | |||
return (o.id === msg.id); | |||
}); | |||
if (!target) | |||
if (!target || !target.isVisible) | |||
return; | |||
let ttl = 35; | |||
@@ -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)) | |||
@@ -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; | |||
@@ -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,6 +1,6 @@ | |||
{ | |||
"name": "isleward_client", | |||
"version": "0.8.6", | |||
"version": "0.9.0", | |||
"description": "isleward", | |||
"dependencies": {}, | |||
"devDependencies": { | |||
@@ -0,0 +1 @@ | |||
.uiAnnouncements{pointer-events:none;position:absolute;left:0px;top:0px;width:100%;top:calc(50% + 92px)}.uiAnnouncements .list{position:relative;width:100%}.uiAnnouncements .list .message{position:absolute;height:36px;left:50%;transform:translateX(-50%);text-align:center;color:#f2f5f5;font-size:18px;background-color:rgba(49,33,54,0.15);padding:8px;text-shadow:2px 2px 0 #312136,-2px -2px 0 #312136,2px -2px 0 #312136,-2px 2px 0 #312136,2px 2px 0 #312136;animation:.5s ease-in-out infinite bounce}.uiAnnouncements .list .message.success{color:#80f643}.uiAnnouncements .list .message.failure{color:#d43346}@keyframes bounce{0%{top:0px}50%{top:4px}100%{top:0px}} |
@@ -0,0 +1 @@ | |||
.uiBuffs{position:absolute;left:16px;top:104px}.uiBuffs .icon{width:40px;height:40px;padding:4px;background-color:rgba(49,33,54,0.75);margin-right:16px;float:left}.uiBuffs .icon .inner{width:32px;height:32px;background:url('../../../images/statusIcons.png') 0 0}.mobile .uiBuffs{left:316px;top:10px} |
@@ -0,0 +1 @@ | |||
.uiCharacters{display:flex;flex-direction:column;align-items:center;position:absolute}.uiCharacters .logo{width:562px;height:200px;margin-bottom:60px}.uiCharacters .bottom{display:flex;height:300px}.uiCharacters .bottom .left,.uiCharacters .bottom .right{background-color:#3a3b4a;filter:drop-shadow(0 -2px 0 #2d2136) drop-shadow(0 2px 0 #2d2136) drop-shadow(2px 0 0 #2d2136) drop-shadow(-2px 0 0 #2d2136)}.uiCharacters .bottom .left{width:400px;overflow-y:auto}.uiCharacters .bottom .left .character{height:50px;width:100%;color:#f2f5f5;cursor:pointer;display:flex;justify-content:center;align-items:center}.uiCharacters .bottom .left .character:hover{background-color:#505360}.uiCharacters .bottom .left .character.selected{background-color:#69696e}.uiCharacters .bottom .right{width:400px;padding:10px;margin-left:30px;display:flex;flex-direction:column}.uiCharacters .bottom .right .portrait{height:205px;background-color:#2d2136;display:flex;justify-content:center;align-items:center}.uiCharacters .bottom .right .portrait .sprite{width:8px;height:8px;transform-origin:50% 50%;transform:scale(16);image-rendering:pixelated;image-rendering:optimizeSpeed;image-rendering:crisp-edges;display:none}.uiCharacters .bottom .right .info{height:30px;margin-bottom:10px;background-color:#2d2136;color:#f2f5f5;display:flex;justify-content:space-between;padding:0px 10px}.uiCharacters .bottom .right .info .name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.uiCharacters .bottom .right .info .class{text-align:right;color:#aabebe}.uiCharacters .bottom .right .buttons{display:flex}.uiCharacters .bottom .right .buttons .btn{background-color:#3a71ba;width:calc((100% - (10px * 2)) / 3);float:left;margin-right:10px;color:#f2f5f5}.uiCharacters .bottom .right .buttons .btn:last-child{margin-right:0px}.uiCharacters .bottom .right .buttons .btn:hover{background-color:#42548d}.uiCharacters .bottom .right .buttons .btn.deleting{background-color:#d43346;color:#f2f5f5}.uiCharacters .message{height:30px;width:100%;margin-top:30px;float:left;text-align:center;color:#f2f5f5;filter:drop-shadow(0 -2px 0 #312136) drop-shadow(0 2px 0 #312136) drop-shadow(2px 0 0 #312136) drop-shadow(-2px 0 0 #312136)}.mobile .uiCharacters{height:300px}.mobile .uiCharacters .logo{display:none} |
@@ -0,0 +1 @@ | |||
.uiContext{display:none;position:absolute;z-index:999999;border:5px solid #42548d;background-color:rgba(49,33,54,0.95);padding:5px;color:#f2f5f5;text-align:center;line-height:15px}.uiContext .list{width:100%;height:100%}.uiContext .list .option{width:100%;padding:5px;color:#f2f5f5;cursor:pointer;display:flex;justify-content:center}.uiContext .list .option:hover:not(.no-hover){background-color:#3a71ba}.uiContext .list .option.divider{line-height:2px;padding:0px;margin:5px 0px;color:transparent;background-color:#69696e}.uiContext .list .option.no-hover:not(.divider){color:#929398}.uiContext .list .option .hotkey{color:#48edff}.uiContext .list .option .hotkey:not(:empty){margin-left:10px} |
@@ -0,0 +1 @@ | |||
.uiCreateCharacter{width:1040px;height:584px}.uiCreateCharacter .logo{width:562px;height:200px;margin-left:240.5px;margin-bottom:54px}.uiCreateCharacter .box-left{float:left;height:276px;width:613px;background-color:#3a3b4a}.uiCreateCharacter .box-left .left,.uiCreateCharacter .box-left .right{float:left;height:100%}.uiCreateCharacter .box-left .left{width:calc(100% - (27px * 2) - 160px);padding:27px 0 27px 27px}.uiCreateCharacter .box-left .left .txtClass,.uiCreateCharacter .box-left .left .txtCostume{cursor:pointer;-webkit-user-select:none}.uiCreateCharacter .box-left .left .txtClass:active,.uiCreateCharacter .box-left .left .txtCostume:active{background-color:#0f1013}.uiCreateCharacter .box-left .left .label{color:#c0c3cf;text-align:center;margin-bottom:8.3px}.uiCreateCharacter .box-left .left .skinBox{display:flex;flex-direction:row;height:35px}.uiCreateCharacter .box-left .left .skinBox .btn{width:35px;margin:0px;flex-shrink:0;height:100%;display:flex;justify-content:center;align-items:center;padding:0px;background-color:#69696e}.uiCreateCharacter .box-left .left .skinBox .btn:first-child{margin-right:10px}.uiCreateCharacter .box-left .left .skinBox .btn:last-child{margin-left:10px}.uiCreateCharacter .box-left .left .skinBox .btn:hover{background-color:#929398}.uiCreateCharacter .box-left .left .skinBox .txtCostume{height:100%;display:flex;justify-content:center;align-items:center;padding:0px}.uiCreateCharacter .box-left .right{width:calc(160px + (27px * 2));padding:27px 27px 27px 27px}.uiCreateCharacter .box-left .portrait{width:100%;height:160px;background-color:#2d2136;padding:16px 0 0 16px;margin-bottom:27px}.uiCreateCharacter .box-left .portrait .sprite{width:8px;height:8px;transform:scale(16);transform-origin:0% 0%;image-rendering:optimizeSpeed;image-rendering:pixelated;image-rendering:crisp-edges}.uiCreateCharacter .box-left .textbox{width:100%;background-color:#1a1c21;border:3px solid #757b92;color:#f2f5f5;margin-bottom:22px}.uiCreateCharacter .box-left .btn{background-color:#3a71ba;width:calc((100% - 27px) / 2);float:left;margin-right:27px;color:#f2f5f5}.uiCreateCharacter .box-left .btn:last-child{margin-right:0px}.uiCreateCharacter .box-left .btn:hover{background-color:#3fa7dd}.uiCreateCharacter .box-left .message{height:27px;width:100%;margin-top:27px;float:left;text-align:center;color:#ff4252}.uiCreateCharacter .box-right{padding:27px 27px 27px 27px;float:left;height:276px;width:400px;margin-left:13px;background-color:#3a3b4a}.uiCreateCharacter .box-right .top{width:100%;color:#f2f5f5}.uiCreateCharacter .box-right .top>*{width:100%;text-align:center}.uiCreateCharacter .box-right .top .heading{margin-bottom:27px;color:#48edff}.uiCreateCharacter .box-right .top .list .prophecy{padding-top:0px;width:50%;float:left;height:24px;margin-bottom:24px;color:#ff4252;cursor:pointer}.uiCreateCharacter .box-right .top .list .prophecy:after{content:' ✗'}.uiCreateCharacter .box-right .top .list .prophecy.active{color:#80f643}.uiCreateCharacter .box-right .top .list .prophecy.active:after{content:' ✔'}.uiCreateCharacter .box-right .top .list .prophecy.disabled{color:#f2f5f5}.uiCreateCharacter .box-right .top .list .prophecy:hover{color:#f2f5f5}.mobile .uiCreateCharacter{height:276px;width:calc(1040px - 80px);display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center}.mobile .uiCreateCharacter .logo{display:none}.mobile .uiCreateCharacter .box-left{width:45%}.mobile .uiCreateCharacter .box-left .skinBox{height:35px}.mobile .uiCreateCharacter .box-right{width:45%} |
@@ -0,0 +1 @@ | |||
.uiDeath{display:none;width:400px;background-color:#3c3f4c;border:4px solid #929398;text-align:center;padding:16px 16px 0px 16px}.uiDeath .msg{color:#f2f5f5}.uiDeath .msg .inner{display:inline-block;color:#ff6942}.uiDeath .penalty{color:#faac45;margin-top:15px}.uiDeath .btn{color:#f2f5f5;width:100%;height:32px;background-color:#3fa7dd;margin:16px 0px;padding-top:8px;cursor:pointer}.uiDeath .btn:hover{background-color:#80c5e9;color:#2d2136}.uiDeath.permadeath .buttons .btn-respawn{display:none}.uiDeath.permadeath .buttons .btn-logout{display:block}.uiDeath .buttons .btn-logout{display:none} |
@@ -0,0 +1 @@ | |||
.uiDialogue{position:absolute;bottom:16px;width:calc(320px + (8px * 2));padding:8px;background-color:rgba(55,48,65,0.9);display:none;box-shadow:0 -2px 0 #2d2136,0 2px 0 #2d2136,2px 0 0 #2d2136,-2px 0 0 #2d2136}.uiDialogue .portraitBox{float:left;margin-right:12px;display:none}.uiDialogue .portraitBox .portrait{width:64px;height:64px}.uiDialogue .textBox{width:calc(100%);float:left;height:100%;color:#f2f5f5;text-align:center;filter:drop-shadow(0 -2px 0 #312136) drop-shadow(0 2px 0 #312136) drop-shadow(2px 0 0 #312136) drop-shadow(-2px 0 0 #312136)} |
@@ -0,0 +1 @@ | |||
.uiEvents{margin-top:10px;width:326px;box-shadow:0 -2px 0 #2d2136,0 2px 0 #2d2136,2px 0 0 #2d2136,-2px 0 0 #2d2136}.uiEvents .heading{color:#ffeb38;padding:8px;background-color:rgba(58,59,74,0.9)}.uiEvents .list .event{cursor:pointer;padding:8px;background-color:rgba(58,59,74,0.9)}.uiEvents .list .event:hover{background-color:rgba(92,93,117,0.9)}.uiEvents .list .event .name{color:#f2f5f5;margin-bottom:3px}.uiEvents .list .event .description{color:#8da7a7}.uiEvents .list .event.active .name{color:#3fa7dd}.uiEvents .list .event.ready .name{color:#80f643}.uiEvents .list .event.ready .description{display:none}.uiEvents .btnCollapse{display:none}.mobile .uiEvents{background-color:rgba(55,48,65,0.9);margin-top:0px}.mobile .uiEvents:not(.active){width:64px;height:64px}.mobile .uiEvents:not(.active):after{content:'';position:absolute;left:0px;top:0px;background:url('../../../images/uiIcons.png');background-position:-128px -128px;width:64px;height:64px}.mobile .uiEvents:not(.active)>*{display:none}.mobile .uiEvents.active{z-index:3;position:absolute;right:0px;top:0px}.mobile .uiEvents.active .btn{display:block;position:absolute;right:calc(100% + 10px);top:0px;background-color:rgba(55,48,65,0.9);width:64px;height:64px;padding-top:0px}.mobile .uiEvents.active .btn .icon{width:100%;height:100%;background:url('../../../images/uiIcons.png') -448px 0} |
@@ -0,0 +1 @@ | |||
.uiHelp{display:none;z-index:2;border:5px solid #3c3f4c;text-align:center;flex-direction:column}.uiHelp>.heading{color:#48edff;width:100%;height:36px;background-color:#3c3f4c;position:relative}.uiHelp>.heading .heading-text{padding-top:8px;margin:auto}.uiHelp .content{overflow-y:auto;background-color:#312136;width:100%;flex:1;display:flex;flex-direction:column;padding:5px}.uiHelp .content .row{padding:5px;display:flex;justify-content:center;background-color:#373041}.uiHelp .content .row+.row{margin-top:5px}.uiHelp .content .row.mobile{display:none}.uiHelp .content .row .topic{color:#3fa7dd;text-align:right;width:30%}.uiHelp .content .row .desc{color:#c0c3cf;text-align:left;width:70%;max-width:400px;padding-left:20px}.uiHelp .content .row .toslink{color:#f2f5f5;cursor:pointer}.uiHelp .content .row .toslink:hover{color:#48edff}.mobile .uiHelp{height:80vh}.mobile .uiHelp .row{display:none}.mobile .uiHelp .row.mobile{display:flex} |
@@ -0,0 +1 @@ | |||
.uiHud{position:absolute;left:10px;top:10px}.uiHud .hudBox{position:absolute;left:0px;top:0px;width:calc(280px + (8px * 2));padding:8px;background-color:rgba(58,59,74,0.9);box-shadow:0 -2px 0 #2d2136,0 2px 0 #2d2136,2px 0 0 #2d2136,-2px 0 0 #2d2136}.uiHud .hudBox .portraitBox{float:left;margin-right:12px}.uiHud .hudBox .portraitBox .portrait{visibility:hidden;width:64px;height:64px}.uiHud .hudBox .boxes{width:calc(100% - 76px);float:left;height:100%}.uiHud .hudBox .boxes .statBox{width:100%;height:18px;margin-bottom:5px;position:relative}.uiHud .hudBox .boxes .statBox:last-child{margin-bottom:0px}.uiHud .hudBox .boxes .statBox [class^="stat"]{position:absolute;left:0px;top:0px;height:100%}.uiHud .hudBox .boxes .statBox .statManaReserve{position:absolute;right:0%;top:0px;left:auto;height:100%;background-color:#c0c3cf}.uiHud .hudBox .boxes .statBox .text{position:absolute;left:0px;top:0px;width:100%;height:100%;text-align:center;color:#f2f5f5;padding:2px 0px;line-height:16px;text-shadow:2px 0 #2d2136,-2px 0 #2d2136,0 -2px #2d2136,0 2px #2d2136,-2px -2px #2d2136,-2px 2px #2d2136,2px -2px #2d2136,2px 2px #2d2136}.uiHud .hudBox .boxes .statBox:nth-child(1){background-color:#802343}.uiHud .hudBox .boxes .statBox:nth-child(2){background-color:#42548d}.uiHud .hudBox .boxes .statBox:nth-child(3){background-color:#386646}.uiHud .hudBox .boxes .statBox .statHp{background-color:#d43346}.uiHud .hudBox .boxes .statBox .statMana{background-color:#3fa7dd}.uiHud .hudBox .boxes .statBox .statXp{background-color:#4ac441}.uiHud .quickBar{position:absolute;left:calc(290px + (8px * 2));top:0px;box-shadow:0 -2px 0 #2d2136,0 2px 0 #2d2136,2px 0 0 #2d2136,-2px 0 0 #2d2136}.uiHud .quickBar .quickItem{display:none;width:80px;height:80px;background-color:rgba(58,59,74,0.9);margin-bottom:8px;cursor:pointer;padding:8px;position:relative}.uiHud .quickBar .quickItem .icon{height:100%;filter:brightness(100%) drop-shadow(0 -4px 0 #373041) drop-shadow(0 4px 0 #373041) drop-shadow(4px 0 0 #373041) drop-shadow(-4px 0 0 #373041)}.uiHud .quickBar .quickItem .info{left:6px;bottom:3px;position:absolute;color:#f2f5f5;filter:drop-shadow(0 -2px 0 #312136) drop-shadow(0 2px 0 #312136) drop-shadow(2px 0 0 #312136) drop-shadow(-2px 0 0 #312136);-moz-filter:drop-shadow(0 -2px 0 #312136) drop-shadow(0 2px 0 #312136) drop-shadow(2px 0 0 #312136) drop-shadow(-2px 0 0 #312136)}.uiHud .quickBar .quickItem:hover .icon{filter:brightness(160%);-moz-filter:brightness(160%)}.uiHud .quickBar .quickItem:hover.empty{background-color:rgba(72,237,255,0.1)} |
@@ -168,6 +168,7 @@ define([ | |||
this.dragItem = el; | |||
events.emit('onHideItemTooltip', this.hoverItem); | |||
events.emit('onStartMoveItem', this.dragItem.data('item')); | |||
this.hoverItem = null; | |||
} else if (this.dragItem) { | |||
let method = 'moveItem'; | |||
@@ -219,6 +220,8 @@ define([ | |||
} | |||
}); | |||
events.emit('onStopMoveItem', this.dragItem.data('item')); | |||
this.build(); | |||
} | |||
@@ -0,0 +1 @@ | |||
.uiLeaderboard{display:none;width:600px;height:410px;border:5px solid rgba(60,63,76,0.9);text-align:center}.uiLeaderboard>.heading{color:#48edff;width:100%;height:36px;background-color:rgba(60,63,76,0.9)}.uiLeaderboard>.heading .heading-text{padding-top:8px;margin:auto}.uiLeaderboard .result{background-color:rgba(55,48,65,0.9);float:left;width:400px;height:calc(100% - 36px);padding:5px}.uiLeaderboard .result .headings{width:100%;height:36px}.uiLeaderboard .result .headings .col{text-align:left;padding:5px 10px;width:50%;float:left;color:#f2f5f5}.uiLeaderboard .result .list{height:calc(100% - 26px - 36px)}.uiLeaderboard .result .list .row{width:100%;height:26px}.uiLeaderboard .result .list .row.self .col{color:#80f643}.uiLeaderboard .result .list .row.online .col{color:#4ac441}.uiLeaderboard .result .list .row .col{padding:5px 10px;float:left;text-align:left;width:50%;color:#c0c3cf;height:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.uiLeaderboard .result .buttons{width:calc(100% - 26px);height:26px}.uiLeaderboard .result .buttons .btn{width:calc((100% - (13px * 3)) / 4);margin-right:13px;float:left;height:100%;color:#f2f5f5;cursor:pointer;background-color:#7a3ad3}.uiLeaderboard .result .buttons .btn:hover{background-color:#a24eff}.uiLeaderboard .result .buttons .btn:last-child{margin-right:0px}.uiLeaderboard .prophecies{float:left;width:calc(100% - 400px);height:calc(100% - 36px);position:relative;background-color:rgba(55,48,65,0.9);padding:5px}.uiLeaderboard .prophecies .heading{width:100%;height:36px;color:#3fa7dd}.uiLeaderboard .prophecies .heading .heading-text{margin:auto}.uiLeaderboard .prophecies .prophecy,.uiLeaderboard .prophecies .btn{cursor:pointer}.uiLeaderboard .prophecies .prophecy{width:100%;padding:5px 10px;background-color:#69696e;color:#f2f5f5;margin-bottom:12px}.uiLeaderboard .prophecies .prophecy.selected{color:#80f643}.uiLeaderboard .prophecies .prophecy:hover{background-color:#929398}.uiLeaderboard .prophecies .prophecy.prophecy-mine,.uiLeaderboard .prophecies .prophecy.prophecy-none{background-color:#929398}.uiLeaderboard .prophecies .prophecy.prophecy-mine:hover,.uiLeaderboard .prophecies .prophecy.prophecy-none:hover{background-color:#c0c3cf}.uiLeaderboard .prophecies .btn-refresh{width:calc(100% - 10px);background-color:#3a71ba;padding:5px 10px;position:absolute;bottom:5px;color:#f2f5f5}.uiLeaderboard .prophecies .btn-refresh:hover{background-color:#3fa7dd}.mobile .uiLeaderboard{z-index:2} |
@@ -0,0 +1 @@ | |||
.uiLogin{display:none;width:562px;height:475px;margin-top:-80px;display:flex;flex-direction:column;align-items:center}.uiLogin>*{flex-shrink:0}.uiLogin .logo{width:562px;height:200px;margin-bottom:48px;filter:drop-shadow(0 -4px 0 #312136) drop-shadow(0 4px 0 #312136) drop-shadow(4px 0 0 #312136) drop-shadow(-4px 0 0 #312136)}.uiLogin .right{height:169px;background-color:#3a3b4a;width:400px;padding:16px}.uiLogin .right .label,.uiLogin .right input{float:left}.uiLogin .right .label{width:30%;padding-top:10px;color:#80f643}.uiLogin .right input{width:70%}.uiLogin .right input,.uiLogin .right .textbox,.uiLogin .right input:-webkit-autofill{-webkit-appearance:none;box-shadow:0 0 0 20px #1a1c21 inset;color:#f2f5f5;-webkit-text-fill-color:#f2f5f5;margin-bottom:16px}.uiLogin .right input,.uiLogin .right .textbox{-webkit-appearance:none;box-shadow:0 0 0 20px #1a1c21 inset;color:#f2f5f5;-webkit-text-fill-color:#f2f5f5;margin-bottom:16px}.uiLogin .right .message{height:16px;width:200%;margin-left:-50%;margin-top:36px;float:left;text-align:center;color:#ff6942;filter:brightness(100%) drop-shadow(0 -4px 0 #312136) drop-shadow(0 4px 0 #312136) drop-shadow(4px 0 0 #312136) drop-shadow(-4px 0 0 #312136);-moz-filter:brightness(100%) drop-shadow(0 -4px 0 #312136) drop-shadow(0 4px 0 #312136) drop-shadow(4px 0 0 #312136) drop-shadow(-4px 0 0 #312136)}.uiLogin .right .top-buttons{width:100%;height:35px}.uiLogin .right .top-buttons .btn{background-color:#3a71ba;width:calc((100% - 16px) / 2);float:left;margin-right:16px;color:#f2f5f5}.uiLogin .right .top-buttons .btn:last-child{margin-right:0px}.uiLogin .right .top-buttons .btn:hover{background-color:#42548d}.uiLogin .news{margin-top:40px;color:#f2f5f5;text-align:center;cursor:pointer;filter:drop-shadow(0 -4px 0 #312136) drop-shadow(0 4px 0 #312136) drop-shadow(4px 0 0 #312136) drop-shadow(-4px 0 0 #312136)}.uiLogin .spacer-h{height:61px}.uiLoginExtra .extra{position:absolute;left:50%;bottom:10px;transform:translateX(-50%);display:flex}.uiLoginExtra .extra .btn{width:180px;padding-left:10px;padding-right:10px;background-color:#b15a30;color:#f2f5f5;filter:drop-shadow(0 -2px 0 #2d2136) drop-shadow(0 2px 0 #2d2136) drop-shadow(2px 0 0 #2d2136) drop-shadow(-2px 0 0 #2d2136)}.uiLoginExtra .extra .btn+.btn{margin-left:20px}.uiLoginExtra .extra .btn:hover{background-color:#763b3b}.uiLoginExtra .version{position:absolute;right:10px;bottom:10px;color:#ffeb38;cursor:pointer;filter:brightness(100%) drop-shadow(0 -4px 0 #312136) drop-shadow(0 4px 0 #312136) drop-shadow(4px 0 0 #312136) drop-shadow(-4px 0 0 #312136);-moz-filter:brightness(100%) drop-shadow(0 -4px 0 #312136) drop-shadow(0 4px 0 #312136) drop-shadow(4px 0 0 #312136) drop-shadow(-4px 0 0 #312136)}.mobile .uiLogin{margin-top:0px}.mobile .uiLogin .logo{margin-bottom:30px}.mobile .uiLogin .news{margin-top:20px} |
@@ -11,11 +11,11 @@ | |||
</div> | |||
<div class="message"></div> | |||
</div> | |||
<div class="news" location="https://gitlab.com/Isleward/play.isleward.com/-/wikis/v0.8.6-Release-Notes">[ Latest Release Notes ]</div> | |||
<div class="news" location="https://gitlab.com/Isleward/play.isleward.com/-/wikis/v0.9.0-Release-Notes">[ Latest Release Notes ]</div> | |||
<div class="extra"> | |||
<div class="el btn btnPatreon monetization" location="https://patreon.com/bigbadwaffle">Pledge on Patreon</div> | |||
<div class="el btn btnPaypal monetization" location="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=BR2CC82WUAVEA">Donate on Paypal</div> | |||
<div class="el btn btnWiki" location="http://wiki.isleward.com/Main_Page">Access the Wiki</div> | |||
</div> | |||
<div class="version" location="https://gitlab.com/Isleward/play.isleward.com/-/wikis/v0.8.6-Release-Notes">v0.8.6</div> | |||
<div class="version" location="https://gitlab.com/Isleward/play.isleward.com/-/wikis/v0.9.0-Release-Notes">v0.9.0</div> | |||
</div> |
@@ -0,0 +1 @@ | |||
.uiMainMenu{display:none;background-color:#373041;border:5px solid #3c3f4c;text-align:center}.uiMainMenu>.heading{color:#48edff;width:100%;height:36px;background-color:#3c3f4c;position:relative}.uiMainMenu>.heading .heading-text{padding-top:8px;margin:auto}.uiMainMenu .options{display:flex;flex-direction:column;padding:10px}.uiMainMenu .options .btn{color:#f2f5f5;width:100%;height:35px;background-color:#3a71ba;cursor:pointer;padding:0px 20px}.uiMainMenu .options .btn+.btn{margin-top:10px}.uiMainMenu .options .btn.btnNames{display:none}.uiMainMenu .options .btn:hover{background-color:#42548d}.uiMainMenu .options .btn.btn-red{background-color:#a82841}.uiMainMenu .options .btn.btn-red:hover{background-color:#802343}.uiMainMenu .options .btn.btn-orange{background-color:#b34b3a}.uiMainMenu .options .btn.btn-orange:hover{background-color:#953f36}.uiMainMenu .options .btnIssue{background-color:#a82841}.uiMainMenu .options .btnIssue:hover{background-color:#802343}.mobile .uiMainMenu .btnScreen{display:none}.mobile .uiMainMenu .btnNames{display:block} |
@@ -0,0 +1 @@ | |||
.uiMenu{position:absolute;right:10px;bottom:10px;width:336px;height:144px;padding:8px;background-color:rgba(55,48,65,0.9)}.uiMenu [class^="btn"]{width:64px;height:64px;margin:0 8px;float:left;cursor:pointer;position:relative}.uiMenu [class^="btn"]:hover{background-color:rgba(242,245,245,0.1)}.uiMenu [class^="btn"] .icon{pointer-events:none;position:absolute;left:0px;top:0px;width:100%;height:100%}.uiMenu [class^="btn"].btnCollapse{display:none}.uiMenu [class^="btn"].btnInventory .icon{background:url('../../../images/uiIcons.png') 0 0}.uiMenu [class^="btn"].btnEquipment .icon{background:url('../../../images/uiIcons.png') -192px 0}.uiMenu [class^="btn"].btnSmithing .icon{background:url('../../../images/uiIcons.png') -128px -64px}.uiMenu [class^="btn"].btnPassives{position:relative}.uiMenu [class^="btn"].btnPassives .points{width:100%;text-align:center;left:0px;bottom:23px;position:absolute;color:#f2f5f5;filter:drop-shadow(0 -2px 0 #312136) drop-shadow(0 2px 0 #312136) drop-shadow(2px 0 0 #312136) drop-shadow(-2px 0 0 #312136)}.uiMenu [class^="btn"].btnPassives .icon{background:url('../../../images/uiIcons.png') -320px -64px}.uiMenu [class^="btn"].btnOnline .icon{background:url('../../../images/uiIcons.png') -64px 0}.uiMenu [class^="btn"].btnHelp .icon{background:url('../../../images/uiIcons.png') -128px 0}.uiMenu [class^="btn"].btnLeaderboard .icon{background:url('../../../images/uiIcons.png') -256px 0}.uiMenu [class^="btn"].btnReputation .icon{background:url('../../../images/uiIcons.png') -320px 0}.uiMenu [class^="btn"].btnMainMenu .icon{background:url('../../../images/uiIcons.png') 0 -64px}.mobile .uiMenu{bottom:auto;top:10px;right:10px;width:64px;height:64px}.mobile .uiMenu:after{content:'';position:absolute;left:0px;top:0px;background:url('../../../images/uiIcons.png');background-position:0 -64px;width:64px;height:64px}.mobile .uiMenu>*{display:none}.mobile .uiMenu.active{display:flex;flex-direction:column;height:calc(100% - 20px);width:200px;z-index:2;flex-wrap:wrap-reverse;align-items:center;justify-content:center}.mobile .uiMenu.active:after{display:none}.mobile .uiMenu.active>*{display:block;margin:0px}.mobile .uiMenu.active .btnCollapse{display:block;position:absolute;right:calc(100% + 10px);top:50%;transform:translateY(-50%);background-color:rgba(55,48,65,0.9);width:64px;height:64px}.mobile .uiMenu.active .btnCollapse .icon{width:100%;height:100%;background:url('../../../images/uiIcons.png') -448px 0} |
@@ -0,0 +1 @@ | |||
.uiMiddleHud{position:absolute;left:calc(50% - 12px);top:calc(50% + 31px)}.uiMiddleHud .btnGather{display:none;background-color:rgba(58,59,74,0.9);padding:8px 10px 8px 10px;width:120px;margin-top:8px;margin-left:calc(12px - 60px);text-align:center;position:absolute;left:calc(50vw - 88px);top:calc(50vh - 113px);width:64px;height:64px}.uiMiddleHud .btnGather .icon{position:absolute;left:0px;top:0px;width:100%;height:100%;background:url(../../../images/uiIcons.png) -448px -64px}.uiMiddleHud .casting{display:none;width:32px;height:5px;position:relative;background-color:#763b3b}.uiMiddleHud .casting .bar{width:0%;height:100%;background-color:#faac45}.uiMiddleHud .casting .text{position:absolute;left:0px;top:0px;padding-top:2px;width:100%;text-align:center;color:#2d2136} |
@@ -0,0 +1 @@ | |||
.uiOnline{display:none;background-color:#3c3f4c;border:5px solid #3c3f4c;text-align:center;width:450px;height:396px}.uiOnline>.heading{color:#48edff;width:100%;height:36px;background-color:#3c3f4c}.uiOnline>.heading .heading-text{padding-top:8px;margin:auto}.uiOnline .bottom{height:calc(100% - 36px);background-color:#373041;padding:8px}.uiOnline .bottom .list{width:100%;height:100%;overflow-y:auto;background-color:#373041;display:flex;flex-direction:column}.uiOnline .bottom .list .heading{height:24px;color:#f2f5f5}.uiOnline .bottom .list .heading>div{float:left;padding:4px;height:24px}.uiOnline .bottom .list .heading>div:nth-child(1){width:10%}.uiOnline .bottom .list .heading>div:nth-child(2){width:55%}.uiOnline .bottom .list .heading>div:nth-child(3){width:35%}.uiOnline .bottom .list .onlineUser{color:#929398;height:24px;cursor:pointer}.uiOnline .bottom .list .onlineUser>div{float:left;padding:4px;height:24px}.uiOnline .bottom .list .onlineUser>div:nth-child(1){width:10%}.uiOnline .bottom .list .onlineUser>div:nth-child(2){width:55%}.uiOnline .bottom .list .onlineUser>div:nth-child(3){width:35%}.uiOnline .bottom .list .onlineUser:hover{background-color:#75668a}.mobile .uiOnline{z-index:2} |
@@ -0,0 +1 @@ | |||
.uiOptions{display:none;width:400px;background-color:#373041;border:5px solid #3c3f4c;flex-direction:column}.uiOptions>.heading{color:#48edff;width:100%;height:36px;background-color:#3c3f4c;position:relative;text-align:center}.uiOptions>.heading .heading-text{padding-top:8px;margin:auto}.uiOptions .bottom{padding:10px;height:100%;overflow-y:auto}.uiOptions .bottom .list{display:flex;flex-direction:column}.uiOptions .bottom .list .heading{color:#929398;border-bottom:2px solid #69696e;margin:0px 10px 5px 10px;padding-bottom:5px}.uiOptions .bottom .list .heading:not(:first-child){margin:10px 10px 5px 10px}.uiOptions .bottom .list .item{height:30px;display:flex;justify-content:space-between;align-items:center}.uiOptions .bottom .list .item .name{color:#3fa7dd;flex:1;height:100%;display:flex;align-items:center;padding:0px 10px;margin-right:10px;cursor:pointer}.uiOptions .bottom .list .item .name:hover{color:#48edff;background-color:#505360}.uiOptions .bottom .list .item .value{color:#f2f5f5;display:flex;align-items:center;justify-content:flex-end;padding-right:10px}.uiOptions .bottom .list .item.volume{flex-wrap:wrap;height:60px}.uiOptions .bottom .list .item.volume .name{pointer-events:none}.uiOptions .bottom .list .item.volume .name,.uiOptions .bottom .list .item.volume .value{width:50%;height:30px}.uiOptions .bottom .list .item.volume .slider{padding:0px 10px;width:100%;height:30px;display:flex;position:relative}.uiOptions .bottom .list .item.volume .slider .btn{width:30px;margin-top:5px;height:calc(100% - 10px);display:flex;justify-content:center;align-items:center;color:#f2f5f5;background-color:#505360;padding-top:unset}.uiOptions .bottom .list .item.volume .slider .btn:first-child{margin-right:10px}.uiOptions .bottom .list .item.volume .slider .btn:last-child{margin-left:10px}.uiOptions .bottom .list .item.volume .slider .btn:hover{background-color:#69696e}.uiOptions .bottom .list .item.volume .slider .bar{width:100%;background-color:#42548d;border-top:10px solid #373041;border-bottom:10px solid #373041;height:100%;position:relative}.uiOptions .bottom .list .item.volume .slider .bar .tick{position:absolute;width:5px;height:20px;top:-5px;left:100%;background-color:#48edff}.mobile .uiOptions{max-height:100%}.mobile .uiOptions .item.screen{display:none} |
@@ -0,0 +1 @@ | |||
.uiOverlay{display:none;position:absolute;left:0px;top:0px;background-color:rgba(60,63,76,0.55);width:100%;height:100%;z-index:99999} |
@@ -0,0 +1 @@ | |||
.uiParty .party{position:absolute;left:16px;top:154px}.uiParty .party .list{overflow-y:auto;max-height:calc(100vh - 591px);padding-right:22px}.uiParty .party .list .member{width:160px;background-color:#3a3b4a;color:#f2f5f5;cursor:pointer}.uiParty .party .list .member+.member{margin-top:5px}.uiParty .party .list .member.differentZone{opacity:.4}.uiParty .party .list .member.differentZone .statBox [class^="stat"]{width:0% !important}.uiParty .party .list .member:last-child{margin-bottom:0px}.uiParty .party .list .member .statBox{width:100%;height:20px;background-color:#3c3f4c;position:relative;display:flex;justify-content:center;align-items:center}.uiParty .party .list .member .statBox+.statBox{border-top:2px solid #2d2136}.uiParty .party .list .member .statBox [class^="stat"]{position:absolute;left:0px;top:0px;height:100%}.uiParty .party .list .member .statBox .text{color:#f2f5f5;z-index:1;padding:0px 2px;overflow:hidden;text-overflow:ellipsis;text-shadow:2px 0 #2d2136,-2px 0 #2d2136,0 -2px #2d2136,0 2px #2d2136,-2px -2px #2d2136,-2px 2px #2d2136,2px -2px #2d2136,2px 2px #2d2136}.uiParty .party .list .member .statBox:nth-child(1){background-color:#802343}.uiParty .party .list .member .statBox:nth-child(2){background-color:#42548d}.uiParty .party .list .member .statBox .statHp{background-color:#d43346}.uiParty .party .list .member .statBox .statMana{background-color:#3fa7dd}.uiParty .invite{position:absolute;right:436px;bottom:10px;background-color:rgba(55,48,65,0.9);padding:10px;color:#f2f5f5;display:flex;flex-direction:column}.uiParty .invite>.text{margin-bottom:15px;text-align:center;display:flex;flex-direction:column}.uiParty .invite>.text .name{margin-top:10px}.uiParty .invite .buttons{display:flex}.uiParty .invite .buttons .btn{width:100%;background-color:#505360;text-align:center;padding:10px;cursor:pointer;display:flex;justify-content:center;align-items:center}.uiParty .invite .buttons .btn .text{pointer-events:none;color:#f2f5f5;text-shadow:2px 0 #2d2136,-2px 0 #2d2136,0 -2px #2d2136,0 2px #2d2136,-2px -2px #2d2136,-2px 2px #2d2136,2px -2px #2d2136,2px 2px #2d2136}.uiParty .invite .buttons .btn+.btn{margin-left:10px}.uiParty .invite .buttons .btn.btnDecline{background-color:#d43346}.uiParty .invite .buttons .btn.btnDecline:hover{background-color:#a82841}.uiParty .invite .buttons .btn.btnAccept{background-color:#3f8d6d}.uiParty .invite .buttons .btn.btnAccept:hover{background-color:#386646}.uiParty.full .party .list .member{padding:5px;background-color:rgba(55,48,65,0.9)}.uiParty.minimal .party .list .statBox:nth-child(2){display:none}.mobile .uiParty .list{max-height:calc(100% - 154px - 10px)} |
@@ -206,4 +206,4 @@ | |||
.mobile .uiParty .list { | |||
max-height: calc(100% - @topPosition - 10px); | |||
} | |||
} |
@@ -0,0 +1 @@ | |||
.uiPassives{display:none;z-index:3;border:5px solid #3c3f4c;text-align:center;height:100%;width:100%;position:absolute;left:0px;top:0px}.uiPassives>.heading{color:#f2f5f5;width:100%;height:36px;background-color:#3c3f4c}.uiPassives>.heading .heading-text{padding-top:8px;margin:auto}.uiPassives .bottom{height:calc(100% - 36px - 36px);background-color:#373041}.uiPassives .bottom .btn.btnReset{position:absolute;height:35px;padding-left:10px;padding-right:10px;bottom:46px;right:10px;background-color:#a82841;color:#f2f5f5;cursor:pointer}.uiPassives .bottom .btn.btnReset:hover{background-color:#d43346}.uiPassives .bottom .canvas{width:calc(100vw - 10px)}.uiPassives .status{width:100%;height:36px;background-color:#3c3f4c}.uiPassives .status .points{padding-top:8px;margin:auto;color:#48edff} |
@@ -0,0 +1 @@ | |||
.uiProgressBar{pointer-events:none;position:absolute;left:0px;top:0px;width:192px;left:calc(50% - 96px);top:calc(50% + 142px)}.uiProgressBar .barContainer{width:100%;height:28px;background-color:#42548d;border:2px solid #312136}.uiProgressBar .barContainer .bar{background-color:#3fa7dd;height:100%}.uiProgressBar .barContainer .text{padding-top:7px;color:#f2f5f5;position:absolute;left:0px;top:0px;text-align:center;width:100%;height:100%;z-index:1;text-shadow:2px 0 #2d2136,-2px 0 #2d2136,0 -2px #2d2136,0 2px #2d2136,-2px -2px #2d2136,-2px 2px #2d2136,2px -2px #2d2136,2px 2px #2d2136} |
@@ -0,0 +1 @@ | |||
.uiQuests{width:326px;box-shadow:0 -2px 0 #2d2136,0 2px 0 #2d2136,2px 0 0 #2d2136,-2px 0 0 #2d2136}.uiQuests .heading{color:#ffeb38;padding:8px;background-color:rgba(58,59,74,0.9)}.uiQuests .list .quest{cursor:pointer;padding:8px;background-color:rgba(58,59,74,0.9)}.uiQuests .list .quest:hover{background-color:rgba(92,93,117,0.9)}.uiQuests .list .quest .zone{color:#69696e;margin-bottom:4px;text-align:right}.uiQuests .list .quest .name{color:#f2f5f5;margin-bottom:3px}.uiQuests .list .quest .description{color:#8da7a7}.uiQuests .list .quest.disabled .description{display:none}.uiQuests .list .quest .reward{display:none;color:#44cb95}.uiQuests .list .quest:hover>.description{display:none}.uiQuests .list .quest:hover>.reward{display:block}.uiQuests .list .quest .ready-text{display:none}.uiQuests .list .quest.active .name{color:#3fa7dd}.uiQuests .list .quest.ready .name{color:#80f643}.uiQuests .list .quest.ready .description{display:none}.uiQuests .list .quest.ready .reward{display:none}.uiQuests .list .quest.ready .ready-text{display:block;color:#f2f5f5}.uiQuests .btn{display:none}.uiQuests.minimal .quest.disabled{display:none}.mobile .uiQuests{background-color:rgba(55,48,65,0.9)}.mobile .uiQuests:not(.active){width:64px;height:64px;margin-left:10px;position:relative}.mobile .uiQuests:not(.active):after{content:'';position:absolute;left:0px;top:0px;background:url('../../../images/uiIcons.png');background-position:-64px -128px;width:64px;height:64px}.mobile .uiQuests:not(.active)>*{display:none}.mobile .uiQuests.active{z-index:3;position:absolute;right:0px;top:0px}.mobile .uiQuests.active .btn{display:block;position:absolute;right:calc(100% + 10px);top:0px;background-color:rgba(55,48,65,0.9);width:64px;height:64px;padding-top:0px}.mobile .uiQuests.active .btn .icon{width:100%;height:100%;background:url('../../../images/uiIcons.png') -448px 0} |
@@ -0,0 +1 @@ | |||
.uiReputation{display:none;width:600px;height:385px;border:5px solid rgba(60,63,76,0.9);text-align:center}.uiReputation>.heading{color:#48edff;width:100%;height:36px;background-color:rgba(60,63,76,0.9)}.uiReputation>.heading .heading-text{padding-top:8px;margin:auto}.uiReputation .list,.uiReputation .info{background-color:rgba(55,48,65,0.9);float:left;height:calc(100% - 36px)}.uiReputation .list{width:40%;padding:15px 15px 15px 15px}.uiReputation .list .faction{width:100%;padding:5px 10px;background-color:#69696e;color:#f2f5f5;margin-bottom:15px;cursor:pointer}.uiReputation .list .faction.selected{color:#80f643}.uiReputation .list .faction:hover{background-color:#929398}.uiReputation .info{width:60%;padding:15px 15px 15px 0px}.uiReputation .info .heading{width:100%;height:36px;color:#3fa7dd}.uiReputation .info .heading .heading-bottom{margin:auto}.uiReputation .info .description{color:#c0c3cf;height:calc(100% - 36px - 25px);text-align:justify}.uiReputation .info .bar-outer{width:100%;margin:auto;height:25px;position:relative}.uiReputation .info .bar-outer .back{width:100%;height:100%;background-color:#533399}.uiReputation .info .bar-outer .front{width:50%;height:100%;position:absolute;left:0px;top:0px;background-color:#7a3ad3}.uiReputation .info .bar-outer .tier{width:100%;height:100%;color:#f2f5f5;text-align:center;position:absolute;left:0px;top:5px;filter:drop-shadow(0 -2px 0 #312136) drop-shadow(0 2px 0 #312136) drop-shadow(2px 0 0 #312136) drop-shadow(-2px 0 0 #312136);-moz-filter:drop-shadow(0 -2px 0 #312136) drop-shadow(0 2px 0 #312136) drop-shadow(2px 0 0 #312136) drop-shadow(-2px 0 0 #312136)}.uiReputation .list:empty{display:none}.uiReputation .list:empty+.info{width:100%}.mobile .uiReputation{z-index:2} |
@@ -0,0 +1 @@ | |||
.uiSpells{position:absolute;right:10px;top:10px;height:72px;box-shadow:0 -2px 0 #2d2136,0 2px 0 #2d2136,2px 0 0 #2d2136,-2px 0 0 #2d2136}.uiSpells .spell{width:64px;height:64px;float:left;margin-left:10px;background-color:#2d2136;cursor:pointer;position:relative;box-sizing:content-box;border:5px solid rgba(58,59,74,0.9);transition-property:filter;transition-duration:.1s}.uiSpells .spell:first-child{margin-left:0px}.uiSpells .spell:hover{filter:brightness(160%);-moz-filter:brightness(160%)}.uiSpells .spell.active .hotkey{color:#80f643}.uiSpells .spell .icon{position:absolute;left:0px;top:0px;width:100%;height:100%}.uiSpells .spell .cooldown{position:absolute;left:0px;top:0px;width:0px;height:100%;background-color:rgba(212,51,70,0.75)}.uiSpells .spell .hotkey{position:absolute;left:-2px;bottom:-6px;color:#f2f5f5;font-size:18px;z-index:2;text-shadow:2px 2px 0 #2d2136,-2px -2px 0 #2d2136,2px -2px 0 #2d2136,-2px 2px 0 #2d2136,2px 2px 0 #2d2136}.uiSpells .spell .hotkey.no-mana{color:#d43346}.mobile .uiSpells{top:auto;bottom:10px;padding:0px;height:auto;background-color:transparent;display:flex;flex-direction:column-reverse}.mobile .uiSpells .spell{position:relative;margin:10px 0px 0px 0px;background-color:rgba(58,59,74,0.9);border:none}.mobile .uiSpells .spell .hotkey{display:none}.mobile .uiSpells .spell.active:before{content:'';width:5px;height:100%;left:-5px;top:0%;background-color:#4ac441;position:absolute} |
@@ -0,0 +1 @@ | |||
.uiStash.scrolls{width:834px}.uiStash.scrolls .grid{overflow-y:auto;width:825px}.uiStash .footer{color:#3fa7dd;background-color:#373041;padding-bottom:7px} |
@@ -0,0 +1 @@ | |||
.uiTalk{border:5px solid rgba(60,63,76,0.9);width:400px;display:none;text-align:center;position:absolute;top:10px}.uiTalk .source{padding:5px 5px;background-color:rgba(60,63,76,0.9)}.uiTalk .source .name{color:#48edff;margin-bottom:5px}.uiTalk .source .msg{color:#f2f5f5;line-height:22px}.uiTalk .options{padding:5px;background-color:rgba(55,48,65,0.9)}.uiTalk .options .option{color:#3fa7dd;padding:5px 5px;cursor:pointer;line-height:22px}.uiTalk .options .option:hover{color:#f2f5f5} |
@@ -0,0 +1 @@ | |||
.uiTarget{position:absolute;left:406px;top:10px;width:calc(200px + (8px * 2));padding:8px;background-color:rgba(58,59,74,0.9);display:none}.uiTarget .boxes{width:100%;float:left;height:100%}.uiTarget .boxes .infoBox{color:#f2f5f5;width:100%;height:18px;margin-bottom:5px;position:relative}.uiTarget .boxes .infoBox>*{float:left}.uiTarget .boxes .infoBox .infoName{width:70%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.uiTarget .boxes .infoBox .infoLevel{width:30%;text-align:right}.uiTarget .boxes .infoBox .infoLevel.high-level{text-shadow:2px 0 #d43346,-2px 0 #d43346,0 -2px #d43346,0 2px #d43346,-2px -2px #d43346,-2px 2px #d43346,2px -2px #d43346,2px 2px #d43346}.uiTarget .boxes .statBox{width:100%;height:18px;margin-bottom:5px;position:relative}.uiTarget .boxes .statBox:nth-child(3){margin-bottom:0px}.uiTarget .boxes .statBox:last-child{display:none;position:absolute;margin-left:-8px;margin-top:13px;background-color:#69696e}.uiTarget .boxes .statBox [class^="stat"]{position:absolute;left:0px;top:0px;height:100%}.uiTarget .boxes .statBox .text{position:absolute;left:0px;top:0px;width:100%;height:100%;text-align:center;color:#f2f5f5;padding:2px 0px;text-shadow:2px 0 #2d2136,-2px 0 #2d2136,0 -2px #2d2136,0 2px #2d2136,-2px -2px #2d2136,-2px 2px #2d2136,2px -2px #2d2136,2px 2px #2d2136}.uiTarget .boxes .statBox:nth-child(2){background-color:#802343}.uiTarget .boxes .statBox:nth-child(3){background-color:#42548d}.uiTarget .boxes .statBox:nth-child(4){background-color:#763b3b}.uiTarget .boxes .statBox .statHp{background-color:#d43346}.uiTarget .boxes .statBox .statMana{background-color:#3fa7dd}.uiTarget .boxes .statBox .statCasting{background-color:#faac45}.mobile .uiTarget{left:10px;top:100px} |
@@ -0,0 +1 @@ | |||
.uiTerms{display:none;width:562px;height:700px;margin-top:-80px;display:flex;flex-direction:column;align-items:center}.uiTerms>*{flex-shrink:0}.uiTerms .logo{width:562px;height:200px;margin-bottom:24px;filter:drop-shadow(0 -4px 0 #312136) drop-shadow(0 4px 0 #312136) drop-shadow(4px 0 0 #312136) drop-shadow(-4px 0 0 #312136)}.uiTerms .heading{color:#ff6942;filter:drop-shadow(0 -4px 0 #312136) drop-shadow(0 4px 0 #312136) drop-shadow(4px 0 0 #312136) drop-shadow(-4px 0 0 #312136);margin-bottom:24px}.uiTerms .content{flex:1;width:100%;overflow-y:auto;background-color:#373041;border:5px solid #3c3f4c;padding:10px;color:#c0c3cf;text-align:justify}.uiTerms .content .title{color:#f2f5f5}.uiTerms .buttons{width:100%;background-color:#373041;display:flex;justify-content:space-between;border-style:solid;border-color:#3c3f4c;border-width:0px 5px 5px 5px;padding:5px}.uiTerms .buttons .btn{background-color:#3a71ba;color:#f2f5f5;height:35px;padding-left:10px;padding-right:10px}.uiTerms .buttons .btn:hover{background-color:#3fa7dd}.uiTerms a{color:#3fa7dd}.uiTerms a:hover{color:#48edff}.mobile .uiTerms{height:80%;margin-top:0px} |
@@ -0,0 +1 @@ | |||
.uiTooltipInfo{position:absolute;right:11px;bottom:164px;background-color:rgba(55,48,65,0.9);padding:8px 32px;line-height:20px;color:#f2f5f5;text-align:center} |
@@ -0,0 +1 @@ | |||
.uiTooltipItem>*{z-index:999999}.uiTooltipItem .tooltip{display:none;position:absolute;margin-left:-4px;margin-top:-4px;background-color:rgba(60,63,76,0.95);pointer-events:none;padding:10px;color:#f2f5f5;text-align:center;line-height:18px;max-width:300px}.uiTooltipItem .tooltip .name{margin-bottom:8px}.uiTooltipItem .tooltip .name .type{color:#7f9c9c}.uiTooltipItem .tooltip .name .power{color:#80f643;display:none}.uiTooltipItem .tooltip>.implicitStats{color:#b8c9c9;margin-bottom:8px;padding-bottom:8px;border-bottom:2px solid #505360}.uiTooltipItem .tooltip>.implicitStats .gainStat{color:#80f643}.uiTooltipItem .tooltip>.implicitStats .loseStat{color:#d43346}.uiTooltipItem .tooltip>.stats{color:#b8c9c9;margin-bottom:8px;padding-bottom:8px;border-bottom:2px solid #505360}.uiTooltipItem .tooltip>.stats .gainStat{color:#80f643}.uiTooltipItem .tooltip>.stats .loseStat{color:#d43346}.uiTooltipItem .tooltip>.stats .enchanted{color:#44cb95 !important}.uiTooltipItem .tooltip .effects{color:#f2f5f5;margin-bottom:8px}.uiTooltipItem .tooltip .faction{color:#7f9c9c;margin-bottom:8px}.uiTooltipItem .tooltip .requires{margin-top:8px;color:#7f9c9c}.uiTooltipItem .tooltip .requires.high-level{color:#d43346}.uiTooltipItem .tooltip .requires .high-level{color:#d43346}.uiTooltipItem .tooltip .requires>*:not(.high-level){color:#7f9c9c}.uiTooltipItem .tooltip .material{color:#7f9c9c;display:none}.uiTooltipItem .tooltip .quest{color:#7f9c9c;display:none}.uiTooltipItem .tooltip .info{color:#4f6666}.uiTooltipItem .tooltip .damage .gainDamage{color:#80f643}.uiTooltipItem .tooltip .damage .loseDamage{color:#d43346}.uiTooltipItem .tooltip .worth{display:none}.uiTooltipItem .tooltip .worth.no-afford{color:#d43346}.uiTooltipItem .tooltip.no-compare .info{display:none}.uiTooltipItem>.btn{position:absolute;background-color:#3fa7dd;color:#f2f5f5;padding:10px;text-align:center}.mobile .uiTooltipItem{z-index:9999999999}.mobile .uiTooltipItem>*{z-index:9999999999} |
@@ -0,0 +1 @@ | |||
.uiTooltips{z-index:4}.uiTooltips .tooltip{display:none;z-index:4;background-color:rgba(58,59,74,0.85);position:absolute;padding:8px;color:#f2f5f5;text-align:justify}.uiTooltips .tooltip.bright{background-color:#c0c3cf;color:#2d2136}.uiTooltips .tooltip .hidden{display:none} |
@@ -0,0 +1 @@ | |||
.uiTrade{width:auto}.uiTrade .no-afford{position:absolute;left:5px;top:5px;width:calc(100% - 10px);height:calc(100% - 10px);background-color:rgba(212,51,70,0.15)}.uiTrade .grid .item .icon.skin{width:16px;height:16px;transform:scale(4);transform-origin:0 0;image-rendering:optimizeSpeed;image-rendering:pixelated;image-rendering:crisp-edges} |
@@ -0,0 +1 @@ | |||
.uiWardrobe{display:none;width:600px;height:350px;border:5px solid #3c3f4c;text-align:center;background-color:#373041}.uiWardrobe>.heading{color:#48edff;width:100%;height:36px;background-color:#3c3f4c;position:relative}.uiWardrobe>.heading .heading-text{padding-top:8px;margin:auto}.uiWardrobe .bottom{height:calc(100% - 36px)}.uiWardrobe .bottom .left,.uiWardrobe .bottom .right{float:left;height:100%}.uiWardrobe .bottom .left{width:calc(100% * .4)}.uiWardrobe .bottom .left .heading{width:100%;height:30px;color:#ffeb38;padding-top:7px}.uiWardrobe .bottom .left .list{width:100%;height:calc(100% - 30px);overflow:auto}.uiWardrobe .bottom .left .list .skinName{width:100%;cursor:pointer;color:white;padding:5px}.uiWardrobe .bottom .left .list .skinName:hover{background-color:#3c3f4c}.uiWardrobe .bottom .left .list .skinName.active{color:#48edff}.uiWardrobe .bottom .left .list .skinName.current:after{content:' (x)'}.uiWardrobe .bottom .right{width:calc(100% * .6);position:relative;background-color:#2d2136}.uiWardrobe .bottom .right .heading{width:100%;height:30px;color:#ffeb38;padding-top:7px}.uiWardrobe .bottom .right .preview{padding-left:calc((100% - (8 * 16px)) / 2);position:relative;height:calc(100% - 80px)}.uiWardrobe .bottom .right .preview .sprite{width:8px;height:8px;position:absolute;left:calc((100% - (8 * 16px)) / 2);top:calc((100% - (8 * 16px)) / 2);transform:scale(16);transform-origin:0% 0%;image-rendering:optimizeSpeed;image-rendering:pixelated;image-rendering:crisp-edges}.uiWardrobe .bottom .right .buttons{width:100%;padding:0px 10px;height:50px}.uiWardrobe .bottom .right .buttons .btn{float:left;width:calc((100% - 50px) / 2);height:40px;padding-top:12px;color:white;cursor:pointer}.uiWardrobe .bottom .right .buttons .btn:first-child{margin-right:50px}.uiWardrobe .bottom .right .buttons .btnCancel{background-color:#d43346}.uiWardrobe .bottom .right .buttons .btnCancel:hover{background-color:#ff4252}.uiWardrobe .bottom .right .buttons .btnApply{background-color:#4ac441}.uiWardrobe .bottom .right .buttons .btnApply:hover{background-color:#80f643} |
@@ -0,0 +1 @@ | |||
.uiWorkbench{display:none;width:827px;height:447px;border:5px solid #3c3f4c;color:#f2f5f5;position:relative;z-index:2}.uiWorkbench>.heading,.uiWorkbench>.itemPicker>.heading{color:#ff6942;width:100%;height:36px;background-color:#3c3f4c;text-align:center}.uiWorkbench>.heading .heading-text,.uiWorkbench>.itemPicker>.heading .heading-text{padding-top:8px;margin:auto}.uiWorkbench>.bottom{background-color:#373041;height:calc(100% - 36px);width:100%}.uiWorkbench>.bottom .heading{color:#3fa7dd;margin-bottom:10px;text-align:center}.uiWorkbench>.bottom .left,.uiWorkbench>.bottom .right{float:left;height:100%;padding:10px}.uiWorkbench>.bottom .left{width:300px}.uiWorkbench>.bottom .left .list{height:calc(100% - 25px);overflow-y:auto;display:flex;flex-direction:column}.uiWorkbench>.bottom .left .list .item{width:100%;padding:5px 10px;cursor:pointer;color:#c0c3cf}.uiWorkbench>.bottom .left .list .item.selected{background-color:#3c3f4c;color:#f2f5f5}.uiWorkbench>.bottom .left .list .item:hover{background-color:#3c3f4c}.uiWorkbench>.bottom .right{width:calc(100% - 300px);display:flex;flex-direction:column;justify-content:space-between}.uiWorkbench>.bottom .right>*{width:100%}.uiWorkbench>.bottom .right .info{height:calc(100% - 100px - 35px);flex:1}.uiWorkbench>.bottom .right .info .title{color:#3fa7dd;padding-bottom:10px;text-align:center}.uiWorkbench>.bottom .right .info .description{color:#c0c3cf;text-align:justify}.uiWorkbench>.bottom .right .materialList{visibility:hidden;margin-bottom:20px}.uiWorkbench>.bottom .right .materialList .material.need{color:#d43346}.uiWorkbench>.bottom .right .needItems{display:none;margin-bottom:20px;flex-direction:column}.uiWorkbench>.bottom .right .needItems .title{color:#3fa7dd;padding-bottom:10px;text-align:center}.uiWorkbench>.bottom .right .needItems .list{display:flex;justify-content:space-around}.uiWorkbench>.bottom .right .buttons{height:40px}.uiWorkbench>.bottom .right .buttons>.btn{height:35px;width:100px;color:#f2f5f5;text-align:center;padding-top:10px;background-color:#3c3f4c;cursor:pointer;float:left}.uiWorkbench>.bottom .right .buttons>.btn:last-child{float:right}.uiWorkbench>.bottom .right .buttons>.btn:hover{background-color:#505360}.uiWorkbench>.itemPicker{display:none;position:absolute;left:0px;top:0px;width:100%;height:100%;background-color:#373041;flex-direction:column}.uiWorkbench>.itemPicker .list{display:flex;flex-wrap:wrap;overflow-y:auto}.mobile .uiWorkbench{z-index:2} |
@@ -0,0 +1,36 @@ | |||
//Prebound Methods | |||
const mathRandom = Math.random.bind(Math); | |||
//Helpers | |||
const willBlock = ({ isAttack, tgtValues: { blockAttackChance, blockSpellChance } }) => { | |||
const blockChance = isAttack ? blockAttackChance : blockSpellChance; | |||
const roll = mathRandom() * 100; | |||
const result = roll < blockChance; | |||
return result; | |||
}; | |||
const willDodge = ({ isAttack, tgtValues: { dodgeAttackChance, dodgeSpellChance } }) => { | |||
const dodgeChance = isAttack ? dodgeAttackChance : dodgeSpellChance; | |||
const roll = mathRandom() * 100; | |||
const result = roll < dodgeChance; | |||
return result; | |||
}; | |||
//Method | |||
const avoid = (config, result) => { | |||
//Heals, among other things, should not be avoided | |||
if (config.noMitigate) | |||
return; | |||
result.blocked = willBlock(config); | |||
if (!result.blocked) | |||
result.dodged = willDodge(config); | |||
}; | |||
//Exports | |||
module.exports = avoid; |
@@ -1,91 +1,39 @@ | |||
let max = Math.max.bind(Math); | |||
let mathRandom = Math.random.bind(Math); | |||
//Imports | |||
const avoid = require('./avoid'); | |||
const scale = require('./scale'); | |||
const mitigate = require('./mitigate'); | |||
//Method | |||
const getDamage = config => { | |||
const { damage, element } = config; | |||
//Add convenience properties | |||
config.srcValues = config.source.stats.values; | |||
config.tgtValues = config.target.stats.values; | |||
if (element) | |||
config.elementName = `element${element[0].toUpperCase()}${element.substr(1)}`; | |||
const result = { | |||
amount: damage, | |||
blocked: false, | |||
dodged: false, | |||
crit: false, | |||
element | |||
}; | |||
avoid(config, result); | |||
scale(config, result); | |||
mitigate(config, result); | |||
//Remove convenience properties | |||
delete config.srcValues; | |||
delete config.tgtValues; | |||
delete config.elementName; | |||
return result; | |||
}; | |||
//Exports | |||
module.exports = { | |||
getDamage: function (config) { | |||
let srcValues = config.source.stats.values; | |||
let tgtValues = config.target.stats.values; | |||
let amount = config.damage; | |||
let blocked = false; | |||
let dodged = false; | |||
let isCrit = false; | |||
//Don't block heals | |||
if (!config.noMitigate) { | |||
let blockChance = config.isAttack ? tgtValues.blockAttackChance : tgtValues.blockSpellChance; | |||
if (mathRandom() * 100 < blockChance) { | |||
blocked = true; | |||
amount = 0; | |||
} | |||
if (!blocked) { | |||
let dodgeChance = config.isAttack ? tgtValues.dodgeAttackChance : tgtValues.dodgeSpellChance; | |||
if (mathRandom() * 100 < dodgeChance) { | |||
dodged = true; | |||
amount = 0; | |||
} | |||
} | |||
} | |||
if (!blocked && !dodged && !config.noScale) { | |||
if (config.statType) { | |||
let statValue = 0; | |||
let statType = config.statType; | |||
if (!(statType instanceof Array)) | |||
statType = [statType]; | |||
statType.forEach(function (s) { | |||
statValue += srcValues[s]; | |||
}); | |||
statValue = max(1, statValue); | |||
let statMult = config.statMult || 1; | |||
amount *= statValue * statMult; | |||
} | |||
let dmgPercent = 100 + (srcValues.dmgPercent || 0); | |||
if (config.isAttack) | |||
dmgPercent += srcValues.physicalPercent || 0; | |||
else | |||
dmgPercent += srcValues.spellPercent || 0; | |||
if (config.element) { | |||
let elementName = 'element' + config.element[0].toUpperCase() + config.element.substr(1); | |||
dmgPercent += (srcValues[elementName + 'Percent'] || 0); | |||
//Don't mitigate heals | |||
if (!config.noMitigate) { | |||
let resist = tgtValues[elementName + 'Resist'] || 0; | |||
amount *= max(0.5 + max((1 - (resist / 100)) / 2, -0.5), 0.5); | |||
} | |||
} else if (!config.noMitigate) | |||
amount *= max(0.5 + max((1 - ((tgtValues.armor || 0) / (srcValues.level * 50))) / 2, -0.5), 0.5); | |||
amount *= (dmgPercent / 100); | |||
if (!config.noCrit) { | |||
let critChance = srcValues.critChance; | |||
critChance += (config.isAttack) ? srcValues.attackCritChance : srcValues.spellCritChance; | |||
let critMultiplier = srcValues.critMultiplier; | |||
critMultiplier += (config.isAttack) ? srcValues.attackCritMultiplier : srcValues.spellCritMultiplier; | |||
if ((config.crit) || (mathRandom() * 100 < critChance)) { | |||
isCrit = true; | |||
amount *= (critMultiplier / 100); | |||
} | |||
} | |||
} | |||
return { | |||
amount, | |||
blocked, | |||
dodged, | |||
crit: isCrit, | |||
element: config.element | |||
}; | |||
} | |||
getDamage | |||
}; |
@@ -0,0 +1,56 @@ | |||
//Prebound Methods | |||
const max = Math.max.bind(Math); | |||
const pow = Math.pow.bind(Math); | |||
//Helpers | |||
const mitigateResistances = ({ elementName, noMitigate, tgtValues }, result) => { | |||
//Don't mitigate physical damage | |||
if (!elementName) | |||
return; | |||
const resist = tgtValues[elementName + 'Resist'] || 0; | |||
const resistanceMultiplier = max(0.5 + max((1 - (resist / 100)) / 2, -0.5), 0.5); | |||
result.amount *= resistanceMultiplier; | |||
}; | |||
const mitigateArmor = ({ element, tgtValues, srcValues }, result) => { | |||
//Don't mitigate elemental damage | |||
if (element) | |||
return; | |||
const armorMultiplier = max(0.5 + max((1 - ((tgtValues.armor || 0) / (srcValues.level * 50))) / 2, -0.5), 0.5); | |||
result.amount *= armorMultiplier; | |||
}; | |||
const mitigatePvp = ({ source, target, srcValues }, result) => { | |||
const isPvp = ( | |||
(source.player || (source.follower && source.follower.master && source.follower.master.player)) && | |||
(target.player || (target.follower && target.follower.master && target.follower.master.player)) | |||
); | |||
if (!isPvp) | |||
return; | |||
const multiplier = 1 / pow(2, srcValues.level / 5); | |||
result.amount *= multiplier; | |||
}; | |||
//Method | |||
const mitigate = (config, result) => { | |||
const { blocked, dodged } = result; | |||
//Heals, among other things, should not be mitigated | |||
if (blocked || dodged || config.noMitigate) | |||
return; | |||
mitigateResistances(config, result); | |||
mitigateArmor(config, result); | |||
mitigatePvp(config, result); | |||
}; | |||
//Exports | |||
module.exports = mitigate; |
@@ -0,0 +1,82 @@ | |||
//Prebound Methods | |||
const mathRandom = Math.random.bind(Math); | |||
const max = Math.max.bind(Math); | |||
//Helpers | |||
const scaleStatType = (config, result) => { | |||
const { statType, statMult = 1, srcValues } = config; | |||
if (!statType) | |||
return; | |||
let statValue = 0; | |||
if (!statType.push) | |||
statValue = srcValues[statType]; | |||
else { | |||
statType.forEach(s => { | |||
statValue += srcValues[s]; | |||
}); | |||
} | |||
statValue = max(1, statValue); | |||
result.amount *= statValue * statMult; | |||
}; | |||
const scalePercentMultipliers = ({ isAttack, elementName, srcValues }, result) => { | |||
const { dmgPercent = 0, physicalPercent = 0, spellPercent = 0 } = srcValues; | |||
let totalPercent = 100 + dmgPercent; | |||
if (isAttack) | |||
totalPercent += physicalPercent; | |||
else | |||
totalPercent += spellPercent; | |||
if (elementName) | |||
totalPercent += (srcValues[elementName + 'Percent'] || 0); | |||
result.amount *= (totalPercent / 100); | |||
}; | |||
const scaleCrit = ({ noCrit, isAttack, crit: forceCrit, srcValues }, result) => { | |||
if (noCrit) | |||
return; | |||
const { critChance, attackCritChance, spellCritChance } = srcValues; | |||
const { critMultiplier, attackCritMultiplier, spellCritMultiplier } = srcValues; | |||
let totalCritChance = critChance; | |||
let totalCritMultiplier = critMultiplier; | |||
if (isAttack) { | |||
totalCritChance += attackCritChance; | |||
totalCritMultiplier += attackCritMultiplier; | |||
} else { | |||
totalCritChance += spellCritChance; | |||
totalCritMultiplier += spellCritMultiplier; | |||
} | |||
const didCrit = forceCrit || mathRandom() * 100 < totalCritChance; | |||
if (didCrit) { | |||
result.crit = true; | |||
result.amount *= (totalCritMultiplier / 100); | |||
} | |||
}; | |||
//Method | |||
const scale = (config, result) => { | |||
const { blocked, dodged } = result; | |||
if (blocked || dodged || config.noScale) | |||
return; | |||
scaleStatType(config, result); | |||
scalePercentMultipliers(config, result); | |||
scaleCrit(config, result); | |||
}; | |||
//Exports | |||
module.exports = scale; |
@@ -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]); | |||
} | |||
}, | |||
@@ -16,6 +16,71 @@ const teleportHome = (physics, obj, mob) => { | |||
obj.aggro.move(); | |||
}; | |||
const performPatrolAction = ({ obj }, node) => { | |||
const { action } = node; | |||
const { chatter, syncer, instance: { scheduler } } = obj; | |||
if (action === 'chat') { | |||
if (!chatter) | |||
obj.addComponent('chatter'); | |||
syncer.set(false, 'chatter', 'msg', node.msg); | |||
return true; | |||
} | |||
if (action === 'wait') { | |||
if (node.cron) { | |||
const isActive = scheduler.isActive(node); | |||
return isActive; | |||
} else if (node.ttl === undefined) { | |||
node.ttl = node.duration; | |||
return false; | |||
} | |||
node.ttl--; | |||
if (!node.ttl) { | |||
delete node .ttl; | |||
return true; | |||
} | |||
} | |||
}; | |||
const getNextPatrolTarget = mob => { | |||
const { patrol, obj: { x, y } } = mob; | |||
let toX, toY; | |||
do { | |||
const toNode = patrol[mob.patrolTargetNode]; | |||
if (toNode.action) { | |||
const nodeDone = performPatrolAction(mob, toNode); | |||
if (!nodeDone) | |||
return true; | |||
mob.patrolTargetNode++; | |||
if (mob.patrolTargetNode >= patrol.length) | |||
mob.patrolTargetNode = 0; | |||
continue; | |||
} | |||
toX = toNode[0]; | |||
toY = toNode[1]; | |||
if ((toX - x === 0) && (toY - y === 0)) { | |||
mob.patrolTargetNode++; | |||
if (mob.patrolTargetNode >= patrol.length) | |||
mob.patrolTargetNode = 0; | |||
} else | |||
break; | |||
} while (toX - x !== 0 || toY - y !== 0); | |||
return [ toX, toY ]; | |||
}; | |||
module.exports = { | |||
type: 'mob', | |||
@@ -112,17 +177,13 @@ module.exports = { | |||
toX = this.originX + ~~(rnd() * (walkDistance * 2)) - walkDistance; | |||
toY = this.originY + ~~(rnd() * (walkDistance * 2)) - walkDistance; | |||
} else if (this.patrol) { | |||
do { | |||
let toNode = this.patrol[this.patrolTargetNode]; | |||
toX = toNode[0]; | |||
toY = toNode[1]; | |||
if ((toX - obj.x === 0) && (toY - obj.y === 0)) { | |||
this.patrolTargetNode++; | |||
if (this.patrolTargetNode >= this.patrol.length) | |||
this.patrolTargetNode = 0; | |||
} else | |||
break; | |||
} while (toX - obj.x !== 0 || toY - obj.y !== 0); | |||
const patrolResult = getNextPatrolTarget(this); | |||
//When an action is performed, we will only get a boolean value back | |||
if (!patrolResult.push) | |||
return; | |||
[toX, toY] = patrolResult; | |||
} | |||
//We use goHome to force followers to follow us around but they should never stay in that state | |||
@@ -135,7 +196,8 @@ module.exports = { | |||
if (dx + dy === 0) | |||
return; | |||
else if (dx <= 1 && dy <= 1) { | |||
if (dx <= 1 && dy <= 1) { | |||
obj.queue({ | |||
action: 'move', | |||
data: { | |||
@@ -143,27 +205,29 @@ module.exports = { | |||
y: toY | |||
} | |||
}); | |||
} else { | |||
let path = this.physics.getPath({ | |||
x: obj.x, | |||
y: obj.y | |||
}, { | |||
x: toX, | |||
y: toY | |||
}, false); | |||
let pLen = path.length; | |||
for (let i = 0; i < pLen; i++) { | |||
let p = path[i]; | |||
obj.queue({ | |||
action: 'move', | |||
data: { | |||
x: p.x, | |||
y: p.y | |||
} | |||
}); | |||
} | |||
return; | |||
} | |||
const path = this.physics.getPath({ | |||
x: obj.x, | |||
y: obj.y | |||
}, { | |||
x: toX, | |||
y: toY | |||
}, false); | |||
const pLen = path.length; | |||
for (let i = 0; i < pLen; i++) { | |||
let p = path[i]; | |||
obj.queue({ | |||
action: 'move', | |||
data: { | |||
x: p.x, | |||
y: p.y | |||
} | |||
}); | |||
} | |||
}, | |||
@@ -229,6 +229,12 @@ module.exports = { | |||
syncer.o.x = obj.x; | |||
syncer.o.y = obj.y; | |||
obj.effects.addEffect({ | |||
type: 'invulnerability', | |||
force: true, | |||
ttl: 28 | |||
}); | |||
obj.aggro.move(); | |||
obj.instance.physics.addObject(obj, obj.x, obj.y); | |||
@@ -1,4 +1,6 @@ | |||
let roles = require('../config/roles'); | |||
const roles = require('../config/roles'); | |||
const sendObjToZone = require('./portal/sendObjToZone'); | |||
module.exports = { | |||
type: 'portal', | |||
@@ -24,30 +26,14 @@ module.exports = { | |||
return; | |||
} | |||
obj.fireEvent('beforeRezone'); | |||
obj.destroyed = true; | |||
await obj.auth.doSave(); | |||
const simpleObj = obj.getSimple(true, false, true); | |||
const { toPos, toRelativePos } = this; | |||
if (toPos) { | |||
simpleObj.x = this.toPos.x; | |||
simpleObj.y = this.toPos.y; | |||
} else if (toRelativePos) { | |||
simpleObj.x = this.obj.x + toRelativePos.x; | |||
simpleObj.y = this.obj.y + toRelativePos.y; | |||
} | |||
const { toZone: zoneName, toPos, toRelativePos } = this; | |||
process.send({ | |||
method: 'rezone', | |||
id: obj.serverId, | |||
args: { | |||
obj: simpleObj, | |||
newZone: this.toZone | |||
} | |||
await sendObjToZone({ | |||
obj, | |||
invokingObj: this, | |||
zoneName, | |||
toPos, | |||
toRelativePos | |||
}); | |||
} | |||
}; |
@@ -0,0 +1,46 @@ | |||
const sendObjToZone = async ({ obj, invokingObj, zoneName, toPos, toRelativePos }) => { | |||
const { instance: { physics, syncer: globalSyncer } } = obj; | |||
if (obj.zoneName === zoneName) { | |||
physics.removeObject(obj, obj.x, obj.y); | |||
obj.x = toPos.x; | |||
obj.y = toPos.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; | |||
await obj.auth.doSave(); | |||
const simpleObj = obj.getSimple(true, false, true); | |||
if (toPos) { | |||
simpleObj.x = toPos.x; | |||
simpleObj.y = toPos.y; | |||
} else if (toRelativePos) { | |||
simpleObj.x = invokingObj.obj.x + toRelativePos.x; | |||
simpleObj.y = invokingObj.obj.y + toRelativePos.y; | |||
} | |||
process.send({ | |||
method: 'rezone', | |||
id: obj.serverId, | |||
args: { | |||
obj: simpleObj, | |||
newZone: zoneName | |||
} | |||
}); | |||
}; | |||
module.exports = sendObjToZone; |
@@ -1,3 +1,6 @@ | |||
//Methods | |||
const die = require('./stats/die'); | |||
let animations = require('../config/animations'); | |||
let spirits = require('../config/spirits'); | |||
let scheduler = require('../misc/scheduler'); | |||
@@ -460,43 +463,7 @@ module.exports = { | |||
}, | |||
die: function (source) { | |||
let obj = this.obj; | |||
let values = this.values; | |||
this.syncer.queue('onGetDamage', { | |||
id: obj.id, | |||
event: true, | |||
text: 'death' | |||
}, -1); | |||
obj.syncer.set(true, null, 'dead', true); | |||
let syncO = obj.syncer.o; | |||
obj.hidden = true; | |||
obj.nonSelectable = true; | |||
syncO.hidden = true; | |||
syncO.nonSelectable = true; | |||
let xpLoss = ~~Math.min(values.xp, values.xpMax * 0.05); | |||
values.xp -= xpLoss; | |||
obj.syncer.setObject(true, 'stats', 'values', 'xp', values.xp); | |||
this.syncer.queue('onDeath', { | |||
source: source.name, | |||
xpLoss: xpLoss | |||
}, [obj.serverId]); | |||
obj.instance.syncer.queue('onGetObject', { | |||
x: obj.x, | |||
y: obj.y, | |||
components: [{ | |||
type: 'attackAnimation', | |||
row: 0, | |||
col: 4 | |||
}] | |||
}, -1); | |||
die(this, source); | |||
}, | |||
respawn: function () { | |||
@@ -0,0 +1,62 @@ | |||
const loseXpOnDeath = ({ stats: { values }, syncer }, deathSource) => { | |||
const { xp, xpMax, level } = values; | |||
const noLoseXp = ( | |||
level < 5 || | |||
deathSource.player || | |||
( | |||
deathSource.follower && | |||
deathSource.follower.master && | |||
deathSource.follower.master.player | |||
) | |||
); | |||
if (noLoseXp) | |||
return 0; | |||
const xpLoss = ~~Math.min(xp, xpMax * 0.05); | |||
values.xp -= xpLoss; | |||
syncer.setObject(true, 'stats', 'values', 'xp', values.xp); | |||
return xpLoss; | |||
}; | |||
const die = (cpnStats, deathSource) => { | |||
const { obj, syncer: syncerGlobal } = cpnStats; | |||
const { x, y, serverId, syncer } = obj; | |||
syncerGlobal.queue('onGetDamage', { | |||
id: obj.id, | |||
event: true, | |||
text: 'death' | |||
}, -1); | |||
syncer.set(true, null, 'dead', true); | |||
const syncO = syncer.o; | |||
obj.hidden = true; | |||
obj.nonSelectable = true; | |||
syncO.hidden = true; | |||
syncO.nonSelectable = true; | |||
const xpLoss = loseXpOnDeath(obj, deathSource); | |||
syncerGlobal.queue('onDeath', { | |||
source: deathSource.name, | |||
xpLoss: xpLoss | |||
}, [serverId]); | |||
syncerGlobal.queue('onGetObject', { | |||
x, | |||
y, | |||
components: [{ | |||
type: 'attackAnimation', | |||
row: 0, | |||
col: 4 | |||
}] | |||
}, -1); | |||
}; | |||
module.exports = die; |
@@ -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,44 @@ 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)); | |||
} | |||
//Tile index 0 is 'no tile' in map files so we need to increment by 1 | |||
const result = tileCountBeforeSheet + tileIndexInSource + 1; | |||
return result; | |||
}, | |||
//Used to send to clients | |||
@@ -0,0 +1,14 @@ | |||
module.exports = { | |||
type: 'invulnerability', | |||
events: { | |||
beforeDealDamage: function (damage) { | |||
if (damage) | |||
damage.amount = 0; | |||
}, | |||
beforeTakeDamage: function (damage, source) { | |||
damage.amount = 0; | |||
} | |||
} | |||
}; |
@@ -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":[ | |||
{ | |||
@@ -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*' | |||
}, { | |||
@@ -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' | |||
}] | |||
} | |||
} | |||
}; |
@@ -13,30 +13,6 @@ module.exports = { | |||
} | |||
}, | |||
objects: { | |||
'sun carp school': { | |||
max: 9, | |||
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: { | |||
@@ -56,406 +32,10 @@ module.exports = { | |||
} | |||
} | |||
}, | |||
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' | |||
} | |||
} | |||
'sun carp school': { | |||
max: 9, | |||
type: 'fish', | |||
quantity: [6, 12] | |||
}, | |||
fireplace: { | |||
components: { | |||
@@ -463,61 +43,6 @@ module.exports = { | |||
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: { | |||
@@ -557,7 +82,7 @@ module.exports = { | |||
level: 2, | |||
regular: { | |||
drops: { | |||
chance: 60, | |||
chance: 55, | |||
rolls: 1 | |||
} | |||
}, | |||
@@ -573,7 +98,7 @@ module.exports = { | |||
level: 3, | |||
regular: { | |||
drops: { | |||
chance: 56, | |||
chance: 50, | |||
rolls: 1 | |||
} | |||
}, | |||
@@ -607,7 +132,7 @@ module.exports = { | |||
level: 4, | |||
regular: { | |||
drops: { | |||
chance: 50, | |||
chance: 45, | |||
rolls: 1 | |||
} | |||
}, | |||
@@ -623,7 +148,6 @@ module.exports = { | |||
level: 5, | |||
regular: { | |||
drops: { | |||
chance: 45, | |||
rolls: 1 | |||
} | |||
} | |||
@@ -645,15 +169,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 +242,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 +270,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, | |||
@@ -5,10 +5,6 @@ let config = [ | |||
name: 'cave', | |||
path: 'config/maps' | |||
}, | |||
{ | |||
name: 'sewer', | |||
path: 'config/maps' | |||
}, | |||
{ | |||
name: 'fjolarok', | |||
path: 'config/maps' | |||
@@ -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 | |||
}] | |||
}; |
@@ -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,5 +1,5 @@ | |||
module.exports = { | |||
version: '0.8.6', | |||
version: '0.9.0', | |||
port: 4000, | |||
startupMessage: 'Server: ready', | |||
defaultZone: 'fjolarok', | |||
@@ -14,5 +14,9 @@ module.exports = { | |||
//eslint-disable-next-line no-process-env | |||
dbPort: process.env.IWD_DB_PORT || 28015, | |||
//eslint-disable-next-line no-process-env | |||
dbName: process.env.IWD_DB_NAME || 'live' | |||
dbName: process.env.IWD_DB_NAME || 'live', | |||
//eslint-disable-next-line no-process-env | |||
dbUser: process.env.IWD_DB_USER || 'admin', | |||
//eslint-disable-next-line no-process-env | |||
dbPass: process.env.IWD_DB_PASS || '' | |||
}; |
@@ -21,6 +21,8 @@ module.exports = { | |||
let projectileConfig = { | |||
caster: this.obj.id, | |||
x: obj.x, | |||
y: obj.y, | |||
components: [{ | |||
idSource: this.obj.id, | |||
idTarget: target.id, | |||
@@ -33,6 +33,8 @@ module.exports = { | |||
let projectileConfig = { | |||
caster: this.obj.id, | |||
extraTargets: 0, | |||
x: obj.x, | |||
y: obj.y, | |||
components: [{ | |||
idSource: this.obj.id, | |||
idTarget: target.id, | |||
@@ -95,6 +97,8 @@ module.exports = { | |||
let projectileConfig = { | |||
caster: obj.id, | |||
x: obj.x, | |||
y: obj.y, | |||
components: [{ | |||
idSource: obj.id, | |||
idTarget: t.id, | |||
@@ -4,7 +4,9 @@ const tableNames = require('./tableNames'); | |||
const r = require('rethinkdbdash')({ | |||
host: serverConfig.dbHost, | |||
port: serverConfig.dbPort, | |||
db: serverConfig.dbName | |||
db: serverConfig.dbName, | |||
user: serverConfig.dbUser, | |||
password: serverConfig.dpPass | |||
}); | |||
module.exports = { | |||
@@ -1,6 +1,6 @@ | |||
require('./globals'); | |||
let server = require('./server'); | |||
let server = require('./server/index'); | |||
let components = require('./components/components'); | |||
let mods = require('./misc/mods'); | |||
let animations = require('./config/animations'); | |||
@@ -49,11 +49,11 @@ let startup = { | |||
onComponentsReady: async function () { | |||
skins.init(); | |||
factions.init(); | |||
await clientConfig.init(); | |||
server.init(this.onServerReady.bind(this)); | |||
}, | |||
onServerReady: async function () { | |||
await server.init(); | |||
await leaderboard.init(); | |||
atlas.init(); | |||
@@ -41,15 +41,24 @@ module.exports = { | |||
global.instancer.instances[0].eventEmitter.emitNoSticky('onBeforeGetDropChances', dropChancesEvent); | |||
let currencyChance = dropChancesEvent.currencyChance; | |||
//If you kill a mob that's too low of a level, idols are much more rare | |||
if ( | |||
blueprint.level && | |||
ownerLevel && | |||
ownerLevel - blueprint.level > 4 | |||
) { | |||
const levelDelta = ownerLevel - blueprint.level; | |||
currencyChance /= Math.pow(levelDelta - 3, 2); | |||
if (blueprint.level) { | |||
//Idol droprate before level 5 is 0, after which it slowly increases and flattens out at level 15 | |||
if (blueprint.level < 5) | |||
currencyChance = 0; | |||
else if (blueprint.level < 14) | |||
currencyChance = (blueprint.level - 4) / 11; | |||
//If you kill a mob that's too low of a level, idols are much more rare | |||
if ( | |||
ownerLevel && | |||
ownerLevel - blueprint.level > 4 | |||
) { | |||
const levelDelta = ownerLevel - blueprint.level; | |||
currencyChance /= Math.pow(levelDelta - 3, 2); | |||
} | |||
} | |||
if (blueprint.noCurrency) | |||
currencyChance = 0; | |||
@@ -18,7 +18,7 @@ module.exports = { | |||
}, | |||
onAfterGetZone: function (zone, config) { | |||
if (zone !== 'fjolarok') | |||
if (zone !== 'fjolgard') | |||
return; | |||
let newRunes = [{ | |||
@@ -18,37 +18,41 @@ module.exports = { | |||
noTargetSelf: true, | |||
cast: function (action) { | |||
let obj = this.obj; | |||
let target = action.target; | |||
const { target } = action; | |||
this.sendBump(target); | |||
this.queueCallback(this.explode.bind(this, target), 1, null, target); | |||
this.sendBump({ | |||
x: obj.x, | |||
y: obj.y - 1 | |||
}); | |||
this.queueCallback(this.explode.bind(this, action), 1, null, target); | |||
return true; | |||
}, | |||
explode: function (target) { | |||
if ((this.obj.destroyed) || (target.destroyed)) | |||
explode: function (action) { | |||
const { obj } = this; | |||
const { target } = action; | |||
if ((obj.destroyed) || (target.destroyed)) | |||
return; | |||
let amount = (this.obj.stats.values.hpMax / 100) * this.drainPercentage; | |||
let damage = { | |||
amount: amount | |||
}; | |||
this.obj.stats.takeDamage(damage, 0, this.obj); | |||
let amount = (obj.stats.values.hpMax / 100) * this.drainPercentage; | |||
const damage = { amount }; | |||
obj.stats.takeDamage(damage, 0, obj); | |||
amount = amount * this.shieldMultiplier; | |||
let heal = { | |||
amount: amount | |||
}; | |||
target.stats.getHp(heal, this.obj); | |||
const heal = { amount }; | |||
target.stats.getHp(heal, obj); | |||
//Only reset the first spell's cooldown if it's an auto attack and not a spell | |||
const firstSpell = target.spellbook.spells[0]; | |||
const resetFirstSpell = ( | |||
firstSpell && | |||
firstSpell.isAttack && | |||
firstSpell.auto | |||
); | |||
if (resetFirstSpell) | |||
target.spellbook.spells[0].cd = 0; | |||
target.spellbook.spells[0].cd = 0; | |||
target.effects.addEffect({ | |||
type: 'frenzy', | |||
ttl: this.frenzyDuration, | |||
@@ -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'); | |||
@@ -15,25 +15,26 @@ module.exports = { | |||
return ++this.lastId; | |||
}, | |||
build: function (skipPush, clientObj, id) { | |||
build: function (isClientObj, id) { | |||
let o = extend({}, objBase); | |||
if (clientObj) | |||
if (isClientObj) | |||
o.update = null; | |||
else { | |||
o.id = id || this.getNextId(); | |||
o.addComponent('syncer'); | |||
o.instance = this.instance; | |||
if (!skipPush) | |||
this.objects.push(o); | |||
} | |||
return o; | |||
}, | |||
pushObjectToList: function (obj) { | |||
this.objects.push(obj); | |||
}, | |||
transferObject: function (o) { | |||
let obj = this.build(); | |||
const obj = this.build(); | |||
let components = o.components; | |||
delete o.components; | |||
@@ -42,11 +43,11 @@ module.exports = { | |||
for (let p in o) | |||
obj[p] = o[p]; | |||
let cLen = components.length; | |||
const cLen = components.length; | |||
for (let i = 0; i < cLen; i++) { | |||
let c = components[i]; | |||
let cpn = obj.addComponent(c.type, null, true); | |||
const cpn = obj.addComponent(c.type, null, true); | |||
for (let p in c) | |||
cpn[p] = c[p]; | |||
@@ -55,7 +56,8 @@ module.exports = { | |||
cpn.transfer(); | |||
} | |||
//this.physics.addObject(obj, obj.x, obj.y); | |||
this.pushObjectToList(obj); | |||
this.physics.addObject(obj, obj.x, obj.y); | |||
return obj; | |||
}, | |||
@@ -65,7 +67,7 @@ module.exports = { | |||
for (let i = 0; i < lLen; i++) { | |||
let l = list[i]; | |||
let obj = this.build(skipPush, l.clientObj, l.id); | |||
let obj = this.build(l.clientObj, l.id); | |||
obj.sheetName = l.sheetName; | |||
obj.cell = l.cell; | |||
@@ -139,6 +141,9 @@ module.exports = { | |||
if (obj.aggro) | |||
obj.aggro.move(); | |||
if (!skipPush) | |||
this.pushObjectToList(obj); | |||
if (lLen === 1) | |||
return obj; | |||
} | |||
@@ -148,6 +153,10 @@ module.exports = { | |||
return this.objects.find(callback); | |||
}, | |||
filter: function (callback) { | |||
return this.objects.filter(callback); | |||
}, | |||
removeObject: function (obj, callback, useServerId) { | |||
let found = this.objects.spliceFirstWhere(o => obj.id === (useServerId ? o.serverId : o.id)); | |||
if (!found) | |||
@@ -168,24 +177,25 @@ module.exports = { | |||
}, | |||
addObject: function (o, callback) { | |||
let newO = this.build(true); | |||
const newO = this.build(); | |||
let components = o.components; | |||
const components = o.components; | |||
delete o.components; | |||
for (let p in o) | |||
newO[p] = o[p]; | |||
let len = components.length; | |||
const len = components.length; | |||
for (let i = 0; i < len; i++) { | |||
let c = components[i]; | |||
const c = components[i]; | |||
let newC = newO.addComponent(c.type, c); | |||
const newC = newO.addComponent(c.type, c); | |||
extend(newC, c); | |||
} | |||
this.objects.push(newO); | |||
this.pushObjectToList(newO); | |||
if (!newO.dead) | |||
this.physics.addObject(newO, newO.x, newO.y); | |||
@@ -1,6 +1,6 @@ | |||
{ | |||
"name": "isleward_server", | |||
"version": "0.8.5", | |||
"version": "0.9.0", | |||
"lockfileVersion": 1, | |||
"requires": true, | |||
"dependencies": { | |||
@@ -332,12 +332,6 @@ | |||
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", | |||
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" | |||
}, | |||
"asap": { | |||
"version": "2.0.6", | |||
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", | |||
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", | |||
"optional": true | |||
}, | |||
"asn1": { | |||
"version": "0.2.4", | |||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", | |||
@@ -538,11 +532,6 @@ | |||
"source-map": "~0.6.0" | |||
} | |||
}, | |||
"clone": { | |||
"version": "2.1.2", | |||
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", | |||
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" | |||
}, | |||
"code-point-at": { | |||
"version": "1.1.0", | |||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", | |||
@@ -796,9 +785,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.2", | |||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.2.tgz", | |||
"integrity": "sha512-QEqIp+gJ/kMHeUun7f5Vv3bteRHppHH/FMBQX/esFj/fuYfjyUKWGMo3VCvIP/V8bE9KcjHmRZrhIz2Z9oNsDA==", | |||
"requires": { | |||
"component-emitter": "~1.3.0", | |||
"component-inherit": "0.0.3", | |||
@@ -809,7 +798,7 @@ | |||
"parseqs": "0.0.6", | |||
"parseuri": "0.0.6", | |||
"ws": "~7.4.2", | |||
"xmlhttprequest-ssl": "~1.5.4", | |||
"xmlhttprequest-ssl": "~1.6.2", | |||
"yeast": "0.1.2" | |||
}, | |||
"dependencies": { | |||
@@ -844,15 +833,6 @@ | |||
"ansi-colors": "^4.1.1" | |||
} | |||
}, | |||
"errno": { | |||
"version": "0.1.7", | |||
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", | |||
"integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", | |||
"optional": true, | |||
"requires": { | |||
"prr": "~1.0.1" | |||
} | |||
}, | |||
"escape-html": { | |||
"version": "1.0.3", | |||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", | |||
@@ -999,6 +979,23 @@ | |||
"prettier-linter-helpers": "^1.0.0" | |||
} | |||
}, | |||
"eslint-plugin-requirejs": { | |||
"version": "4.0.1", | |||
"resolved": "https://registry.npmjs.org/eslint-plugin-requirejs/-/eslint-plugin-requirejs-4.0.1.tgz", | |||
"integrity": "sha512-7SCBeOZha5E1TGRxbfvNypG0/1Da3gonaT8IeWfNN9iUriamtnwXrGwYipEFr/yMHNCHRpua4LL/7DSov6aUEQ==", | |||
"dev": true, | |||
"requires": { | |||
"ignore": "5.0.5" | |||
}, | |||
"dependencies": { | |||
"ignore": { | |||
"version": "5.0.5", | |||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.0.5.tgz", | |||
"integrity": "sha512-kOC8IUb8HSDMVcYrDVezCxpJkzSQWTAzf3olpKM6o9rM5zpojx23O0Fl8Wr4+qJ6ZbPEHqf1fdwev/DS7v7pmA==", | |||
"dev": true | |||
} | |||
} | |||
}, | |||
"eslint-scope": { | |||
"version": "5.1.1", | |||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", | |||
@@ -1287,11 +1284,6 @@ | |||
"rimraf": "2" | |||
} | |||
}, | |||
"function-bind": { | |||
"version": "1.1.1", | |||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", | |||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" | |||
}, | |||
"functional-red-black-tree": { | |||
"version": "1.0.1", | |||
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", | |||
@@ -1444,9 +1436,9 @@ | |||
}, | |||
"dependencies": { | |||
"lodash": { | |||
"version": "4.17.20", | |||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", | |||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" | |||
"version": "4.17.21", | |||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", | |||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" | |||
} | |||
} | |||
}, | |||
@@ -1454,6 +1446,7 @@ | |||
"version": "4.2.3", | |||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", | |||
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", | |||
"dev": true, | |||
"optional": true | |||
}, | |||
"gtoken": { | |||
@@ -1488,14 +1481,6 @@ | |||
"har-schema": "^2.0.0" | |||
} | |||
}, | |||
"has": { | |||
"version": "1.0.3", | |||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", | |||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", | |||
"requires": { | |||
"function-bind": "^1.1.1" | |||
} | |||
}, | |||
"has-binary2": { | |||
"version": "1.0.3", | |||
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", | |||
@@ -1645,11 +1630,6 @@ | |||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", | |||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" | |||
}, | |||
"is": { | |||
"version": "3.3.0", | |||
"resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", | |||
"integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==" | |||
}, | |||
"is-extglob": { | |||
"version": "2.1.1", | |||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", | |||
@@ -1783,40 +1763,6 @@ | |||
"safe-buffer": "^5.0.1" | |||
} | |||
}, | |||
"less": { | |||
"version": "3.9.0", | |||
"resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz", | |||
"integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==", | |||
"requires": { | |||
"clone": "^2.1.2", | |||
"errno": "^0.1.1", | |||
"graceful-fs": "^4.1.2", | |||
"image-size": "~0.5.0", | |||
"mime": "^1.4.1", | |||
"mkdirp": "^0.5.0", | |||
"promise": "^7.1.1", | |||
"request": "^2.83.0", | |||
"source-map": "~0.6.0" | |||
}, | |||
"dependencies": { | |||
"image-size": { | |||
"version": "0.5.5", | |||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", | |||
"integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", | |||
"optional": true | |||
} | |||
} | |||
}, | |||
"less-middleware": { | |||
"version": "3.1.0", | |||
"resolved": "https://registry.npmjs.org/less-middleware/-/less-middleware-3.1.0.tgz", | |||
"integrity": "sha512-1FcTlNE73AVTNwcBykDbCnDPgKZT4VuCZxtlst/i4nB93Y/NsVQsZopK78zfDcT/2lsjBa5xZI8g4SFUhJqsJg==", | |||
"requires": { | |||
"less": "~3.9.0", | |||
"mkdirp": "~0.5.1", | |||
"node.extend": "~2.0.2" | |||
} | |||
}, | |||
"levn": { | |||
"version": "0.4.1", | |||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", | |||
@@ -1828,9 +1774,9 @@ | |||
} | |||
}, | |||
"lodash": { | |||
"version": "4.17.19", | |||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", | |||
"integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", | |||
"version": "4.17.21", | |||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", | |||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", | |||
"dev": true | |||
}, | |||
"lru-cache": { | |||
@@ -1893,7 +1839,8 @@ | |||
"minimist": { | |||
"version": "1.2.5", | |||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", | |||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" | |||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", | |||
"dev": true | |||
}, | |||
"minipass": { | |||
"version": "2.9.0", | |||
@@ -1918,6 +1865,7 @@ | |||
"version": "0.5.4", | |||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", | |||
"integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", | |||
"dev": true, | |||
"requires": { | |||
"minimist": "^1.2.5" | |||
} | |||
@@ -2073,15 +2021,6 @@ | |||
} | |||
} | |||
}, | |||
"node.extend": { | |||
"version": "2.0.2", | |||
"resolved": "https://registry.npmjs.org/node.extend/-/node.extend-2.0.2.tgz", | |||
"integrity": "sha512-pDT4Dchl94/+kkgdwyS2PauDFjZG0Hk0IcHIB+LkW27HLDtdoeMxHTxZh39DYbPP8UflWXWj9JcdDozF+YDOpQ==", | |||
"requires": { | |||
"has": "^1.0.3", | |||
"is": "^3.2.1" | |||
} | |||
}, | |||
"nopt": { | |||
"version": "3.0.6", | |||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", | |||
@@ -2284,15 +2223,6 @@ | |||
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", | |||
"dev": true | |||
}, | |||
"promise": { | |||
"version": "7.3.1", | |||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", | |||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", | |||
"optional": true, | |||
"requires": { | |||
"asap": "~2.0.3" | |||
} | |||
}, | |||
"proxy-addr": { | |||
"version": "2.0.6", | |||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", | |||
@@ -2302,12 +2232,6 @@ | |||
"ipaddr.js": "1.9.1" | |||
} | |||
}, | |||
"prr": { | |||
"version": "1.0.1", | |||
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", | |||
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", | |||
"optional": true | |||
}, | |||
"psl": { | |||
"version": "1.8.0", | |||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", | |||
@@ -3020,14 +2944,14 @@ | |||
} | |||
}, | |||
"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", | |||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", | |||
"integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" | |||
"version": "1.6.2", | |||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.2.tgz", | |||
"integrity": "sha512-tYOaldF/0BLfKuoA39QMwD4j2m8lq4DIncqj1yuNELX4vz9+z/ieG/vwmctjJce+boFHXstqhWnHSxc4W8f4qg==" | |||
}, | |||
"yallist": { | |||
"version": "3.1.1", | |||
@@ -1,6 +1,6 @@ | |||
{ | |||
"name": "isleward_server", | |||
"version": "0.8.6", | |||
"version": "0.9.0", | |||
"description": "isleward", | |||
"dependencies": { | |||
"axios": "^0.21.1", | |||
@@ -10,7 +10,6 @@ | |||
"express-minify": "^1.0.0", | |||
"google-spreadsheet": "^3.1.15", | |||
"image-size": "^0.9.2", | |||
"less-middleware": "^3.1.0", | |||
"rethinkdbdash": "^2.3.31", | |||
"socket.io": "^2.4.1", | |||
"universal-analytics": "^0.4.23" | |||
@@ -19,6 +18,7 @@ | |||
"babel-eslint": "^10.1.0", | |||
"eslint": "^7.12.0", | |||
"eslint-plugin-prettier": "^3.1.4", | |||
"eslint-plugin-requirejs": "^4.0.1", | |||
"sqlite3": "^5.0.0" | |||
} | |||
} |
@@ -7,11 +7,13 @@ module.exports = { | |||
playing: 0, | |||
onHandshake: function (socket) { | |||
let p = objects.build(); | |||
const p = objects.build(); | |||
p.socket = socket; | |||
p.addComponent('auth'); | |||
p.addComponent('player'); | |||
objects.pushObjectToList(p); | |||
this.players.push(p); | |||
}, | |||
@@ -1,120 +0,0 @@ | |||
let compression = require('compression'); | |||
let minify = require('express-minify'); | |||
let config = require('./config/serverConfig'); | |||
let router = require('./security/router'); | |||
let rest = require('./security/rest'); | |||
module.exports = { | |||
init: function (callback) { | |||
let app = require('express')(); | |||
let server = require('http').createServer(app); | |||
let socketServer = require('socket.io')(server, { | |||
transports: ['websocket'] | |||
}); | |||
global.cons.sockets = socketServer.sockets; | |||
app.use(compression()); | |||
app.use(minify()); | |||
app.use(function (req, res, next) { | |||
if ( | |||
!rest.willHandle(req.url) && | |||
req.url.indexOf('/server') !== 0 && | |||
req.url.indexOf('/mods') !== 0 | |||
) | |||
req.url = '/client/' + req.url; | |||
next(); | |||
}); | |||
let lessMiddleware = require('less-middleware'); | |||
app.use(lessMiddleware('../', { | |||
render: { | |||
strictMath: true | |||
} | |||
})); | |||
rest.init(app); | |||
app.get('/', this.requests.root.bind(this)); | |||
app.get(/^(.*)$/, this.requests.default.bind(this)); | |||
socketServer.on('connection', this.listeners.onConnection.bind(this)); | |||
let port = config.port || 4000; | |||
server.listen(port, function () { | |||
let message = config.startupMessage || 'Server: Ready'; | |||
_.log(message); | |||
callback(); | |||
}); | |||
}, | |||
listeners: { | |||
onConnection: function (socket) { | |||
socket.on('handshake', this.listeners.onHandshake.bind(this, socket)); | |||
socket.on('disconnect', this.listeners.onDisconnect.bind(this, socket)); | |||
socket.on('request', this.listeners.onRequest.bind(this, socket)); | |||
socket.emit('handshake'); | |||
}, | |||
onHandshake: function (socket) { | |||
cons.onHandshake(socket); | |||
}, | |||
onDisconnect: function (socket) { | |||
cons.onDisconnect(socket); | |||
}, | |||
onRequest: function (socket, msg, callback) { | |||
msg.callback = callback; | |||
if (!msg.data) | |||
msg.data = {}; | |||
if (msg.cpn) { | |||
if (!router.allowedCpn(msg)) | |||
return; | |||
cons.route(socket, msg); | |||
} else if (msg.threadModule) { | |||
if (!router.allowedGlobalCall(msg.threadModule, msg.method)) | |||
return; | |||
cons.route(socket, msg); | |||
} else { | |||
if (!router.allowedGlobal(msg)) | |||
return; | |||
msg.socket = socket; | |||
global[msg.module][msg.method](msg); | |||
} | |||
} | |||
}, | |||
requests: { | |||
root: function (req, res) { | |||
res.sendFile('index.html'); | |||
}, | |||
default: function (req, res) { | |||
let root = req.url.split('/')[1]; | |||
let file = req.params[0]; | |||
file = file.replace('/' + root + '/', ''); | |||
const validModPatterns = ['.png', '/ui/', '/clientComponents/', '/audio/']; | |||
const validRequest = ( | |||
root !== 'server' || | |||
( | |||
file.includes('mods/') && | |||
validModPatterns.some(v => file.includes(v)) | |||
) | |||
); | |||
if (!validRequest) | |||
return null; | |||
res.sendFile(file, { | |||
root: '../' + root | |||
}); | |||
} | |||
} | |||
}; |
@@ -0,0 +1,63 @@ | |||
//Imports | |||
const http = require('http'); | |||
const socketIo = require('socket.io'); | |||
const express = require('express'); | |||
const compression = require('compression'); | |||
const minify = require('express-minify'); | |||
const rest = require('../security/rest'); | |||
const { | |||
port = 4000, | |||
startupMessage = 'Server: Ready' | |||
} = require('../config/serverConfig'); | |||
const onConnection = require('./onConnection'); | |||
const { appRoot, appFile } = require('./requestHandlers'); | |||
//Methods | |||
const init = async () => { | |||
return new Promise(resolve => { | |||
const app = express(); | |||
const server = http.createServer(app); | |||
const socketServer = socketIo(server, { | |||
transports: ['websocket'] | |||
}); | |||
global.cons.sockets = socketServer.sockets; | |||
app.use(compression()); | |||
app.use(minify()); | |||
app.use((req, res, next) => { | |||
if ( | |||
!rest.willHandle(req.url) && | |||
req.url.indexOf('/server') !== 0 && | |||
req.url.indexOf('/mods') !== 0 | |||
) | |||
req.url = '/client/' + req.url; | |||
next(); | |||
}); | |||
rest.init(app); | |||
app.get('/', appRoot); | |||
app.get(/^(.*)$/, appFile); | |||
socketServer.on('connection', onConnection); | |||
server.listen(port, () => { | |||
_.log(startupMessage); | |||
resolve(); | |||
}); | |||
}); | |||
}; | |||
//Exports | |||
module.exports = { | |||
init | |||
}; |