@@ -15,6 +15,41 @@ define([ | |||
offsetY: 0, | |||
eventCallbacks: {}, | |||
width: scale, | |||
height: scale, | |||
isVisible: true, | |||
init: function (template) { | |||
const tplCpns = template.components || []; | |||
delete template.components; | |||
for (let p in template) { | |||
const value = template[p]; | |||
this[p] = value; | |||
} | |||
//We need to set visibility before components kick in as they sometimes need access to isVisible | |||
this.updateVisibility(); | |||
tplCpns.forEach(c => { | |||
//Map ids to objects | |||
let keys = Object.keys(c).filter(k => { | |||
return (k.indexOf('id') === 0 && k.length > 2); | |||
}); | |||
keys.forEach(k => { | |||
let value = c[k]; | |||
let newKey = k.substr(2, k.length).toLowerCase(); | |||
c[newKey] = this.objects.find(o => o.id === value); | |||
delete c[k]; | |||
}); | |||
this.addComponent(c.type, c); | |||
}); | |||
}, | |||
addComponent: function (type, options) { | |||
let c = this[type]; | |||
@@ -82,30 +117,7 @@ define([ | |||
}, | |||
setSpritePosition: function () { | |||
const { sprite, chatter, stats, x, y } = this; | |||
if (!sprite) | |||
return; | |||
renderer.setSpritePosition(this); | |||
['nameSprite', 'chatSprite'].forEach((s, i) => { | |||
const subSprite = this[s]; | |||
if (!subSprite) | |||
return; | |||
let yAdd = scale; | |||
if (i === 1) { | |||
yAdd *= -0.8; | |||
yAdd -= (chatter.msg.split('\r\n').length - 1) * scale * 0.8; | |||
} | |||
subSprite.x = (x * scale) + (scale / 2) - (subSprite.width / 2); | |||
subSprite.y = (y * scale) + yAdd; | |||
}); | |||
if (stats) | |||
stats.updateHpSprite(); | |||
}, | |||
updateVisibility: function () { | |||
@@ -0,0 +1,232 @@ | |||
define([ | |||
'js/components/components', | |||
'js/rendering/renderer', | |||
'js/system/events', | |||
'js/config' | |||
], function ( | |||
components, | |||
renderer, | |||
events, | |||
config | |||
) { | |||
return { | |||
components: [], | |||
offsetX: 0, | |||
offsetY: 0, | |||
eventCallbacks: {}, | |||
init: function (template) { | |||
const tplCpns = template.components || []; | |||
delete template.components; | |||
let syncTypes = ['portrait', 'area']; | |||
for (let p in template) { | |||
let value = template[p]; | |||
let type = typeof (value); | |||
if (type === 'object') { | |||
if (syncTypes.indexOf(p) > -1) | |||
this[p] = value; | |||
} else | |||
this[p] = value; | |||
} | |||
if (this.sheetName) | |||
this.sprite = renderer.buildObject(this); | |||
if (this.name && this.sprite) { | |||
this.nameSprite = renderer.buildText({ | |||
layerName: 'effects', | |||
text: this.name, | |||
x: (this.x * scale) + (scale / 2), | |||
y: (this.y * scale) + scale | |||
}); | |||
} | |||
//We need to set visibility before components kick in as they sometimes need access to isVisible | |||
this.updateVisibility(); | |||
tplCpns.forEach(c => { | |||
//Map ids to objects | |||
let keys = Object.keys(c).filter(k => { | |||
return (k.indexOf('id') === 0 && k.length > 2); | |||
}); | |||
keys.forEach(k => { | |||
let value = c[k]; | |||
let newKey = k.substr(2, k.length).toLowerCase(); | |||
c[newKey] = this.objects.find(o => o.id === value); | |||
delete c[k]; | |||
}); | |||
this.addComponent(c.type, c); | |||
}); | |||
}, | |||
addComponent: function (type, options) { | |||
let c = this[type]; | |||
if (!c || options.new) { | |||
const template = components.getTemplate(type); | |||
if (!template) | |||
return; | |||
c = $.extend(true, {}, template); | |||
c.obj = this; | |||
for (let o in options) | |||
c[o] = options[o]; | |||
//Only use component to initialize other components? | |||
if (c.init && c.init(options)) | |||
return null; | |||
this[c.type] = c; | |||
this.components.push(c); | |||
return c; | |||
} | |||
if (c.extend) | |||
c.extend(options); | |||
return c; | |||
}, | |||
removeComponent: function (type) { | |||
let cpn = this[type]; | |||
if (!cpn) | |||
return; | |||
this.components.spliceWhere(c => { | |||
return c === cpn; | |||
}); | |||
delete this[type]; | |||
}, | |||
update: function () { | |||
const oComponents = this.components; | |||
let len = oComponents.length; | |||
for (let i = 0; i < len; i++) { | |||
const c = oComponents[i]; | |||
if (c.update) | |||
c.update(); | |||
if (c.destroyed) { | |||
if (c.destroy) | |||
c.destroy(); | |||
oComponents.splice(i, 1); | |||
i--; | |||
len--; | |||
delete this[c.type]; | |||
} | |||
} | |||
}, | |||
on: function (eventName, callback) { | |||
let list = this.eventCallbacks[eventName] || (this.eventCallbacks[eventName] = []); | |||
list.push(events.on(eventName, callback)); | |||
}, | |||
setSpritePosition: function () { | |||
const { sprite, chatter, stats, x, y } = this; | |||
if (!sprite) | |||
return; | |||
renderer.setSpritePosition(this); | |||
['nameSprite', 'chatSprite'].forEach((s, i) => { | |||
const subSprite = this[s]; | |||
if (!subSprite) | |||
return; | |||
let yAdd = scale; | |||
if (i === 1) { | |||
yAdd *= -0.8; | |||
yAdd -= (chatter.msg.split('\r\n').length - 1) * scale * 0.8; | |||
} | |||
subSprite.x = (x * scale) + (scale / 2) - (subSprite.width / 2); | |||
subSprite.y = (y * scale) + yAdd; | |||
}); | |||
if (stats) | |||
stats.updateHpSprite(); | |||
}, | |||
updateVisibility: function () { | |||
const { x, y, hidden, isVisible } = this; | |||
const vis = ( | |||
!hidden && | |||
( | |||
this.self || | |||
( | |||
renderer.sprites[x] && | |||
renderer.sprites[x][y] && | |||
renderer.sprites[x][y].length > 0 && | |||
!renderer.isHidden(x, y) | |||
) | |||
) | |||
); | |||
if (vis === isVisible) | |||
return; | |||
this.isVisible = vis; | |||
this.setVisible(vis); | |||
}, | |||
setVisible: function (visible) { | |||
if (this.sprite) | |||
this.sprite.visible = visible; | |||
if (this.nameSprite) | |||
this.nameSprite.visible = (visible && config.showNames); | |||
if (!visible && this.stats && this.stats.hpSprite && this.stats.hpSprite.visible) { | |||
this.stats.hpSprite.visible = false; | |||
this.stats.hpSpriteInner.visible = false; | |||
} | |||
this.components.forEach(c => { | |||
if (c.setVisible) | |||
c.setVisible(visible); | |||
}); | |||
}, | |||
destroy: function () { | |||
if (this.sprite) | |||
renderer.destroyObject(this); | |||
if (this.nameSprite) { | |||
renderer.destroyObject({ | |||
layerName: 'effects', | |||
sprite: this.nameSprite | |||
}); | |||
} | |||
const oComponents = this.components; | |||
const cLen = oComponents.length; | |||
for (let i = 0; i < cLen; i++) { | |||
const c = oComponents[i]; | |||
if (c.destroy) | |||
c.destroy(); | |||
} | |||
this.destroyed = true; | |||
this.offEvents(); | |||
}, | |||
offEvents: function () { | |||
if (this.pather) | |||
this.pather.resetPath(); | |||
for (let e in this.eventCallbacks) | |||
this.eventCallbacks[e].forEach(c => events.off(e, c)); | |||
} | |||
}; | |||
}); |
@@ -1,4 +1,5 @@ | |||
define([ | |||
'js/objects/objBaseLegacy', | |||
'js/objects/objBase', | |||
'js/system/events', | |||
'js/rendering/renderer', | |||
@@ -6,6 +7,7 @@ define([ | |||
'js/config', | |||
'js/system/globals' | |||
], function ( | |||
objBaseLegacy, | |||
objBase, | |||
events, | |||
renderer, | |||
@@ -118,54 +120,12 @@ define([ | |||
}, | |||
buildObject: function (template) { | |||
let obj = $.extend(true, {}, objBase); | |||
const base = template.components?.some(c => c.type === 'sprite') ? objBase : objBaseLegacy; | |||
const obj = $.extend(true, {}, base); | |||
let components = template.components || []; | |||
delete template.components; | |||
let syncTypes = ['portrait', 'area']; | |||
for (let p in template) { | |||
let value = template[p]; | |||
let type = typeof (value); | |||
if (type === 'object') { | |||
if (syncTypes.indexOf(p) > -1) | |||
obj[p] = value; | |||
} else | |||
obj[p] = value; | |||
} | |||
if (obj.sheetName) | |||
obj.sprite = renderer.buildObject(obj); | |||
if (obj.name && obj.sprite) { | |||
obj.nameSprite = renderer.buildText({ | |||
layerName: 'effects', | |||
text: obj.name, | |||
x: (obj.x * scale) + (scale / 2), | |||
y: (obj.y * scale) + scale | |||
}); | |||
} | |||
obj.init(template); | |||
//We need to set visibility before components kick in as they sometimes need access to isVisible | |||
obj.updateVisibility(); | |||
components.forEach(c => { | |||
//Map ids to objects | |||
let keys = Object.keys(c).filter(k => { | |||
return (k.indexOf('id') === 0 && k.length > 2); | |||
}); | |||
keys.forEach(k => { | |||
let value = c[k]; | |||
let newKey = k.substr(2, k.length).toLowerCase(); | |||
c[newKey] = this.objects.find(o => o.id === value); | |||
delete c[k]; | |||
}); | |||
obj.addComponent(c.type, c); | |||
}); | |||
this.objects.push(obj); | |||
if (obj.self) { | |||
events.emit('onGetPlayer', obj); | |||
@@ -179,8 +139,6 @@ define([ | |||
}, true); | |||
} | |||
this.objects.push(obj); | |||
return obj; | |||
}, | |||
@@ -6,7 +6,12 @@ define([ | |||
return { | |||
type: 'sprite', | |||
sprite: null, | |||
alpha: 1, | |||
tint: undefined, | |||
layerName: undefined, | |||
sheetName: undefined, | |||
sprite: undefined, | |||
init: function (blueprint) { | |||
this.buildSprite(); | |||
@@ -30,17 +35,15 @@ define([ | |||
if (!sprite) | |||
return; | |||
[ | |||
'x', | |||
'y', | |||
'visible', | |||
'width', | |||
'height' | |||
].forEach(p => { | |||
const value = obj[p]; | |||
if (sprite[p] !== value) | |||
sprite[p] = value; | |||
Object.entries({ | |||
x: (obj.x * scale) + (obj.offsetX || 0), | |||
y: (obj.y * scale) + (obj.offsetY || 0), | |||
visible: obj.isVisible, | |||
width: obj.width, | |||
height: obj.height | |||
}).forEach(([k, v]) => { | |||
if (sprite[k] !== v && v !== undefined) | |||
sprite[k] = v; | |||
}); | |||
[ | |||
@@ -49,7 +52,7 @@ define([ | |||
].forEach(p => { | |||
const value = this[p]; | |||
if (sprite[p] !== value) | |||
if (sprite[p] !== value && value !== undefined) | |||
sprite[p] = value; | |||
}); | |||
}, | |||
@@ -0,0 +1,23 @@ | |||
module.exports = { | |||
type: 'sprite', | |||
sheetName: null, | |||
cell: null, | |||
layerName: 'mobs', | |||
init: function (blueprint) { | |||
this.sheetName = blueprint.sheetName; | |||
this.cell = blueprint.cell; | |||
}, | |||
simplify: function (self) { | |||
const { sheetName, cell, layerName } = this; | |||
return { | |||
type: 'sprite', | |||
sheetName, | |||
cell, | |||
layerName | |||
}; | |||
} | |||
}; |
@@ -226,24 +226,19 @@ module.exports = { | |||
deltaY = 1; | |||
} | |||
let components = [{ | |||
this.obj.syncer.setComponent(false, 'bumpAnimation', { | |||
type: 'bumpAnimation', | |||
deltaX: deltaX, | |||
deltaY: deltaY | |||
}]; | |||
deltaX, | |||
deltaY | |||
}); | |||
//During casting we only bump | |||
if ((target) && (this.animation)) { | |||
components.push({ | |||
if (target && this.animation) { | |||
this.obj.syncer.setComponent(false, 'animation', { | |||
type: 'animation', | |||
template: this.animation | |||
}); | |||
} | |||
this.obj.instance.syncer.queue('onGetObject', { | |||
id: this.obj.id, | |||
components: components | |||
}, -1); | |||
}, | |||
simplify: function (self) { | |||
@@ -75,11 +75,11 @@ const buildRegularObject = (mapModule, blueprint) => { | |||
const buildClientObject = (mapModule, blueprint) => { | |||
const { mapScale } = mapModule; | |||
const { cell } = blueprint; | |||
const { width, height, polyline } = blueprint; | |||
if ((cell.width) && (!cell.polyline)) { | |||
blueprint.width = cell.width / mapScale; | |||
blueprint.height = cell.height / mapScale; | |||
if (width && !polyline) { | |||
blueprint.width = width / mapScale; | |||
blueprint.height = height / mapScale; | |||
} | |||
const obj = objects.buildObjects([blueprint], true).getSimple(true); | |||
@@ -87,19 +87,15 @@ const buildClientObject = (mapModule, blueprint) => { | |||
}; | |||
//Builder | |||
const buildObject = (mapModule, layerName, cell) => { | |||
const buildObject = (mapModule, layerName, mapObj) => { | |||
const { mapScale } = mapModule; | |||
cell.properties = getObjectifiedProperties(cell.properties); | |||
cell.polyline = cell.polyline || cell.polygon; | |||
const x = cell.x / mapScale; | |||
const y = (cell.y / mapScale) - 1; | |||
const { gid, x, y, width, height, sheetName, cell, polyline, polygon, properties } = mapObj; | |||
const clientObj = (layerName === 'clientObjects'); | |||
const cellInfo = mapModule.getCellInfo(cell.gid, x, y, layerName); | |||
const cellInfo = mapModule.getCellInfo(gid, x, y, layerName); | |||
let name = (cell.name || ''); | |||
let name = (mapObj.name || ''); | |||
let objZoneName = name; | |||
if (name.indexOf('|') > -1) { | |||
const split = name.split('|'); | |||
@@ -108,17 +104,29 @@ const buildObject = (mapModule, layerName, cell) => { | |||
} | |||
const blueprint = { | |||
id: cell.properties.id, | |||
clientObj: clientObj, | |||
sheetName: cell.isDefined('sheetName') ? cell.sheetName : cellInfo.sheetName, | |||
cell: cell.isDefined('cell') ? cell.cell : cellInfo.cell - 1, | |||
x, | |||
y, | |||
sheetName: sheetName !== undefined ? sheetName : cellInfo.sheetName, | |||
cell: cell !== undefined ? cell : cellInfo.cell - 1, | |||
x: x / mapScale, | |||
y: (y / mapScale) - 1, | |||
name: name, | |||
properties: cell.properties || {}, | |||
layerName: layerName | |||
layerName: layerName, | |||
properties: getObjectifiedProperties(properties), | |||
polyline: polyline ?? polygon | |||
}; | |||
blueprint.id = blueprint.properties.id; | |||
if (blueprint.sheetName && blueprint.cell !== undefined) { | |||
blueprint.properties.cpnSprite = { | |||
cell: blueprint.cell, | |||
sheetName: blueprint.sheetName | |||
}; | |||
delete blueprint.sheetName; | |||
delete blueprint.cell; | |||
} | |||
if (objZoneName !== name) | |||
blueprint.objZoneName = objZoneName; | |||
@@ -134,13 +142,13 @@ const buildObject = (mapModule, layerName, cell) => { | |||
if ((blueprint.properties.cpnNotice) || (blueprint.properties.cpnLightPatch) || (layerName === 'rooms') || (layerName === 'hiddenRooms')) { | |||
blueprint.y++; | |||
blueprint.width = cell.width / mapScale; | |||
blueprint.height = cell.height / mapScale; | |||
} else if (cell.width === 24) | |||
blueprint.width = width / mapScale; | |||
blueprint.height = height / mapScale; | |||
} else if (width === 24) | |||
blueprint.x++; | |||
if (cell.polyline) | |||
mapObjects.polyline(mapModule.size, blueprint, cell, mapScale); | |||
if (polyline) | |||
mapObjects.polyline(mapModule.size, blueprint, mapObj, mapScale); | |||
if (layerName === 'rooms') | |||
buildRoom(mapModule, blueprint); | |||