@@ -146,6 +146,14 @@ | |||
"func-style": [1,"expression"], | |||
"indent": [2, "tab"], | |||
"key-spacing": [2,{"afterColon":true}], | |||
"max-lines-per-function": [ | |||
2, | |||
{ | |||
"max": 120, | |||
"skipBlankLines": false, | |||
"skipComments": false | |||
} | |||
], | |||
"new-parens": 2, | |||
"no-inline-comments": 2, | |||
"no-lonely-if": 2, | |||
@@ -13,3 +13,4 @@ helpers/sqlite-to-rethink/rethinkdb_data | |||
helpers/sqlite-to-rethink/tmp | |||
helpers/sqlite-to-rethink/log_file | |||
helpers/sqlite-to-rethink/rethinkdb.exe | |||
.idea |
@@ -1,4 +1,4 @@ | |||
image: node:lts-jessie | |||
image: node:10 | |||
stages: | |||
- test | |||
@@ -16,24 +16,26 @@ audit: | |||
lint-server: | |||
stage: test | |||
script: | |||
- npm install -g eslint eslint-plugin-prettier prettier babel-eslint | |||
- npm install eslint eslint-plugin-prettier prettier babel-eslint | |||
- cd src/server | |||
- eslint . | |||
- ../../node_modules/.bin/eslint . | |||
only: | |||
- merge_requests | |||
- master | |||
allow_failure: true | |||
lint-client: | |||
stage: test | |||
script: | |||
- npm install -g eslint eslint-plugin-prettier prettier babel-eslint | |||
- npm install eslint eslint-plugin-prettier prettier babel-eslint | |||
- cd src/client | |||
- eslint . | |||
- ../../node_modules/.bin/eslint . | |||
only: | |||
- merge_requests | |||
- master | |||
allow_failure: true | |||
build-image: | |||
build-image-latest: | |||
stage: build | |||
image: docker:stable | |||
services: | |||
@@ -41,10 +43,28 @@ build-image: | |||
before_script: | |||
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY | |||
variables: | |||
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG | |||
IMAGE_TAG_REF: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG | |||
IMAGE_TAG_ALIAS: $CI_REGISTRY_IMAGE:latest | |||
script: | |||
- docker build -t $IMAGE_TAG . | |||
- docker push $IMAGE_TAG | |||
- docker build -t $IMAGE_TAG_REF -t $IMAGE_TAG_ALIAS . | |||
- docker push $IMAGE_TAG_REF | |||
- docker push $IMAGE_TAG_ALIAS | |||
only: | |||
- master | |||
- tags | |||
build-image-stable: | |||
stage: build | |||
image: docker:stable | |||
services: | |||
- docker:dind | |||
before_script: | |||
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY | |||
variables: | |||
IMAGE_TAG_REF: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG | |||
IMAGE_TAG_ALIAS: $CI_REGISTRY_IMAGE:stable | |||
script: | |||
- docker build -t $IMAGE_TAG_REF -t $IMAGE_TAG_ALIAS . | |||
- docker push $IMAGE_TAG_REF | |||
- docker push $IMAGE_TAG_ALIAS | |||
only: | |||
- tags |
@@ -1,5 +1,5 @@ | |||
# Base image on Node.js 10.x LTS (dubnium) | |||
FROM node:10 | |||
FROM node:10-alpine | |||
# Create app directory | |||
WORKDIR /usr/src/isleward | |||
@@ -17,4 +17,4 @@ RUN npm install --only-production | |||
EXPOSE 4000 | |||
# Launch Isleward server | |||
CMD ["node", "--expose-gc", "index.js"] | |||
CMD ["node", "index.js"] |
@@ -2,14 +2,14 @@ | |||
const r = null; | |||
//Count the amount of permadead characters | |||
r.db('test').table('character').filter({ | |||
r.db('live').table('character').filter({ | |||
value: { | |||
permadead: true | |||
} | |||
}).count(); | |||
//Count the amount of permadead characters per spirit | |||
r.db('test').table('character') | |||
r.db('live').table('character') | |||
.filter({ | |||
value: { | |||
permadead: true | |||
@@ -21,7 +21,7 @@ r.db('test').table('character') | |||
.count(); | |||
//All players that are level 20 | |||
r.db('test').table('character') | |||
r.db('live').table('character') | |||
.filter(row => { | |||
return row('value')('components').contains(cpn => { | |||
return cpn('type').eq('stats').and(cpn('values')('level').ge(20)); | |||
@@ -29,10 +29,11 @@ r.db('test').table('character') | |||
}); | |||
//Group by mod action source, aggregate and order by count | |||
r.db('test').table('modLog') | |||
r.db('live').table('modLog') | |||
.group(f => f('value')('source')).count().ungroup().orderBy('reduction'); | |||
r.db('test').table('character') | |||
//List Items with dex > 30 | |||
r.db('live').table('character') | |||
.concatMap(row => { | |||
return row('value')('components') | |||
.filter(cpn => { | |||
@@ -51,8 +52,8 @@ r.db('test').table('character') | |||
}); | |||
}); | |||
//Play time per account from low to thigh | |||
r.db('test').table('character') | |||
//Play time per account from low to high | |||
r.db('live').table('character') | |||
.concatMap(row => { | |||
return row('value')('components') | |||
.filter(cpn => { | |||
@@ -70,3 +71,57 @@ r.db('test').table('character') | |||
.sum('played') | |||
.ungroup() | |||
.orderBy('reduction'); | |||
//Amount of characters per level | |||
r.db('live').table('character') | |||
.concatMap(row => { | |||
return row('value')('components') | |||
.filter(cpn => { | |||
return cpn('type').eq('stats'); | |||
}) | |||
.concatMap(c => { | |||
return [{ | |||
level: c('values')('level') | |||
}]; | |||
}); | |||
}) | |||
.group('level') | |||
.count(); | |||
r.db('live').table('character') | |||
.concatMap(row => { | |||
return row('value')('components') | |||
.filter(cpn => { | |||
return cpn('type').eq('stats'); | |||
}) | |||
.concatMap(c => { | |||
return [{ | |||
level: c('values')('level'), | |||
xp: c('values')('xpTotal') | |||
}]; | |||
}); | |||
}) | |||
.filter(c => { | |||
return c('level').eq(2); | |||
}) | |||
.group('xp') | |||
.count(); | |||
r.db('live').table('character') | |||
.concatMap(row => { | |||
return row('value')('components') | |||
.filter(cpn => { | |||
return cpn('type').eq('stats'); | |||
}) | |||
.concatMap(c => { | |||
return [{ | |||
level: c('values')('level'), | |||
xp: c('values')('xpTotal'), | |||
streaks: c('stats')('mobKillStreaks') | |||
}]; | |||
}); | |||
}) | |||
.filter(c => { | |||
return c('level').eq(2).and(c('xp').eq(10)); | |||
}); |
@@ -11,7 +11,7 @@ | |||
<link rel="stylesheet" href="css/main.css"> | |||
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script> | |||
<script src="js/system/addons.js"></script> | |||
<script src="plugins/require.min.js" data-main="js/app"></script> | |||
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" data-main="js/app"></script> | |||
<script>if (window.module) module = window.module;</script> | |||
<link rel="icon" href="images/favicon.ico"> | |||
<link rel="apple-touch-icon" href="images/icon.png"> | |||
@@ -5,17 +5,16 @@ require.config({ | |||
baseUrl: '', | |||
waitSeconds: 120, | |||
paths: { | |||
socket: 'plugins/socket', | |||
wquery: 'plugins/jquery.min', | |||
text: 'plugins/text', | |||
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', | |||
text: 'https://cdnjs.cloudflare.com/ajax/libs/require-text/2.0.12/text.min', | |||
html: 'plugins/html', | |||
css: 'plugins/css', | |||
css: 'https://cdnjs.cloudflare.com/ajax/libs/require-css/0.1.10/css.min', | |||
main: 'js/main', | |||
helpers: 'js/misc/helpers', | |||
particles: 'plugins/pixi.particles', | |||
picture: 'plugins/pixi.picture', | |||
pixi: 'plugins/pixi.min', | |||
howler: 'plugins/howler.min' | |||
particles: 'plugins/pixi.particles.min', | |||
pixi: 'https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.1.3/pixi.min', | |||
howler: 'https://cdnjs.cloudflare.com/ajax/libs/howler/2.1.2/howler.core.min' | |||
}, | |||
shim: { | |||
howler: { | |||
@@ -24,12 +23,12 @@ require.config({ | |||
socket: { | |||
exports: 'io' | |||
}, | |||
wquery: { | |||
jquery: { | |||
exports: '$' | |||
}, | |||
helpers: { | |||
deps: [ | |||
'wquery' | |||
'jquery' | |||
] | |||
}, | |||
pixi: { | |||
@@ -40,11 +39,6 @@ require.config({ | |||
'pixi' | |||
] | |||
}, | |||
picture: { | |||
deps: [ | |||
'pixi' | |||
] | |||
}, | |||
main: { | |||
deps: [ | |||
'helpers', | |||
@@ -32,7 +32,8 @@ let components = [ | |||
'serverActions', | |||
'social', | |||
'passives', | |||
'sound' | |||
'sound', | |||
'whirlwind' | |||
].map(function (c) { | |||
return 'js/components/' + c; | |||
}); | |||
@@ -1,14 +1,12 @@ | |||
define([ | |||
'js/rendering/renderer', | |||
'picture' | |||
'js/rendering/renderer' | |||
], function ( | |||
renderer, | |||
picture | |||
renderer | |||
) { | |||
return { | |||
type: 'lightPatch', | |||
color: 'f7ffb2', | |||
color: 'ffeb38', | |||
patches: [], | |||
rays: [], | |||
@@ -20,11 +18,13 @@ define([ | |||
let x = obj.x; | |||
let y = obj.y; | |||
let maxDistance = Math.sqrt(Math.pow(obj.width / 2, 2) + Math.pow(obj.height / 2, 2)); | |||
let maxDistance = Math.sqrt(Math.pow(obj.width / 3, 2) + Math.pow(obj.height / 3, 2)); | |||
for (let i = 0; i < obj.width; i++) { | |||
for (let j = 0; j < obj.height; j++) { | |||
let distance = maxDistance - Math.sqrt(Math.pow((obj.width / 2) - i, 2) + Math.pow((obj.width / 2) - i, 2)); | |||
let alpha = distance / maxDistance; | |||
let distance = maxDistance - Math.sqrt(Math.pow((obj.width / 2) - i, 2) + Math.pow((obj.width / 2) - j, 2)); | |||
const maxAlpha = (distance / maxDistance) * 0.2; | |||
if (maxAlpha <= 0.05) | |||
continue; | |||
let sprite = renderer.buildObject({ | |||
x: (x + i), | |||
@@ -33,11 +33,17 @@ define([ | |||
cell: 0, | |||
layerName: 'lightPatches' | |||
}); | |||
sprite.alpha = (0.2 + (Math.random() * 1)) * alpha; | |||
sprite.alpha = (maxAlpha * 0.3) + (Math.random() * (maxAlpha * 0.7)); | |||
sprite.tint = '0x' + this.color; | |||
sprite.blendMode = PIXI.BLEND_MODES.OVERLAY; | |||
sprite.pluginName = 'picture'; | |||
const size = (3 + ~~(Math.random() * 6)) * scaleMult; | |||
sprite.width = size; | |||
sprite.height = size; | |||
sprite.x += scaleMult * ~~(Math.random() * 4); | |||
sprite.y += scaleMult * ~~(Math.random() * 4); | |||
sprite.blendMode = PIXI.BLEND_MODES.ADD; | |||
this.patches.push(sprite); | |||
} | |||
@@ -0,0 +1,67 @@ | |||
define([ | |||
'js/rendering/effects' | |||
], function ( | |||
effects | |||
) { | |||
return { | |||
type: 'whirlwind', | |||
source: null, | |||
row: null, | |||
col: null, | |||
delay: 40, | |||
coordinates: [], | |||
objects: null, | |||
init: async function (blueprint) { | |||
await this.getObjectsModule(); | |||
if (!this.source) { | |||
this.obj.destroyed = true; | |||
return; | |||
} | |||
this.coordinates.forEach(([x, y], i) => { | |||
const wait = i * this.delay; | |||
setTimeout(this.spawnThing.bind(this, x, y), wait); | |||
}); | |||
effects.register(this); | |||
}, | |||
getObjectsModule: async function () { | |||
return new Promise(res => { | |||
require(['js/objects/objects'], o => { | |||
this.objects = o; | |||
res(); | |||
}); | |||
}); | |||
}, | |||
spawnThing: function (x, y) { | |||
const { row, col } = this; | |||
this.objects.buildObject({ | |||
x, | |||
y, | |||
components: [{ | |||
type: 'attackAnimation', | |||
row, | |||
col | |||
}] | |||
}); | |||
}, | |||
renderManual: function () { | |||
}, | |||
destroy: function () { | |||
effects.unregister(this); | |||
} | |||
}; | |||
}); |
@@ -73,22 +73,6 @@ if (!String.prototype.padStart) { | |||
}; | |||
} | |||
if (!String.prototype.padStart) { | |||
//eslint-disable-next-line no-extend-native | |||
String.prototype.padStart = function padStart (targetLength, padString) { | |||
targetLength = targetLength >> 0; | |||
padString = String(typeof padString !== 'undefined' ? padString : ' '); | |||
if (this.length >= targetLength) | |||
return String(this); | |||
targetLength = targetLength - this.length; | |||
if (targetLength > padString.length) | |||
padString += padString.repeat(targetLength / padString.length); | |||
return padString.slice(0, targetLength) + String(this); | |||
}; | |||
} | |||
window._ = { | |||
get2dArray: function (w, h, def) { | |||
def = def || 0; | |||
@@ -18,8 +18,8 @@ define([ | |||
addComponent: function (type, options) { | |||
let c = this[type]; | |||
if ((!c) || (options.new)) { | |||
let template = components.getTemplate(type); | |||
if (!c || options.new) { | |||
const template = components.getTemplate(type); | |||
if (!template) | |||
return; | |||
@@ -30,7 +30,7 @@ define([ | |||
c[o] = options[o]; | |||
//Only use component to initialize other components? | |||
if ((c.init) && (c.init(options))) | |||
if (c.init && c.init(options)) | |||
return null; | |||
this[c.type] = c; | |||
@@ -49,18 +49,18 @@ define([ | |||
if (!cpn) | |||
return; | |||
this.components.spliceWhere(function (c) { | |||
return (c === cpn); | |||
this.components.spliceWhere(c => { | |||
return c === cpn; | |||
}); | |||
delete this[type]; | |||
}, | |||
update: function () { | |||
let oComponents = this.components; | |||
const oComponents = this.components; | |||
let len = oComponents.length; | |||
for (let i = 0; i < len; i++) { | |||
let c = oComponents[i]; | |||
const c = oComponents[i]; | |||
if (c.update) | |||
c.update(); | |||
@@ -86,7 +86,7 @@ define([ | |||
return; | |||
this.sprite.x = (this.x * scale) + (this.flipX ? scale : 0) + this.offsetX; | |||
let oldY = this.sprite.x; | |||
const oldY = this.sprite.y; | |||
this.sprite.y = (this.y * scale) + this.offsetY; | |||
if (this.sprite.width > scale) { | |||
@@ -101,10 +101,10 @@ define([ | |||
if (oldY !== this.sprite.y) | |||
renderer.reorder(); | |||
this.sprite.scale.x = (this.flipX ? -scaleMult : scaleMult); | |||
this.sprite.scale.x = this.flipX ? -scaleMult : scaleMult; | |||
['nameSprite', 'chatSprite'].forEach(function (s, i) { | |||
let sprite = this[s]; | |||
['nameSprite', 'chatSprite'].forEach((s, i) => { | |||
const sprite = this[s]; | |||
if (!sprite) | |||
return; | |||
@@ -116,7 +116,7 @@ define([ | |||
sprite.x = (this.x * scale) + (scale / 2) - (sprite.width / 2); | |||
sprite.y = (this.y * scale) + yAdd; | |||
}, this); | |||
}); | |||
if (this.stats) | |||
this.stats.updateHpSprite(); | |||
@@ -127,9 +127,9 @@ define([ | |||
this.sprite.visible = visible; | |||
if (this.nameSprite) | |||
this.nameSprite.visible = ((visible) && (config.showNames)); | |||
this.nameSprite.visible = (visible && config.showNames); | |||
this.components.forEach(function (c) { | |||
this.components.forEach(c => { | |||
if (c.setVisible) | |||
c.setVisible(visible); | |||
}); | |||
@@ -145,10 +145,10 @@ define([ | |||
}); | |||
} | |||
let oComponents = this.components; | |||
let cLen = oComponents.length; | |||
const oComponents = this.components; | |||
const cLen = oComponents.length; | |||
for (let i = 0; i < cLen; i++) { | |||
let c = oComponents[i]; | |||
const c = oComponents[i]; | |||
if (c.destroy) | |||
c.destroy(); | |||
} | |||
@@ -162,11 +162,8 @@ define([ | |||
if (this.pather) | |||
this.pather.onDeath(); | |||
for (let e in this.eventCallbacks) { | |||
this.eventCallbacks[e].forEach(function (c) { | |||
events.off(e, c); | |||
}, this); | |||
} | |||
for (let e in this.eventCallbacks) | |||
this.eventCallbacks[e].forEach(c => events.off(e, c)); | |||
} | |||
}; | |||
}); |
@@ -1,9 +1,7 @@ | |||
define([ | |||
'js/rendering/renderer', | |||
'picture' | |||
'js/rendering/renderer' | |||
], function ( | |||
renderer, | |||
picture | |||
renderer | |||
) { | |||
return { | |||
build: function (config) { | |||
@@ -80,8 +78,7 @@ define([ | |||
lightPatch.width = scaleMult * 3; | |||
lightPatch.height = scaleMult * 3; | |||
lightPatch.blendMode = PIXI.BLEND_MODES.OVERLAY; | |||
lightPatch.pluginName = 'picture'; | |||
lightPatch.blendMode = PIXI.BLEND_MODES.ADD; | |||
line.sprites.push(lightPatch); | |||
} | |||
@@ -6,8 +6,7 @@ define([ | |||
'js/rendering/tileOpacity', | |||
'js/rendering/particles', | |||
'js/rendering/shaders/outline', | |||
'js/rendering/spritePool', | |||
'picture' | |||
'js/rendering/spritePool' | |||
], function ( | |||
resources, | |||
events, | |||
@@ -16,8 +15,7 @@ define([ | |||
tileOpacity, | |||
particles, | |||
shaderOutline, | |||
spritePool, | |||
picture | |||
spritePool | |||
) { | |||
let pixi = PIXI; | |||
let mRandom = Math.random.bind(Math); | |||
@@ -71,8 +69,8 @@ define([ | |||
hiddenRooms: null, | |||
init: function () { | |||
PIXI.GC_MODES.DEFAULT = PIXI.GC_MODES.AUTO; | |||
PIXI.SCALE_MODES.DEFAULT = PIXI.SCALE_MODES.NEAREST; | |||
PIXI.settings.GC_MODE = PIXI.GC_MODES.AUTO; | |||
PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST; | |||
events.on('onGetMap', this.onGetMap.bind(this)); | |||
events.on('onToggleFullscreen', this.toggleScreen.bind(this)); | |||
@@ -84,7 +82,9 @@ define([ | |||
this.showTilesW = Math.ceil((this.width / scale) / 2) + 3; | |||
this.showTilesH = Math.ceil((this.height / scale) / 2) + 3; | |||
this.renderer = pixi.autoDetectRenderer(this.width, this.height, { | |||
this.renderer = new PIXI.Renderer({ | |||
width: this.width, | |||
height: this.height, | |||
backgroundColor: '0x2d2136' | |||
}); | |||
@@ -335,7 +335,7 @@ define([ | |||
this.clean(); | |||
spritePool.clean(); | |||
this.stage.filters = [new PIXI.filters.VoidFilter()]; | |||
this.stage.filters = [new PIXI.filters.AlphaFilter()]; | |||
this.stage.filterArea = new PIXI.Rectangle(0, 0, w * scale, h * scale); | |||
this.hiddenRooms = msg.hiddenRooms; | |||
@@ -786,7 +786,7 @@ define([ | |||
obj.sprite.texture = this.getTexture(obj.sheetName, obj.cell, obj.sprite.width / scaleMult); | |||
}, | |||
reorder: function (sprite) { | |||
reorder: function () { | |||
this.layers.mobs.children.sort((a, b) => b.y - a.y); | |||
}, | |||
@@ -1,174 +0,0 @@ | |||
/* | |||
* Require-CSS RequireJS css! loader plugin | |||
* 0.1.8 | |||
* Guy Bedford 2014 | |||
* MIT | |||
*/ | |||
/* | |||
* | |||
* Usage: | |||
* require(['css!./mycssFile']); | |||
* | |||
* Tested and working in (up to latest versions as of March 2013): | |||
* Android | |||
* iOS 6 | |||
* IE 6 - 10 | |||
* Chome 3 - 26 | |||
* Firefox 3.5 - 19 | |||
* Opera 10 - 12 | |||
* | |||
* browserling.com used for virtual testing environment | |||
* | |||
* Credit to B Cavalier & J Hann for the IE 6 - 9 method, | |||
* refined with help from Martin Cermak | |||
* | |||
* Sources that helped along the way: | |||
* - https://developer.mozilla.org/en-US/docs/Browser_detection_using_the_user_agent | |||
* - http://www.phpied.com/when-is-a-stylesheet-really-loaded/ | |||
* - https://github.com/cujojs/curl/blob/master/src/curl/plugin/css.js | |||
* | |||
*/ | |||
define(function() { | |||
//>>excludeStart('excludeRequireCss', pragmas.excludeRequireCss) | |||
if (typeof window == 'undefined') | |||
return { | |||
load: function(n, r, load) { | |||
load() | |||
} | |||
}; | |||
var head = document.getElementsByTagName('head')[0]; | |||
var engine = window.navigator.userAgent.match(/Trident\/([^ ;]*)|AppleWebKit\/([^ ;]*)|Opera\/([^ ;]*)|rv\:([^ ;]*)(.*?)Gecko\/([^ ;]*)|MSIE\s([^ ;]*)|AndroidWebKit\/([^ ;]*)/) || 0; | |||
// use <style> @import load method (IE < 9, Firefox < 18) | |||
var useImportLoad = false; | |||
// set to false for explicit <link> load checking when onload doesn't work perfectly (webkit) | |||
var useOnload = true; | |||
// trident / msie | |||
if (engine[1] || engine[7]) | |||
useImportLoad = parseInt(engine[1]) < 6 || parseInt(engine[7]) <= 9; | |||
// webkit | |||
else if (engine[2] || engine[8]) | |||
useOnload = false; | |||
// gecko | |||
else if (engine[4]) | |||
useImportLoad = parseInt(engine[4]) < 18; | |||
//>>excludeEnd('excludeRequireCss') | |||
//main api object | |||
var cssAPI = {}; | |||
//>>excludeStart('excludeRequireCss', pragmas.excludeRequireCss) | |||
cssAPI.pluginBuilder = './css-builder'; | |||
// <style> @import load method | |||
var curStyle, curSheet; | |||
var createStyle = function() { | |||
curStyle = document.createElement('style'); | |||
head.appendChild(curStyle); | |||
curSheet = curStyle.styleSheet || curStyle.sheet; | |||
} | |||
var ieCnt = 0; | |||
var ieLoads = []; | |||
var ieCurCallback; | |||
var createIeLoad = function(url) { | |||
curSheet.addImport(url); | |||
curStyle.onload = function() { | |||
processIeLoad() | |||
}; | |||
ieCnt++; | |||
if (ieCnt == 31) { | |||
createStyle(); | |||
ieCnt = 0; | |||
} | |||
} | |||
var processIeLoad = function() { | |||
ieCurCallback(); | |||
var nextLoad = ieLoads.shift(); | |||
if (!nextLoad) { | |||
ieCurCallback = null; | |||
return; | |||
} | |||
ieCurCallback = nextLoad[1]; | |||
createIeLoad(nextLoad[0]); | |||
} | |||
var importLoad = function(url, callback) { | |||
if (!curSheet || !curSheet.addImport) | |||
createStyle(); | |||
if (curSheet && curSheet.addImport) { | |||
// old IE | |||
if (ieCurCallback) { | |||
ieLoads.push([url, callback]); | |||
} else { | |||
createIeLoad(url); | |||
ieCurCallback = callback; | |||
} | |||
} else { | |||
// old Firefox | |||
curStyle.textContent = '@import "' + url + '";'; | |||
var loadInterval = setInterval(function() { | |||
try { | |||
curStyle.sheet.cssRules; | |||
clearInterval(loadInterval); | |||
callback(); | |||
} catch (e) {} | |||
}, 10); | |||
} | |||
} | |||
// <link> load method | |||
var linkLoad = function(url, callback) { | |||
var link = document.createElement('link'); | |||
link.type = 'text/css'; | |||
link.rel = 'stylesheet'; | |||
if (useOnload) { | |||
link.onload = function() { | |||
link.onload = function() {}; | |||
// for style dimensions queries, a short delay can still be necessary | |||
setTimeout(callback, 7); | |||
} | |||
} else { | |||
var loadInterval = setInterval(function() { | |||
for (var i = 0; i < document.styleSheets.length; i++) { | |||
var sheet = document.styleSheets[i]; | |||
if (sheet.href == link.href) { | |||
clearInterval(loadInterval); | |||
return callback(); | |||
} | |||
} | |||
}, 10); | |||
} | |||
link.href = url; | |||
head.appendChild(link); | |||
} | |||
//>>excludeEnd('excludeRequireCss') | |||
cssAPI.normalize = function(name, normalize) { | |||
if (name.substr(name.length - 4, 4) == '.css') | |||
name = name.substr(0, name.length - 4); | |||
return normalize(name); | |||
} | |||
//>>excludeStart('excludeRequireCss', pragmas.excludeRequireCss) | |||
cssAPI.load = function(cssId, req, load, config) { | |||
(useImportLoad ? importLoad : linkLoad)(req.toUrl(cssId + '.css'), load); | |||
} | |||
//>>excludeEnd('excludeRequireCss') | |||
return cssAPI; | |||
}); |
@@ -46,14 +46,11 @@ if (!Array.prototype.random) { | |||
* @namespace PIXI.particles | |||
*/ | |||
(function () { | |||
"use strict"; | |||
// Check for window, fallback to global | |||
var global = typeof window !== 'undefined' ? window : GLOBAL; | |||
let global = typeof window !== 'undefined' ? window : GLOBAL; | |||
// Define PIXI Flash namespace | |||
var particles = {}; | |||
let particles = {}; | |||
// Export for Node-compatible environments like Electron | |||
if (typeof module !== 'undefined' && module.exports) { | |||
@@ -68,52 +65,46 @@ if (!Array.prototype.random) { | |||
} | |||
// If we're in the browser make sure PIXI is available | |||
else if (typeof PIXI === 'undefined') { | |||
if (true) { | |||
throw "pixi-particles requires pixi.js to be loaded first"; | |||
} else { | |||
throw "Requires pixi.js"; | |||
} | |||
if (true) | |||
throw 'pixi-particles requires pixi.js to be loaded first'; | |||
else | |||
throw 'Requires pixi.js'; | |||
} | |||
// Assign to global namespace | |||
global.PIXI.particles = global.PIXI.particles || particles; | |||
}()); | |||
})(); | |||
/** | |||
* @module Pixi Particles | |||
* @namespace PIXI.particles | |||
*/ | |||
(function (PIXI, undefined) { | |||
"use strict"; | |||
var BLEND_MODES = PIXI.BLEND_MODES || PIXI.blendModes; | |||
var Texture = PIXI.Texture; | |||
let BLEND_MODES = PIXI.BLEND_MODES || PIXI.blendModes; | |||
let Texture = PIXI.Texture; | |||
/** | |||
* Contains helper functions for particles and emitters to use. | |||
* @class ParticleUtils | |||
* @static | |||
*/ | |||
var ParticleUtils = {}; | |||
let ParticleUtils = {}; | |||
var DEG_TO_RADS = ParticleUtils.DEG_TO_RADS = Math.PI / 180; | |||
let DEG_TO_RADS = ParticleUtils.DEG_TO_RADS = Math.PI / 180; | |||
ParticleUtils.useAPI3 = false; | |||
// avoid the string replacement of '"1.6.7"' | |||
var version = PIXI["VER" + "SION"]; // jshint ignore:line | |||
if (version && parseInt(version.substring(0, version.indexOf("."))) >= 3) { | |||
let version = PIXI['VER' + 'SION']; // jshint ignore:line | |||
if (version && parseInt(version.substring(0, version.indexOf('.'))) >= 3) | |||
ParticleUtils.useAPI3 = true; | |||
} | |||
var empty = ParticleUtils.EMPTY_TEXTURE = null; | |||
let empty = ParticleUtils.EMPTY_TEXTURE = null; | |||
if (ParticleUtils.useAPI3) { | |||
empty = ParticleUtils.EMPTY_TEXTURE = Texture.EMPTY; | |||
//prevent any events from being used on the empty texture, as well as destruction of it | |||
//v4 of Pixi does this, but doing it again won't hurt | |||
empty.on = empty.destroy = empty.once = empty.emit = function () {}; | |||
} else { | |||
var canvas = document.createElement("canvas"); | |||
let canvas = document.createElement('canvas'); | |||
canvas.width = canvas.height = 1; | |||
empty = ParticleUtils.EMPTY_TEXTURE = PIXI.Texture.fromCanvas(canvas); | |||
//have the particle not render, even though we have an empty canvas that would be | |||
@@ -133,10 +124,10 @@ if (!Array.prototype.random) { | |||
ParticleUtils.rotatePoint = function (angle, p) { | |||
if (!angle) return; | |||
angle *= DEG_TO_RADS; | |||
var s = Math.sin(angle); | |||
var c = Math.cos(angle); | |||
var xnew = p.x * c - p.y * s; | |||
var ynew = p.x * s + p.y * c; | |||
let s = Math.sin(angle); | |||
let c = Math.cos(angle); | |||
let xnew = p.x * c - p.y * s; | |||
let ynew = p.x * s + p.y * c; | |||
p.x = xnew; | |||
p.y = ynew; | |||
}; | |||
@@ -162,7 +153,7 @@ if (!Array.prototype.random) { | |||
*/ | |||
ParticleUtils.normalize = function (point) { | |||
if ((point.x != 0) || (point.y != 0)) { | |||
var oneOverLen = 1 / ParticleUtils.length(point); | |||
let oneOverLen = 1 / ParticleUtils.length(point); | |||
point.x *= oneOverLen; | |||
point.y *= oneOverLen; | |||
} | |||
@@ -206,11 +197,11 @@ if (!Array.prototype.random) { | |||
output.length = 0; | |||
else | |||
output = []; | |||
if (color.charAt(0) == "#") | |||
if (color.charAt(0) == '#') | |||
color = color.substr(1); | |||
else if (color.indexOf("0x") === 0) | |||
else if (color.indexOf('0x') === 0) | |||
color = color.substr(2); | |||
var alpha; | |||
let alpha; | |||
if (color.length == 8) { | |||
alpha = color.substr(0, 2); | |||
color = color.substr(2); | |||
@@ -234,17 +225,17 @@ if (!Array.prototype.random) { | |||
* @static | |||
*/ | |||
ParticleUtils.generateEase = function (segments) { | |||
var qty = segments.length; | |||
var oneOverQty = 1 / qty; | |||
let qty = segments.length; | |||
let oneOverQty = 1 / qty; | |||
/* | |||
* Calculates the percentage of change at a given point in time (0-1 inclusive). | |||
* @param {Number} time The time of the ease, 0-1 inclusive. | |||
* @return {Number} The percentage of the change, 0-1 inclusive (unless your | |||
* ease goes outside those bounds). | |||
*/ | |||
var simpleEase = function (time) { | |||
var t, s; | |||
var i = (qty * time) | 0; //do a quick floor operation | |||
let simpleEase = function (time) { | |||
let t, s; | |||
let i = (qty * time) | 0; //do a quick floor operation | |||
t = (time - (i * oneOverQty)) * qty; | |||
s = segments[i] || segments[qty - 1]; | |||
return (s.s + t * (2 * (1 - t) * (s.cp - s.s) + t * (s.e - s.s))); | |||
@@ -262,25 +253,21 @@ if (!Array.prototype.random) { | |||
ParticleUtils.getBlendMode = function (name) { | |||
if (!name) return BLEND_MODES.NORMAL; | |||
name = name.toUpperCase(); | |||
while (name.indexOf(" ") >= 0) | |||
name = name.replace(" ", "_"); | |||
while (name.indexOf(' ') >= 0) | |||
name = name.replace(' ', '_'); | |||
return BLEND_MODES[name] || BLEND_MODES.NORMAL; | |||
}; | |||
PIXI.particles.ParticleUtils = ParticleUtils; | |||
}(PIXI)); | |||
})(PIXI); | |||
/** | |||
* @module Pixi Particles | |||
* @namespace PIXI.particles | |||
*/ | |||
(function (PIXI, undefined) { | |||
"use strict"; | |||
var ParticleUtils = PIXI.particles.ParticleUtils; | |||
var Sprite = PIXI.Sprite; | |||
var useAPI3 = ParticleUtils.useAPI3; | |||
let ParticleUtils = PIXI.particles.ParticleUtils; | |||
let Sprite = PIXI.Sprite; | |||
let useAPI3 = ParticleUtils.useAPI3; | |||
/** | |||
* An individual particle image. You shouldn't have to deal with these. | |||
@@ -288,15 +275,14 @@ if (!Array.prototype.random) { | |||
* @constructor | |||
* @param {Emitter} emitter The emitter that controls this particle. | |||
*/ | |||
var Particle = function (emitter) { | |||
let Particle = function (emitter) { | |||
//start off the sprite with a blank texture, since we are going to replace it | |||
//later when the particle is initialized. Pixi v2 requires a texture, v3 supplies a | |||
//blank texture for us. | |||
if (useAPI3) { | |||
if (useAPI3) | |||
Sprite.call(this); | |||
} else { | |||
else | |||
Sprite.call(this, ParticleUtils.EMPTY_TEXTURE); | |||
} | |||
/** | |||
* The emitter that controls this particle. | |||
@@ -489,7 +475,7 @@ if (!Array.prototype.random) { | |||
}; | |||
// Reference to the prototype | |||
var p = Particle.prototype = Object.create(Sprite.prototype); | |||
let p = Particle.prototype = Object.create(Sprite.prototype); | |||
/** | |||
* Initializes the particle for use, based on the properties that have to | |||
@@ -563,9 +549,8 @@ if (!Array.prototype.random) { | |||
if (useAPI3) { | |||
//remove warning on PIXI 3 | |||
this.texture = art || ParticleUtils.EMPTY_TEXTURE; | |||
} else { | |||
} else | |||
this.setTexture(art || ParticleUtils.EMPTY_TEXTURE); | |||
} | |||
}; | |||
/** | |||
@@ -594,7 +579,7 @@ if (!Array.prototype.random) { | |||
} | |||
//determine our interpolation value | |||
var lerp = this.age * this._oneOverLife; //lifetime / maxLife; | |||
let lerp = this.age * this._oneOverLife; //lifetime / maxLife; | |||
if (this.ease) { | |||
if (this.ease.length == 4) { | |||
//the t, b, c, d parameters that some tween libraries use | |||
@@ -612,7 +597,7 @@ if (!Array.prototype.random) { | |||
this.alpha = (this.endAlpha - this.startAlpha) * lerp + this.startAlpha; | |||
//interpolate scale | |||
if (this._doScale) { | |||
var scale = (this.endScale - this.startScale) * lerp + this.startScale; | |||
let scale = (this.endScale - this.startScale) * lerp + this.startScale; | |||
this.rawScale.x = this.rawScale.y = scale; | |||
this.scale.x = this.scale.y = ~~(scale / 2) * 2; | |||
} | |||
@@ -620,7 +605,7 @@ if (!Array.prototype.random) { | |||
if (this._doNormalMovement) { | |||
//interpolate speed | |||
if (this._doSpeed) { | |||
var speed = (this.endSpeed - this.startSpeed) * lerp + this.startSpeed; | |||
let speed = (this.endSpeed - this.startSpeed) * lerp + this.startSpeed; | |||
ParticleUtils.normalize(this.velocity); | |||
ParticleUtils.scaleBy(this.velocity, speed); | |||
} else if (this._doAcceleration) { | |||
@@ -628,12 +613,12 @@ if (!Array.prototype.random) { | |||
this.velocity.y += this.acceleration.y * delta; | |||
} | |||
//adjust position based on velocity | |||
var dir = this.direction; | |||
let dir = this.direction; | |||
if (dir) { | |||
var dx = dir.x; | |||
var dy = dir.y; | |||
var vx = this.velocity.x; | |||
var vy = this.velocity.y; | |||
let dx = dir.x; | |||
let dy = dir.y; | |||
let vx = this.velocity.x; | |||
let vy = this.velocity.y; | |||
if ((vy > 0) && (dy < 0)) | |||
vy *= -1; | |||
this.rawPosition.x += dx * vx * delta; | |||
@@ -648,15 +633,15 @@ if (!Array.prototype.random) { | |||
} | |||
//interpolate color | |||
if (this._doColor) { | |||
var r = (this._eR - this._sR) * lerp + this._sR; | |||
var g = (this._eG - this._sG) * lerp + this._sG; | |||
var b = (this._eB - this._sB) * lerp + this._sB; | |||
let r = (this._eR - this._sR) * lerp + this._sR; | |||
let g = (this._eG - this._sG) * lerp + this._sG; | |||
let b = (this._eB - this._sB) * lerp + this._sB; | |||
this.tint = ParticleUtils.combineRGBComponents(r, g, b); | |||
} | |||
//update rotation | |||
if (this.rotationSpeed !== 0) { | |||
if (this.rotationSpeed !== 0) | |||
this.rotation += this.rotationSpeed * delta; | |||
} else if (this.acceleration) { | |||
else if (this.acceleration) { | |||
if (this.allowRotation) | |||
this.rotation = Math.atan2(this.velocity.y, this.velocity.x); // + Math.PI / 2; | |||
else | |||
@@ -700,9 +685,9 @@ if (!Array.prototype.random) { | |||
*/ | |||
Particle.parseArt = function (art) { | |||
//convert any strings to Textures. | |||
var i; | |||
let i; | |||
for (i = art.length; i >= 0; --i) { | |||
if (typeof art[i] == "string") | |||
if (typeof art[i] === 'string') | |||
art[i] = PIXI.Texture.fromImage(art[i]); | |||
} | |||
//particles from different base textures will be slower in WebGL than if they | |||
@@ -711,7 +696,7 @@ if (!Array.prototype.random) { | |||
for (i = art.length - 1; i > 0; --i) { | |||
if (art[i].baseTexture != art[i - 1].baseTexture) { | |||
if (window.console) | |||
console.warn("PixiParticles: using particle textures from different images may hinder performance in WebGL"); | |||
console.warn('PixiParticles: using particle textures from different images may hinder performance in WebGL'); | |||
break; | |||
} | |||
} | |||
@@ -733,20 +718,16 @@ if (!Array.prototype.random) { | |||
}; | |||
PIXI.particles.Particle = Particle; | |||
}(PIXI)); | |||
})(PIXI); | |||
/** | |||
* @module Pixi Particles | |||
* @namespace PIXI.particles | |||
*/ | |||
(function (PIXI, undefined) { | |||
"use strict"; | |||
var ParticleUtils = PIXI.particles.ParticleUtils, | |||
let ParticleUtils = PIXI.particles.ParticleUtils, | |||
Particle = PIXI.particles.Particle, | |||
ParticleContainer = PIXI.particles.ParticleContainer || PIXI.ParticleContainer; | |||
ParticleContainer = PIXI.ParticleContainer; | |||
/** | |||
* A particle emitter. | |||
@@ -761,7 +742,7 @@ if (!Array.prototype.random) { | |||
* @param {Boolean} [config.emit=true] If config.emit is explicitly passed as false, the Emitter | |||
* will start disabled. | |||
*/ | |||
var Emitter = function (particleParent, particleImages, config) { | |||
let Emitter = function (particleParent, particleImages, config) { | |||
this.chance = config.chance || null; | |||
this.allowRotation = config.allowRotation || false; | |||
this.randomColor = config.randomColor || false; | |||
@@ -1098,22 +1079,22 @@ if (!Array.prototype.random) { | |||
}; | |||
// Reference to the prototype | |||
var p = Emitter.prototype = {}; | |||
let p = Emitter.prototype = {}; | |||
var helperPoint = new PIXI.Point(); | |||
let helperPoint = new PIXI.Point(); | |||
/** | |||
* Time between particle spawns in seconds. If this value is not a number greater than 0, | |||
* it will be set to 1 (particle per second) to prevent infinite loops. | |||
* @property {Number} frequency | |||
*/ | |||
Object.defineProperty(p, "frequency", { | |||
Object.defineProperty(p, 'frequency', { | |||
get: function () { | |||
return this._frequency; | |||
}, | |||
set: function (value) { | |||
//do some error checking to prevent infinite loops | |||
if (typeof value == "number" && value > 0) | |||
if (typeof value === 'number' && value > 0) | |||
this._frequency = value; | |||
else | |||
this._frequency = 1; | |||
@@ -1126,7 +1107,7 @@ if (!Array.prototype.random) { | |||
* pooled particles, if the emitter has already been used. | |||
* @property {Function} particleConstructor | |||
*/ | |||
Object.defineProperty(p, "particleConstructor", { | |||
Object.defineProperty(p, 'particleConstructor', { | |||
get: function () { | |||
return this._particleConstructor; | |||
}, | |||
@@ -1136,9 +1117,9 @@ if (!Array.prototype.random) { | |||
//clean up existing particles | |||
this.cleanup(); | |||
//scrap all the particles | |||
for (var particle = this._poolFirst; particle; particle = particle.next) { | |||
for (let particle = this._poolFirst; particle; particle = particle.next) | |||
particle.destroy(); | |||
} | |||
this._poolFirst = null; | |||
//re-initialize the emitter so that the new constructor can do anything it needs to | |||
if (this._origConfig && this._origArt) | |||
@@ -1151,7 +1132,7 @@ if (!Array.prototype.random) { | |||
* The display object to add particles to. Settings this will dump any active particles. | |||
* @property {PIXI.DisplayObjectContainer} parent | |||
*/ | |||
Object.defineProperty(p, "parent", { | |||
Object.defineProperty(p, 'parent', { | |||
get: function () { | |||
return this._parent; | |||
}, | |||
@@ -1159,7 +1140,7 @@ if (!Array.prototype.random) { | |||
//if our previous parent was a ParticleContainer, then we need to remove | |||
//pooled particles from it | |||
if (this._parentIsPC) { | |||
for (var particle = this._poolFirst; particle; particle = particle.next) { | |||
for (let particle = this._poolFirst; particle; particle = particle.next) { | |||
if (particle.parent) | |||
particle.parent.removeChild(particle); | |||
} | |||
@@ -1190,7 +1171,7 @@ if (!Array.prototype.random) { | |||
//set up the array of data, also ensuring that it is an array | |||
art = Array.isArray(art) ? art.slice() : [art]; | |||
//run the art through the particle class's parsing function | |||
var partClass = this._particleConstructor; | |||
let partClass = this._particleConstructor; | |||
this.particleImages = partClass.parseArt ? partClass.parseArt(art) : art; | |||
/////////////////////////// | |||
// Particle Properties // | |||
@@ -1208,7 +1189,7 @@ if (!Array.prototype.random) { | |||
} else | |||
this.startSpeed = this.endSpeed = 0; | |||
//set up acceleration | |||
var acceleration = config.acceleration; | |||
let acceleration = config.acceleration; | |||
if (acceleration && (acceleration.x || acceleration.y)) { | |||
this.endSpeed = this.startSpeed; | |||
this.acceleration = new PIXI.Point(acceleration.x, acceleration.y); | |||
@@ -1261,7 +1242,7 @@ if (!Array.prototype.random) { | |||
this.particleBlendMode = ParticleUtils.getBlendMode(config.blendMode); | |||
//use the custom ease if provided | |||
if (config.ease) { | |||
this.customEase = typeof config.ease == "function" ? | |||
this.customEase = typeof config.ease === 'function' ? | |||
config.ease : | |||
ParticleUtils.generateEase(config.ease); | |||
} else | |||
@@ -1279,41 +1260,41 @@ if (!Array.prototype.random) { | |||
this.particlesPerWave = 1; | |||
this.particleSpacing = 0; | |||
this.angleStart = 0; | |||
var spawnCircle; | |||
let spawnCircle; | |||
//determine the spawn function to use | |||
switch (config.spawnType) { | |||
case "rect": | |||
this.spawnType = "rect"; | |||
case 'rect': | |||
this.spawnType = 'rect'; | |||
this._spawnFunc = this._spawnRect; | |||
var spawnRect = config.spawnRect; | |||
this.spawnRect = new PIXI.Rectangle(spawnRect.x, spawnRect.y, spawnRect.w, spawnRect.h); | |||
break; | |||
case "circle": | |||
this.spawnType = "circle"; | |||
case 'circle': | |||
this.spawnType = 'circle'; | |||
this._spawnFunc = this._spawnCircle; | |||
spawnCircle = config.spawnCircle; | |||
this.spawnCircle = new PIXI.Circle(spawnCircle.x, spawnCircle.y, spawnCircle.r); | |||
break; | |||
case "ring": | |||
this.spawnType = "ring"; | |||
case 'ring': | |||
this.spawnType = 'ring'; | |||
this._spawnFunc = this._spawnRing; | |||
spawnCircle = config.spawnCircle; | |||
this.spawnCircle = new PIXI.Circle(spawnCircle.x, spawnCircle.y, spawnCircle.r); | |||
this.spawnCircle.minRadius = spawnCircle.minR; | |||
break; | |||
case "burst": | |||
this.spawnType = "burst"; | |||
case 'burst': | |||
this.spawnType = 'burst'; | |||
this._spawnFunc = this._spawnBurst; | |||
this.particlesPerWave = config.particlesPerWave; | |||
this.particleSpacing = config.particleSpacing; | |||
this.angleStart = config.angleStart ? config.angleStart : 0; | |||
break; | |||
case "point": | |||
this.spawnType = "point"; | |||
case 'point': | |||
this.spawnType = 'point'; | |||
this._spawnFunc = this._spawnPoint; | |||
break; | |||
default: | |||
this.spawnType = "point"; | |||
this.spawnType = 'point'; | |||
this._spawnFunc = this._spawnPoint; | |||
break; | |||
} | |||
@@ -1360,10 +1341,8 @@ if (!Array.prototype.random) { | |||
if (this._parentIsPC) { | |||
particle.alpha = 0; | |||
particle.visible = false; | |||
} else { | |||
if (particle.parent) | |||
particle.parent.removeChild(particle); | |||
} | |||
} else if (particle.parent) | |||
particle.parent.removeChild(particle); | |||
//decrease count | |||
--this.particleCount; | |||
}; | |||
@@ -1376,7 +1355,7 @@ if (!Array.prototype.random) { | |||
p.rotate = function (newRot) { | |||
if (this.rotation == newRot) return; | |||
//caclulate the difference in rotation for rotating spawnPos | |||
var diff = newRot - this.rotation; | |||
let diff = newRot - this.rotation; | |||
this.rotation = newRot; | |||
//rotate spawnPos | |||
ParticleUtils.rotatePoint(diff, this.spawnPos); | |||
@@ -1424,7 +1403,7 @@ if (!Array.prototype.random) { | |||
* stops new particles from being created, but allows existing ones to die out. | |||
* @property {Boolean} emit | |||
*/ | |||
Object.defineProperty(p, "emit", { | |||
Object.defineProperty(p, 'emit', { | |||
get: function () { | |||
return this._emit; | |||
}, | |||
@@ -1440,25 +1419,25 @@ if (!Array.prototype.random) { | |||
* @param {Number} delta Time elapsed since the previous frame, in __seconds__. | |||
*/ | |||
p.update = function (delta) { | |||
var r = []; | |||
let r = []; | |||
//if we don't have a parent to add particles to, then don't do anything. | |||
//this also works as a isDestroyed check | |||
if (!this._parent) return; | |||
//update existing particles | |||
var i, particle, next; | |||
let i, particle, next; | |||
for (particle = this._activeParticlesFirst; particle; particle = next) { | |||
next = particle.next; | |||
particle.update(delta); | |||
} | |||
var prevX, prevY; | |||
let prevX, prevY; | |||
//if the previous position is valid, store these for later interpolation | |||
if (this._prevPosIsValid) { | |||
prevX = this._prevEmitterPos.x; | |||
prevY = this._prevEmitterPos.y; | |||
} | |||
//store current position of the emitter as local variables | |||
var curX = this.ownerPos.x + this.spawnPos.x; | |||
var curY = this.ownerPos.y + this.spawnPos.y; | |||
let curX = this.ownerPos.x + this.spawnPos.x; | |||
let curY = this.ownerPos.y + this.spawnPos.y; | |||
//spawn new particles | |||
if (this.emit) { | |||
//decrease spawn timer | |||
@@ -1499,7 +1478,7 @@ if (!Array.prototype.random) { | |||
var emitPosX, emitPosY; | |||
if (this._prevPosIsValid && this._posChanged) { | |||
//1 - _spawnTimer / delta, but _spawnTimer is negative | |||
var lerp = 1 + this._spawnTimer / delta; | |||
let lerp = 1 + this._spawnTimer / delta; | |||
emitPosX = (curX - prevX) * lerp + prevX; | |||
emitPosY = (curY - prevY) * lerp + prevY; | |||
} else //otherwise just set to the spawn position | |||
@@ -1509,22 +1488,22 @@ if (!Array.prototype.random) { | |||
} | |||
//create enough particles to fill the wave (non-burst types have a wave of 1) | |||
i = 0; | |||
for (var len = Math.min(this.particlesPerWave, this.maxParticles - this.particleCount); i < len; ++i) { | |||
for (let len = Math.min(this.particlesPerWave, this.maxParticles - this.particleCount); i < len; ++i) { | |||
//create particle | |||
var p; | |||
if (this._poolFirst) { | |||
p = this._poolFirst; | |||
this._poolFirst = this._poolFirst.next; | |||
p.next = null; | |||
} else { | |||
} else | |||
p = new this.particleConstructor(this); | |||
} | |||
r.push(p); | |||
//set a random texture if we have more than one | |||
if (this.particleImages.length > 1) { | |||
if (this.particleImages.length > 1) | |||
p.applyArt(this.particleImages.random()); | |||
} else { | |||
else { | |||
//if they are actually the same texture, a standard particle | |||
//will quit early from the texture setting in setTexture(). | |||
p.applyArt(this.particleImages[0]); | |||
@@ -1537,36 +1516,34 @@ if (!Array.prototype.random) { | |||
p.startSpeed = this.startSpeed; | |||
p.endSpeed = this.endSpeed; | |||
} else { | |||
var startSpeed = this.startSpeed; | |||
let startSpeed = this.startSpeed; | |||
p.startSpeed = startSpeed.min + ~~(Math.random() * (startSpeed.max - startSpeed.min)); | |||
var endSpeed = this.endSpeed; | |||
let endSpeed = this.endSpeed; | |||
p.endSpeed = endSpeed.min + ~~(Math.random() * (endSpeed.max - endSpeed.min)); | |||
} | |||
p.acceleration.x = this.acceleration.x; | |||
p.acceleration.y = this.acceleration.y; | |||
if (this.minimumScaleMultiplier != 1) { | |||
var rand = Math.random() * (1 - this.minimumScaleMultiplier) + this.minimumScaleMultiplier; | |||
let rand = Math.random() * (1 - this.minimumScaleMultiplier) + this.minimumScaleMultiplier; | |||
p.startScale = this.startScale * rand; | |||
p.endScale = this.endScale * rand; | |||
} else if (!this.randomScale) { | |||
p.startScale = this.startScale; | |||
p.endScale = this.endScale; | |||
} else { | |||
if (!this.randomScale) { | |||
p.startScale = this.startScale; | |||
p.endScale = this.endScale; | |||
} else { | |||
var startScale = this.startScale; | |||
p.startScale = startScale.min + ~~(Math.random() * (startScale.max - startScale.min)); | |||
var endScale = this.endScale; | |||
p.endScale = endScale.min + ~~(Math.random() * (endScale.max - endScale.min)); | |||
} | |||
let startScale = this.startScale; | |||
p.startScale = startScale.min + ~~(Math.random() * (startScale.max - startScale.min)); | |||
let endScale = this.endScale; | |||
p.endScale = endScale.min + ~~(Math.random() * (endScale.max - endScale.min)); | |||
} | |||
if (!this.randomColor) { | |||
p.startColor = this.startColor; | |||
p.endColor = this.endColor; | |||
} else { | |||
var startColor = this.startColor; | |||
let startColor = this.startColor; | |||
p.startColor = startColor[~~(Math.random() * startColor.length)]; | |||
var endColor = this.endColor; | |||
let endColor = this.endColor; | |||
p.endColor = endColor[~~(Math.random() * endColor.length)]; | |||
} | |||
//randomize the rotation speed | |||
@@ -1600,14 +1577,14 @@ if (!Array.prototype.random) { | |||
} else { | |||
//kind of hacky, but performance friendly | |||
//shuffle children to correct place | |||
var children = this._parent.children; | |||
let children = this._parent.children; | |||
//avoid using splice if possible | |||
if (children[0] == p) | |||
children.shift(); | |||
else if (children[children.length - 1] == p) | |||
children.pop(); | |||
else { | |||
var index = children.indexOf(p); | |||
let index = children.indexOf(p); | |||
children.splice(index, 1); | |||
} | |||
if (this.addAtBack) | |||
@@ -1620,9 +1597,9 @@ if (!Array.prototype.random) { | |||
this._activeParticlesLast.next = p; | |||
p.prev = this._activeParticlesLast; | |||
this._activeParticlesLast = p; | |||
} else { | |||
} else | |||
this._activeParticlesLast = this._activeParticlesFirst = p; | |||
} | |||
++this.particleCount; | |||
} | |||
} | |||
@@ -1701,9 +1678,10 @@ if (!Array.prototype.random) { | |||
//particle angle and rotation of emitter | |||
if (this.minStartRotation == this.maxStartRotation) | |||
p.rotation = this.minStartRotation + this.rotation; | |||
else | |||
else { | |||
p.rotation = Math.random() * (this.maxStartRotation - this.minStartRotation) + | |||
this.minStartRotation + this.rotation; | |||
} | |||
//place the particle at a random radius in the circle | |||
helperPoint.x = Math.random() * this.spawnCircle.radius; | |||
helperPoint.y = 0; | |||
@@ -1730,14 +1708,15 @@ if (!Array.prototype.random) { | |||
* @param {int} i The particle number in the current wave. Not used for this function. | |||
*/ | |||
p._spawnRing = function (p, emitPosX, emitPosY, i) { | |||
var spawnCircle = this.spawnCircle; | |||
let spawnCircle = this.spawnCircle; | |||
//set the initial rotation/direction of the particle based on starting | |||
//particle angle and rotation of emitter | |||
if (this.minStartRotation == this.maxStartRotation) | |||
p.rotation = this.minStartRotation + this.rotation; | |||
else | |||
else { | |||
p.rotation = Math.random() * (this.maxStartRotation - this.minStartRotation) + | |||
this.minStartRotation + this.rotation; | |||
} | |||
//place the particle at a random radius in the ring | |||
if (spawnCircle.minRadius == spawnCircle.radius) { | |||
helperPoint.x = Math.random() * (spawnCircle.radius - spawnCircle.minRadius) + | |||
@@ -1746,7 +1725,7 @@ if (!Array.prototype.random) { | |||
helperPoint.x = spawnCircle.radius; | |||
helperPoint.y = 0; | |||
//rotate the point to a random angle in the circle | |||
var angle = Math.random() * 360; | |||
let angle = Math.random() * 360; | |||
p.rotation += angle; | |||
ParticleUtils.rotatePoint(angle, helperPoint); | |||
//offset by the circle's center | |||
@@ -1786,7 +1765,7 @@ if (!Array.prototype.random) { | |||
* @method cleanup | |||
*/ | |||
p.cleanup = function () { | |||
var particle, next; | |||
let particle, next; | |||
for (particle = this._activeParticlesFirst; particle; particle = next) { | |||
next = particle.next; | |||
this.recycle(particle); | |||
@@ -1805,8 +1784,8 @@ if (!Array.prototype.random) { | |||
//puts all active particles in the pool, and removes them from the particle parent | |||
this.cleanup(); | |||
//wipe the pool clean | |||
var next; | |||
for (var particle = this._poolFirst; particle; particle = next) { | |||
let next; | |||
for (let particle = this._poolFirst; particle; particle = next) { | |||
//store next value so we don't lose it in our destroy call | |||
next = particle.next; | |||
particle.destroy(); | |||
@@ -1816,61 +1795,57 @@ if (!Array.prototype.random) { | |||
}; | |||
PIXI.particles.Emitter = Emitter; | |||
}(PIXI)); | |||
})(PIXI); | |||
(function (undefined) { | |||
// Check for window, fallback to global | |||
var global = typeof window !== 'undefined' ? window : GLOBAL; | |||
let global = typeof window !== 'undefined' ? window : GLOBAL; | |||
// Deprecate support for the cloudkid namespace | |||
if (typeof cloudkid === "undefined") { | |||
if (typeof cloudkid === 'undefined') | |||
global.cloudkid = {}; | |||
} | |||
// Get classes from the PIXI.particles namespace | |||
Object.defineProperties(global.cloudkid, { | |||
AnimatedParticle: { | |||
get: function () { | |||
if (true) { | |||
console.warn("cloudkid namespace is deprecated, please use PIXI.particles"); | |||
} | |||
if (true) | |||
console.warn('cloudkid namespace is deprecated, please use PIXI.particles'); | |||
return PIXI.particles.AnimatedParticle; | |||
} | |||
}, | |||
Emitter: { | |||
get: function () { | |||
if (true) { | |||
console.warn("cloudkid namespace is deprecated, please use PIXI.particles"); | |||
} | |||
if (true) | |||
console.warn('cloudkid namespace is deprecated, please use PIXI.particles'); | |||
return PIXI.particles.Emitter; | |||
} | |||
}, | |||
Particle: { | |||
get: function () { | |||
if (true) { | |||
console.warn("cloudkid namespace is deprecated, please use PIXI.particles"); | |||
} | |||
if (true) | |||
console.warn('cloudkid namespace is deprecated, please use PIXI.particles'); | |||
return PIXI.particles.Particle; | |||
} | |||
}, | |||
ParticleUtils: { | |||
get: function () { | |||
if (true) { | |||
console.warn("cloudkid namespace is deprecated, please use PIXI.particles"); | |||
} | |||
if (true) | |||
console.warn('cloudkid namespace is deprecated, please use PIXI.particles'); | |||
return PIXI.particles.ParticleUtils; | |||
} | |||
}, | |||
PathParticle: { | |||
get: function () { | |||
if (true) { | |||
console.warn("cloudkid namespace is deprecated, please use PIXI.particles"); | |||
} | |||
if (true) | |||
console.warn('cloudkid namespace is deprecated, please use PIXI.particles'); | |||
return PIXI.particles.PathParticle; | |||
} | |||
} | |||
}); | |||
}()); | |||
})(); |
@@ -1,428 +0,0 @@ | |||
var __extends = (this && this.__extends) || function(d, b) { | |||
for (var p in b) | |||
if (b.hasOwnProperty(p)) d[p] = b[p]; | |||
function __() { | |||
this.constructor = d; | |||
} | |||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | |||
}; | |||
var PIXI; | |||
(function(PIXI) { | |||
var extras; | |||
(function(extras) { | |||
var shaderLib = [{ | |||
vertUniforms: "", | |||
vertCode: "vTextureCoord = aTextureCoord;", | |||
fragUniforms: "uniform vec4 uTextureClamp;", | |||
fragCode: "vec2 textureCoord = clamp(vTextureCoord, uTextureClamp.xy, uTextureClamp.zw);" | |||
}, { | |||
vertUniforms: "uniform mat3 uTransform;", | |||
vertCode: "vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;", | |||
fragUniforms: "", | |||
fragCode: "vec2 textureCoord = vTextureCoord;" | |||
}, { | |||
vertUniforms: "uniform mat3 uTransform;", | |||
vertCode: "vTextureCoord = (uTransform * vec3(aTextureCoord, 1.0)).xy;", | |||
fragUniforms: "uniform mat3 uMapCoord;\nuniform vec4 uClampFrame;\nuniform vec2 uClampOffset;", | |||
fragCode: "vec2 textureCoord = mod(vTextureCoord - uClampOffset, vec2(1.0, 1.0)) + uClampOffset;" + | |||
"\ntextureCoord = (uMapCoord * vec3(textureCoord, 1.0)).xy;" + | |||
"\ntextureCoord = clamp(textureCoord, uClampFrame.xy, uClampFrame.zw);" | |||
}]; | |||
var PictureShader = (function(_super) { | |||
__extends(PictureShader, _super); | |||
function PictureShader(gl, vert, frag, tilingMode) { | |||
var lib = shaderLib[tilingMode]; | |||
_super.call(this, gl, vert.replace(/%SPRITE_UNIFORMS%/gi, lib.vertUniforms) | |||
.replace(/%SPRITE_CODE%/gi, lib.vertCode), frag.replace(/%SPRITE_UNIFORMS%/gi, lib.fragUniforms) | |||
.replace(/%SPRITE_CODE%/gi, lib.fragCode)); | |||
this.bind(); | |||
this.tilingMode = tilingMode; | |||
this.tempQuad = new PIXI.Quad(gl); | |||
this.tempQuad.initVao(this); | |||
this.uniforms.uColor = new Float32Array([1, 1, 1, 1]); | |||
this.uniforms.uSampler = [0, 1]; | |||
} | |||
PictureShader.blendVert = "\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec4 aColor;\n\nuniform mat3 projectionMatrix;\nuniform mat3 mapMatrix;\n\nvarying vec2 vTextureCoord;\nvarying vec2 vMapCoord;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n %SPRITE_CODE%\n vMapCoord = (mapMatrix * vec3(aVertexPosition, 1.0)).xy;\n}\n"; | |||
return PictureShader; | |||
}(PIXI.Shader)); | |||
extras.PictureShader = PictureShader; | |||
})(extras = PIXI.extras || (PIXI.extras = {})); | |||
})(PIXI || (PIXI = {})); | |||
var PIXI; | |||
(function(PIXI) { | |||
var extras; | |||
(function(extras) { | |||
var overlayFrag = "\nvarying vec2 vTextureCoord;\nvarying vec2 vMapCoord;\nvarying vec4 vColor;\n\nuniform sampler2D uSampler[2];\nuniform vec4 uColor;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n %SPRITE_CODE%\n vec4 source = texture2D(uSampler[0], textureCoord) * uColor;\n vec4 target = texture2D(uSampler[1], vMapCoord);\n\n //reverse hardlight\n if (source.a == 0.0) {\n gl_FragColor = vec4(0, 0, 0, 0);\n return;\n }\n //yeah, premultiplied\n vec3 Cb = source.rgb/source.a, Cs;\n if (target.a > 0.0) {\n Cs = target.rgb / target.a;\n }\n vec3 multiply = Cb * Cs * 2.0;\n vec3 Cs2 = Cs * 2.0 - 1.0;\n vec3 screen = Cb + Cs2 - Cb * Cs2;\n vec3 B;\n if (Cb.r <= 0.5) {\n B.r = multiply.r;\n } else {\n B.r = screen.r;\n }\n if (Cb.g <= 0.5) {\n B.g = multiply.g;\n } else {\n B.g = screen.g;\n }\n if (Cb.b <= 0.5) {\n B.b = multiply.b;\n } else {\n B.b = screen.b;\n }\n vec4 res;\n res.xyz = (1.0 - source.a) * Cs + source.a * B;\n res.a = source.a + target.a * (1.0-source.a);\n gl_FragColor = vec4(res.xyz * res.a, res.a);\n}\n"; | |||
var HardLightShader = (function(_super) { | |||
__extends(HardLightShader, _super); | |||
function HardLightShader(gl, tilingMode) { | |||
_super.call(this, gl, extras.PictureShader.blendVert, overlayFrag, tilingMode); | |||
} | |||
return HardLightShader; | |||
}(extras.PictureShader)); | |||
extras.HardLightShader = HardLightShader; | |||
})(extras = PIXI.extras || (PIXI.extras = {})); | |||
})(PIXI || (PIXI = {})); | |||
var PIXI; | |||
(function(PIXI) { | |||
var extras; | |||
(function(extras) { | |||
function mapFilterBlendModesToPixi(gl, array) { | |||
if (array === void 0) { | |||
array = []; | |||
} | |||
array[PIXI.BLEND_MODES.OVERLAY] = [new extras.OverlayShader(gl, 0), new extras.OverlayShader(gl, 1), new extras.OverlayShader(gl, 2)]; | |||
array[PIXI.BLEND_MODES.HARD_LIGHT] = [new extras.HardLightShader(gl, 0), new extras.HardLightShader(gl, 1), new extras.HardLightShader(gl, 2)]; | |||
return array; | |||
} | |||
extras.mapFilterBlendModesToPixi = mapFilterBlendModesToPixi; | |||
})(extras = PIXI.extras || (PIXI.extras = {})); | |||
})(PIXI || (PIXI = {})); | |||
var PIXI; | |||
(function(PIXI) { | |||
var extras; | |||
(function(extras) { | |||
var normalFrag = "\nvarying vec2 vTextureCoord;\nvarying vec4 vColor;\n\nuniform sampler2D uSampler[2];\nuniform vec4 uColor;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n %SPRITE_CODE%\n\n vec4 sample = texture2D(uSampler[0], textureCoord);\n gl_FragColor = sample * uColor;\n}\n"; | |||
var normalVert = "\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\nattribute vec4 aColor;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n %SPRITE_CODE%\n}\n"; | |||
var NormalShader = (function(_super) { | |||
__extends(NormalShader, _super); | |||
function NormalShader(gl, tilingMode) { | |||
_super.call(this, gl, normalVert, normalFrag, tilingMode); | |||
} | |||
return NormalShader; | |||
}(extras.PictureShader)); | |||
extras.NormalShader = NormalShader; | |||
})(extras = PIXI.extras || (PIXI.extras = {})); | |||
})(PIXI || (PIXI = {})); | |||
var PIXI; | |||
(function(PIXI) { | |||
var extras; | |||
(function(extras) { | |||
var overlayFrag = "\nvarying vec2 vTextureCoord;\nvarying vec2 vMapCoord;\nvarying vec4 vColor;\n\nuniform sampler2D uSampler[2];\nuniform vec4 uColor;\n%SPRITE_UNIFORMS%\n\nvoid main(void)\n{\n %SPRITE_CODE%\n vec4 source = texture2D(uSampler[0], textureCoord) * uColor;\n vec4 target = texture2D(uSampler[1], vMapCoord);\n\n //reverse hardlight\n if (source.a == 0.0) {\n gl_FragColor = vec4(0, 0, 0, 0);\n return;\n }\n //yeah, premultiplied\n vec3 Cb = source.rgb/source.a, Cs;\n if (target.a > 0.0) {\n Cs = target.rgb / target.a;\n }\n vec3 multiply = Cb * Cs * 2.0;\n vec3 Cb2 = Cb * 2.0 - 1.0;\n vec3 screen = Cb2 + Cs - Cb2 * Cs;\n vec3 B;\n if (Cs.r <= 0.5) {\n B.r = multiply.r;\n } else {\n B.r = screen.r;\n }\n if (Cs.g <= 0.5) {\n B.g = multiply.g;\n } else {\n B.g = screen.g;\n }\n if (Cs.b <= 0.5) {\n B.b = multiply.b;\n } else {\n B.b = screen.b;\n }\n vec4 res;\n res.xyz = (1.0 - source.a) * Cs + source.a * B;\n res.a = source.a + target.a * (1.0-source.a);\n\n if ((target.r <= 0.1) && (target.g <= 0.1) && (target.b <= 0.1)) {\n res.r = 0.177;\n res.g = 0.13;\n res.b = 0.212;\n }\n\n gl_FragColor = vec4(res.xyz * res.a, res.a);\n}\n"; | |||
var OverlayShader = (function(_super) { | |||
__extends(OverlayShader, _super); | |||
function OverlayShader(gl, tilingMode) { | |||
_super.call(this, gl, extras.PictureShader.blendVert, overlayFrag, tilingMode); | |||
} | |||
return OverlayShader; | |||
}(extras.PictureShader)); | |||
extras.OverlayShader = OverlayShader; | |||
})(extras = PIXI.extras || (PIXI.extras = {})); | |||
})(PIXI || (PIXI = {})); | |||
var PIXI; | |||
(function(PIXI) { | |||
var extras; | |||
(function(extras) { | |||
function nextPow2(v) { | |||
v += (v === 0) ? 1 : 0; | |||
--v; | |||
v |= v >>> 1; | |||
v |= v >>> 2; | |||
v |= v >>> 4; | |||
v |= v >>> 8; | |||
v |= v >>> 16; | |||
return v + 1; | |||
} | |||
var PictureRenderer = (function(_super) { | |||
__extends(PictureRenderer, _super); | |||
function PictureRenderer(renderer) { | |||
_super.call(this, renderer); | |||
} | |||
PictureRenderer.prototype.onContextChange = function() { | |||
var gl = this.renderer.gl; | |||
this.drawModes = extras.mapFilterBlendModesToPixi(gl); | |||
this.normalShader = [new extras.NormalShader(gl, 0), new extras.NormalShader(gl, 1), new extras.NormalShader(gl, 2)]; | |||
this._tempClamp = new Float32Array(4); | |||
this._tempColor = new Float32Array(4); | |||
this._tempRect = new PIXI.Rectangle(); | |||
this._tempRect2 = new PIXI.Rectangle(); | |||
this._tempRect3 = new PIXI.Rectangle(); | |||
this._tempMatrix = new PIXI.Matrix(); | |||
this._tempMatrix2 = new PIXI.Matrix(); | |||
this._bigBuf = new Uint8Array(1 << 20); | |||
this._renderTexture = new PIXI.BaseRenderTexture(1024, 1024); | |||
}; | |||
PictureRenderer.prototype.start = function() {}; | |||
PictureRenderer.prototype.flush = function() {}; | |||
PictureRenderer.prototype._getRenderTexture = function(minWidth, minHeight) { | |||
if (this._renderTexture.width < minWidth || | |||
this._renderTexture.height < minHeight) { | |||
minHeight = nextPow2(minWidth); | |||
minHeight = nextPow2(minHeight); | |||
this._renderTexture.resize(minWidth, minHeight); | |||
} | |||
return this._renderTexture; | |||
}; | |||
PictureRenderer.prototype._getBuf = function(size) { | |||
var buf = this._bigBuf; | |||
if (buf.length < size) { | |||
size = nextPow2(size); | |||
buf = new Uint8Array(size); | |||
this._bigBuf = buf; | |||
} | |||
return buf; | |||
}; | |||
PictureRenderer.prototype.render = function(sprite) { | |||
if (!sprite.texture.valid) { | |||
return; | |||
} | |||
var tilingMode = 0; | |||
if (sprite.tileTransform) { | |||
tilingMode = this._isSimpleSprite(sprite) ? 1 : 2; | |||
} | |||
var blendShader = this.drawModes[sprite.blendMode]; | |||
if (blendShader) { | |||
this._renderBlend(sprite, blendShader[tilingMode]); | |||
} else { | |||
this._renderNormal(sprite, this.normalShader[tilingMode]); | |||
} | |||
}; | |||
PictureRenderer.prototype._renderNormal = function(sprite, shader) { | |||
var renderer = this.renderer; | |||
renderer.bindShader(shader); | |||
renderer.state.setBlendMode(sprite.blendMode); | |||
this._renderInner(sprite, shader); | |||
}; | |||
PictureRenderer.prototype._renderBlend = function(sprite, shader) { | |||
var renderer = this.renderer; | |||
var spriteBounds = sprite.getBounds(); | |||
var renderTarget = renderer._activeRenderTarget; | |||
var matrix = renderTarget.projectionMatrix; | |||
var flipX = matrix.a < 0; | |||
var flipY = matrix.d < 0; | |||
var resolution = renderTarget.resolution; | |||
var screen = this._tempRect; | |||
var fr = renderTarget.sourceFrame || renderTarget.destinationFrame; | |||
screen.x = 0; | |||
screen.y = 0; | |||
screen.width = fr.width; | |||
screen.height = fr.height; | |||
var bounds = this._tempRect2; | |||
var fbw = fr.width * resolution, | |||
fbh = fr.height * resolution; | |||
bounds.x = (spriteBounds.x + matrix.tx / matrix.a) * resolution + fbw / 2; | |||
bounds.y = (spriteBounds.y + matrix.ty / matrix.d) * resolution + fbh / 2; | |||
bounds.width = spriteBounds.width * resolution; | |||
bounds.height = spriteBounds.height * resolution; | |||
if (flipX) { | |||
bounds.y = fbw - bounds.width - bounds.x; | |||
} | |||
if (flipY) { | |||
bounds.y = fbh - bounds.height - bounds.y; | |||
} | |||
var screenBounds = this._tempRect3; | |||
var x_1 = Math.floor(Math.max(screen.x, bounds.x)); | |||
var x_2 = Math.ceil(Math.min(screen.x + screen.width, bounds.x + bounds.width)); | |||
var y_1 = Math.floor(Math.max(screen.y, bounds.y)); | |||
var y_2 = Math.ceil(Math.min(screen.y + screen.height, bounds.y + bounds.height)); | |||
var pixelsWidth = x_2 - x_1; | |||
var pixelsHeight = y_2 - y_1; | |||
if (pixelsWidth <= 0 || pixelsHeight <= 0) { | |||
return; | |||
} | |||
var rt = this._getRenderTexture(pixelsWidth, pixelsHeight); | |||
renderer.bindTexture(rt, 1, true); | |||
var gl = renderer.gl; | |||
if (renderer.renderingToScreen && renderTarget.root) { | |||
var buf = this._getBuf(pixelsWidth * pixelsHeight * 4); | |||
gl.readPixels(x_1, y_1, pixelsWidth, pixelsHeight, gl.RGBA, gl.UNSIGNED_BYTE, this._bigBuf); | |||
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, pixelsWidth, pixelsHeight, gl.RGBA, gl.UNSIGNED_BYTE, this._bigBuf); | |||
} else { | |||
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, x_1, y_1, pixelsWidth, pixelsHeight); | |||
} | |||
renderer.bindShader(shader); | |||
renderer.state.setBlendMode(PIXI.BLEND_MODES.NORMAL); | |||
if (shader.uniforms.mapMatrix) { | |||
var mapMatrix = this._tempMatrix; | |||
mapMatrix.a = bounds.width / rt.width / spriteBounds.width; | |||
if (flipX) { | |||
mapMatrix.a = -mapMatrix.a; | |||
mapMatrix.tx = (bounds.x - x_1) / rt.width - (spriteBounds.x + spriteBounds.width) * mapMatrix.a; | |||
} else { | |||
mapMatrix.tx = (bounds.x - x_1) / rt.width - spriteBounds.x * mapMatrix.a; | |||
} | |||
mapMatrix.d = bounds.height / rt.height / spriteBounds.height; | |||
if (flipY) { | |||
mapMatrix.d = -mapMatrix.d; | |||
mapMatrix.ty = (bounds.y - y_1) / rt.height - (spriteBounds.y + spriteBounds.height) * mapMatrix.d; | |||
} else { | |||
mapMatrix.ty = (bounds.y - y_1) / rt.height - spriteBounds.y * mapMatrix.d; | |||
} | |||
shader.uniforms.mapMatrix = mapMatrix.toArray(true); | |||
} | |||
this._renderInner(sprite, shader); | |||
}; | |||
PictureRenderer.prototype._renderInner = function(sprite, shader) { | |||
var renderer = this.renderer; | |||
if (shader.tilingMode > 0) { | |||
this._renderWithShader(sprite, shader.tilingMode === 1, shader); | |||
} else { | |||
this._renderSprite(sprite, shader); | |||
} | |||
}; | |||
PictureRenderer.prototype._renderWithShader = function(ts, isSimple, shader) { | |||
var quad = shader.tempQuad; | |||
var renderer = this.renderer; | |||
renderer.bindVao(quad.vao); | |||
var vertices = quad.vertices; | |||
var _width = ts._width; | |||
var _height = ts._height; | |||
var _anchorX = ts._anchor._x; | |||
var _anchorY = ts._anchor._y; | |||
var w0 = _width * (1 - _anchorX); | |||
var w1 = _width * -_anchorX; | |||
var h0 = _height * (1 - _anchorY); | |||
var h1 = _height * -_anchorY; | |||
var wt = ts.transform.worldTransform; | |||
var a = wt.a; | |||
var b = wt.b; | |||
var c = wt.c; | |||
var d = wt.d; | |||
var tx = wt.tx; | |||
var ty = wt.ty; | |||
vertices[0] = (a * w1) + (c * h1) + tx; | |||
vertices[1] = (d * h1) + (b * w1) + ty; | |||
vertices[2] = (a * w0) + (c * h1) + tx; | |||
vertices[3] = (d * h1) + (b * w0) + ty; | |||
vertices[4] = (a * w0) + (c * h0) + tx; | |||
vertices[5] = (d * h0) + (b * w0) + ty; | |||
vertices[6] = (a * w1) + (c * h0) + tx; | |||
vertices[7] = (d * h0) + (b * w1) + ty; | |||
vertices = quad.uvs; | |||
vertices[0] = vertices[6] = -ts.anchor.x; | |||
vertices[1] = vertices[3] = -ts.anchor.y; | |||
vertices[2] = vertices[4] = 1.0 - ts.anchor.x; | |||
vertices[5] = vertices[7] = 1.0 - ts.anchor.y; | |||
quad.upload(); | |||
var tex = ts._texture; | |||
var lt = ts.tileTransform.localTransform; | |||
var uv = ts.uvTransform; | |||
var mapCoord = uv.mapCoord; | |||
var uClampFrame = uv.uClampFrame; | |||
var uClampOffset = uv.uClampOffset; | |||
var w = tex.width; | |||
var h = tex.height; | |||
var W = _width; | |||
var H = _height; | |||
var tempMat = this._tempMatrix2; | |||
tempMat.set(lt.a * w / W, lt.b * w / H, lt.c * h / W, lt.d * h / H, lt.tx / W, lt.ty / H); | |||
tempMat.invert(); | |||
if (isSimple) { | |||
tempMat.append(mapCoord); | |||
} else { | |||
shader.uniforms.uMapCoord = mapCoord.toArray(true); | |||
shader.uniforms.uClampFrame = uClampFrame; | |||
shader.uniforms.uClampOffset = uClampOffset; | |||
} | |||
shader.uniforms.uTransform = tempMat.toArray(true); | |||
var color = this._tempColor; | |||
var alpha = ts.worldAlpha; | |||
PIXI.utils.hex2rgb(ts.tint, color); | |||
color[0] *= alpha; | |||
color[1] *= alpha; | |||
color[2] *= alpha; | |||
color[3] = alpha; | |||
shader.uniforms.uColor = color; | |||
renderer.bindTexture(tex, 0, true); | |||
quad.vao.draw(this.renderer.gl.TRIANGLES, 6, 0); | |||
}; | |||
PictureRenderer.prototype._renderSprite = function(sprite, shader) { | |||
var renderer = this.renderer; | |||
var quad = shader.tempQuad; | |||
renderer.bindVao(quad.vao); | |||
var uvs = sprite.texture._uvs; | |||
var vertices = quad.vertices; | |||
var vd = sprite.vertexData; | |||
for (var i = 0; i < 8; i++) { | |||
quad.vertices[i] = vd[i]; | |||
} | |||
quad.uvs[0] = uvs.x0; | |||
quad.uvs[1] = uvs.y0; | |||
quad.uvs[2] = uvs.x1; | |||
quad.uvs[3] = uvs.y1; | |||
quad.uvs[4] = uvs.x2; | |||
quad.uvs[5] = uvs.y2; | |||
quad.uvs[6] = uvs.x3; | |||
quad.uvs[7] = uvs.y3; | |||
quad.upload(); | |||
var frame = sprite.texture.frame; | |||
var base = sprite.texture.baseTexture; | |||
var clamp = this._tempClamp; | |||
var eps = 0.5 / base.resolution; | |||
clamp[0] = (frame.x + eps) / base.width; | |||
clamp[1] = (frame.y + eps) / base.height; | |||
clamp[2] = (frame.x + frame.width - eps) / base.width; | |||
clamp[3] = (frame.y + frame.height - eps) / base.height; | |||
shader.uniforms.uTextureClamp = clamp; | |||
var color = this._tempColor; | |||
PIXI.utils.hex2rgb(sprite.tint, color); | |||
var alpha = sprite.worldAlpha; | |||
color[0] *= alpha; | |||
color[1] *= alpha; | |||
color[2] *= alpha; | |||
color[3] = alpha; | |||
shader.uniforms.uColor = color; | |||
renderer.bindTexture(base, 0, true); | |||
quad.vao.draw(this.renderer.gl.TRIANGLES, 6, 0); | |||
}; | |||
PictureRenderer.prototype._isSimpleSprite = function(ts) { | |||
var renderer = this.renderer; | |||
var tex = ts._texture; | |||
var baseTex = tex.baseTexture; | |||
var isSimple = baseTex.isPowerOfTwo && tex.frame.width === baseTex.width && tex.frame.height === baseTex.height; | |||
if (isSimple) { | |||
if (!baseTex._glTextures[renderer.CONTEXT_UID]) { | |||
if (baseTex.wrapMode === PIXI.WRAP_MODES.CLAMP) { | |||
baseTex.wrapMode = PIXI.WRAP_MODES.REPEAT; | |||
} | |||
} else { | |||
isSimple = baseTex.wrapMode !== PIXI.WRAP_MODES.CLAMP; | |||
} | |||
} | |||
return isSimple; | |||
}; | |||
return PictureRenderer; | |||
}(PIXI.ObjectRenderer)); | |||
extras.PictureRenderer = PictureRenderer; | |||
PIXI.WebGLRenderer.registerPlugin('picture', PictureRenderer); | |||
PIXI.CanvasRenderer.registerPlugin('picture', PIXI.CanvasSpriteRenderer); | |||
})(extras = PIXI.extras || (PIXI.extras = {})); | |||
})(PIXI || (PIXI = {})); | |||
var PIXI; | |||
(function(PIXI) { | |||
var extras; | |||
(function(extras) { | |||
var PictureSprite = (function(_super) { | |||
__extends(PictureSprite, _super); | |||
function PictureSprite(texture) { | |||
_super.call(this, texture); | |||
this.pluginName = 'picture'; | |||
} | |||
return PictureSprite; | |||
}(PIXI.Sprite)); | |||
extras.PictureSprite = PictureSprite; | |||
})(extras = PIXI.extras || (PIXI.extras = {})); | |||
})(PIXI || (PIXI = {})); | |||
var PIXI; | |||
(function(PIXI) { | |||
var extras; | |||
(function(extras) { | |||
var PictureTilingSprite = (function(_super) { | |||
__extends(PictureTilingSprite, _super); | |||
function PictureTilingSprite(texture) { | |||
_super.call(this, texture); | |||
this.pluginName = 'picture'; | |||
} | |||
return PictureTilingSprite; | |||
}(extras.TilingSprite)); | |||
extras.PictureTilingSprite = PictureTilingSprite; | |||
})(extras = PIXI.extras || (PIXI.extras = {})); | |||
})(PIXI || (PIXI = {})); |
@@ -1,391 +0,0 @@ | |||
/** | |||
* @license RequireJS text 2.0.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. | |||
* Available via the MIT or new BSD license. | |||
* see: http://github.com/requirejs/text for details | |||
*/ | |||
/*jslint regexp: true */ | |||
/*global require, XMLHttpRequest, ActiveXObject, | |||
define, window, process, Packages, | |||
java, location, Components, FileUtils */ | |||
define(['module'], function (module) { | |||
'use strict'; | |||
var text, fs, Cc, Ci, xpcIsWindows, | |||
progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], | |||
xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, | |||
bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im, | |||
hasLocation = typeof location !== 'undefined' && location.href, | |||
defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), | |||
defaultHostName = hasLocation && location.hostname, | |||
defaultPort = hasLocation && (location.port || undefined), | |||
buildMap = {}, | |||
masterConfig = (module.config && module.config()) || {}; | |||
text = { | |||
version: '2.0.14', | |||
strip: function (content) { | |||
//Strips <?xml ...?> declarations so that external SVG and XML | |||
//documents can be added to a document without worry. Also, if the string | |||
//is an HTML document, only the part inside the body tag is returned. | |||
if (content) { | |||
content = content.replace(xmlRegExp, ""); | |||
var matches = content.match(bodyRegExp); | |||
if (matches) { | |||
content = matches[1]; | |||
} | |||
} else { | |||
content = ""; | |||
} | |||
return content; | |||
}, | |||
jsEscape: function (content) { | |||
return content.replace(/(['\\])/g, '\\$1') | |||
.replace(/[\f]/g, "\\f") | |||
.replace(/[\b]/g, "\\b") | |||
.replace(/[\n]/g, "\\n") | |||
.replace(/[\t]/g, "\\t") | |||
.replace(/[\r]/g, "\\r") | |||
.replace(/[\u2028]/g, "\\u2028") | |||
.replace(/[\u2029]/g, "\\u2029"); | |||
}, | |||
createXhr: masterConfig.createXhr || function () { | |||
//Would love to dump the ActiveX crap in here. Need IE 6 to die first. | |||
var xhr, i, progId; | |||
if (typeof XMLHttpRequest !== "undefined") { | |||
return new XMLHttpRequest(); | |||
} else if (typeof ActiveXObject !== "undefined") { | |||
for (i = 0; i < 3; i += 1) { | |||
progId = progIds[i]; | |||
try { | |||
xhr = new ActiveXObject(progId); | |||
} catch (e) {} | |||
if (xhr) { | |||
progIds = [progId]; // so faster next time | |||
break; | |||
} | |||
} | |||
} | |||
return xhr; | |||
}, | |||
/** | |||
* Parses a resource name into its component parts. Resource names | |||
* look like: module/name.ext!strip, where the !strip part is | |||
* optional. | |||
* @param {String} name the resource name | |||
* @returns {Object} with properties "moduleName", "ext" and "strip" | |||
* where strip is a boolean. | |||
*/ | |||
parseName: function (name) { | |||
var modName, ext, temp, | |||
strip = false, | |||
index = name.lastIndexOf("."), | |||
isRelative = name.indexOf('./') === 0 || | |||
name.indexOf('../') === 0; | |||
if (index !== -1 && (!isRelative || index > 1)) { | |||
modName = name.substring(0, index); | |||
ext = name.substring(index + 1); | |||
} else { | |||
modName = name; | |||
} | |||
temp = ext || modName; | |||
index = temp.indexOf("!"); | |||
if (index !== -1) { | |||
//Pull off the strip arg. | |||
strip = temp.substring(index + 1) === "strip"; | |||
temp = temp.substring(0, index); | |||
if (ext) { | |||
ext = temp; | |||
} else { | |||
modName = temp; | |||
} | |||
} | |||
return { | |||
moduleName: modName, | |||
ext: ext, | |||
strip: strip | |||
}; | |||
}, | |||
xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, | |||
/** | |||
* Is an URL on another domain. Only works for browser use, returns | |||
* false in non-browser environments. Only used to know if an | |||
* optimized .js version of a text resource should be loaded | |||
* instead. | |||
* @param {String} url | |||
* @returns Boolean | |||
*/ | |||
useXhr: function (url, protocol, hostname, port) { | |||
var uProtocol, uHostName, uPort, | |||
match = text.xdRegExp.exec(url); | |||
if (!match) { | |||
return true; | |||
} | |||
uProtocol = match[2]; | |||
uHostName = match[3]; | |||
uHostName = uHostName.split(':'); | |||
uPort = uHostName[1]; | |||
uHostName = uHostName[0]; | |||
return (!uProtocol || uProtocol === protocol) && | |||
(!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && | |||
((!uPort && !uHostName) || uPort === port); | |||
}, | |||
finishLoad: function (name, strip, content, onLoad) { | |||
content = strip ? text.strip(content) : content; | |||
if (masterConfig.isBuild) { | |||
buildMap[name] = content; | |||
} | |||
onLoad(content); | |||
}, | |||
load: function (name, req, onLoad, config) { | |||
//Name has format: some.module.filext!strip | |||
//The strip part is optional. | |||
//if strip is present, then that means only get the string contents | |||
//inside a body tag in an HTML string. For XML/SVG content it means | |||
//removing the <?xml ...?> declarations so the content can be inserted | |||
//into the current doc without problems. | |||
// Do not bother with the work if a build and text will | |||
// not be inlined. | |||
if (config && config.isBuild && !config.inlineText) { | |||
onLoad(); | |||
return; | |||
} | |||
masterConfig.isBuild = config && config.isBuild; | |||
var parsed = text.parseName(name), | |||
nonStripName = parsed.moduleName + | |||
(parsed.ext ? '.' + parsed.ext : ''), | |||
url = req.toUrl(nonStripName), | |||
useXhr = (masterConfig.useXhr) || | |||
text.useXhr; | |||
// Do not load if it is an empty: url | |||
if (url.indexOf('empty:') === 0) { | |||
onLoad(); | |||
return; | |||
} | |||
//Load the text. Use XHR if possible and in a browser. | |||
if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { | |||
text.get(url, function (content) { | |||
text.finishLoad(name, parsed.strip, content, onLoad); | |||
}, function (err) { | |||
if (onLoad.error) { | |||
onLoad.error(err); | |||
} | |||
}); | |||
} else { | |||
//Need to fetch the resource across domains. Assume | |||
//the resource has been optimized into a JS module. Fetch | |||
//by the module name + extension, but do not include the | |||
//!strip part to avoid file system issues. | |||
req([nonStripName], function (content) { | |||
text.finishLoad(parsed.moduleName + '.' + parsed.ext, | |||
parsed.strip, content, onLoad); | |||
}); | |||
} | |||
}, | |||
write: function (pluginName, moduleName, write, config) { | |||
if (buildMap.hasOwnProperty(moduleName)) { | |||
var content = text.jsEscape(buildMap[moduleName]); | |||
write.asModule(pluginName + "!" + moduleName, | |||
"define(function () { return '" + | |||
content + | |||
"';});\n"); | |||
} | |||
}, | |||
writeFile: function (pluginName, moduleName, req, write, config) { | |||
var parsed = text.parseName(moduleName), | |||
extPart = parsed.ext ? '.' + parsed.ext : '', | |||
nonStripName = parsed.moduleName + extPart, | |||
//Use a '.js' file name so that it indicates it is a | |||
//script that can be loaded across domains. | |||
fileName = req.toUrl(parsed.moduleName + extPart) + '.js'; | |||
//Leverage own load() method to load plugin value, but only | |||
//write out values that do not have the strip argument, | |||
//to avoid any potential issues with ! in file names. | |||
text.load(nonStripName, req, function (value) { | |||
//Use own write() method to construct full module value. | |||
//But need to create shell that translates writeFile's | |||
//write() to the right interface. | |||
var textWrite = function (contents) { | |||
return write(fileName, contents); | |||
}; | |||
textWrite.asModule = function (moduleName, contents) { | |||
return write.asModule(moduleName, fileName, contents); | |||
}; | |||
text.write(pluginName, nonStripName, textWrite, config); | |||
}, config); | |||
} | |||
}; | |||
if (masterConfig.env === 'node' || (!masterConfig.env && | |||
typeof process !== "undefined" && | |||
process.versions && | |||
!!process.versions.node && | |||
!process.versions['node-webkit'] && | |||
!process.versions['atom-shell'])) { | |||
//Using special require.nodeRequire, something added by r.js. | |||
fs = require.nodeRequire('fs'); | |||
text.get = function (url, callback, errback) { | |||
try { | |||
var file = fs.readFileSync(url, 'utf8'); | |||
//Remove BOM (Byte Mark Order) from utf8 files if it is there. | |||
if (file[0] === '\uFEFF') { | |||
file = file.substring(1); | |||
} | |||
callback(file); | |||
} catch (e) { | |||
if (errback) { | |||
errback(e); | |||
} | |||
} | |||
}; | |||
} else if (masterConfig.env === 'xhr' || (!masterConfig.env && | |||
text.createXhr())) { | |||
text.get = function (url, callback, errback, headers) { | |||
var xhr = text.createXhr(), header; | |||
xhr.open('GET', url, true); | |||
//Allow plugins direct access to xhr headers | |||
if (headers) { | |||
for (header in headers) { | |||
if (headers.hasOwnProperty(header)) { | |||
xhr.setRequestHeader(header.toLowerCase(), headers[header]); | |||
} | |||
} | |||
} | |||
//Allow overrides specified in config | |||
if (masterConfig.onXhr) { | |||
masterConfig.onXhr(xhr, url); | |||
} | |||
xhr.onreadystatechange = function (evt) { | |||
var status, err; | |||
//Do not explicitly handle errors, those should be | |||
//visible via console output in the browser. | |||
if (xhr.readyState === 4) { | |||
status = xhr.status || 0; | |||
if (status > 399 && status < 600) { | |||
//An http 4xx or 5xx error. Signal an error. | |||
err = new Error(url + ' HTTP status: ' + status); | |||
err.xhr = xhr; | |||
if (errback) { | |||
errback(err); | |||
} | |||
} else { | |||
callback(xhr.responseText); | |||
} | |||
if (masterConfig.onXhrComplete) { | |||
masterConfig.onXhrComplete(xhr, url); | |||
} | |||
} | |||
}; | |||
xhr.send(null); | |||
}; | |||
} else if (masterConfig.env === 'rhino' || (!masterConfig.env && | |||
typeof Packages !== 'undefined' && typeof java !== 'undefined')) { | |||
//Why Java, why is this so awkward? | |||
text.get = function (url, callback) { | |||
var stringBuffer, line, | |||
encoding = "utf-8", | |||
file = new java.io.File(url), | |||
lineSeparator = java.lang.System.getProperty("line.separator"), | |||
input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), | |||
content = ''; | |||
try { | |||
stringBuffer = new java.lang.StringBuffer(); | |||
line = input.readLine(); | |||
// Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 | |||
// http://www.unicode.org/faq/utf_bom.html | |||
// Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: | |||
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 | |||
if (line && line.length() && line.charAt(0) === 0xfeff) { | |||
// Eat the BOM, since we've already found the encoding on this file, | |||
// and we plan to concatenating this buffer with others; the BOM should | |||
// only appear at the top of a file. | |||
line = line.substring(1); | |||
} | |||
if (line !== null) { | |||
stringBuffer.append(line); | |||
} | |||
while ((line = input.readLine()) !== null) { | |||
stringBuffer.append(lineSeparator); | |||
stringBuffer.append(line); | |||
} | |||
//Make sure we return a JavaScript string and not a Java string. | |||
content = String(stringBuffer.toString()); //String | |||
} finally { | |||
input.close(); | |||
} | |||
callback(content); | |||
}; | |||
} else if (masterConfig.env === 'xpconnect' || (!masterConfig.env && | |||
typeof Components !== 'undefined' && Components.classes && | |||
Components.interfaces)) { | |||
//Avert your gaze! | |||
Cc = Components.classes; | |||
Ci = Components.interfaces; | |||
Components.utils['import']('resource://gre/modules/FileUtils.jsm'); | |||
xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); | |||
text.get = function (url, callback) { | |||
var inStream, convertStream, fileObj, | |||
readData = {}; | |||
if (xpcIsWindows) { | |||
url = url.replace(/\//g, '\\'); | |||
} | |||
fileObj = new FileUtils.File(url); | |||
//XPCOM, you so crazy | |||
try { | |||
inStream = Cc['@mozilla.org/network/file-input-stream;1'] | |||
.createInstance(Ci.nsIFileInputStream); | |||
inStream.init(fileObj, 1, 0, false); | |||
convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] | |||
.createInstance(Ci.nsIConverterInputStream); | |||
convertStream.init(inStream, "utf-8", inStream.available(), | |||
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); | |||
convertStream.readString(inStream.available(), readData); | |||
convertStream.close(); | |||
inStream.close(); | |||
callback(readData.value); | |||
} catch (e) { | |||
throw new Error((fileObj && fileObj.path || '') + ': ' + e); | |||
} | |||
}; | |||
} | |||
return text; | |||
}); |
@@ -1,354 +0,0 @@ | |||
const sqData = new Map(); | |||
const sq = { | |||
default: function (q) { | |||
const type = typeof(q); | |||
if (type === 'string') { | |||
if (q[0] === '<') | |||
return this.build(q); | |||
return sq.find(q); | |||
} else if (type === 'object') | |||
return sq.wrap([q]); | |||
document.addEventListener('DOMContentLoaded', q, false); | |||
}, | |||
build: function (tpl) { | |||
let el = document.createElement('template'); | |||
el.innerHTML = tpl.trim(); | |||
return sq.wrap([el.content.firstChild]); | |||
}, | |||
find: function (queryString) { | |||
if (!this[0]) | |||
return sq.wrap(document.querySelectorAll(queryString)); | |||
let els = []; | |||
this.each(el => els.push(...el.querySelectorAll(queryString))); | |||
return sq.wrap(els); | |||
}, | |||
children: function (filter) { | |||
if (!filter) | |||
return sq.wrap(this[0].children); | |||
return this.find(filter); | |||
}, | |||
parent: function () { | |||
let parents = []; | |||
this.each(el => parents.push(el.parentElement)); | |||
return sq.wrap(parents); | |||
}, | |||
on: function (event, fn, preventDefault) { | |||
let fnHandler = function (fn, el, noDefault, e) { | |||
e.target = el; | |||
requestAnimationFrame(fn.bind(null, e)); | |||
if (noDefault) { | |||
e.preventDefault(); | |||
return false; | |||
} | |||
}; | |||
this.each(el => el.addEventListener(event, fnHandler.bind(null, fn, el, preventDefault))); | |||
return this; | |||
}, | |||
off: function () { | |||
let newNodes = []; | |||
this.each(el => { | |||
let newNode = el.cloneNode(true); | |||
el.parentNode.replaceChild(newNode, el); | |||
newNodes.push(newNode); | |||
}); | |||
return this.wrap(newNodes); | |||
}, | |||
clone: function () { | |||
let newNode = this[0].cloneNode(true); | |||
return this.wrap([newNode]); | |||
}, | |||
each: function (fn) { | |||
const len = this.length; | |||
for (let i = 0; i < len; i++) | |||
fn(this[i]); | |||
}, | |||
appendTo: function (el) { | |||
if (typeof(el) === 'string') | |||
el = sq.find(el)[0]; | |||
else | |||
el = el.on ? el[0] : el; | |||
this.each(c => el.appendChild(c)); | |||
return this; | |||
}, | |||
prependTo: function (el) { | |||
el[0].insertBefore(this[0], el.children()[0]); | |||
return this; | |||
}, | |||
remove: function () { | |||
this.each(el => el.remove()); | |||
}, | |||
addClass: function (classNames) { | |||
if (classNames) | |||
classNames.split(' ').forEach(c => this.each(el => el.classList.add(c))); | |||
return this; | |||
}, | |||
removeClass: function (classNames) { | |||
classNames.split(' ').forEach(c => this.each(el => el.classList.remove(c))); | |||
return this; | |||
}, | |||
hasClass: function (className) { | |||
return this[0].classList.contains(className); | |||
}, | |||
toggleClass: function (className) { | |||
this.hasClass(className) ? this.removeClass(className) : this.addClass(className); | |||
}, | |||
show: function () { | |||
this.each(el => { | |||
if ($(el).css('display') !== 'none') | |||
return; | |||
let newDisplay = el.oldDisplay || 'block'; | |||
delete el.oldDisplay; | |||
el.attributeStyleMap.set('display', newDisplay); | |||
}); | |||
return this; | |||
}, | |||
hide: function () { | |||
this.each(el => { | |||
let oldDisplay = $(el).css('display'); | |||
if (oldDisplay !== 'none') | |||
el.oldDisplay = oldDisplay; | |||
el.attributeStyleMap.set('display', 'none'); | |||
}); | |||
return this; | |||
}, | |||
css: function (property, value) { | |||
let config = property; | |||
let aLen = arguments.length; | |||
if (aLen === 1 && typeof(property) === 'string') { | |||
let value = this[0].attributeStyleMap.get(property); | |||
if (!value) { | |||
let styles = this[0].computedStyleMap(); | |||
value = (styles.get(property) || {}); | |||
} | |||
return value.value; | |||
} else if (aLen === 2) { | |||
config = { | |||
[property]: value | |||
}; | |||
} | |||
Object.keys(config).forEach(c => { | |||
let val = config[c]; | |||
if (['left', 'top', 'width', 'height'].includes(c) && (!val.indexOf || val.indexOf('%') === -1)) | |||
val += 'px'; | |||
this.each(el => { | |||
if (val) | |||
el.style[c] = val; | |||
else | |||
el.attributeStyleMap.delete(c); | |||
}); | |||
}); | |||
return this; | |||
}, | |||
empty: function () { | |||
let node = this[0]; | |||
while (node.firstChild) | |||
node.removeChild(node.firstChild); | |||
return this; | |||
}, | |||
is: function (state) { | |||
return (this.width() && this.height()); | |||
}, | |||
html: function (val) { | |||
if (!arguments.length) | |||
return this[0].innerHTML; | |||
this[0].innerHTML = val; | |||
return this; | |||
}, | |||
click: function () { | |||
this[0].click(); | |||
return this; | |||
}, | |||
next: function () { | |||
return sq.wrap([this[0].nextSibling]); | |||
}, | |||
scrollTop: function (value) { | |||
if (!arguments.length) | |||
return this[0].scrollTop; | |||
this[0].scrollTop = value; | |||
}, | |||
val: function (val) { | |||
if (!arguments.length) | |||
return this[0].value; | |||
this[0].value = val; | |||
return this; | |||
}, | |||
attr: function (property, value) { | |||
if (arguments.length === 1) | |||
return this[0].getAttribute(property); | |||
this[0].setAttribute(property, value); | |||
return this; | |||
}, | |||
insertAfter: function (el) { | |||
el[0].parentNode.insertBefore(this[0], el[0].nextSibling); | |||
return this; | |||
}, | |||
insertBefore: function (el) { | |||
el[0].parentNode.insertBefore(this[0], el[0]); | |||
return this; | |||
}, | |||
index: function () { | |||
let el = this[0]; | |||
return Array.prototype.indexOf.call(el.parentElement.children, el); | |||
}, | |||
offset: function () { | |||
return this[0].getBoundingClientRect(); | |||
}, | |||
data: function (property, value) { | |||
let dataSet = sqData.get(this[0]); | |||
if (!dataSet) { | |||
dataSet = {}; | |||
sqData.set(this[0], dataSet); | |||
} | |||
if (arguments.length === 1) | |||
return dataSet[property]; | |||
dataSet[property] = value; | |||
return this; | |||
}, | |||
removeData: function (property) { | |||
if (this.dataSet) | |||
delete this.dataSet[property]; | |||
return this; | |||
}, | |||
wrap: function (els) { | |||
let res = { | |||
length: els.length | |||
}; | |||
Object.keys(sq) | |||
.forEach(k => res[k] = sq[k].bind(res)); | |||
for (let i = 0; i < els.length; i++) | |||
res[i] = els[i]; | |||
return res; | |||
}, | |||
width: function (val) { | |||
if (val) { | |||
this.css('width', val); | |||
return this; | |||
} | |||
return this[0].offsetWidth; | |||
}, | |||
height: function (val) { | |||
if (val) { | |||
this.css('height', val); | |||
return this; | |||
} | |||
return this[0].offsetHeight; | |||
}, | |||
eq: function (index) { | |||
return sq.wrap([this[index]]); | |||
}, | |||
focus: function () { | |||
this[0].focus(); | |||
return this; | |||
}, | |||
blur: function () { | |||
this[0].blur(); | |||
return this; | |||
}, | |||
cloneRecursive: function (o, newO) { | |||
if (typeof o !== 'object') | |||
return o; | |||
if (!o) | |||
return o; | |||
if (o instanceof Array) { | |||
if (!newO || !newO.push) | |||
newO = []; | |||
for (let i = 0; i < o.length; i++) | |||
newO[i] = sq.cloneRecursive(o[i], newO[i]); | |||
return newO; | |||
} | |||
if (!newO || typeof(newO) !== 'object') | |||
newO = {}; | |||
for (let i in o) { | |||
if (o.hasOwnProperty(i)) | |||
newO[i] = sq.cloneRecursive(o[i], newO[i]); | |||
} | |||
return newO; | |||
}, | |||
extend: function (temp, o) { | |||
let aLen = arguments.length; | |||
for (let i = 2; i < aLen; i++) | |||
sq.cloneRecursive(arguments[i], o); | |||
return o; | |||
} | |||
}; | |||
window.$ = sq.default.bind(sq); | |||
Object.keys(sq).forEach(k => window.$[k] = sq[k].bind(sq)); |
@@ -1 +0,0 @@ | |||
const sq={default:function(t){const e=typeof t;return"string"===e?"<"===t[0]?this.build(t):sq.find(t):"object"===e?sq.wrap([t]):void document.addEventListener("DOMContentLoaded",t,!1)},build:function(t){let e=document.createElement("template");return e.innerHTML=t.trim(),sq.wrap([e.content.firstChild])},find:function(t){const e=(this[0]||document).querySelectorAll(t);return sq.wrap(e)},children:function(){return sq.wrap(this[0].children)},parent:function(){return sq.wrap([this[0].parentElement])},on:function(t,e){return this.each(n=>n.addEventListener(t,t=>{t.target=n,e(t)})),this},each:function(t){const e=this.length;for(let n=0;n<e;n++)t(this[n])},appendTo:function(t){return t="string"==typeof t?sq.find(t)[0]:t.on?t[0]:t,this.each(e=>t.appendChild(e)),this},prependTo:function(t){return t[0].insertBefore(this[0],t.children()[0]),this},remove:function(){this.each(t=>t.remove())},addClass:function(t){return t.split(" ").forEach(t=>this.each(e=>e.classList.add(t))),this},removeClass:function(t){return t.split(" ").forEach(t=>this.each(e=>e.classList.remove(t))),this},hasClass:function(t){return this[0].classList.contains(t)},toggleClass:function(t){this.hasClass(t)?this.removeClass(t):this.addClass(t)},show:function(){return this.each(t=>t.attributeStyleMap.set("display","block")),this},hide:function(){return this.each(t=>t.attributeStyleMap.set("display","none")),this},css:function(t,e){let n=t,i=arguments.length;return 1===i&&"string"==typeof t?(this[0].attributeStyleMap.get(t)||{}).value:(2===i&&(n={[t]:e}),Object.keys(n).forEach(t=>{let e=n[t];!["left","top","width","height"].includes(t)||e.indexOf&&-1!==e.indexOf("%")||(e+="px"),this.each(n=>e?n.attributeStyleMap.set(t,e):n.attributeStyleMap.delete(t))}),this)},empty:function(){let t=this[0];for(;t.firstChild;)t.removeChild(t.firstChild);return this},is:function(t){return this.width()&&this.height()},html:function(t){return arguments.length?(this[0].innerHTML=t,this):this[0].innerHTML},click:function(){return this[0].click(),this},next:function(){return sq.wrap([this[0].nextSibling])},scrollTop:function(t){if(!arguments.length)return this[0].scrollTop;this[0].scrollTop=t},val:function(t){return arguments.length?(this[0].value=t,this):this[0].value},attr:function(t,e){return 1===arguments.length?this[0].getAttribute(t):(this[0].setAttribute(t,e),this)},insertAfter:function(t){return t[0].parentNode.insertBefore(this[0],t[0].nextSibling),this},insertBefore:function(t){return t[0].parentNode.insertBefore(this[0],t[0]),this},index:function(){let t=this[0];return Array.prototype.indexOf.call(t.parentElement.children,t)},offset:function(){return this[0].getBoundingClientRect()},data:function(t,e){return this.dataSet||(this.dataSet={}),1===arguments.length?this.dataSet[t]:(this.dataSet[t]=e,this)},removeData:function(t){return this.dataSet&&delete this.dataSet[t],this},wrap:function(t){let e={length:t.length};Object.keys(sq).forEach(t=>e[t]=sq[t].bind(e));for(let n=0;n<t.length;n++)e[n]=t[n];return e},width:function(){return this[0].offsetWidth},height:function(){return this[0].offsetHeight},eq:function(t){return sq.wrap([this[t]])},focus:function(){return this[0].focus(),this},cloneRecursive:function(t,e){if("object"!=typeof t)return t;if(!t)return t;if(t instanceof Array){e&&e.push||(e=[]);for(let n=0;n<t.length;n++)e[n]=sq.cloneRecursive(t[n],e[n]);return e}e||(e={});for(let n in t)t.hasOwnProperty(n)&&(e[n]=sq.cloneRecursive(t[n],e[n]));return e},extend:function(t,e){let n=arguments.length;for(let t=2;t<n;t++)sq.cloneRecursive(arguments[t],e);return e}};window.$=sq.default.bind(sq),Object.keys(sq).forEach(t=>window.$[t]=sq[t].bind(sq)); |
@@ -150,12 +150,56 @@ define([ | |||
.find('.icon') | |||
.css('background', 'url("' + spritesheet + '") ' + imgX + 'px ' + imgY + 'px') | |||
.off() | |||
.on('contextmenu', this.showContext.bind(this, item)) | |||
.on('mousedown', this.buildSlot.bind(this, elSlot)) | |||
.on('mousemove', this.onHoverItem.bind(this, elSlot, item, null)) | |||
.on('mouseleave', this.onHoverItem.bind(this, null, null)); | |||
}); | |||
}, | |||
openAugmentUi: function (item) { | |||
events.emit('onSetSmithItem', { | |||
item: item | |||
}); | |||
}, | |||
showContext: function (item, e) { | |||
let menuItems = { | |||
unequip: { | |||
text: 'unequip', | |||
callback: this.unequipItem.bind(this, item) | |||
}, | |||
augment: { | |||
text: 'craft', | |||
callback: this.openAugmentUi.bind(this, item) | |||
} | |||
}; | |||
let config = []; | |||
config.push(menuItems.unequip); | |||
if (item.slot) | |||
config.push(menuItems.augment); | |||
events.emit('onContextMenu', config, e); | |||
e.preventDefault(); | |||
return false; | |||
}, | |||
unequipItem: function (item) { | |||
client.request({ | |||
cpn: 'player', | |||
method: 'performAction', | |||
data: { | |||
cpn: 'equipment', | |||
method: 'unequip', | |||
data: item.id | |||
} | |||
}); | |||
}, | |||
onInspectTarget: function (result) { | |||
this.isInspecting = true; | |||
@@ -168,6 +212,9 @@ define([ | |||
}, | |||
buildSlot: function (el, e) { | |||
if (e && e.button !== 0) | |||
return; | |||
if (this.isInspecting) | |||
return; | |||
@@ -408,7 +455,7 @@ define([ | |||
'item quality': stats.magicFind + '%', | |||
'item quantity': stats.itemQuantity + '%', | |||
gap1: '', | |||
'sprint chance': (stats.sprintChance || 0) + '%', | |||
'sprint chance': ((~~(stats.sprintChance * 100) / 100) || 0) + '%', | |||
gap2: '', | |||
'xp increase': stats.xpIncrease + '%', | |||
gap3: '', | |||
@@ -5,7 +5,7 @@ | |||
z-index: 2; | |||
border: 5px solid @blackB; | |||
text-align: center; | |||
width: 474px; | |||
width: 500px; | |||
height: 712px; | |||
> .heading { | |||
@@ -68,12 +68,16 @@ | |||
flex-direction: column; | |||
flex-wrap: wrap; | |||
.left, .right { | |||
.left, | |||
.right { | |||
width: 96px; | |||
padding: 8px; | |||
} | |||
.left, .stats, .right, .bottom { | |||
.left, | |||
.stats, | |||
.right, | |||
.bottom { | |||
height: 528px; | |||
} | |||
@@ -105,8 +109,11 @@ | |||
font { | |||
color: @yellowB; | |||
} | |||
} | |||
} | |||
} | |||
.quick { | |||
@@ -117,9 +124,10 @@ | |||
justify-content: center; | |||
.slot { | |||
} | |||
} | |||
} | |||
.runes { | |||
@@ -134,10 +142,17 @@ | |||
&:last-child { | |||
margin-right: 0px; | |||
} | |||
} | |||
} | |||
.left, .right, .itemList, .runes, .tools, .quick { | |||
.left, | |||
.right, | |||
.itemList, | |||
.runes, | |||
.tools, | |||
.quick { | |||
.slot { | |||
width: 80px; | |||
height: 80px; | |||
@@ -216,6 +231,7 @@ | |||
&[slot^="quick-0"] .icon { | |||
background-position: -128px -384px; | |||
} | |||
} | |||
.icon { | |||
@@ -246,8 +262,11 @@ | |||
&.empty { | |||
background-color: fade(@blueA, 10%); | |||
} | |||
} | |||
} | |||
} | |||
.itemList { | |||
@@ -284,6 +303,7 @@ | |||
drop-shadow(2px 0px 0px @blackD) | |||
drop-shadow(-2px 0px 0px @blackD); | |||
} | |||
} | |||
&.new { | |||
@@ -302,11 +322,17 @@ | |||
drop-shadow(2px 0px 0px @blackD) | |||
drop-shadow(-2px 0px 0px @blackD); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
.mobile .uiEquipment { | |||
@@ -327,7 +353,9 @@ | |||
justify-content: space-between; | |||
position: relative; | |||
.left, .right, .quick { | |||
.left, | |||
.right, | |||
.quick { | |||
display: flex; | |||
flex-direction: row; | |||
justify-content: space-between; | |||
@@ -337,6 +365,7 @@ | |||
.slot { | |||
margin-bottom: 0px; | |||
} | |||
} | |||
.stats { | |||
@@ -361,6 +390,7 @@ | |||
order: 2; | |||
padding: 0px 8px 0px 0px; | |||
} | |||
} | |||
.runes { | |||
@@ -371,5 +401,7 @@ | |||
bottom: 8px; | |||
padding: 0px 8px 0px 8px; | |||
} | |||
} | |||
} |
@@ -11,11 +11,11 @@ | |||
</div> | |||
<div class="message"></div> | |||
</div> | |||
<div class="news" location="https://gitlab.com/Isleward/isleward/tags/v0.3.2">[ Latest Release Notes ]</div> | |||
<div class="news" location="https://gitlab.com/Isleward/isleward/tags/v0.3.3">[ Latest Release Notes ]</div> | |||
<div class="extra"> | |||
<div class="el btn btnPatreon" location="https://patreon.com/bigbadwaffle">Pledge on Patreon</div> | |||
<div class="el btn btnPaypal" 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/isleward/tags/v0.3.2">v0.3.2</div> | |||
<div class="version" location="https://gitlab.com/Isleward/isleward/tags/v0.3.3">v0.3.3</div> | |||
</div> |
@@ -26,7 +26,7 @@ define([ | |||
postRender: function () { | |||
this.onEvent('onToggleOptions', this.toggle.bind(this)); | |||
//Can only toggle fullscreen directly in a listener, not deferred the way wQuery does it | |||
//Can only toggle fullscreen directly in a listener, not deferred the way jQuery does it | |||
this.el.find('.btnScreen')[0].addEventListener('click', this.toggleScreen.bind(this)); | |||
this.el.find('.btnNames').on('click', events.emit.bind(events, 'onKeyDown', 'v')); | |||
this.el.find('.btnCharSelect').on('click', this.charSelect.bind(this)); | |||
@@ -145,16 +145,6 @@ define([ | |||
}; | |||
events.emit('onGetAnnouncement', resultMsg); | |||
return; | |||
} else if (msg.item.eq) { | |||
let resultMsg = { | |||
msg: 'Cannot augment equipped items', | |||
type: 'failure', | |||
zIndex: 9999999, | |||
top: 180 | |||
}; | |||
events.emit('onGetAnnouncement', resultMsg); | |||
return; | |||
} | |||
@@ -180,13 +170,15 @@ define([ | |||
this.offEvent(this.eventClickInv); | |||
$('.uiInventory').data('ui').toggle(); | |||
$('.uiInventory').data('ui').hide(); | |||
this.show(); | |||
this.el.show(); | |||
this.shown = true; | |||
msg.success = false; | |||
if (!msg || !msg.item || !msg.item.slot || msg.item.eq) | |||
if (!msg || !msg.item || !msg.item.slot) | |||
return; | |||
this.item = msg.item; | |||
@@ -56,6 +56,9 @@ define([ | |||
}) | |||
.next().html(hotkey); | |||
if (spell.autoActive) | |||
el.addClass('active'); | |||
//HACK - we don't actually know how long a tick is | |||
if (spell.cd) { | |||
this.onGetSpellCooldowns({ | |||
@@ -82,9 +82,9 @@ module.exports = { | |||
} | |||
return { | |||
amount: amount, | |||
blocked: blocked, | |||
dodged: dodged, | |||
amount, | |||
blocked, | |||
dodged, | |||
crit: isCrit, | |||
element: config.element | |||
}; | |||
@@ -321,7 +321,10 @@ module.exports = { | |||
if (!highest || l.threat > highest.threat) { | |||
highest = l; | |||
closest = Math.max(Math.abs(x - obj.x), Math.abs(y - obj.y)); | |||
} else if (l.threat === highest.threat) { | |||
} else if (l.threat === highest.threat && l.threat !== 0) { | |||
//Don't chase a closer target if both targets are at 0 threat because | |||
// this means that neither of them have attacked the target. | |||
// This stops people from griefing other players by pulling mobs to them. | |||
let distance = Math.max(Math.abs(x - obj.x), Math.abs(y - obj.y)); | |||
if (distance < closest) { | |||
highest = l; | |||
@@ -54,12 +54,8 @@ module.exports = { | |||
this.obj.syncer.set(true, 'dialogue', 'state', null); | |||
}, | |||
getState: function (sourceObj, state) { | |||
getState: function (sourceObj, state = 1) { | |||
let result = null; | |||
state = state || 1; | |||
//Goto? | |||
if ((state + '').indexOf('.') > -1) { | |||
let config = this.states[(state + '').split('.')[0]]; | |||
if (!config) | |||
@@ -89,7 +85,6 @@ module.exports = { | |||
return null; | |||
let useMsg = stateConfig.msg; | |||
if (stateConfig.cpn) { | |||
let cpn = sourceObj[stateConfig.cpn]; | |||
let newArgs = extend([], stateConfig.args); | |||
@@ -1,3 +1,5 @@ | |||
const { applyItemStats } = require('./equipment/helpers'); | |||
module.exports = { | |||
type: 'equipment', | |||
@@ -116,16 +118,7 @@ module.exports = { | |||
this.unequip(this.eq[slot], true); | |||
} | |||
let stats = item.stats; | |||
for (let s in stats) { | |||
let val = stats[s]; | |||
obj.stats.addStat(s, val); | |||
} | |||
(item.implicitStats || []).forEach(function (s) { | |||
obj.stats.addStat(s.stat, s.value); | |||
}, this); | |||
applyItemStats(obj, item, true); | |||
item.eq = true; | |||
this.eq[slot] = itemId; | |||
@@ -142,6 +135,7 @@ module.exports = { | |||
obj.fireEvent('afterEquipItem', item); | |||
}, | |||
unequip: function (itemId, ignoreSpaceCheck) { | |||
let item = itemId; | |||
if (typeof (itemId) === 'object') | |||
@@ -168,21 +162,11 @@ module.exports = { | |||
return; | |||
} | |||
let stats = item.stats; | |||
delete item.eq; | |||
delete this.eq[item.equipSlot]; | |||
delete item.equipSlot; | |||
for (let s in stats) { | |||
let val = stats[s]; | |||
obj.stats.addStat(s, -val); | |||
} | |||
(item.implicitStats || []).forEach(function (s) { | |||
obj.stats.addStat(s.stat, -s.value); | |||
}, this); | |||
applyItemStats(obj, item, false); | |||
inventory.setItemPosition(itemId); | |||
@@ -198,6 +182,7 @@ module.exports = { | |||
this.unequipAttrRqrGear(); | |||
}, | |||
unequipAll: function () { | |||
let eq = this.eq; | |||
Object.keys(this.eq).forEach(function (slot) { | |||
@@ -281,7 +266,8 @@ module.exports = { | |||
let message = ({ | |||
int: `You suddenly feel too stupid to wear your ${item.name}`, | |||
str: `Your weak body can no longer equip your ${item.name}`, | |||
dex: `Your sluggish physique cannot possibly equip your ${item.name}` | |||
dex: `Your sluggish physique cannot possibly equip your ${item.name}`, | |||
level: `Your level is too low to equip your ${item.name}` | |||
})[errors[0]]; | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
@@ -0,0 +1,14 @@ | |||
module.exports = { | |||
applyItemStats: ({ stats: objStats }, { stats, implicitStats = [] }, isEq) => { | |||
for (let s in stats) { | |||
const value = stats[s]; | |||
const useValue = isEq ? value : -value; | |||
objStats.addStat(s, useValue); | |||
} | |||
implicitStats.forEach(({ stat, value }) => { | |||
const useValue = isEq ? value : -value; | |||
objStats.addStat(stat, useValue); | |||
}); | |||
} | |||
}; |
@@ -42,8 +42,10 @@ module.exports = { | |||
this.items[name] = list; | |||
this.regenList(list); | |||
} else if (list.level !== requestLevel) | |||
} else if (list.level !== requestLevel) { | |||
list.level = requestLevel; | |||
this.regenList(list); | |||
} | |||
let result = list.items.map(m => { | |||
let item = requestedBy.inventory.simplifyItem(m); | |||
@@ -18,6 +18,10 @@ let commandRoles = { | |||
mute: 5, | |||
unmute: 5, | |||
//Super Mods | |||
broadcast: 8, | |||
saveAll: 8, | |||
//Admin | |||
getItem: 10, | |||
getGold: 10, | |||
@@ -44,7 +48,9 @@ let localCommands = [ | |||
'roll', | |||
'giveSkin', | |||
'block', | |||
'unblock' | |||
'unblock', | |||
'broadcast', | |||
'saveAll' | |||
]; | |||
module.exports = { | |||
@@ -86,7 +92,7 @@ module.exports = { | |||
}); | |||
} | |||
if (localCommands.indexOf(actionName) > -1) | |||
if (localCommands.includes(actionName)) | |||
this[actionName](config); | |||
else { | |||
atlas.performAction(this.obj, { | |||
@@ -603,6 +609,9 @@ module.exports = { | |||
}, | |||
getMaterials: function (config) { | |||
if (typeof(config) === 'object') | |||
config = 100; | |||
let inventory = this.obj.inventory; | |||
Object.entries(configMaterials).forEach(([material, blueprint]) => { | |||
@@ -613,5 +622,25 @@ module.exports = { | |||
...blueprint | |||
}); | |||
}); | |||
}, | |||
broadcast: function (msg) { | |||
if (typeof(msg) === 'object') | |||
msg = Object.keys(msg).join(' '); | |||
cons.emit('event', { | |||
event: 'onGetMessages', | |||
data: { | |||
messages: [{ | |||
class: 'color-blueA', | |||
message: msg, | |||
type: 'chat' | |||
}] | |||
} | |||
}); | |||
}, | |||
saveAll: function () { | |||
connections.forceSaveAll(); | |||
} | |||
}; |
@@ -81,6 +81,10 @@ module.exports = { | |||
return; | |||
} | |||
this.completeGathering(gathering, isFish); | |||
}, | |||
completeGathering: function (gathering, isFish) { | |||
let resourceNode = gathering.resourceNode; | |||
let gatherResult = extend({ | |||
obj: gathering | |||
@@ -5,6 +5,7 @@ let classes = require('../config/spirits'); | |||
let mtx = require('../mtx/mtx'); | |||
let factions = require('../config/factions'); | |||
let itemEffects = require('../items/itemEffects'); | |||
const { applyItemStats } = require('./equipment/helpers'); | |||
module.exports = { | |||
type: 'inventory', | |||
@@ -142,13 +143,31 @@ module.exports = { | |||
}, | |||
enchantItem: function (msg) { | |||
let item = this.findItem(msg.itemId); | |||
if ((!item) || (!item.slot) || (item.eq) || (item.noAugment) || ((msg.action === 'scour') && (item.power === 0))) { | |||
const { itemId, action } = msg; | |||
const item = this.findItem(itemId); | |||
if (!item) | |||
return; | |||
const { eq, slot, power, noAugment } = item; | |||
if (!slot || noAugment || (action === 'scour' && !power)) { | |||
this.resolveCallback(msg); | |||
return; | |||
} | |||
enchanter.enchant(this.obj, item, msg); | |||
const obj = this.obj; | |||
if (eq) { | |||
applyItemStats(obj, item, false); | |||
enchanter.enchant(obj, item, msg); | |||
applyItemStats(obj, item, true); | |||
if (item.slot !== slot) | |||
obj.equipment.unequip(itemId); | |||
} else | |||
enchanter.enchant(obj, item, msg); | |||
obj.equipment.unequipAttrRqrGear(); | |||
}, | |||
getEnchantMaterials: function (msg) { | |||
@@ -249,15 +268,7 @@ module.exports = { | |||
const hasSpace = this.hasSpace(item, true); | |||
if (!hasSpace) { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: 'Your bags are too full to split that stack', | |||
type: 'info' | |||
}] | |||
}, [this.obj.serverId]); | |||
this.notifyNoBagSpace(); | |||
return; | |||
} | |||
@@ -548,6 +559,8 @@ module.exports = { | |||
hookItemEvents: function (items) { | |||
items = items || this.items; | |||
if (!items.push) | |||
items = [ items ]; | |||
let iLen = items.length; | |||
for (let i = 0; i < iLen; i++) { | |||
let item = items[i]; | |||
@@ -568,6 +581,7 @@ module.exports = { | |||
try { | |||
let effectModule = require('../' + effectUrl); | |||
e.events = effectModule.events; | |||
e.text = effectModule.events.onGetText(item, e); | |||
} catch (error) {} | |||
} | |||
}); | |||
@@ -778,7 +792,7 @@ module.exports = { | |||
let existItem = this.items.find(i => i.name === item.name); | |||
if (existItem) { | |||
exists = true; | |||
existItem.quantity = (existItem.quantity || 1) + (item.quantity || 1); | |||
existItem.quantity = ~~(existItem.quantity || 1) + ~~(item.quantity || 1); | |||
item = existItem; | |||
} | |||
} | |||
@@ -793,16 +807,8 @@ module.exports = { | |||
let iLen = items.length; | |||
if (!this.hasSpace(item)) { | |||
if (!hideMessage) { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: 'Your bags are too full to loot any more items', | |||
type: 'info' | |||
}] | |||
}, [this.obj.serverId]); | |||
} | |||
if (!hideMessage) | |||
this.notifyNoBagSpace(); | |||
return false; | |||
} | |||
@@ -830,19 +836,18 @@ module.exports = { | |||
} | |||
if (this.obj.player) { | |||
let messages = []; | |||
let msg = item.name; | |||
if (quantity) | |||
msg += ' x' + quantity; | |||
else if ((item.stats) && (item.stats.weight)) | |||
msg += ` ${item.stats.weight}lb`; | |||
messages.push({ | |||
const messages = [{ | |||
class: 'q' + item.quality, | |||
message: 'loot: {' + msg + '}', | |||
item: item, | |||
type: 'loot' | |||
}); | |||
}]; | |||
if (!hideAlert) { | |||
this.obj.instance.syncer.queue('onGetDamage', { | |||
@@ -860,23 +865,8 @@ module.exports = { | |||
} | |||
} | |||
if (item.effects) { | |||
item.effects.forEach(function (e) { | |||
if (e.mtx) { | |||
let mtxUrl = mtx.get(e.mtx); | |||
let mtxModule = require('../' + mtxUrl); | |||
e.events = mtxModule.events; | |||
} else if (e.type) { | |||
let effectUrl = itemEffects.get(e.type); | |||
try { | |||
let effectModule = require('../' + effectUrl); | |||
e.text = effectModule.events.onGetText(item, e); | |||
e.events = effectModule.events; | |||
} catch (error) {} | |||
} | |||
}); | |||
} | |||
if (item.effects) | |||
this.hookItemEvents([item]); | |||
if (!exists) | |||
this.items.push(item); | |||
@@ -896,10 +886,8 @@ module.exports = { | |||
this.obj.syncer.setArray(true, 'inventory', 'getItems', this.simplifyItem(item), true); | |||
} | |||
if (!hideMessage) { | |||
if (fromMob) | |||
this.obj.fireEvent('afterLootMobItem', item); | |||
} | |||
if (!hideMessage && fromMob) | |||
this.obj.fireEvent('afterLootMobItem', item); | |||
return item; | |||
}, | |||
@@ -948,7 +936,8 @@ module.exports = { | |||
let itemBlueprint = { | |||
level: this.obj.stats.values.level, | |||
magicFind: magicFind, | |||
bonusMagicFind: bonusMagicFind | |||
bonusMagicFind: bonusMagicFind, | |||
noCurrency: i > 0 | |||
}; | |||
let useItem = generator.generate(itemBlueprint, playerObject.stats.values.level); | |||
@@ -1067,5 +1056,16 @@ module.exports = { | |||
canEquipItem: function (item) { | |||
return (this.equipItemErrors(item).length === 0); | |||
}, | |||
notifyNoBagSpace: function () { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: 'Your bags are too full to loot any more items', | |||
type: 'info' | |||
}] | |||
}, [this.obj.serverId]); | |||
} | |||
}; |
@@ -104,7 +104,17 @@ module.exports = { | |||
} while (toX - obj.x !== 0 || toY - obj.y !== 0); | |||
} | |||
if (abs(obj.x - toX) <= 1 && abs(obj.y - toY) <= 1) { | |||
//We use goHome to force followers to follow us around but they should never stay in that state | |||
// since it messes with combat | |||
if (obj.follower) | |||
this.goHome = false; | |||
const dx = abs(obj.x - toX); | |||
const dy = abs(obj.y - toY); | |||
if (dx + dy === 0) | |||
return; | |||
else if (dx <= 1 && dy <= 1) { | |||
obj.queue({ | |||
action: 'move', | |||
data: { | |||
@@ -134,11 +144,6 @@ module.exports = { | |||
}); | |||
} | |||
} | |||
//We use goHome to force followers to follow us around but they should never stay in that state | |||
// since it messes with combat | |||
if (obj.follower) | |||
this.goHome = false; | |||
}, | |||
fight: function (target) { | |||
@@ -137,6 +137,49 @@ module.exports = { | |||
} | |||
}, | |||
sendPrivateMessage: function (messageString) { | |||
let playerName = ''; | |||
//Check if there's a space in the name | |||
if (messageString[1] === "'") { | |||
playerName = messageString.substring(2, messageString.indexOf("'", 2)); | |||
messageString = messageString.replace("@'" + playerName + "' ", ''); | |||
} else { | |||
playerName = messageString.substring(1, messageString.indexOf(' ')); | |||
messageString = messageString.replace('@' + playerName + ' ', ''); | |||
} | |||
if (playerName === this.obj.name) | |||
return; | |||
let target = cons.players.find(p => p.name === playerName); | |||
if (!target) | |||
return; | |||
this.obj.socket.emit('event', { | |||
event: 'onGetMessages', | |||
data: { | |||
messages: [{ | |||
class: 'color-yellowB', | |||
message: '(you to ' + playerName + '): ' + messageString, | |||
type: 'chat', | |||
source: this.obj.name | |||
}] | |||
} | |||
}); | |||
target.socket.emit('event', { | |||
event: 'onGetMessages', | |||
data: { | |||
messages: [{ | |||
class: 'color-yellowB', | |||
message: '(' + this.obj.name + ' to you): ' + messageString, | |||
type: 'chat', | |||
source: this.obj.name | |||
}] | |||
} | |||
}); | |||
}, | |||
chat: function (msg) { | |||
if (!msg.data.message) | |||
return; | |||
@@ -201,48 +244,9 @@ module.exports = { | |||
}; | |||
events.emit('onBeforeSendMessage', msgEvent); | |||
messageString = msgEvent.msg; | |||
if (messageString[0] === '@') { | |||
let playerName = ''; | |||
//Check if there's a space in the name | |||
if (messageString[1] === "'") { | |||
playerName = messageString.substring(2, messageString.indexOf("'", 2)); | |||
messageString = messageString.replace("@'" + playerName + "' ", ''); | |||
} else { | |||
playerName = messageString.substring(1, messageString.indexOf(' ')); | |||
messageString = messageString.replace('@' + playerName + ' ', ''); | |||
} | |||
if (playerName === this.obj.name) | |||
return; | |||
let target = cons.players.find(p => p.name === playerName); | |||
if (!target) | |||
return; | |||
this.obj.socket.emit('event', { | |||
event: 'onGetMessages', | |||
data: { | |||
messages: [{ | |||
class: 'color-yellowB', | |||
message: '(you to ' + playerName + '): ' + messageString, | |||
type: 'chat', | |||
source: this.obj.name | |||
}] | |||
} | |||
}); | |||
target.socket.emit('event', { | |||
event: 'onGetMessages', | |||
data: { | |||
messages: [{ | |||
class: 'color-yellowB', | |||
message: '(' + this.obj.name + ' to you): ' + messageString, | |||
type: 'chat', | |||
source: this.obj.name | |||
}] | |||
} | |||
}); | |||
} else if (messageString[0] === '$') | |||
if (messageString[0] === '@') | |||
this.sendPrivateMessage(messageString); | |||
else if (messageString[0] === '$') | |||
this.sendCustomChannelMessage(msg); | |||
else if (messageString[0] === '%') | |||
this.sendPartyMessage(msg); | |||
@@ -386,6 +386,70 @@ module.exports = { | |||
} | |||
}, | |||
preDeath: function (source) { | |||
const obj = this.obj; | |||
let deathEvent = {}; | |||
let killSource = source; | |||
if (source.follower) | |||
killSource = source.follower.master; | |||
if (killSource.player) | |||
killSource.stats.kill(obj); | |||
obj.fireEvent('afterDeath', deathEvent); | |||
if (obj.player) { | |||
obj.syncer.setObject(false, 'stats', 'values', 'hp', this.values.hp); | |||
if (deathEvent.permadeath) { | |||
obj.auth.permadie(); | |||
obj.instance.syncer.queue('onGetMessages', { | |||
messages: { | |||
class: 'color-redA', | |||
message: `(level ${this.values.level}) ${obj.name} has forever left the shores of the living.` | |||
} | |||
}, -1); | |||
this.syncer.queue('onPermadeath', { | |||
source: killSource.name | |||
}, [obj.serverId]); | |||
} else | |||
this.values.hp = 0; | |||
obj.player.die(killSource, deathEvent.permadeath); | |||
} else { | |||
obj.effects.die(); | |||
if (this.obj.spellbook) | |||
this.obj.spellbook.die(); | |||
obj.destroyed = true; | |||
let deathAnimation = _.getDeepProperty(animations, ['mobs', obj.sheetName, obj.cell, 'death']); | |||
if (deathAnimation) { | |||
obj.instance.syncer.queue('onGetObject', { | |||
x: obj.x, | |||
y: obj.y, | |||
components: [deathAnimation] | |||
}, -1); | |||
} | |||
if (obj.inventory) { | |||
let aggroList = obj.aggro.list; | |||
let aLen = aggroList.length; | |||
for (let i = 0; i < aLen; i++) { | |||
let a = aggroList[i]; | |||
if (a.damage <= 0 || !a.obj.has('serverId')) | |||
continue; | |||
obj.inventory.dropBag(a.obj.name, killSource); | |||
} | |||
} | |||
} | |||
}, | |||
die: function (source) { | |||
let obj = this.obj; | |||
let values = this.values; | |||
@@ -479,23 +543,18 @@ module.exports = { | |||
}, | |||
takeDamage: function (damage, threatMult, source) { | |||
if (this.values.hp <= 0) | |||
return; | |||
let obj = this.obj; | |||
source.fireEvent('beforeDealDamage', damage, obj); | |||
obj.fireEvent('beforeTakeDamage', damage, source); | |||
//Maybe the attacker was stunned? | |||
if (damage.failed) | |||
return; | |||
//Maybe something else killed this mob already? | |||
if (obj.destroyed) | |||
if (damage.failed || obj.destroyed) | |||
return; | |||
let amount = damage.amount; | |||
if (amount > this.values.hp) | |||
amount = this.values.hp; | |||
let amount = Math.min(this.values.hp, damage.amount); | |||
damage.dealt = amount; | |||
@@ -547,67 +606,8 @@ module.exports = { | |||
obj.instance.eventEmitter.emitNoSticky('onBeforeActorDies', death, obj, source); | |||
obj.fireEvent('beforeDeath', death); | |||
if (death.success) { | |||
let deathEvent = {}; | |||
let killSource = source; | |||
if (source.follower) | |||
killSource = source.follower.master; | |||
if (killSource.player) | |||
killSource.stats.kill(obj); | |||
obj.fireEvent('afterDeath', deathEvent); | |||
if (obj.player) { | |||
obj.syncer.setObject(false, 'stats', 'values', 'hp', this.values.hp); | |||
if (deathEvent.permadeath) { | |||
obj.auth.permadie(); | |||
obj.instance.syncer.queue('onGetMessages', { | |||
messages: { | |||
class: 'color-redA', | |||
message: `(level ${this.values.level}) ${obj.name} has forever left the shores of the living.` | |||
} | |||
}, -1); | |||
this.syncer.queue('onPermadeath', { | |||
source: killSource.name | |||
}, [obj.serverId]); | |||
} else | |||
this.values.hp = 0; | |||
obj.player.die(killSource, deathEvent.permadeath); | |||
} else { | |||
obj.effects.die(); | |||
if (this.obj.spellbook) | |||
this.obj.spellbook.die(); | |||
obj.destroyed = true; | |||
let deathAnimation = _.getDeepProperty(animations, ['mobs', obj.sheetName, obj.cell, 'death']); | |||
if (deathAnimation) { | |||
obj.instance.syncer.queue('onGetObject', { | |||
x: obj.x, | |||
y: obj.y, | |||
components: [deathAnimation] | |||
}, -1); | |||
} | |||
if (obj.inventory) { | |||
let aggroList = obj.aggro.list; | |||
let aLen = aggroList.length; | |||
for (let i = 0; i < aLen; i++) { | |||
let a = aggroList[i]; | |||
if (a.damage <= 0 || !a.obj.has('serverId')) | |||
continue; | |||
obj.inventory.dropBag(a.obj.name, killSource); | |||
} | |||
} | |||
} | |||
} | |||
if (death.success) | |||
this.preDeath(source); | |||
} else { | |||
source.aggro.tryEngage(obj, 0); | |||
obj.syncer.setObject(false, 'stats', 'values', 'hp', this.values.hp); | |||
@@ -1,11 +1,13 @@ | |||
module.exports = { | |||
type: 'syncer', | |||
o: { | |||
components: [] | |||
}, | |||
oSelf: { | |||
components: [] | |||
}, | |||
reset: function () { | |||
this.o = { | |||
components: [] | |||
@@ -15,6 +17,7 @@ module.exports = { | |||
components: [] | |||
}; | |||
}, | |||
get: function (self) { | |||
let o = this.o; | |||
if (self) | |||
@@ -31,6 +34,7 @@ module.exports = { | |||
return o; | |||
}, | |||
set: function (self, cpnType, property, value) { | |||
let o = this.o; | |||
if (self) | |||
@@ -50,6 +54,19 @@ module.exports = { | |||
} else | |||
o[property] = value; | |||
}, | |||
setComponent: function (self, cpnType, cpn) { | |||
let o = this.o; | |||
if (self) | |||
o = this.oSelf; | |||
let exists = o.components.find(c => c.type === cpnType); | |||
if (exists) | |||
extend(exists, cpn); | |||
else | |||
o.components.push(cpn); | |||
}, | |||
setObject: function (self, cpnType, object, property, value) { | |||
let o = this.o; | |||
if (self) | |||
@@ -71,6 +88,7 @@ module.exports = { | |||
obj[property] = value; | |||
}, | |||
setArray: function (self, cpnType, property, value, noDuplicate) { | |||
let o = this.o; | |||
if (self) | |||
@@ -2,6 +2,17 @@ let generator = require('../items/generator'); | |||
let statGenerator = require('../items/generators/stats'); | |||
let skins = require('../config/skins'); | |||
const sendMessage = ({ instance, id, serverId }, color, message) => { | |||
instance.syncer.queue('onGetMessages', { | |||
id: id, | |||
messages: [{ | |||
class: color, | |||
message, | |||
type: 'info' | |||
}] | |||
}, [serverId]); | |||
}; | |||
module.exports = { | |||
type: 'trade', | |||
@@ -26,7 +37,7 @@ module.exports = { | |||
init: function (blueprint) { | |||
this.blueprint = blueprint; | |||
this.gold = blueprint.gold; | |||
this.gold = blueprint.gold; | |||
this.items = []; | |||
this.regenCd = this.regenCdMax; | |||
@@ -169,15 +180,7 @@ module.exports = { | |||
canAfford = this.gold >= ~~(item.worth * markup); | |||
if (!canAfford) { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: 'you can\'t afford that item', | |||
type: 'info' | |||
}] | |||
}, [this.obj.serverId]); | |||
sendMessage(this.obj, 'color-redA', 'You can\'t afford that item.'); | |||
this.resolveCallback(msg); | |||
return; | |||
} | |||
@@ -191,15 +194,7 @@ module.exports = { | |||
let haveSkin = this.obj.auth.doesOwnSkin(item.skinId); | |||
if (haveSkin) { | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-redA', | |||
message: 'you have already unlocked that skin', | |||
type: 'info' | |||
}] | |||
}, [this.obj.serverId]); | |||
sendMessage(this.obj, 'color-redA', 'You have already unlocked that skin.'); | |||
this.resolveCallback(msg); | |||
return; | |||
} | |||
@@ -240,15 +235,7 @@ module.exports = { | |||
this.obj.syncer.setArray(true, 'trade', 'removeItems', item.id); | |||
} else { | |||
this.obj.auth.saveSkin(item.skinId); | |||
this.obj.instance.syncer.queue('onGetMessages', { | |||
id: this.obj.id, | |||
messages: [{ | |||
class: 'color-greenB', | |||
message: 'Unlocked skin: ' + item.name, | |||
type: 'info' | |||
}] | |||
}, [this.obj.serverId]); | |||
sendMessage(this.obj, 'color-greenB', `Unlocked skin: ${item.name}.`); | |||
} | |||
if (item.worth.currency) { | |||
@@ -1,11 +1,25 @@ | |||
let combat = require('../../combat/combat'); | |||
module.exports = { | |||
type: 'lifeDrain', | |||
events: { | |||
afterTick: function () { | |||
this.obj.stats.takeDamage({ | |||
amount: this.amount | |||
}, 1, this.caster); | |||
let newDamage = combat.getDamage({ | |||
source: { | |||
stats: { | |||
values: {} | |||
} | |||
}, | |||
isAttack: false, | |||
target: this.obj, | |||
damage: this.amount, | |||
element: this.element, | |||
noScale: this.noScale, | |||
noCrit: true | |||
}); | |||
this.obj.stats.takeDamage(newDamage, 1, this.caster); | |||
} | |||
} | |||
}; |
@@ -56,6 +56,7 @@ module.exports = { | |||
mob.syncer.set(false, 'chatter', 'msg', text); | |||
} | |||
}, | |||
addComponents: function (config) { | |||
let objects = this.instance.objects.objects; | |||
@@ -70,13 +71,17 @@ module.exports = { | |||
let mLen = mobs.length; | |||
for (let i = 0; i < mLen; i++) { | |||
let mob = objects.find(o => (o.id === mobs[i])); | |||
let mob = objects.find(o => o.id === mobs[i]); | |||
for (let j = 0; j < cLen; j++) { | |||
let c = components[j]; | |||
mob.addComponent(c.type, components[j]); | |||
const newComponent = mob.addComponent(c.type, components[j]); | |||
//Likely, nobody knows about this new component, so we need to sync it | |||
mob.syncer.setComponent(false, c.type, newComponent.simplify()); | |||
} | |||
} | |||
}, | |||
removeComponents: function (config) { | |||
let objects = this.instance.objects.objects; | |||
@@ -25,5 +25,11 @@ module.exports = { | |||
itemSprite: [11, 2], | |||
baseWeight: 3, | |||
ttl: 30 | |||
}, | |||
'Stink Carp': { | |||
sheetName: 'objects', | |||
itemSprite: [11, 0], | |||
baseWeight: 5, | |||
ttl: 30 | |||
} | |||
}; |
@@ -641,4 +641,4 @@ | |||
"type":"map", | |||
"version":1, | |||
"width":200 | |||
} | |||
} |
@@ -206,6 +206,7 @@ module.exports = { | |||
col: 4, | |||
applyEffect: { | |||
type: 'lifeDrain', | |||
element: 'poison', | |||
ttl: balance.mobs.viridianSerpent.spitDotDuration, | |||
amount: balance.mobs.viridianSerpent.spitDotAmount | |||
}, | |||
@@ -2,7 +2,7 @@ module.exports = { | |||
name: 'Fishing Tournament', | |||
description: 'Catch the heaviest Ancient Carp for a chance to win Angler\'s Marks. Speak with Angler Nayla for more info.', | |||
distance: -1, | |||
cron: '0 19 * * *', | |||
cron: '0 7,19 * * *', | |||
notifications: [{ | |||
mark: 0, | |||
@@ -77,7 +77,7 @@ module.exports = { | |||
fish.push(t); | |||
}); | |||
let rewardCounts = [35, 20, 10]; | |||
let rewardCounts = [25, 15, 7]; | |||
let tpl = { | |||
name: 'Angler\'s Mark', | |||
sprite: [12, 9], | |||
@@ -3814,8 +3814,8 @@ | |||
"x":0, | |||
"y":0 | |||
}], | |||
"nextlayerid":10, | |||
"nextobjectid":882, | |||
"nextlayerid":11, | |||
"nextobjectid":885, | |||
"orientation":"orthogonal", | |||
"properties":[ | |||
{ | |||
@@ -0,0 +1,39 @@ | |||
module.exports = { | |||
name: 'Sewer', | |||
level: [11, 13], | |||
mobs: { | |||
default: { | |||
faction: 'fjolgard', | |||
deathRep: -5 | |||
}, | |||
stinktooth: { | |||
faction: 'fjolgard', | |||
grantRep: { | |||
fjolgard: 15 | |||
}, | |||
level: 13, | |||
regular: { | |||
}, | |||
rare: { | |||
count: 0 | |||
}, | |||
spells: [{ | |||
type: 'whirlwind', | |||
range: 1 | |||
}] | |||
} | |||
}, | |||
objects: { | |||
'stink carp school': { | |||
max: 3000, | |||
type: 'fish', | |||
quantity: [1, 3] | |||
} | |||
} | |||
}; |
@@ -1046,7 +1046,7 @@ | |||
"y":0 | |||
}], | |||
"nextlayerid":12, | |||
"nextobjectid":891, | |||
"nextobjectid":893, | |||
"orientation":"orthogonal", | |||
"properties":[ | |||
{ | |||
@@ -26,4 +26,31 @@ module.exports = [{ | |||
name: 'Empty Vial', | |||
quantity: 1 | |||
}] | |||
}, { | |||
name: 'Stinky Oil', | |||
description: 'Makes your weapon both stinkier, and hurtier.', | |||
item: { | |||
name: 'Stinky Oil', | |||
type: 'consumable', | |||
sprite: [0, 1], | |||
description: 'Makes your weapon both stinkier, and hurtier.', | |||
worth: 0, | |||
noSalvage: true, | |||
noAugment: true, | |||
uses: 1, | |||
cdMax: 85, | |||
effects: [{ | |||
type: 'augmentWeapon', | |||
rolls: { | |||
duration: 500 | |||
} | |||
}] | |||
}, | |||
materials: [{ | |||
name: 'Stink Carp', | |||
quantity: 3 | |||
}, { | |||
name: 'Empty Vial', | |||
quantity: 1 | |||
}] | |||
}]; |
@@ -1,5 +1,5 @@ | |||
module.exports = { | |||
version: '0.3.2', | |||
version: '0.3.3', | |||
port: 4000, | |||
startupMessage: 'Server: ready', | |||
defaultZone: 'fjolarok', | |||
@@ -12,5 +12,7 @@ module.exports = { | |||
//eslint-disable-next-line no-process-env | |||
dbHost: process.env.IWD_DB_HOST || 'localhost', | |||
//eslint-disable-next-line no-process-env | |||
dbPort: process.env.IWD_DB_PORT || 28015 | |||
dbPort: process.env.IWD_DB_PORT || 28015, | |||
//eslint-disable-next-line no-process-env | |||
dbName: process.env.IWD_DB_NAME || 'live' | |||
}; |
@@ -54,7 +54,7 @@ module.exports = { | |||
let range = this.auraRange; | |||
members.forEach(function (m) { | |||
members.forEach(m => { | |||
let effect = effects[m]; | |||
let obj = objects.find(f => (f.serverId === m)); | |||
@@ -88,7 +88,16 @@ module.exports = { | |||
ttl: -1, | |||
new: true | |||
}); | |||
}, this); | |||
}); | |||
//Remove effects from players who are no longer in the party | |||
Object.entries(effects).forEach(([serverId, effect]) => { | |||
if (!members.find(m => ~~m === ~~serverId)) { | |||
delete effects[serverId]; | |||
const obj = objects.find(f => ~~f.serverId === ~~serverId); | |||
obj.effects.removeEffect(effect); | |||
} | |||
}); | |||
}, | |||
updateInactive: function () { | |||
@@ -9,14 +9,13 @@ module.exports = { | |||
cast: function (action) { | |||
let obj = this.obj; | |||
let { x, y, instance: { physics, syncer } } = obj; | |||
let radius = this.radius; | |||
let x = obj.x; | |||
let y = obj.y; | |||
const particleConfig = extend({}, this.particles); | |||
let physics = obj.instance.physics; | |||
let syncer = obj.instance.syncer; | |||
this.obj.fireEvent('beforeSpawnParticles', this, particleConfig); | |||
const particleConfig = extend({}, this.particles); | |||
@@ -239,10 +239,13 @@ module.exports = { | |||
type === 'number' && | |||
isNaN(value) | |||
) || | |||
['obj', 'currentAction', 'autoActive', 'events'].includes(p) | |||
['obj', 'currentAction', 'events'].includes(p) | |||
) | |||
continue; | |||
if (p === 'autoActive') | |||
value = value !== null; | |||
values[p] = value; | |||
} | |||
@@ -0,0 +1,71 @@ | |||
const coordinates = [ | |||
[[0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1]] | |||
]; | |||
//const maxTicks = 8; | |||
module.exports = { | |||
type: 'whirlwind', | |||
cdMax: 5, | |||
manaCost: 10, | |||
range: 1, | |||
damage: 0.0001, | |||
isAttack: true, | |||
channelDuration: 100, | |||
isCasting: false, | |||
ticker: 0, | |||
cast: function (action) { | |||
if (this.isCasting) | |||
return; | |||
//this.isCasting = true; | |||
const { x: playerX, y: playerY } = this.obj; | |||
const coords = coordinates[this.range - 1].map(([x, y]) => [x + playerX, y + playerY]); | |||
let blueprint = { | |||
caster: this.obj.id, | |||
components: [{ | |||
idSource: this.obj.id, | |||
type: 'whirlwind', | |||
coordinates: coords, | |||
row: 3, | |||
col: 0 | |||
}] | |||
}; | |||
this.obj.instance.syncer.queue('onGetObject', blueprint, -1); | |||
return true; | |||
}, | |||
reachDestination: function (selfEffect) { | |||
const { effects, destroyed } = this.obj; | |||
if (destroyed) | |||
return; | |||
effects.removeEffect(selfEffect); | |||
}, | |||
spawnDamager: function (x, y) { | |||
const { destroyed, instance } = this.obj; | |||
if (destroyed) | |||
return; | |||
instance.syncer.queue('onGetObject', { | |||
x, | |||
y, | |||
components: [{ | |||
type: 'attackAnimation', | |||
row: 3, | |||
col: 0 | |||
}] | |||
}, -1); | |||
} | |||
}; |
@@ -24,10 +24,6 @@ let startup = { | |||
onDbReady: async function () { | |||
await fixes.fixDb(); | |||
setInterval(function () { | |||
global.gc(); | |||
}, 60000); | |||
process.on('uncaughtException', this.onError.bind(this)); | |||
animations.init(); | |||
@@ -7,6 +7,147 @@ let configCurrencies = require('./config/currencies'); | |||
let configSlots = require('./config/slots'); | |||
let generator = require('./generator'); | |||
const reroll = (item, msg) => { | |||
let enchantedStats = item.enchantedStats; | |||
delete item.enchantedStats; | |||
delete item.implicitStats; | |||
delete msg.addStatMsgs; | |||
if ((item.stats) && (item.stats.lvlRequire)) { | |||
item.level += item.stats.lvlRequire; | |||
delete item.originalLevel; | |||
} | |||
item.stats = {}; | |||
let bpt = { | |||
slot: item.slot, | |||
type: item.type, | |||
sprite: item.sprite, | |||
spritesheet: item.spritesheet | |||
}; | |||
generatorSlots.generate(item, bpt); | |||
generatorTypes.generate(item, bpt); | |||
generatorStats.generate(item, bpt); | |||
for (let p in enchantedStats) { | |||
if (!item.stats[p]) | |||
item.stats[p] = 0; | |||
item.stats[p] += enchantedStats[p]; | |||
if (p === 'lvlRequire') { | |||
if (!item.originalLevel) | |||
item.originalLevel = item.level; | |||
item.level -= enchantedStats[p]; | |||
if (item.level < 1) | |||
item.level = 1; | |||
} | |||
} | |||
item.enchantedStats = enchantedStats || null; | |||
}; | |||
const relevel = item => { | |||
if (item.slot === 'tool') | |||
return; | |||
let offset = 1 + ~~(Math.random() * 2); | |||
const maxLevel = consts.maxLevel; | |||
if (!item.originalLevel) | |||
item.level = Math.min(maxLevel, item.level + offset); | |||
else { | |||
offset = Math.min(maxLevel - item.originalLevel, offset); | |||
item.originalLevel = Math.min(maxLevel, item.originalLevel + offset); | |||
item.level = Math.min(maxLevel, item.level + offset); | |||
} | |||
}; | |||
const reslot = (item, msg) => { | |||
if (item.effects || item.slot === 'tool') | |||
return; | |||
if (item.originalLevel) | |||
item.level = item.originalLevel; | |||
delete item.enchantedStats; | |||
delete msg.addStatMsgs; | |||
let possibleStats = Object.keys(item.stats || {}); | |||
let newItem = generator.generate({ | |||
slot: configSlots.getRandomSlot(item.slot), | |||
level: item.level, | |||
quality: item.quality, | |||
stats: possibleStats, | |||
limitSlotStats: true | |||
}); | |||
delete item.spritesheet; | |||
delete item.stats; | |||
delete item.spell; | |||
delete item.implicitStats; | |||
delete item.power; | |||
extend(item, newItem); | |||
}; | |||
const reforge = item => { | |||
if (!item.spell) | |||
return; | |||
let spellName = item.spell.name.toLowerCase(); | |||
let oldSpell = item.spell; | |||
delete item.spell; | |||
generatorSpells.generate(item, { | |||
spellName: spellName | |||
}); | |||
item.spell = extend(oldSpell, item.spell); | |||
}; | |||
const scour = (item, result) => { | |||
if (!item.power) | |||
return; | |||
for (let p in item.enchantedStats) { | |||
let value = item.enchantedStats[p]; | |||
if (item.stats[p]) { | |||
result.addStatMsgs.push({ | |||
stat: p, | |||
value: -value | |||
}); | |||
item.stats[p] -= value; | |||
if (item.stats[p] <= 0) | |||
delete item.stats[p]; | |||
if (p === 'lvlRequire') { | |||
item.level = Math.min(consts.maxLevel, item.level + value); | |||
delete item.originalLevel; | |||
} | |||
} | |||
} | |||
delete item.enchantedStats; | |||
delete item.power; | |||
}; | |||
const augment = (item, inventory, result, msg) => { | |||
let newPower = (item.power || 0) + 1; | |||
if (newPower > 3) { | |||
inventory.resolveCallback(msg); | |||
return; | |||
} | |||
item.power = newPower; | |||
generatorStats.generate(item, { | |||
statCount: 1 | |||
}, result); | |||
}; | |||
module.exports = { | |||
enchant: function (obj, item, msg) { | |||
let inventory = obj.inventory; | |||
@@ -36,142 +177,24 @@ module.exports = { | |||
inventory.destroyItem(invMaterial.id, m.quantity); | |||
}); | |||
if (msg.action === 'reroll') { | |||
let enchantedStats = item.enchantedStats; | |||
delete item.enchantedStats; | |||
delete item.implicitStats; | |||
delete msg.addStatMsgs; | |||
if ((item.stats) && (item.stats.lvlRequire)) { | |||
item.level += item.stats.lvlRequire; | |||
delete item.originalLevel; | |||
} | |||
item.stats = {}; | |||
let bpt = { | |||
slot: item.slot, | |||
type: item.type, | |||
sprite: item.sprite, | |||
spritesheet: item.spritesheet | |||
}; | |||
generatorSlots.generate(item, bpt); | |||
generatorTypes.generate(item, bpt); | |||
generatorStats.generate(item, bpt); | |||
for (let p in enchantedStats) { | |||
if (!item.stats[p]) | |||
item.stats[p] = 0; | |||
item.stats[p] += enchantedStats[p]; | |||
if (p === 'lvlRequire') { | |||
item.level -= enchantedStats[p]; | |||
if (item.level < 1) | |||
item.level = 1; | |||
} | |||
} | |||
item.enchantedStats = enchantedStats || null; | |||
} else if (msg.action === 'relevel') { | |||
if (item.slot === 'tool') | |||
return; | |||
let offset = 1 + ~~(Math.random() * 2); | |||
const maxLevel = consts.maxLevel; | |||
if (!item.originalLevel) | |||
item.level = Math.min(maxLevel, item.level + offset); | |||
else { | |||
offset = Math.min(maxLevel - item.originalLevel, offset); | |||
item.originalLevel = Math.min(maxLevel, item.originalLevel + offset); | |||
item.level = Math.min(maxLevel, item.level + offset); | |||
} | |||
} else if (msg.action === 'reslot') { | |||
if (item.effects || item.slot === 'tool') | |||
return; | |||
if (item.originalLevel) | |||
item.level = item.originalLevel; | |||
delete item.enchantedStats; | |||
delete msg.addStatMsgs; | |||
let possibleStats = Object.keys(item.stats || {}); | |||
let newItem = generator.generate({ | |||
slot: configSlots.getRandomSlot(item.slot), | |||
level: item.level, | |||
quality: item.quality, | |||
stats: possibleStats, | |||
limitSlotStats: true | |||
}); | |||
delete item.spritesheet; | |||
delete item.stats; | |||
delete item.spell; | |||
delete item.implicitStats; | |||
delete item.power; | |||
extend(item, newItem); | |||
} else if (msg.action === 'reforge') { | |||
if (!item.spell) | |||
return; | |||
let spellName = item.spell.name.toLowerCase(); | |||
let oldSpell = item.spell; | |||
delete item.spell; | |||
generatorSpells.generate(item, { | |||
spellName: spellName | |||
}); | |||
item.spell = extend(oldSpell, item.spell); | |||
} else if (msg.action === 'scour') { | |||
if (!item.power) | |||
return; | |||
for (let p in item.enchantedStats) { | |||
let value = item.enchantedStats[p]; | |||
if (item.stats[p]) { | |||
result.addStatMsgs.push({ | |||
stat: p, | |||
value: -value | |||
}); | |||
item.stats[p] -= value; | |||
if (item.stats[p] <= 0) | |||
delete item.stats[p]; | |||
if (p === 'lvlRequire') { | |||
item.level = Math.min(consts.maxLevel, item.level + value); | |||
delete item.originalLevel; | |||
} | |||
} | |||
} | |||
delete item.enchantedStats; | |||
delete item.power; | |||
} else { | |||
let newPower = (item.power || 0) + 1; | |||
if (newPower > 3) { | |||
inventory.resolveCallback(msg); | |||
return; | |||
} | |||
item.power = newPower; | |||
this.addStat(item, result); | |||
} | |||
if (msg.action === 'reroll') | |||
reroll(item, msg); | |||
else if (msg.action === 'relevel') | |||
relevel(item); | |||
else if (msg.action === 'reslot') | |||
reslot(item, msg); | |||
else if (msg.action === 'reforge') | |||
reforge(item); | |||
else if (msg.action === 'scour') | |||
scour(item, result); | |||
else | |||
augment(item, inventory, result, msg); | |||
obj.syncer.setArray(true, 'inventory', 'getItems', inventory.simplifyItem(item)); | |||
inventory.resolveCallback(msg, result); | |||
}, | |||
addStat: function (item, result) { | |||
generatorStats.generate(item, { | |||
statCount: 1 | |||
}, result); | |||
}, | |||
getEnchantMaterials: function (item, action) { | |||
let result = null; | |||
@@ -39,6 +39,8 @@ module.exports = { | |||
const levelDelta = ownerLevel - blueprint.level; | |||
currencyChance /= Math.pow(levelDelta - 3, 2); | |||
} | |||
if (blueprint.noCurrency) | |||
currencyChance = 0; | |||
if ((!blueprint.slot) && (!blueprint.noSpell)) { | |||
isSpell = blueprint.spell; | |||
@@ -94,6 +96,11 @@ module.exports = { | |||
} | |||
delete item.stats[stat]; | |||
if (stat === 'lvlRequire') { | |||
item.level = item.originalLevel; | |||
delete item.originalLevel; | |||
} | |||
}, | |||
pickRandomSlot: function () { | |||
@@ -190,8 +190,12 @@ module.exports = { | |||
this.actionQueue.spliceWhere(a => a.priority); | |||
this.actionQueue.splice(0, 0, action); | |||
} else { | |||
if (action.priority) | |||
if (action.priority) { | |||
this.spellbook.stopCasting(); | |||
this.actionQueue.splice(0, 0, action); | |||
return; | |||
} | |||
this.actionQueue.push(action); | |||
} | |||
}, | |||
@@ -266,7 +270,7 @@ module.exports = { | |||
if (!action.force) { | |||
if (physics.isTileBlocking(data.x, data.y)) | |||
return false; | |||
return true; | |||
data.success = true; | |||
this.fireEvent('beforeMove', data); | |||
@@ -289,7 +293,7 @@ module.exports = { | |||
(deltaX === 0) && | |||
(deltaY === 0) | |||
) | |||
) | |||
) | |||
return false; | |||
} | |||
@@ -300,7 +304,7 @@ module.exports = { | |||
this.x = data.x; | |||
this.y = data.y; | |||
} else | |||
} else | |||
return false; | |||
} else { | |||
physics.removeObject(this, this.x, this.y, data.x, data.y); | |||
@@ -168,11 +168,6 @@ | |||
"resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", | |||
"integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" | |||
}, | |||
"bluebird": { | |||
"version": "2.11.0", | |||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", | |||
"integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" | |||
}, | |||
"body-parser": { | |||
"version": "1.18.3", | |||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", | |||
@@ -1401,12 +1396,19 @@ | |||
} | |||
} | |||
}, | |||
"rethinkdb": { | |||
"version": "2.3.3", | |||
"resolved": "https://registry.npmjs.org/rethinkdb/-/rethinkdb-2.3.3.tgz", | |||
"integrity": "sha1-PcZYbiL6HavuDSVOZL0ON5+tL3I=", | |||
"rethinkdbdash": { | |||
"version": "2.3.31", | |||
"resolved": "https://registry.npmjs.org/rethinkdbdash/-/rethinkdbdash-2.3.31.tgz", | |||
"integrity": "sha512-6nXrKFjdg2Ug0YpdmPWSvyD/2EisHnFNt4FWZ74dcXGK48ievSv+cNFTmVv+KjLi6I9CCf6w4CKZ6yCYTfMfdQ==", | |||
"requires": { | |||
"bluebird": ">= 2.3.2 < 3" | |||
"bluebird": ">= 3.0.1" | |||
}, | |||
"dependencies": { | |||
"bluebird": { | |||
"version": "3.5.5", | |||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", | |||
"integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" | |||
} | |||
} | |||
}, | |||
"rimraf": { | |||
@@ -9,7 +9,7 @@ | |||
"express-minify": "^1.0.0", | |||
"google-spreadsheet": "^2.0.7", | |||
"less-middleware": "^3.1.0", | |||
"rethinkdb": "^2.3.3", | |||
"rethinkdbdash": "^2.3.31", | |||
"socket.io": "^2.2.0", | |||
"sqlite3": "^4.0.6", | |||
"universal-analytics": "^0.4.20" | |||
@@ -1,226 +0,0 @@ | |||
let firebase = require('firebase'); | |||
let fConfig = require('./firebaseConfig'); | |||
let fs = require('fs'); | |||
module.exports = { | |||
db: null, | |||
io: null, | |||
init: async function (oldIo, convert) { | |||
this.io = oldIo; | |||
firebase.initializeApp(fConfig); | |||
this.db = firebase.database(); | |||
if (!process.send && convert) | |||
await this.convert(); | |||
this.bindHandlers(); | |||
}, | |||
bindHandlers: function () { | |||
this.io.process = () => {}; | |||
this.io.get = this.get.bind(this); | |||
this.io.set = this.set.bind(this); | |||
this.io.getAsync = this.getAsync.bind(this); | |||
this.io.setAsync = this.setAsync.bind(this); | |||
this.io.getAllAsync = this.getAllAsync.bind(this); | |||
this.io.deleteAsync = this.deleteAsync.bind(this); | |||
this.io.on = this.on.bind(this); | |||
}, | |||
convert: async function () { | |||
const skip = [ | |||
'character', | |||
'characterList', | |||
'stash', | |||
'skins', | |||
'login', | |||
'leaderboard', | |||
'customMap', | |||
//'mail', | |||
'customChannels', | |||
'error', | |||
'modLog', | |||
'accountInfo' | |||
]; | |||
let tables = Object.keys(io.tables); | |||
for (let table of tables) { | |||
if (await this.tableExists(table)) | |||
continue; | |||
await this.createTable(table); | |||
} | |||
const options = { | |||
login: { | |||
noParse: true | |||
}, | |||
mail: { | |||
noParse: true | |||
}, | |||
error: { | |||
noParse: true | |||
}, | |||
skins: { | |||
noParse: true | |||
} | |||
}; | |||
for (let table of tables) { | |||
if (skip.includes(table)) { | |||
//eslint-disable-next-line no-console | |||
console.log(`Skipping ${table}`); | |||
continue; | |||
} | |||
//eslint-disable-next-line no-console | |||
console.log(`Converting ${table}`); | |||
if (table === 'character') { | |||
await this.convertCorrupted('character', {}, true); | |||
continue; | |||
} else if (table === 'mail') { | |||
await this.convertCorrupted('mail', { | |||
noParse: true | |||
}); | |||
continue; | |||
} | |||
let records = await io.getAllAsync({ | |||
table: table, | |||
...options[table] | |||
}); | |||
let length = records.length; | |||
//eslint-disable-next-line no-console | |||
console.log(`${length} records`); | |||
let i = 0; | |||
for (let record of records) { | |||
//eslint-disable-next-line no-console | |||
console.log(++i + '/' + length); | |||
//if (table === 'login' && i < 12400) | |||
// continue; | |||
if (!record.key || record.key.indexOf('.') > -1 || record.key.indexOf('$') > -1 || record.key.indexOf('#') > -1) { | |||
//eslint-disable-next-line no-console | |||
console.log(`Invalid key ${record.key}`); | |||
fs.appendFileSync(`failed-${table}`, record.key + '\r\n'); | |||
continue; | |||
} else | |||
await this.write(table, record.key, record.value); | |||
} | |||
} | |||
}, | |||
convertCorrupted: async function (table, options, showErrors) { | |||
let records = await io.getAllAsync({ | |||
table: 'characterList' | |||
}); | |||
let length = records.length; | |||
let i = 0; | |||
for (let record of records) { | |||
//eslint-disable-next-line no-console | |||
console.log(++i + '/' + length); | |||
let charList = record.value; | |||
for (let charName of charList) { | |||
charName = charName.name || charName; | |||
try { | |||
let character = await io.getAsync({ | |||
table: table, | |||
key: charName, | |||
...options | |||
}); | |||
if (!character) { | |||
if (showErrors) { | |||
//eslint-disable-next-line no-console | |||
console.log(charName + ' failed'); | |||
} | |||
} else | |||
await this.write(table, charName, character); | |||
} catch (e) {} | |||
} | |||
} | |||
}, | |||
tableExists: async function (table) { | |||
let res = await this.db.ref(`/${table}/{placeholder}/`).once('value'); | |||
return (res.val() === 1); | |||
}, | |||
createTable: async function (table) { | |||
await this.db.ref(`/${table}/`).set({ | |||
'{placeholder}': 1 | |||
}); | |||
}, | |||
on: async function (options) { | |||
this.db.ref(options.path).on('value', res => { | |||
options.callback(res.val()); | |||
}); | |||
}, | |||
get: async function (options) { | |||
let res = await this.db.ref(`/${options.field}/${options.ent}`).once('value'); | |||
if (options.callback) | |||
options.callback(res.val()); | |||
}, | |||
set: async function (options) { | |||
await this.db.ref(`/${options.field}/${options.ent}`).set(options.value); | |||
if (options.callback) | |||
options.callback(); | |||
}, | |||
getAsync: async function (options) { | |||
let res = (await this.db.ref(`/${options.table}/${options.key}`).once('value')).val(); | |||
if (!res && !options.noDefault && !options.noParse) | |||
res = options.isArray ? [] : {}; | |||
else if (typeof(res) === 'string' && !options.noParse) | |||
res = JSON.parse(res); | |||
return res; | |||
}, | |||
setAsync: async function (options) { | |||
await this.db.ref(`/${options.table}/${options.key}`).set(options.value); | |||
}, | |||
getAllAsync: async function (options) { | |||
let res = await this.db.ref(`/${options.table}`).once('value'); | |||
res = res.val(); | |||
res = Object.keys(res).map(r => { | |||
return { | |||
key: r, | |||
value: res[r] | |||
}; | |||
}); | |||
return res; | |||
}, | |||
deleteAsync: async function (options) { | |||
await this.db.ref(`/${options.table}/${options.key}`).remove(); | |||
}, | |||
read: async function (table, key) { | |||
let res = await this.db.ref(`/${table}/${key}`).once('value'); | |||
return res.val(); | |||
}, | |||
write: async function (table, key, value) { | |||
await this.db.ref(`/${table}/${key}`).set(value); | |||
} | |||
}; |
@@ -1,5 +1,10 @@ | |||
let r = require('rethinkdb'); | |||
let serverConfig = require('../config/serverConfig'); | |||
const serverConfig = require('../config/serverConfig'); | |||
const r = require('rethinkdbdash')({ | |||
host: serverConfig.dbHost, | |||
port: serverConfig.dbPort, | |||
db: serverConfig.dbName | |||
}); | |||
const dbConfig = { | |||
host: serverConfig.dbHost, | |||
@@ -26,8 +31,6 @@ module.exports = { | |||
staticCon: null, | |||
init: async function (cbReady) { | |||
this.staticCon = await this.getConnection(); | |||
await this.create(); | |||
cbReady(); | |||
@@ -41,14 +44,14 @@ module.exports = { | |||
const con = await this.getConnection(); | |||
try { | |||
await r.dbCreate(this.useDb).run(con); | |||
await r.dbCreate(this.useDb).run(); | |||
} catch (e) { | |||
} | |||
for (const table of tables) { | |||
try { | |||
await r.tableCreate(table).run(con); | |||
await r.tableCreate(table).run(); | |||
} catch (e) { | |||
if (!e.message.includes('already exists')) | |||
_.log(e); | |||
@@ -68,7 +71,7 @@ module.exports = { | |||
let res = await r.table(table) | |||
.get(key) | |||
.run(con); | |||
.run(); | |||
if (res) | |||
return res.value; | |||
@@ -89,9 +92,7 @@ module.exports = { | |||
const con = await this.getConnection(); | |||
let res = await r.table(table) | |||
.run(con); | |||
res = await res.toArray(); | |||
.run(); | |||
if (res) | |||
return res; | |||
@@ -109,8 +110,6 @@ module.exports = { | |||
value, | |||
conflict = 'update' | |||
}) { | |||
const con = await this.getConnection(); | |||
try { | |||
await r.table(table) | |||
.insert({ | |||
@@ -119,12 +118,10 @@ module.exports = { | |||
}, { | |||
conflict | |||
}) | |||
.run(con); | |||
.run(); | |||
} catch (e) { | |||
this.logError(e, table, id); | |||
} | |||
con.close(); | |||
}, | |||
deleteAsync: async function ({ | |||
@@ -136,15 +133,13 @@ module.exports = { | |||
await r.table(table) | |||
.get(key) | |||
.delete() | |||
.run(con); | |||
con.close(); | |||
.run(); | |||
}, | |||
subscribe: function (table) { | |||
return r.table(table) | |||
.changes() | |||
.run(this.staticCon); | |||
.run(); | |||
}, | |||
append: async function ({ | |||
@@ -153,8 +148,6 @@ module.exports = { | |||
value, | |||
field | |||
}) { | |||
const con = await this.getConnection(); | |||
try { | |||
await r.table(table) | |||
.get(key) | |||
@@ -169,12 +162,10 @@ module.exports = { | |||
} | |||
); | |||
}) | |||
.run(con); | |||
.run(); | |||
} catch (e) { | |||
this.logError(e, table, key); | |||
} | |||
con.close(); | |||
}, | |||
exists: async function ({ | |||
@@ -185,9 +176,7 @@ module.exports = { | |||
let res = await r.table(table) | |||
.get(key) | |||
.run(con); | |||
con.close(); | |||
.run(); | |||
return !!res; | |||
}, | |||
@@ -6,6 +6,8 @@ let globalZone = require('../config/zoneBase'); | |||
let randomMap = require('./randomMap'); | |||
let events = require('../misc/events'); | |||
const mapObjects = require('./map/mapObjects'); | |||
let mapFile = null; | |||
let mapScale = null; | |||
let padding = null; | |||
@@ -325,8 +327,9 @@ module.exports = { | |||
} | |||
}, | |||
object: function (layerName, cell) { | |||
//Fix for newer versions of tiled | |||
//Fixes for newer versions of tiled | |||
cell.properties = objectifyProperties(cell.properties); | |||
cell.polyline = cell.polyline || cell.polygon; | |||
let clientObj = (layerName === 'clientObjects'); | |||
let cellInfo = this.builders.getCellInfo(cell.gid); | |||
@@ -370,34 +373,8 @@ module.exports = { | |||
} else if (cell.width === 24) | |||
blueprint.x++; | |||
if (cell.polyline) { | |||
let lowX = this.size.w; | |||
let lowY = this.size.h; | |||
let highX = 0; | |||
let highY = 0; | |||
blueprint.area = cell.polyline.map(function (v) { | |||
let x = ~~((v.x + cell.x) / mapScale); | |||
let y = ~~((v.y + cell.y) / mapScale); | |||
if (x < lowX) | |||
lowX = x; | |||
if (x > highX) | |||
highX = x; | |||
if (y < lowY) | |||
lowY = y; | |||
if (y > highY) | |||
highY = y; | |||
return [x, y]; | |||
}); | |||
blueprint.x = lowX; | |||
blueprint.y = lowY; | |||
blueprint.width = (highX - lowX); | |||
blueprint.height = (highY - lowY); | |||
} | |||
if (cell.polyline) | |||
mapObjects.polyline(this.size, blueprint, cell, mapScale); | |||
if (layerName === 'rooms') { | |||
if (blueprint.properties.exit) { | |||
@@ -0,0 +1,30 @@ | |||
module.exports = { | |||
polyline: function (size, blueprint, cell, mapScale) { | |||
let lowX = size.w; | |||
let lowY = size.h; | |||
let highX = 0; | |||
let highY = 0; | |||
blueprint.area = cell.polyline.map(function (v) { | |||
let x = ~~((v.x + cell.x) / mapScale); | |||
let y = ~~((v.y + cell.y) / mapScale); | |||
if (x < lowX) | |||
lowX = x; | |||
if (x > highX) | |||
highX = x; | |||
if (y < lowY) | |||
lowY = y; | |||
if (y > highY) | |||
highY = y; | |||
return [x, y]; | |||
}); | |||
blueprint.x = lowX; | |||
blueprint.y = lowY; | |||
blueprint.width = (highX - lowX); | |||
blueprint.height = (highY - lowY); | |||
} | |||
}; |
@@ -12,125 +12,133 @@ module.exports = { | |||
let oList = objects.objects; | |||
let oLen = oList.length; | |||
//OPTIMIZE: Store a list of all players | |||
let pList = oList.filter(f => f.player); | |||
let pLen = pList.length; | |||
if (pLen === 0) | |||
this.updateZoneEmpty(objects, oList, oLen); | |||
else if (pLen > 0) | |||
this.updateZoneNotEmpty(objects, oList, oLen, pList, pLen); | |||
oLen = oList.length; | |||
for (let i = 0; i < oList.length; i++) | |||
oList[i].syncer.reset(); | |||
}, | |||
updateZoneEmpty: function (objects, oList, oLen) { | |||
for (let i = 0; i < oLen; i++) { | |||
let o = oList[i]; | |||
if (!o.destroyed) | |||
continue; | |||
objects.removeObject(o); | |||
oLen--; | |||
i--; | |||
} | |||
}, | |||
updateZoneNotEmpty: function (objects, oList, oLen, pList, pLen) { | |||
let queueFunction = this.queue.bind(this, 'onGetObject'); | |||
let cache = {}; | |||
if (pLen === 0) { | |||
for (let i = 0; i < oLen; i++) { | |||
let o = oList[i]; | |||
if (!o.destroyed) | |||
continue; | |||
for (let i = 0; i < oLen; i++) { | |||
let o = oList[i]; | |||
let oId = o.id; | |||
let ox = o.x; | |||
let oy = o.y; | |||
if (!o.syncer) | |||
continue; | |||
let destroyed = o.destroyed; | |||
let sync = null; | |||
let syncSelf = null; | |||
if (!destroyed) { | |||
sync = o.syncer.get(); | |||
syncSelf = o.syncer.get(true); | |||
} else { | |||
sync = { | |||
id: o.id, | |||
destroyed: true | |||
}; | |||
objects.removeObject(o); | |||
oLen--; | |||
i--; | |||
} | |||
} else if (pLen > 0) { | |||
let queueFunction = this.queue.bind(this, 'onGetObject'); | |||
for (let i = 0; i < oLen; i++) { | |||
let o = oList[i]; | |||
let oId = o.id; | |||
let ox = o.x; | |||
let oy = o.y; | |||
if (!o.syncer) | |||
continue; | |||
let destroyed = o.destroyed; | |||
let sync = null; | |||
let syncSelf = null; | |||
if (!destroyed) { | |||
sync = o.syncer.get(); | |||
syncSelf = o.syncer.get(true); | |||
} else { | |||
sync = { | |||
id: o.id, | |||
destroyed: true | |||
}; | |||
objects.removeObject(o); | |||
oLen--; | |||
i--; | |||
} | |||
let toList = []; | |||
let completeList = []; | |||
let completeObj = null; | |||
let sendTo = false; | |||
let sendComplete = false; | |||
for (let j = 0; j < pLen; j++) { | |||
let p = pList[j]; | |||
let px = p.x; | |||
let py = p.y; | |||
let toList = []; | |||
let completeList = []; | |||
let completeObj = null; | |||
let canSee = (Math.abs(ox - px) <= 25 && Math.abs(oy - py) < 14); | |||
let sendTo = false; | |||
let sendComplete = false; | |||
let hasSeen = p.player.hasSeen(oId); | |||
for (let j = 0; j < pLen; j++) { | |||
let p = pList[j]; | |||
let px = p.x; | |||
let py = p.y; | |||
if (hasSeen) { | |||
if (canSee) { | |||
if (p.id === oId && syncSelf) | |||
queueFunction(syncSelf, [ p.serverId ]); | |||
let canSee = (Math.abs(ox - px) <= 25 && Math.abs(oy - py) < 14); | |||
if (sync) { | |||
toList.push(p.serverId); | |||
sendTo = true; | |||
} | |||
} | |||
let hasSeen = p.player.hasSeen(oId); | |||
if (destroyed || !canSee) { | |||
if (!canSee) | |||
queueFunction({ id: oId, destroyed: true }, [ p.serverId ]); | |||
if (hasSeen) { | |||
if (canSee) { | |||
if (p.id === oId && syncSelf) | |||
queueFunction(syncSelf, [ p.serverId ]); | |||
p.player.unsee(oId); | |||
} | |||
} else if (!destroyed && canSee) { | |||
let cached = null; | |||
if (p.id === oId) { | |||
let syncO = o.getSimple(true); | |||
syncO.self = true; | |||
queueFunction(syncO, [ p.serverId ]); | |||
p.player.see(oId); | |||
continue; | |||
} else { | |||
cached = cache[oId]; | |||
if (!cached) | |||
cached = cache[oId] = o.getSimple(); | |||
if (sync) { | |||
toList.push(p.serverId); | |||
sendTo = true; | |||
} | |||
} | |||
completeObj = cached; | |||
completeList.push(p.serverId); | |||
sendComplete = true; | |||
if (destroyed || !canSee) { | |||
if (!canSee) | |||
queueFunction({ id: oId, destroyed: true }, [ p.serverId ]); | |||
p.player.unsee(oId); | |||
} | |||
} else if (!destroyed && canSee) { | |||
let cached = null; | |||
if (p.id === oId) { | |||
let syncO = o.getSimple(true); | |||
syncO.self = true; | |||
queueFunction(syncO, [ p.serverId ]); | |||
p.player.see(oId); | |||
continue; | |||
} else { | |||
cached = cache[oId]; | |||
if (!cached) | |||
cached = cache[oId] = o.getSimple(); | |||
} | |||
} | |||
if (sendTo) | |||
queueFunction(sync, toList); | |||
if (sendComplete) | |||
queueFunction(completeObj, completeList); | |||
completeObj = cached; | |||
completeList.push(p.serverId); | |||
sendComplete = true; | |||
p.player.see(oId); | |||
} | |||
} | |||
if (sendTo) | |||
queueFunction(sync, toList); | |||
if (sendComplete) | |||
queueFunction(completeObj, completeList); | |||
} | |||
this.send(); | |||
for (let i = 0; i < oLen; i++) | |||
oList[i].syncer.reset(); | |||
}, | |||
queue: function (event, obj, to) { | |||
//Send to all players in zone? | |||
if (to === -1) { | |||
//OPTIMIZE: Store a list of all players | |||
let pList = this.objects.objects.filter(o => o.player); | |||
to = pList.map(p => p.serverId); | |||
} | |||
@@ -147,17 +155,16 @@ module.exports = { | |||
obj: obj | |||
}); | |||
}, | |||
send: function () { | |||
if (!this.dirty) | |||
return; | |||
this.dirty = false; | |||
let buffer = this.buffer; | |||
process.send({ | |||
method: 'events', | |||
data: buffer | |||
data: this.buffer | |||
}); | |||
this.buffer = {}; | |||
@@ -45,10 +45,6 @@ let onDbReady = function () { | |||
mods.init(onModsReady); | |||
setInterval(function () { | |||
global.gc(); | |||
}, 60000); | |||
process.on('uncaughtException', async function (e) { | |||
if (e.toString().indexOf('ERR_IPC_CHANNEL_CLOSED') > -1) | |||
return; | |||