Move to Renderer V2

This commit is contained in:
duckietm
2024-04-03 09:27:56 +02:00
parent 110c3ad393
commit b3134ce50b
4080 changed files with 115593 additions and 66375 deletions
@@ -0,0 +1,398 @@
import { IObjectVisualizationData, RoomObjectVariable, RoomObjectVisualizationType } from '@nitrots/api';
import { AnimationData, AnimationFrame, AnimationStateData } from '../data';
import { FurnitureAnimatedVisualizationData } from './FurnitureAnimatedVisualizationData';
import { FurnitureVisualization } from './FurnitureVisualization';
export class FurnitureAnimatedVisualization extends FurnitureVisualization
{
public static TYPE: string = RoomObjectVisualizationType.FURNITURE_ANIMATED;
public static DEFAULT_ANIMATION_ID: number = 0;
protected _state: number = -1;
protected _frameIncrease: number = 1;
private _animationData: AnimationStateData = new AnimationStateData();
private _animationScale: number = 0;
private _animationChangeTime: number = 0;
private _animatedLayerCount: number = 0;
private _directionChanged: boolean = false;
public initialize(data: IObjectVisualizationData): boolean
{
if(!(data instanceof FurnitureAnimatedVisualizationData)) return false;
return super.initialize(data);
}
public dispose(): void
{
super.dispose();
if(this._animationData)
{
this._animationData.dispose();
this._animationData = null;
}
}
protected get animatedLayerCount(): number
{
return this._animatedLayerCount;
}
public get animationId(): number
{
return this._animationData.animationId;
}
protected getAnimationId(animationData: AnimationStateData): number
{
if((this.animationId !== FurnitureAnimatedVisualization.DEFAULT_ANIMATION_ID) && this.data.hasAnimation(this._animationScale, this.animationId)) return this.animationId;
return FurnitureAnimatedVisualization.DEFAULT_ANIMATION_ID;
}
protected updateObject(scale: number, direction: number): boolean
{
if(super.updateObject(scale, direction))
{
const state = this.object.getState(0);
if(state !== this._state)
{
this.setAnimation(state);
this._state = state;
this._animationChangeTime = (this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_STATE_UPDATE_TIME) || 0);
}
return true;
}
return false;
}
protected updateModel(scale: number): boolean
{
if(super.updateModel(scale))
{
if(this.usesAnimationResetting())
{
const updateTime = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_STATE_UPDATE_TIME);
if(updateTime > this._animationChangeTime)
{
this._animationChangeTime = updateTime;
this.setAnimation(this._state);
}
}
const state = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_AUTOMATIC_STATE_INDEX);
if(!isNaN(state))
{
const animationId = this.data.getAnimationId(this._animationScale, state);
this.setAnimation(animationId);
}
return true;
}
return false;
}
private isPlayingTransition(animationData: AnimationStateData, animationId: number): boolean
{
if(!AnimationData.isTransitionFromAnimation(animationData.animationId) && !AnimationData.isTransitionToAnimation(animationData.animationId)) return false;
if(animationId !== animationData.animationAfterTransitionId) return false;
if(animationData.animationOver) return false;
return true;
}
private getCurrentState(animationData: AnimationStateData): number
{
const animationId = animationData.animationId;
if(!AnimationData.isTransitionFromAnimation(animationId) && !AnimationData.isTransitionToAnimation(animationId)) return animationId;
return animationData.animationAfterTransitionId;
}
protected setAnimation(animationId: number): void
{
if(!this.data) return;
this.setSubAnimation(this._animationData, animationId, (this._state >= 0));
}
protected setSubAnimation(animationData: AnimationStateData, animationId: number, _arg_3: boolean = true): boolean
{
const currentAnimation = animationData.animationId;
if(_arg_3)
{
if(this.isPlayingTransition(animationData, animationId)) return false;
const state = this.getCurrentState(animationData);
if(animationId !== state)
{
if(!this.data.isImmediateChange(this._animationScale, animationId, state))
{
let transition = AnimationData.getTransitionFromAnimationId(state);
if(this.data.hasAnimation(this._animationScale, transition))
{
animationData.animationAfterTransitionId = animationId;
animationId = transition;
}
else
{
transition = AnimationData.getTransitionToAnimationId(animationId);
if(this.data.hasAnimation(this._animationScale, transition))
{
animationData.animationAfterTransitionId = animationId;
animationId = transition;
}
}
}
}
else
{
if(AnimationData.isTransitionFromAnimation(animationData.animationId))
{
const transition = AnimationData.getTransitionToAnimationId(animationId);
if(this.data.hasAnimation(this._animationScale, transition))
{
animationData.animationAfterTransitionId = animationId;
animationId = transition;
}
}
else if(!AnimationData.isTransitionToAnimation(animationData.animationId))
{
if(this.usesAnimationResetting())
{
const transition = AnimationData.getTransitionFromAnimationId(state);
if(this.data.hasAnimation(this._animationScale, transition))
{
animationData.animationAfterTransitionId = animationId;
animationId = transition;
}
else
{
const transition = AnimationData.getTransitionToAnimationId(animationId);
if(this.data.hasAnimation(this._animationScale, transition))
{
animationData.animationAfterTransitionId = animationId;
animationId = transition;
}
}
}
}
}
}
if(currentAnimation !== animationId)
{
animationData.animationId = animationId;
return true;
}
return false;
}
protected getLastFramePlayed(layerId: number): boolean
{
return this._animationData.getLastFramePlayed(layerId);
}
protected resetAllAnimationFrames(): void
{
if(!this._animationData) return;
this._animationData.setLayerCount(this._animatedLayerCount);
}
protected updateAnimation(scale: number): number
{
if(!this.data) return 0;
if(scale !== this._animationScale)
{
this._animationScale = scale;
this._animatedLayerCount = this.data.getLayerCount(scale);
this.resetAllAnimationFrames();
}
const update = this.updateAnimations(scale);
this._directionChanged = false;
return update;
}
protected updateAnimations(scale: number): number
{
if(this._animationData.animationOver && !this._directionChanged) return 0;
const update = this.updateFramesForAnimation(this._animationData, scale);
if(this._animationData.animationOver)
{
if((AnimationData.isTransitionFromAnimation(this._animationData.animationId)) || (AnimationData.isTransitionToAnimation(this._animationData.animationId)))
{
this.setAnimation(this._animationData.animationAfterTransitionId);
this._animationData.animationOver = false;
}
}
return update;
}
protected updateFramesForAnimation(animationData: AnimationStateData, scale: number): number
{
if(animationData.animationOver && !this._directionChanged) return 0;
const animationId = this.getAnimationId(animationData);
let frameCount = animationData.frameCounter;
if(!frameCount) frameCount = this.data.getStartFrame(scale, animationId, this._direction);
frameCount += this.frameIncrease;
animationData.frameCounter = frameCount;
animationData.animationOver = true;
let animationPlayed = false;
let layerId = (this._animatedLayerCount - 1);
let update = 0;
let layerUpdate = (1 << (this._animatedLayerCount - 1));
while(layerId >= 0)
{
let sequenceId = 0;
animationPlayed = animationData.getAnimationPlayed(layerId);
if(!animationPlayed || this._directionChanged)
{
let lastFramePlayed = animationData.getLastFramePlayed(layerId);
let frame = animationData.getFrame(layerId);
if(frame)
{
if(frame.isLastFrame && (frame.remainingFrameRepeats <= this.frameIncrease))
{
lastFramePlayed = true;
}
}
if((this._directionChanged || !frame) || ((frame.remainingFrameRepeats >= 0) && ((frame.remainingFrameRepeats = (frame.remainingFrameRepeats - this.frameIncrease)) <= 0)))
{
sequenceId = AnimationFrame.SEQUENCE_NOT_DEFINED;
if(frame) sequenceId = frame.activeSequence;
if(sequenceId === AnimationFrame.SEQUENCE_NOT_DEFINED)
{
frame = this.data.getFrame(scale, animationId, this._direction, layerId, frameCount);
}
else
{
frame = this.data.getFrameFromSequence(scale, animationId, this._direction, layerId, sequenceId, (frame.activeSequenceOffset + frame.repeats), frameCount);
}
animationData.setFrame(layerId, frame);
update = (update | layerUpdate);
}
if(!frame || (frame.remainingFrameRepeats == AnimationFrame.FRAME_REPEAT_FOREVER))
{
lastFramePlayed = true;
animationPlayed = true;
}
else
{
animationData.animationOver = false;
}
animationData.setLastFramePlayed(layerId, lastFramePlayed);
animationData.setAnimationPlayed(layerId, animationPlayed);
}
layerUpdate = (layerUpdate >> 1);
layerId--;
}
return update;
}
protected getFrameNumber(scale: number, layerId: number): number
{
const currentFrame = this._animationData.getFrame(layerId);
if(!currentFrame) return super.getFrameNumber(scale, layerId);
return currentFrame.id;
}
protected getLayerXOffset(scale: number, direction: number, layerId: number): number
{
const offset = super.getLayerXOffset(scale, direction, layerId);
const currentFrame = this._animationData.getFrame(layerId);
if(!currentFrame) return offset;
return (offset + currentFrame.x);
}
protected getLayerYOffset(scale: number, direction: number, layerId: number): number
{
const offset = super.getLayerYOffset(scale, direction, layerId);
const currentFrame = this._animationData.getFrame(layerId);
if(!currentFrame) return offset;
return (offset + currentFrame.y);
}
protected usesAnimationResetting(): boolean
{
return false;
}
protected setDirection(direction: number): void
{
if(this._direction === direction) return;
super.setDirection(direction);
this._directionChanged = true;
}
protected get frameIncrease(): number
{
return this._frameIncrease;
}
protected get data(): FurnitureAnimatedVisualizationData
{
return this._data as FurnitureAnimatedVisualizationData;
}
}
@@ -0,0 +1,90 @@
import { AnimationFrame, AnimationSizeData, SizeData } from '../data';
import { FurnitureVisualizationData } from './FurnitureVisualizationData';
export class FurnitureAnimatedVisualizationData extends FurnitureVisualizationData
{
protected createSizeData(scale: number, layerCount: number, angle: number): SizeData
{
return new AnimationSizeData(layerCount, angle);
}
protected processVisualElement(sizeData: SizeData, key: string, data: any): boolean
{
if(!sizeData || !key || !data) return false;
switch(key)
{
case 'animations':
if(!(sizeData instanceof AnimationSizeData) || !sizeData.defineAnimations(data)) return false;
break;
default:
if(!super.processVisualElement(sizeData, key, data)) return false;
break;
}
return true;
}
public hasAnimation(scale: number, animationId: number): boolean
{
const size = this.getSizeData(scale) as AnimationSizeData;
if(!size) return null;
return size.hasAnimation(animationId);
}
public getAnimationCount(scale: number): number
{
const size = this.getSizeData(scale) as AnimationSizeData;
if(!size) return null;
return size.getAnimationCount();
}
public getAnimationId(scale: number, animationId: number): number
{
const size = this.getSizeData(scale) as AnimationSizeData;
if(!size) return null;
return size.getAnimationId(animationId);
}
public isImmediateChange(scale: number, animationId: number, _arg_3: number): boolean
{
const size = this.getSizeData(scale) as AnimationSizeData;
if(!size) return null;
return size.isImmediateChange(animationId, _arg_3);
}
public getStartFrame(scale: number, animationId: number, direction: number): number
{
const size = this.getSizeData(scale) as AnimationSizeData;
if(!size) return null;
return size.getStartFrame(animationId, direction);
}
public getFrame(scale: number, animationId: number, direction: number, layerId: number, frameCount: number): AnimationFrame
{
const size = this.getSizeData(scale) as AnimationSizeData;
if(!size) return null;
return size.getFrame(animationId, direction, layerId, frameCount);
}
public getFrameFromSequence(scale: number, animationId: number, direction: number, layerId: number, sequenceId: number, offset: number, frameCount: number): AnimationFrame
{
const size = this.getSizeData(scale) as AnimationSizeData;
if(!size) return null;
return size.getFrameFromSequence(animationId, direction, layerId, sequenceId, offset, frameCount);
}
}
@@ -0,0 +1,19 @@
import { FurnitureBrandedImageVisualization } from './FurnitureBrandedImageVisualization';
export class FurnitureBBVisualization extends FurnitureBrandedImageVisualization
{
protected getLayerXOffset(scale: number, direction: number, layerId: number): number
{
return super.getLayerXOffset(scale, direction, layerId) + this._offsetX;
}
protected getLayerYOffset(scale: number, direction: number, layerId: number): number
{
return super.getLayerYOffset(scale, direction, layerId) + this._offsetY;
}
protected getLayerZOffset(scale: number, direction: number, layerId: number): number
{
return super.getLayerZOffset(scale, direction, layerId) + this._offsetZ;
}
}
@@ -0,0 +1,89 @@
import { RoomObjectVariable } from '@nitrots/api';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureBadgeDisplayVisualization extends FurnitureAnimatedVisualization
{
private static BADGE: string = 'BADGE';
private _badgeId: string = '';
private _badgeAssetNameNormalScale: string = '';
private _badgeAssetNameSmallScale: string = '';
private _badgeVisibleInState: number = -1;
protected updateModel(scale: number): boolean
{
let updateModel = super.updateModel(scale);
const badgeStatus = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BADGE_IMAGE_STATUS);
const badgeId = this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_BADGE_ASSET_NAME);
if(badgeStatus === -1)
{
this._badgeAssetNameNormalScale = '';
this._badgeAssetNameSmallScale = '';
}
else if((badgeStatus === 1) && (badgeId !== this._badgeId))
{
this._badgeId = badgeId;
this._badgeAssetNameNormalScale = this._badgeId;
if(this._badgeAssetNameSmallScale === '') this._badgeAssetNameSmallScale = this._badgeAssetNameNormalScale + '_32';
const visibleInState = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BADGE_VISIBLE_IN_STATE);
if(!isNaN(visibleInState)) this._badgeVisibleInState = visibleInState;
updateModel = true;
}
return updateModel;
}
protected getSpriteAssetName(scale: number, layerId: number): string
{
const tag = this.getLayerTag(scale, this.direction, layerId);
if((tag !== FurnitureBadgeDisplayVisualization.BADGE) || ((this._badgeVisibleInState !== -1) && (this.object.getState(0) !== this._badgeVisibleInState))) return super.getSpriteAssetName(scale, layerId);
if(scale === 32) return this._badgeAssetNameSmallScale;
return this._badgeAssetNameNormalScale;
}
protected getLayerXOffset(scale: number, direction: number, layerId: number): number
{
let offset = super.getLayerXOffset(scale, direction, layerId);
if(this.getLayerTag(scale, direction, layerId) === FurnitureBadgeDisplayVisualization.BADGE)
{
const asset = this.getAsset(((scale === 32) ? this._badgeAssetNameSmallScale : this._badgeAssetNameNormalScale), layerId);
if(asset)
{
if(scale === 64) offset += ((40 - asset.width) / 2);
else offset += ((20 - asset.width) / 2);
}
}
return offset;
}
protected getLayerYOffset(scale: number, direction: number, layerId: number): number
{
let offset = super.getLayerYOffset(scale, direction, layerId);
if(this.getLayerTag(scale, direction, layerId) === FurnitureBadgeDisplayVisualization.BADGE)
{
const asset = this.getAsset(((scale === 32) ? this._badgeAssetNameSmallScale : this._badgeAssetNameNormalScale), layerId);
if(asset)
{
if(scale === 64) offset += ((40 - asset.height) / 2);
else offset += ((20 - asset.height) / 2);
}
}
return offset;
}
}
@@ -0,0 +1,62 @@
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureBottleVisualization extends FurnitureAnimatedVisualization
{
private static ANIMATION_ID_OFFSET_SLOW1: number = 20;
private static ANIMATION_ID_OFFSET_SLOW2: number = 9;
private static ANIMATION_ID_ROLL: number = -1;
private _stateQueue: number[];
private _running: boolean;
constructor()
{
super();
this._stateQueue = [];
this._running = false;
}
protected setAnimation(animationId: number): void
{
if(animationId === -1)
{
if(!this._running)
{
this._running = true;
this._stateQueue = [];
this._stateQueue.push(FurnitureBottleVisualization.ANIMATION_ID_ROLL);
return;
}
}
if((animationId >= 0) && (animationId <= 7))
{
if(this._running)
{
this._running = false;
this._stateQueue = [];
this._stateQueue.push(FurnitureBottleVisualization.ANIMATION_ID_OFFSET_SLOW1);
this._stateQueue.push(FurnitureBottleVisualization.ANIMATION_ID_OFFSET_SLOW2 + animationId);
this._stateQueue.push(animationId);
return;
}
super.setAnimation(animationId);
}
}
protected updateAnimation(scale: number): number
{
if(this.getLastFramePlayed(0))
{
if(this._stateQueue.length) super.setAnimation(this._stateQueue.shift());
}
return super.updateAnimation(scale);
}
}
@@ -0,0 +1,210 @@
import { RoomObjectVariable } from '@nitrots/api';
import { GetAssetManager } from '@nitrots/assets';
import { Texture } from 'pixi.js';
import { FurnitureVisualization } from './FurnitureVisualization';
export class FurnitureBrandedImageVisualization extends FurnitureVisualization
{
protected static BRANDED_IMAGE: string = 'branded_image';
protected static STATE_0: number = 0;
protected static STATE_1: number = 1;
protected static STATE_2: number = 2;
protected static STATE_3: number = 3;
protected _imageUrl: string;
protected _shortUrl: string;
protected _imageReady: boolean;
protected _offsetX: number;
protected _offsetY: number;
protected _offsetZ: number;
protected _currentFrame: number;
protected _totalFrames: number;
constructor()
{
super();
this._imageUrl = null;
this._shortUrl = null;
this._imageReady = false;
this._offsetX = 0;
this._offsetY = 0;
this._offsetZ = 0;
this._currentFrame = -1;
this._totalFrames = -1;
}
public dispose(): void
{
super.dispose();
if(this._imageUrl)
{
(this.asset && this.asset.disposeAsset(this._imageUrl));
// dispose all
}
}
protected updateObject(scale: number, direction: number): boolean
{
if(!super.updateObject(scale, direction)) return false;
if(this._imageReady) this.checkAndCreateImageForCurrentState();
return true;
}
protected updateModel(scale: number): boolean
{
const flag = super.updateModel(scale);
if(flag)
{
this._offsetX = (this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BRANDING_OFFSET_X) || 0);
this._offsetY = (this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BRANDING_OFFSET_Y) || 0);
this._offsetZ = (this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BRANDING_OFFSET_Z) || 0);
}
if(!this._imageReady)
{
this._imageReady = this.checkIfImageReady();
if(this._imageReady)
{
this.checkAndCreateImageForCurrentState();
return true;
}
}
else
{
if(this.checkIfImageChanged())
{
this._imageReady = false;
this._imageUrl = null;
return true;
}
}
return flag;
}
private checkIfImageChanged(): boolean
{
const imageUrl = this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_BRANDING_IMAGE_URL);
if(imageUrl && (imageUrl === this._imageUrl)) return false;
(this.asset && this.asset.disposeAsset(this._imageUrl));
return true;
}
protected checkIfImageReady(): boolean
{
const model = this.object && this.object.model;
if(!model) return false;
const imageUrl = this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_BRANDING_IMAGE_URL);
if(!imageUrl) return false;
if(this._imageUrl && (this._imageUrl === imageUrl)) return false;
const imageStatus = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_BRANDING_IMAGE_STATUS);
if(imageStatus === 1)
{
let texture: Texture = null;
texture = GetAssetManager().getTexture(imageUrl);
if(!texture) return false;
this.imageReady(texture, imageUrl);
return true;
}
return false;
}
protected imageReady(texture: Texture, imageUrl: string): void
{
if(!texture)
{
this._imageUrl = null;
return;
}
this._imageUrl = imageUrl;
}
protected checkAndCreateImageForCurrentState(): void
{
if(!this._imageUrl) return;
const texture = GetAssetManager().getTexture(this._imageUrl);
if(!texture) return;
const state = this.object.getState(0);
this.addBackgroundAsset(texture, state, 0);
}
protected addBackgroundAsset(texture: Texture, state: number, frame: number): void
{
let x = 0;
let y = 0;
let flipH = false;
let flipV = false;
switch(state)
{
case FurnitureBrandedImageVisualization.STATE_0:
x = 0;
y = 0;
flipH = false;
flipV = false;
break;
case FurnitureBrandedImageVisualization.STATE_1:
x = -(texture.width);
y = 0;
flipH = true;
flipV = false;
break;
case FurnitureBrandedImageVisualization.STATE_2:
x = -(texture.width);
y = -(texture.height);
flipH = true;
flipV = true;
break;
case FurnitureBrandedImageVisualization.STATE_3:
x = 0;
y = -(texture.height);
flipH = false;
flipV = true;
break;
}
this.asset.addAsset(`${this._imageUrl}_${frame}`, texture, true, x, y, flipH, flipV);
}
protected getSpriteAssetName(scale: number, layerId: number): string
{
const tag = this.getLayerTag(scale, this._direction, layerId);
if((tag === FurnitureBrandedImageVisualization.BRANDED_IMAGE) && this._imageUrl)
{
return `${this._imageUrl}_${this.getFrameNumber(scale, layerId)}`;
}
return super.getSpriteAssetName(scale, layerId);
}
}
@@ -0,0 +1,6 @@
import { FurnitureVisualization } from './FurnitureVisualization';
export class FurnitureBuilderPlaceholderVisualization extends FurnitureVisualization
{
}
@@ -0,0 +1,29 @@
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureCounterClockVisualization extends FurnitureAnimatedVisualization
{
private static SECONDS_SPRITE: string = 'seconds_sprite';
private static TEN_SECONDS_SPRITE: string = 'ten_seconds_sprite';
private static MINUTES_SPRITE: string = 'minutes_sprite';
private static TEN_MINUTES_SPRITE: string = 'ten_minutes_sprite';
protected getFrameNumber(scale: number, layerId: number): number
{
const tag = this.getLayerTag(scale, this.direction, layerId);
const animation = this.object.getState(0);
switch(tag)
{
case FurnitureCounterClockVisualization.SECONDS_SPRITE: return Math.floor((animation % 60) % 10);
case FurnitureCounterClockVisualization.TEN_SECONDS_SPRITE: return Math.floor((animation % 60) / 10);
case FurnitureCounterClockVisualization.MINUTES_SPRITE: return Math.floor((animation / 60) % 10);
case FurnitureCounterClockVisualization.TEN_MINUTES_SPRITE: return Math.floor(((animation / 60) / 10) % 10);
default: return super.getFrameNumber(scale, layerId);
}
}
public get animationId(): number
{
return 0;
}
}
@@ -0,0 +1,6 @@
import { RoomObjectSpriteVisualization } from '../RoomObjectSpriteVisualization';
export class FurnitureCuboidVisualization extends RoomObjectSpriteVisualization
{
}
@@ -0,0 +1,56 @@
import { Texture } from 'pixi.js';
import { IsometricImageFurniVisualization } from './IsometricImageFurniVisualization';
export class FurnitureDynamicThumbnailVisualization extends IsometricImageFurniVisualization
{
private _cachedUrl: string;
constructor()
{
super();
this._cachedUrl = null;
this._hasOutline = true;
}
protected updateModel(scale: number): boolean
{
if(this.object)
{
const thumbnailUrl = this.getThumbnailURL();
if(this._cachedUrl !== thumbnailUrl)
{
this._cachedUrl = thumbnailUrl;
if(this._cachedUrl && (this._cachedUrl !== ''))
{
const image = new Image();
image.src = thumbnailUrl;
image.crossOrigin = '*';
image.onload = () =>
{
const texture = Texture.from(image);
texture.source.scaleMode = 'linear';
this.setThumbnailImages(texture);
};
}
else
{
this.setThumbnailImages(null);
}
}
}
return super.updateModel(scale);
}
protected getThumbnailURL(): string
{
throw (new Error('This method must be overridden!'));
}
}
@@ -0,0 +1,51 @@
import { RoomObjectVariable } from '@nitrots/api';
import { FurnitureDynamicThumbnailVisualization } from './FurnitureDynamicThumbnailVisualization';
export class FurnitureExternalImageVisualization extends FurnitureDynamicThumbnailVisualization
{
private _url: string;
private _typePrefix: string;
constructor()
{
super();
this._url = null;
this._typePrefix = null;
}
protected getThumbnailURL(): string
{
if(!this.object) return null;
if(this._url) return this._url;
const jsonString = this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_DATA);
if(!jsonString || jsonString === '') return null;
if(this.object.type.indexOf('') >= 0)
{
this._typePrefix = (this.object.type.indexOf('') >= 0) ? '' : 'postcards/selfie/';
}
const json = JSON.parse(jsonString);
let url = (json.w || '');
url = this.buildThumbnailUrl(url);
this._url = url;
return this._url;
}
private buildThumbnailUrl(url: string): string
{
url = url.replace('.png', '_small.png');
if(url.indexOf('.png') === -1) url = (url + '_small.png');
return url;
}
}
@@ -0,0 +1,110 @@
import { IAdvancedMap, IParticleSystem, RoomObjectVariable } from '@nitrots/api';
import { AdvancedMap, NitroLogger } from '@nitrots/utils';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
import { FurnitureParticleSystem } from './FurnitureParticleSystem';
export class FurnitureFireworksVisualization extends FurnitureAnimatedVisualization
{
private _particleSystems: IAdvancedMap<number, FurnitureParticleSystem>;
private _currentParticleSystem: FurnitureParticleSystem;
public dispose(): void
{
super.dispose();
this._currentParticleSystem = null;
if(this._particleSystems)
{
for(const particleSystem of this._particleSystems.getValues()) particleSystem.dispose();
this._particleSystems = null;
}
}
protected updateObject(scale: number, direction: number): boolean
{
if(super.updateObject(scale, direction))
{
if(!this._particleSystems)
{
this.readDefinition();
if(this._particleSystems) this._currentParticleSystem = this._particleSystems.getValue(scale);
else NitroLogger.log('ERROR Particle systems could not be read!', this.object.type);
}
else
{
if((scale !== this._scale) || (this._particleSystems.getValue(scale) !== this._currentParticleSystem))
{
const particleSystem = this._particleSystems.getValue(scale);
particleSystem.copyStateFrom(this._currentParticleSystem);
if(this._currentParticleSystem) this._currentParticleSystem.reset();
this._currentParticleSystem = particleSystem;
}
}
return true;
}
return false;
}
protected updateSprites(scale: number, update: boolean, animation: number): void
{
super.updateSprites(scale, update, animation);
if(this._currentParticleSystem) this._currentParticleSystem.updateSprites();
}
protected updateAnimation(scale: number): number
{
if(this._currentParticleSystem) this._currentParticleSystem.updateAnimation();
return super.updateAnimation(scale);
}
protected setAnimation(id: number): void
{
if(this._currentParticleSystem) this._currentParticleSystem.setAnimation(id);
super.setAnimation(id);
}
protected getLayerYOffset(scale: number, direction: number, layerId: number): number
{
if(this._currentParticleSystem && this._currentParticleSystem.controlsSprite(layerId))
{
return this._currentParticleSystem.getLayerYOffset(scale, direction, layerId);
}
return super.getLayerYOffset(scale, direction, layerId);
}
private readDefinition(): boolean
{
if(!this.object || !this.object.model) return false;
const fireworksData = this.object.model.getValue<IParticleSystem[]>(RoomObjectVariable.FURNITURE_FIREWORKS_DATA);
if(!fireworksData || !fireworksData.length) return false;
this._particleSystems = new AdvancedMap();
for(const particleData of fireworksData)
{
const size = particleData.size;
const particleSystem = new FurnitureParticleSystem(this);
particleSystem.parseData(particleData);
this._particleSystems.add(size, particleSystem);
}
return true;
}
}
@@ -0,0 +1,78 @@
import { IRoomGeometry, RoomObjectVariable } from '@nitrots/api';
import { FurnitureFireworksVisualization } from './FurnitureFireworksVisualization';
export class FurnitureGiftWrappedFireworksVisualization extends FurnitureFireworksVisualization
{
private static PRESENT_DEFAULT_STATE: number = 0;
private static MAX_PACKET_TYPE_VALUE: number = 9;
private static MAX_RIBBON_TYPE_VALUE: number = 11;
private _packetType: number = 0;
private _ribbonType: number = 0;
private _lastAnimationId: number = 0;
public update(geometry: IRoomGeometry, time: number, update: boolean, skipUpdate: boolean)
{
this.updatePresentWrap();
super.update(geometry, time, update, skipUpdate);
}
private updatePresentWrap(): void
{
if(!this.object) return;
const local3 = 1000;
const extras = this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_EXTRAS);
const typeIndex = parseInt(extras);
const packetType = Math.floor((typeIndex / local3));
const ribbonType = (typeIndex % local3);
this._packetType = ((packetType > FurnitureGiftWrappedFireworksVisualization.MAX_PACKET_TYPE_VALUE) ? 0 : packetType);
this._ribbonType = ((ribbonType > FurnitureGiftWrappedFireworksVisualization.MAX_RIBBON_TYPE_VALUE) ? 0 : ribbonType);
}
public getFrameNumber(scale: number, layerId: number): number
{
if(this._lastAnimationId === FurnitureGiftWrappedFireworksVisualization.PRESENT_DEFAULT_STATE)
{
if(layerId <= 1) return this._packetType;
if(layerId === 2) return this._ribbonType;
}
return super.getFrameNumber(scale, layerId);
}
public getSpriteAssetName(scale: number, layerId: number): string
{
const size = this.getValidSize(scale);
let assetName = this._type;
let layerCode = '';
if(layerId < (this.spriteCount - 1))
{
layerCode = String.fromCharCode(('a'.charCodeAt(0) + layerId));
}
else
{
layerCode = 'sd';
}
const frameNumber = this.getFrameNumber(scale, layerId);
assetName = (assetName + ((((('_' + size) + '_') + layerCode) + '_') + this.direction));
assetName = (assetName + ('_' + frameNumber));
return assetName;
}
protected setAnimation(animationId: number): void
{
this._lastAnimationId = animationId;
super.setAnimation(animationId);
}
}
@@ -0,0 +1,60 @@
import { IRoomGeometry, RoomObjectVariable } from '@nitrots/api';
import { FurnitureVisualization } from './FurnitureVisualization';
export class FurnitureGiftWrappedVisualization extends FurnitureVisualization
{
private _packetType: number = 0;
private _ribbonType: number = 0;
public update(geometry: IRoomGeometry, time: number, update: boolean, skipUpdate: boolean): void
{
this.updatePresentWrap();
super.update(geometry, time, update, skipUpdate);
}
private updatePresentWrap(): void
{
if(!this.object) return;
const extras = this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_EXTRAS);
const local3 = 1000;
const typeIndex = parseInt(extras);
this._packetType = Math.floor((typeIndex / local3));
this._ribbonType = (typeIndex % local3);
}
public getFrameNumber(scale: number, layerId: number): number
{
if(layerId <= 1) return this._packetType;
return this._ribbonType;
}
public getSpriteAssetName(scale: number, layerId: number): string
{
const size = this.getValidSize(scale);
let assetName = this._type;
let layerCode = '';
if(layerId < (this.spriteCount - 1))
{
layerCode = String.fromCharCode(('a'.charCodeAt(0) + layerId));
}
else
{
layerCode = 'sd';
}
const frameNumber = this.getFrameNumber(scale, layerId);
assetName = (assetName + ((((('_' + size) + '_') + layerCode) + '_') + this.direction));
assetName = (assetName + ('_' + frameNumber));
return assetName;
}
}
@@ -0,0 +1,89 @@
import { IGraphicAsset, IRoomObjectSprite, RoomObjectVariable } from '@nitrots/api';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureGuildCustomizedVisualization extends FurnitureAnimatedVisualization
{
public static PRIMARY_COLOUR_SPRITE_TAG: string = 'COLOR1';
public static SECONDARY_COLOUR_SPRITE_TAG: string = 'COLOR2';
public static BADGE: string = 'BADGE';
public static DEFAULT_COLOR_1: number = 0xEEEEEE;
public static DEFAULT_COLOR_2: number = 0x4B4B4B;
private _color1: number;
private _color2: number;
private _badgeAssetNameNormalScale: string;
private _badgeAssetNameSmallScale: string;
constructor()
{
super();
this._color1 = FurnitureGuildCustomizedVisualization.DEFAULT_COLOR_1;
this._color2 = FurnitureGuildCustomizedVisualization.DEFAULT_COLOR_2;
this._badgeAssetNameNormalScale = '';
this._badgeAssetNameSmallScale = '';
}
protected updateModel(scale: number): boolean
{
const flag = super.updateModel(scale);
if(this._badgeAssetNameNormalScale === '')
{
const assetName = this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_GUILD_CUSTOMIZED_ASSET_NAME);
if(assetName)
{
this._badgeAssetNameNormalScale = assetName;
this._badgeAssetNameSmallScale = (this._badgeAssetNameNormalScale + '_32');
}
}
const color1 = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_GUILD_CUSTOMIZED_COLOR_1);
this._color1 = color1 ? color1 : FurnitureGuildCustomizedVisualization.DEFAULT_COLOR_1;
const color2 = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_GUILD_CUSTOMIZED_COLOR_2);
this._color2 = color2 ? color2 : FurnitureGuildCustomizedVisualization.DEFAULT_COLOR_2;
return flag;
}
protected getLayerColor(scale: number, layerId: number, colorId: number): number
{
const tag = this.getLayerTag(scale, this._direction, layerId);
switch(tag)
{
case FurnitureGuildCustomizedVisualization.PRIMARY_COLOUR_SPRITE_TAG: return this._color1;
case FurnitureGuildCustomizedVisualization.SECONDARY_COLOUR_SPRITE_TAG: return this._color2;
}
return super.getLayerColor(scale, layerId, colorId);
}
public getSpriteAssetName(scale: number, layerId: number): string
{
const tag = this.getLayerTag(scale, this._direction, layerId);
if(tag === FurnitureGuildCustomizedVisualization.BADGE)
{
if(scale === 32) return this._badgeAssetNameSmallScale;
return this._badgeAssetNameNormalScale;
}
return super.getSpriteAssetName(scale, layerId);
}
protected getLibraryAssetNameForSprite(asset: IGraphicAsset, sprite: IRoomObjectSprite): string
{
if(sprite.tag === FurnitureGuildCustomizedVisualization.BADGE)
{
return '%group.badge.url%' + sprite.libraryAssetName.replace('badge_', '');
}
return super.getLibraryAssetNameForSprite(asset, sprite);
}
}
@@ -0,0 +1,144 @@
import { IGraphicAsset, IRoomObjectSprite, RoomObjectVariable } from '@nitrots/api';
import { TextureUtils } from '@nitrots/utils';
import { Matrix, Sprite, Texture } from 'pixi.js';
import { IsometricImageFurniVisualization } from './IsometricImageFurniVisualization';
export class FurnitureGuildIsometricBadgeVisualization extends IsometricImageFurniVisualization
{
public static PRIMARY_COLOUR_SPRITE_TAG: string = 'COLOR1';
public static SECONDARY_COLOUR_SPRITE_TAG: string = 'COLOR2';
public static DEFAULT_COLOR_1: number = 0xEEEEEE;
public static DEFAULT_COLOR_2: number = 0x4B4B4B;
private _color1: number;
private _color2: number;
protected updateModel(scale: number): boolean
{
const flag = super.updateModel(scale);
if(!this.hasThumbnailImage)
{
const assetName = this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_GUILD_CUSTOMIZED_ASSET_NAME);
if(assetName && assetName.length) this.setThumbnailImages(this.getBitmapAsset(assetName));
}
const color1 = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_GUILD_CUSTOMIZED_COLOR_1);
this._color1 = color1 ? color1 : FurnitureGuildIsometricBadgeVisualization.DEFAULT_COLOR_1;
const color2 = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_GUILD_CUSTOMIZED_COLOR_2);
this._color2 = color2 ? color2 : FurnitureGuildIsometricBadgeVisualization.DEFAULT_COLOR_2;
return flag;
}
protected generateTransformedThumbnail(texture: Texture, asset: IGraphicAsset): Texture
{
const scale = 1.1;
const matrix = new Matrix();
const difference = (asset.width / texture.width);
switch(this.direction)
{
case 2:
matrix.a = difference;
matrix.b = (-0.5 * difference);
matrix.c = 0;
matrix.d = (difference * scale);
matrix.tx = 0;
matrix.ty = ((0.5 * difference) * texture.width);
break;
case 0:
case 4:
matrix.a = difference;
matrix.b = (0.5 * difference);
matrix.c = 0;
matrix.d = (difference * scale);
matrix.tx = 0;
matrix.ty = 0;
break;
default:
matrix.a = difference;
matrix.b = 0;
matrix.c = 0;
matrix.d = difference;
matrix.tx = 0;
matrix.ty = 0;
}
const sprite = new Sprite(texture);
sprite.setFromMatrix(matrix);
sprite.position.set(0);
return TextureUtils.generateTexture(sprite);
/* const renderTexture = RenderTexture.create({
width: asset.width,
height: asset.height
});
PixiApplicationProxy.instance.renderer.render(sprite, {
renderTexture,
clear: true,
});
return renderTexture; */
/* const sprite = new NitroSprite(texture);
const renderTexture = RenderTexture.create({
width: (asset.width + matrix.tx),
height: (asset.height + matrix.ty)
});
sprite.position.set(0)
PixiApplicationProxy.instance.renderer.render(sprite, {
renderTexture,
clear: true,
transform: matrix
});
return renderTexture; */
}
protected getLayerColor(scale: number, layerId: number, colorId: number): number
{
const tag = this.getLayerTag(scale, this._direction, layerId);
switch(tag)
{
case FurnitureGuildIsometricBadgeVisualization.PRIMARY_COLOUR_SPRITE_TAG: return this._color1;
case FurnitureGuildIsometricBadgeVisualization.SECONDARY_COLOUR_SPRITE_TAG: return this._color2;
}
return super.getLayerColor(scale, layerId, colorId);
}
protected getLibraryAssetNameForSprite(asset: IGraphicAsset, sprite: IRoomObjectSprite): string
{
if(sprite.tag === FurnitureGuildIsometricBadgeVisualization.THUMBNAIL)
{
if(this.object && this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_GUILD_CUSTOMIZED_ASSET_NAME))
{
return '%group.badge.url%' + this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_GUILD_CUSTOMIZED_ASSET_NAME);
}
}
return super.getLibraryAssetNameForSprite(asset, sprite);
}
private getBitmapAsset(name: string)
{
const asset = this.asset.getAsset(name);
if(!asset || !asset.texture) return null;
return asset.texture;
}
}
@@ -0,0 +1,64 @@
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureHabboWheelVisualization extends FurnitureAnimatedVisualization
{
private static ANIMATION_ID_OFFSET_SLOW1: number = 10;
private static ANIMATION_ID_OFFSET_SLOW2: number = 20;
private static ANIMATION_ID_START_ROLL: number = 31;
private static ANIMATION_ID_ROLL: number = 32;
private _stateQueue: number[];
private _running: boolean;
constructor()
{
super();
this._stateQueue = [];
this._running = false;
}
protected setAnimation(animationId: number): void
{
if(animationId === -1)
{
if(!this._running)
{
this._running = true;
this._stateQueue = [];
this._stateQueue.push(FurnitureHabboWheelVisualization.ANIMATION_ID_START_ROLL);
this._stateQueue.push(FurnitureHabboWheelVisualization.ANIMATION_ID_ROLL);
return;
}
}
if((animationId > 0) && (animationId <= FurnitureHabboWheelVisualization.ANIMATION_ID_OFFSET_SLOW1))
{
if(this._running)
{
this._running = false;
this._stateQueue = [];
this._stateQueue.push(FurnitureHabboWheelVisualization.ANIMATION_ID_OFFSET_SLOW1 + animationId);
this._stateQueue.push(FurnitureHabboWheelVisualization.ANIMATION_ID_OFFSET_SLOW2 + animationId);
this._stateQueue.push(animationId);
return;
}
super.setAnimation(animationId);
}
}
protected updateAnimation(scale: number): number
{
if(this.getLastFramePlayed(1) && this.getLastFramePlayed(2) && this.getLastFramePlayed(3))
{
if(this._stateQueue.length) super.setAnimation(this._stateQueue.shift());
}
return super.updateAnimation(scale);
}
}
@@ -0,0 +1,75 @@
import { IGraphicAsset } from '@nitrots/api';
import { GetAssetManager } from '@nitrots/assets';
import { TextureUtils } from '@nitrots/utils';
import { Matrix, Sprite, Texture } from 'pixi.js';
import { FurnitureBBVisualization } from './FurnitureBBVisualization';
import { FurnitureBrandedImageVisualization } from './FurnitureBrandedImageVisualization';
export class FurnitureIsometricBBVisualization extends FurnitureBBVisualization
{
private _needsTransform: boolean = true;
protected generateTransformedImage(texture: Texture, asset: IGraphicAsset): void
{
const scale = 1.1;
const matrix = new Matrix();
const difference = (asset.width / texture.width);
switch(this.direction)
{
case 2:
matrix.a = difference;
matrix.b = (-0.5 * difference);
matrix.c = 0;
matrix.d = (difference * scale);
matrix.tx = 0;
matrix.ty = ((0.5 * difference) * texture.width);
break;
case 0:
case 4:
matrix.a = difference;
matrix.b = (0.5 * difference);
matrix.c = 0;
matrix.d = (difference * scale);
matrix.tx = 0;
matrix.ty = 0;
break;
default:
matrix.a = difference;
matrix.b = 0;
matrix.c = 0;
matrix.d = difference;
matrix.tx = 0;
matrix.ty = 0;
}
const sprite = new Sprite(texture);
const newTexture = TextureUtils.createAndWriteRenderTexture((asset.width + matrix.tx), (asset.height + matrix.ty), sprite, matrix);
this.asset.disposeAsset(`${this._imageUrl}_0`);
this.asset.addAsset(`${this._imageUrl}_0`, newTexture, true, sprite.x, sprite.y, asset.flipH, asset.flipV);
this._needsTransform = false;
}
protected checkAndCreateImageForCurrentState(): void
{
super.checkAndCreateImageForCurrentState();
this._needsTransform = true;
}
protected getSpriteAssetName(scale: number, layerId: number): string
{
const tag = this.getLayerTag(scale, this._direction, layerId);
if((tag === FurnitureBrandedImageVisualization.BRANDED_IMAGE) && this._imageUrl)
{
if(this._needsTransform) this.generateTransformedImage(GetAssetManager().getTexture(this._imageUrl), this.getAsset(super.getSpriteAssetName(scale, layerId)));
return `${this._imageUrl}_${this.getFrameNumber(scale, layerId)}`;
}
return super.getSpriteAssetName(scale, layerId);
}
}
@@ -0,0 +1,143 @@
import { AvatarSetType, IAvatarImage, IAvatarImageListener, IGraphicAsset, IObjectVisualizationData, RoomObjectVariable } from '@nitrots/api';
import { Texture } from 'pixi.js';
import { FurnitureMannequinVisualizationData } from './FurnitureMannequinVisualizationData';
import { FurnitureVisualization } from './FurnitureVisualization';
export class FurnitureMannequinVisualization extends FurnitureVisualization implements IAvatarImageListener
{
private static AVATAR_IMAGE_SPRITE_TAG: string = 'avatar_image';
private _mannequinScale: number = -1;
private _figure: string = null;
private _gender: string = null;
private _avatarImage: IAvatarImage = null;
private _avatarWidth: number = 90;
private _avatarHeight: number = 130;
private _needsUpdate: boolean = false;
private _placeHolderFigure: string = 'hd-99999-99998';
private _disposed: boolean = false;
public initialize(data: IObjectVisualizationData): boolean
{
if(!(data instanceof FurnitureMannequinVisualizationData)) return false;
return super.initialize(data);
}
public dispose(): void
{
if(this._disposed) return;
this._disposed = true;
if(this._avatarImage)
{
this._avatarImage.dispose();
this._avatarImage = null;
}
super.dispose();
}
protected updateObject(scale: number, direction: number): boolean
{
const updateObject = super.updateObject(scale, direction);
if(updateObject)
{
if(this._mannequinScale !== scale)
{
this._mannequinScale = scale;
this.updateAvatar();
}
}
return updateObject;
}
protected updateModel(scale: number): boolean
{
let updateModel = super.updateModel(scale);
if(updateModel)
{
const figure = (this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_MANNEQUIN_FIGURE) || null);
if(figure)
{
this._figure = `${ figure }.${ this._placeHolderFigure }`;
this._gender = (this.object.model.getValue<string>(RoomObjectVariable.FURNITURE_MANNEQUIN_GENDER) || null);
this.updateAvatar();
}
}
updateModel = (updateModel || this._needsUpdate);
this._needsUpdate = false;
return updateModel;
}
private updateAvatar(): void
{
if(this._avatarImage)
{
this._avatarImage.dispose();
this._avatarImage = null;
}
this._avatarImage = this.data.createAvatarImage(this._figure, this._mannequinScale, this._gender, this);
}
public resetFigure(figure: string): void
{
this.updateAvatar();
this._needsUpdate = true;
}
protected getLayerXOffset(scale: number, direction: number, layerId: number): number
{
const tag = this.getLayerTag(scale, direction, layerId);
if((tag === FurnitureMannequinVisualization.AVATAR_IMAGE_SPRITE_TAG) && this._avatarImage) return (-(this._avatarWidth) / 3);
return super.getLayerXOffset(scale, direction, layerId);
}
protected getLayerYOffset(scale: number, direction: number, layerId: number): number
{
const tag = this.getLayerTag(scale, direction, layerId);
if((tag === FurnitureMannequinVisualization.AVATAR_IMAGE_SPRITE_TAG) && this._avatarImage) return (-(this._avatarHeight) / 3);
return super.getLayerYOffset(scale, direction, layerId);
}
public getTexture(scale: number, layerId: number, asset: IGraphicAsset): Texture
{
const tag = this.getLayerTag(scale, this.direction, layerId);
if((tag === FurnitureMannequinVisualization.AVATAR_IMAGE_SPRITE_TAG) && this._avatarImage)
{
this._avatarImage.setDirection(AvatarSetType.FULL, this.direction);
return this._avatarImage.processAsTexture(AvatarSetType.FULL, false);
}
return super.getTexture(scale, layerId, asset);
}
public get disposed(): boolean
{
return this._disposed;
}
protected get data(): FurnitureMannequinVisualizationData
{
return this._data as FurnitureMannequinVisualizationData;
}
}
@@ -0,0 +1,32 @@
import { IAvatarEffectListener, IAvatarImage, IAvatarImageListener } from '@nitrots/api';
import { AvatarVisualizationData } from '../avatar';
import { FurnitureVisualizationData } from './FurnitureVisualizationData';
export class FurnitureMannequinVisualizationData extends FurnitureVisualizationData
{
private _avatarData: AvatarVisualizationData;
constructor()
{
super();
this._avatarData = new AvatarVisualizationData();
}
public dispose(): void
{
super.dispose();
if(this._avatarData)
{
this._avatarData.dispose();
this._avatarData = null;
}
}
public createAvatarImage(figure: string, size: number, gender: string = null, avatarListener: IAvatarImageListener = null, effectListener: IAvatarEffectListener = null): IAvatarImage
{
return this._avatarData.createAvatarImage(figure, size, gender, avatarListener, effectListener);
}
}
@@ -0,0 +1,313 @@
import { IAdvancedMap, IGraphicAsset, IParticleSystem, IRoomObjectSprite } from '@nitrots/api';
import { AdvancedMap, TextureUtils, Vector3d } from '@nitrots/utils';
import { AlphaFilter, Graphics, Matrix, Point, Sprite, Texture } from 'pixi.js';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
import { FurnitureParticleSystemEmitter } from './FurnitureParticleSystemEmitter';
export class FurnitureParticleSystem
{
private _emitters: IAdvancedMap<number, FurnitureParticleSystemEmitter>;
private _visualization: FurnitureAnimatedVisualization;
private _size: number;
private _canvasId: number = -1;
private _offsetY: number;
private _currentEmitter: FurnitureParticleSystemEmitter;
private _canvasTexture: Texture;
private _roomSprite: IRoomObjectSprite;
private _hasIgnited: boolean = false;
private _centerX: number = 0;
private _centerY: number = 0;
private _scaleMultiplier: number = 1;
private _blackOverlay: Graphics;
private _blackOverlayAlphaTransform: AlphaFilter;
private _particleColorTransform: AlphaFilter;
private _identityMatrix: Matrix;
private _translationMatrix: Matrix;
private _blend: number = 1;
private _bgColor: number = 0xFF000000;
private _emptySprite: Sprite;
private _isDone: boolean = false;
constructor(visualization: FurnitureAnimatedVisualization)
{
this._emitters = new AdvancedMap();
this._visualization = visualization;
this._blackOverlayAlphaTransform = new AlphaFilter();
this._blackOverlayAlphaTransform.alpha = 1;
this._particleColorTransform = new AlphaFilter();
this._identityMatrix = new Matrix();
this._translationMatrix = new Matrix();
}
public dispose(): void
{
for(const emitter of this._emitters.getValues()) emitter.dispose();
this._emitters = null;
if(this._canvasTexture)
{
this._canvasTexture.destroy();
this._canvasTexture = null;
}
if(this._blackOverlay)
{
this._blackOverlay.destroy();
this._blackOverlay = null;
}
if(this._emptySprite)
{
this._emptySprite.destroy();
this._emptySprite = null;
}
this._blackOverlayAlphaTransform = null;
this._particleColorTransform = null;
this._identityMatrix = null;
this._translationMatrix = null;
}
public reset(): void
{
if(this._currentEmitter) this._currentEmitter.reset();
this._currentEmitter = null;
this._hasIgnited = false;
this._isDone = false;
this.updateCanvas();
}
public setAnimation(id: number): void
{
if(this._currentEmitter) this._currentEmitter.reset();
this._currentEmitter = this._emitters.getValue(id);
this._hasIgnited = false;
this._isDone = false;
this.updateCanvas();
}
private updateCanvas(): void
{
if(!this._currentEmitter || (this._canvasId === -1)) return;
this._roomSprite = this._visualization.getSprite(this._canvasId);
if(this._roomSprite && this._roomSprite.texture)
{
if((this._roomSprite.width <= 1) || (this._roomSprite.height <= 1)) return;
if(this._canvasTexture && ((this._canvasTexture.width !== this._roomSprite.width) || (this._canvasTexture.height !== this._roomSprite.height))) this._canvasTexture = null;
this.clearCanvas();
this._centerX = -(this._roomSprite.offsetX);
this._centerY = -(this._roomSprite.offsetY);
this._roomSprite.texture = this._canvasTexture;
}
}
public getLayerYOffset(scale: number, direction: number, layerId: number): number
{
if(this._currentEmitter && (this._currentEmitter.roomObjectSpriteId === layerId))
{
return this._currentEmitter.y * this._scaleMultiplier;
}
return 0;
}
public controlsSprite(k: number): boolean
{
if(this._currentEmitter) return this._currentEmitter.roomObjectSpriteId == k;
return false;
}
public updateSprites(): void
{
if(!this._currentEmitter || !this._roomSprite) return;
if(this._canvasTexture && (this._roomSprite.texture !== this._canvasTexture))
{
this._roomSprite.texture = this._canvasTexture;
}
if(this._hasIgnited)
{
if(this._currentEmitter.roomObjectSpriteId >= 0) this._visualization.getSprite(this._currentEmitter.roomObjectSpriteId).visible = false;
}
}
public updateAnimation(): void
{
if(!this._currentEmitter || !this._roomSprite || this._isDone) return;
const k = 10;
if(!this._hasIgnited && this._currentEmitter.hasIgnited) this._hasIgnited = true;
const offsetY = (this._offsetY * this._scaleMultiplier);
this._currentEmitter.update();
if(this._hasIgnited)
{
if(this._currentEmitter.roomObjectSpriteId >= 0)
{
this._visualization.getSprite(this._currentEmitter.roomObjectSpriteId).visible = false;
}
if(!this._canvasTexture) this.updateCanvas();
this.clearCanvas();
for(const particle of this._currentEmitter.particles)
{
const tx = (this._centerX + ((((particle.x - particle.z) * k) / 10) * this._scaleMultiplier));
const ty = ((this._centerY - offsetY) + ((((particle.y + ((particle.x + particle.z) / 2)) * k) / 10) * this._scaleMultiplier));
const asset = particle.getAsset();
if(asset && asset.texture)
{
if(particle.fade && (particle.alphaMultiplier < 1))
{
this._translationMatrix.identity();
this._translationMatrix.translate((tx + asset.offsetX), (ty + asset.offsetY));
const sprite = new Sprite(asset.texture);
this._particleColorTransform.alpha = particle.alphaMultiplier;
sprite.filters = [this._particleColorTransform];
TextureUtils.writeToTexture(sprite, this._canvasTexture, false, this._translationMatrix);
}
else
{
const point = new Point((tx + asset.offsetX), (ty + asset.offsetY));
const sprite = new Sprite(asset.texture);
sprite.x = point.x;
sprite.y = point.y;
TextureUtils.writeToTexture(sprite, this._canvasTexture, false);
}
}
else
{
const sprite = new Sprite(Texture.WHITE);
sprite.tint = 0xFFFFFF;
sprite.x = (tx - 1);
sprite.y = (ty - 1);
sprite.width = 2;
sprite.height = 2;
TextureUtils.writeToTexture(sprite, this._canvasTexture, false);
}
}
if(!this._currentEmitter.particles.length)
{
this._isDone = true;
return;
}
}
}
public parseData(particleSystem: IParticleSystem): void
{
this._size = particleSystem.size;
this._canvasId = ((particleSystem.canvasId !== undefined) ? particleSystem.canvasId : -1);
this._offsetY = ((particleSystem.offsetY !== undefined) ? particleSystem.offsetY : 10);
this._scaleMultiplier = (this._size / 64);
this._blend = ((particleSystem.blend !== undefined) ? particleSystem.blend : 1);
this._blend = Math.min(this._blend, 1);
this._blackOverlayAlphaTransform.alpha = this._blend;
const bgColor = ((particleSystem.bgColor !== undefined) ? particleSystem.bgColor : '0');
this._bgColor = (parseInt(bgColor, 16) || 0x000000);
if(!particleSystem.emitters || !particleSystem.emitters.length) return;
for(const emitter of particleSystem.emitters)
{
const emitterId = emitter.id;
const emitterName = emitter.name;
const emitterSpriteId = emitter.spriteId;
const particleEmitter = new FurnitureParticleSystemEmitter(emitterName, emitterSpriteId);
this._emitters.add(emitterId, particleEmitter);
const maxNumParticles = emitter.maxNumParticles;
const particlesPerFrame = emitter.particlesPerFrame;
const burstPulse = ((emitter.burstPulse !== undefined) ? emitter.burstPulse : 1);
const fuseTime = emitter.fuseTime;
const simulationForce = emitter.simulation.force;
const simulationDirection = emitter.simulation.direction;
const simulationGravity = emitter.simulation.gravity;
const simulationAirFriction = emitter.simulation.airFriction;
const simulationShape = emitter.simulation.shape;
const simulationEnergy = emitter.simulation.energy;
for(const particle of emitter.particles)
{
const lifeTime = particle.lifeTime;
const isEmitter = (particle.isEmitter || false);
const fade = (particle.fade || false);
const frames: IGraphicAsset[] = [];
for(const name of particle.frames) frames.push(this._visualization.asset.getAsset(name));
particleEmitter.configureParticle(lifeTime, isEmitter, frames, fade);
}
particleEmitter.setup(maxNumParticles, particlesPerFrame, simulationForce, new Vector3d(0, simulationDirection, 0), simulationGravity, simulationAirFriction, simulationShape, simulationEnergy, fuseTime, burstPulse);
}
}
public copyStateFrom(particleSystem: FurnitureParticleSystem): void
{
let emitterId = 0;
if(particleSystem._emitters && particleSystem._currentEmitter)
{
emitterId = particleSystem._emitters.getKey(particleSystem._emitters.getValues().indexOf(particleSystem._currentEmitter));
}
this.setAnimation(emitterId);
if(this._currentEmitter) this._currentEmitter.copyStateFrom(particleSystem._currentEmitter, (particleSystem._size / this._size));
this._canvasTexture = null;
}
private clearCanvas(): void
{
if(!this._emptySprite)
{
this._emptySprite = new Sprite(Texture.EMPTY);
this._emptySprite.alpha = 0;
}
if(!this._canvasTexture)
{
this._canvasTexture = TextureUtils.createRenderTexture(this._roomSprite.width, this._roomSprite.height);
}
else
{
TextureUtils.writeToTexture(this._emptySprite, this._canvasTexture, true);
}
}
}
@@ -0,0 +1,277 @@
import { IGraphicAsset, IVector3D } from '@nitrots/api';
import { Vector3d } from '@nitrots/utils';
import { ParticleSystemParticle } from '../data';
import { FurnitureParticleSystemParticle } from './FurnitureParticleSystemParticle';
export class FurnitureParticleSystemEmitter extends FurnitureParticleSystemParticle
{
public static CONE: string = 'cone';
public static PLANE: string = 'plane';
public static SPHERE: string = 'sphere';
private _name: string;
private _roomObjectSpriteId: number = -1;
private _force: number;
private _timeStep: number = 0.1;
private _gravity: number;
private _airFriction: number;
private _explosionShape: string;
private _particleConfigurations: ParticleSystemParticle[];
private _particles: FurnitureParticleSystemParticle[];
private _maxNumberOfParticles: number;
private _particlesPerFrame: number;
private _emittedParticles: number;
private _fuseTime: number = 10;
private _energy: number = 1;
private _hasIgnited: boolean = false;
private _burstPulse: number = 1;
private _emitterDirection: IVector3D;
constructor(name: string = '', spriteId: number = -1)
{
super();
this._particles = [];
this._name = name;
this._roomObjectSpriteId = spriteId;
this._particleConfigurations = [];
}
public dispose(): void
{
for(const k of this._particles) k.dispose();
this._particles = null;
this._particleConfigurations = null;
super.dispose();
}
public setup(maxNumOfParticles: number, particlesPerFrame: number, force: number, direction: IVector3D, gravity: number, airFriction: number, explosionShape: string, energy: number, fuseTime: number, burstPulse: number): void
{
this._maxNumberOfParticles = maxNumOfParticles;
this._particlesPerFrame = particlesPerFrame;
this._force = force;
this._emitterDirection = direction;
this._emitterDirection.normalize();
this._gravity = gravity;
this._airFriction = airFriction;
this._explosionShape = explosionShape;
this._fuseTime = fuseTime;
this._energy = energy;
this._burstPulse = burstPulse;
this.reset();
}
public reset(): void
{
for(const particle of this._particles) particle.dispose();
this._particles = [];
this._emittedParticles = 0;
this._hasIgnited = false;
this.init(0, 0, 0, this._emitterDirection, this._force, this._timeStep, this._fuseTime, true);
}
public copyStateFrom(emitter: FurnitureParticleSystemEmitter, scale: number): void
{
super.copy(emitter, scale);
this._force = emitter._force;
this._emitterDirection = emitter._emitterDirection;
this._gravity = emitter._gravity;
this._airFriction = emitter._airFriction;
this._explosionShape = emitter._explosionShape;
this._fuseTime = emitter._fuseTime;
this._energy = emitter._energy;
this._burstPulse = emitter._burstPulse;
this._timeStep = emitter._timeStep;
this._hasIgnited = emitter._hasIgnited;
}
public configureParticle(lifeTIme: number, isEmitter: boolean, frames: IGraphicAsset[], fade: boolean): void
{
const particle: ParticleSystemParticle = {};
particle.lifeTime = lifeTIme;
particle.isEmitter = isEmitter;
particle.frames = frames;
particle.fade = fade;
this._particleConfigurations.push(particle);
}
protected ignite(): void
{
this._hasIgnited = true;
if(this._emittedParticles < this._maxNumberOfParticles)
{
if(this.age > 1) this.releaseParticles(this, this.direction);
}
}
private releaseParticles(particle: FurnitureParticleSystemParticle, direction: IVector3D = null): void
{
if(!direction) direction = new Vector3d();
const newDirection = new Vector3d();
const randomParticle = this.getRandomParticleConfiguration();
let i = 0;
while(i < this._particlesPerFrame)
{
switch(this._explosionShape)
{
case FurnitureParticleSystemEmitter.CONE:
newDirection.x = ((this.randomBoolean(0.5)) ? Math.random() : -(Math.random()));
newDirection.y = -(Math.random() + 1);
newDirection.z = ((this.randomBoolean(0.5)) ? Math.random() : -(Math.random()));
break;
case FurnitureParticleSystemEmitter.PLANE:
newDirection.x = ((this.randomBoolean(0.5)) ? Math.random() : -(Math.random()));
newDirection.y = 0;
newDirection.z = ((this.randomBoolean(0.5)) ? Math.random() : -(Math.random()));
break;
case FurnitureParticleSystemEmitter.SPHERE:
newDirection.x = ((this.randomBoolean(0.5)) ? Math.random() : -(Math.random()));
newDirection.y = ((this.randomBoolean(0.5)) ? Math.random() : -(Math.random()));
newDirection.z = ((this.randomBoolean(0.5)) ? Math.random() : -(Math.random()));
break;
}
newDirection.normalize();
const newParticle = new FurnitureParticleSystemParticle();
let lifeTime = 0;
let isEmitter = false;
let fade = false;
let frames: IGraphicAsset[] = [];
if(randomParticle)
{
lifeTime = Math.floor(((Math.random() * randomParticle.lifeTime) + 10));
isEmitter = randomParticle.isEmitter;
frames = randomParticle.frames;
fade = randomParticle.fade;
}
else
{
lifeTime = Math.trunc(Math.floor(((Math.random() * 20) + 10)));
isEmitter = false;
frames = [];
}
newParticle.init(particle.x, particle.y, particle.z, newDirection, this._energy, this._timeStep, lifeTime, isEmitter, frames, fade);
this._particles.push(newParticle);
this._emittedParticles++;
i++;
}
}
private getRandomParticleConfiguration(): ParticleSystemParticle
{
const index: number = Math.trunc(Math.floor((Math.random() * this._particleConfigurations.length)));
return this._particleConfigurations[index];
}
public update(): void
{
super.update();
this.accumulateForces();
this.verlet();
this.satisfyConstraints();
if(!this.isAlive && (this._emittedParticles < this._maxNumberOfParticles))
{
if((this.age % this._burstPulse) === 0) this.releaseParticles(this, this.direction);
}
}
public verlet(): void
{
if(this.isAlive || (this._emittedParticles < this._maxNumberOfParticles))
{
const x = this.x;
const y = this.y;
const z = this.z;
this.x = (((2 - this._airFriction) * this.x) - ((1 - this._airFriction) * this.lastX));
this.y = ((((2 - this._airFriction) * this.y) - ((1 - this._airFriction) * this.lastY)) + ((this._gravity * this._timeStep) * this._timeStep));
this.z = (((2 - this._airFriction) * this.z) - ((1 - this._airFriction) * this.lastZ));
this.lastX = x;
this.lastY = y;
this.lastZ = z;
}
const particles: FurnitureParticleSystemParticle[] = [];
for(const particle of this._particles)
{
particle.update();
const x = particle.x;
const y = particle.y;
const z = particle.z;
particle.x = (((2 - this._airFriction) * particle.x) - ((1 - this._airFriction) * particle.lastX));
particle.y = ((((2 - this._airFriction) * particle.y) - ((1 - this._airFriction) * particle.lastY)) + ((this._gravity * this._timeStep) * this._timeStep));
particle.z = (((2 - this._airFriction) * particle.z) - ((1 - this._airFriction) * particle.lastZ));
particle.lastX = x;
particle.lastY = y;
particle.lastZ = z;
if((particle.y > 10) || !particle.isAlive) particles.push(particle);
}
for(const particle of particles)
{
if(particle.isEmitter)
{
//
}
this._particles.splice(this._particles.indexOf(particle), 1);
particle.dispose();
}
}
private satisfyConstraints(): void
{
}
private accumulateForces(): void
{
for(const k of this._particles)
{
//
}
}
public get particles(): FurnitureParticleSystemParticle[]
{
return this._particles;
}
public get hasIgnited(): boolean
{
return this._hasIgnited;
}
private randomBoolean(k: number): boolean
{
return Math.random() < k;
}
public get roomObjectSpriteId(): number
{
return this._roomObjectSpriteId;
}
}
@@ -0,0 +1,196 @@
import { IGraphicAsset, IVector3D } from '@nitrots/api';
import { Vector3d } from '@nitrots/utils';
export class FurnitureParticleSystemParticle
{
private _x: number;
private _y: number;
private _z: number;
private _lastX: number;
private _lastY: number;
private _lastZ: number;
private _hasMoved: boolean = false;
private _particleDirection: IVector3D;
private _age: number = 0;
private _lifeTime: number;
private _isEmitter: boolean = false;
private _fade: boolean = false;
private _fadeTime: number;
private _alphaMultiplier: number = 1;
private _frames: IGraphicAsset[];
public init(x: number, y: number, z: number, direction: IVector3D, energy: number, timeStep: number, lifeTime: number, isEmitter: boolean = false, frames: IGraphicAsset[] = null, fade: boolean = false): void
{
this._x = x;
this._y = y;
this._z = z;
this._particleDirection = new Vector3d(direction.x, direction.y, direction.z);
this._particleDirection.multiply(energy);
this._lastX = (this._x - (this._particleDirection.x * timeStep));
this._lastY = (this._y - (this._particleDirection.y * timeStep));
this._lastZ = (this._z - (this._particleDirection.z * timeStep));
this._age = 0;
this._hasMoved = false;
this._lifeTime = lifeTime;
this._isEmitter = isEmitter;
this._frames = frames;
this._fade = fade;
this._alphaMultiplier = 1;
this._fadeTime = (0.5 + (Math.random() * 0.5));
}
public dispose(): void
{
this._particleDirection = null;
}
public update(): void
{
this._age++;
if(this._age === this._lifeTime) this.ignite();
if(this._fade)
{
if((this._age / this._lifeTime) > this._fadeTime)
{
this._alphaMultiplier = ((this._lifeTime - this._age) / (this._lifeTime * (1 - this._fadeTime)));
}
}
}
public getAsset(): IGraphicAsset
{
if(((this._frames) && (this._frames.length > 0)))
{
return this._frames[(this._age % this._frames.length)];
}
return null;
}
protected ignite(): void
{
}
public get fade(): boolean
{
return this._fade;
}
public get alphaMultiplier(): number
{
return this._alphaMultiplier;
}
public get direction(): IVector3D
{
return this._particleDirection;
}
public get age(): number
{
return this._age;
}
public get isEmitter(): boolean
{
return this._isEmitter;
}
public get isAlive(): boolean
{
return this._age <= this._lifeTime;
}
public get x(): number
{
return this._x;
}
public set x(x: number)
{
this._x = x;
}
public get y(): number
{
return this._y;
}
public set y(y: number)
{
this._y = y;
}
public get z(): number
{
return this._z;
}
public set z(z: number)
{
this._z = z;
}
public get lastX(): number
{
return this._lastX;
}
public set lastX(y: number)
{
this._hasMoved = true;
this._lastX = y;
}
public get lastY(): number
{
return this._lastY;
}
public set lastY(k: number)
{
this._hasMoved = true;
this._lastY = k;
}
public get lastZ(): number
{
return this._lastZ;
}
public set lastZ(z: number)
{
this._hasMoved = true;
this._lastZ = z;
}
public get hasMoved(): boolean
{
return this._hasMoved;
}
public toString(): string
{
return [this._x, this._y, this._z].toString();
}
public copy(particle: FurnitureParticleSystemParticle, scale: number): void
{
this._x = (particle._x * scale);
this._y = (particle._y * scale);
this._z = (particle._z * scale);
this._lastX = (particle._lastX * scale);
this._lastY = (particle._lastY * scale);
this._lastZ = (particle._lastZ * scale);
this._hasMoved = particle.hasMoved;
this._particleDirection = particle._particleDirection;
this._age = particle._age;
this._lifeTime = particle._lifeTime;
this._isEmitter = particle._isEmitter;
this._fade = particle._fade;
this._fadeTime = particle._fadeTime;
this._alphaMultiplier = particle._alphaMultiplier;
}
}
@@ -0,0 +1,160 @@
import { Point } from 'pixi.js';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurniturePartyBeamerVisualization extends FurnitureAnimatedVisualization
{
private static UPDATE_INTERVAL: number = 2;
private static AREA_DIAMETER_SMALL: number = 15;
private static AREA_DIAMETER_LARGE: number = 31;
private static ANIM_SPEED_FAST: number = 2;
private static ANIM_SPEED_SLOW: number = 1;
private _animPhaseIndex: number[];
private _animDirectionIndex: number[];
private _animSpeedIndex: number[];
private _animFactorIndex: number[];
private _animOffsetIndex: Point[];
constructor()
{
super();
this._animOffsetIndex = [];
}
protected updateAnimation(scale: number): number
{
if(!this._animSpeedIndex) this.initItems(scale);
let sprite = this.getSprite(2);
if(sprite) this._animOffsetIndex[0] = this.getNewPoint(scale, 0);
sprite = this.getSprite(3);
if(sprite) this._animOffsetIndex[1] = this.getNewPoint(scale, 1);
return super.updateAnimation(scale);
}
private getNewPoint(scale: number, layerId: number): Point
{
let diameter = 0;
let animationPhase: number = this._animPhaseIndex[layerId];
let animationDirection: number = this._animDirectionIndex[layerId];
const animationSpeed: number = this._animSpeedIndex[layerId];
const animationFactor: number = this._animFactorIndex[layerId];
let _local_7 = 1;
if(scale == 32)
{
diameter = FurniturePartyBeamerVisualization.AREA_DIAMETER_SMALL;
_local_7 = 0.5;
}
else
{
diameter = FurniturePartyBeamerVisualization.AREA_DIAMETER_LARGE;
}
const _local_9: number = (animationPhase + (animationDirection * animationSpeed));
if(Math.abs(_local_9) >= diameter)
{
if(animationDirection > 0)
{
animationPhase = (animationPhase - (_local_9 - diameter));
}
else
{
animationPhase = (animationPhase + (-(diameter) - _local_9));
}
animationDirection = -(animationDirection);
this._animDirectionIndex[layerId] = animationDirection;
}
const _local_10: number = ((diameter - Math.abs(animationPhase)) * animationFactor);
let _local_11: number = ((animationDirection * Math.sin(Math.abs((animationPhase / 4)))) * _local_10);
if(animationDirection > 0)
{
_local_11 = (_local_11 - _local_10);
}
else
{
_local_11 = (_local_11 + _local_10);
}
animationPhase = (animationPhase + ((animationDirection * animationSpeed) * _local_7));
this._animPhaseIndex[layerId] = animationPhase;
if(Math.trunc(_local_11) == 0) this._animFactorIndex[layerId] = this.getRandomAmplitudeFactor();
return new Point(animationPhase, _local_11);
}
private initItems(scale: number): void
{
let diameter: number;
if(scale === 32)
{
diameter = FurniturePartyBeamerVisualization.AREA_DIAMETER_SMALL;
}
else
{
diameter = FurniturePartyBeamerVisualization.AREA_DIAMETER_LARGE;
}
this._animPhaseIndex = [];
this._animPhaseIndex.push(((Math.random() * diameter) * 1.5));
this._animPhaseIndex.push(((Math.random() * diameter) * 1.5));
this._animDirectionIndex = [];
this._animDirectionIndex.push(1);
this._animDirectionIndex.push(-1);
this._animSpeedIndex = [];
this._animSpeedIndex.push(FurniturePartyBeamerVisualization.ANIM_SPEED_FAST);
this._animSpeedIndex.push(FurniturePartyBeamerVisualization.ANIM_SPEED_SLOW);
this._animFactorIndex = [];
this._animFactorIndex.push(this.getRandomAmplitudeFactor());
this._animFactorIndex.push(this.getRandomAmplitudeFactor());
}
protected getLayerXOffset(scale: number, direction: number, layerId: number): number
{
if((layerId === 2) || (layerId === 3))
{
if(this._animOffsetIndex.length == 2)
{
return this._animOffsetIndex[(layerId - 2)].x;
}
}
return super.getLayerXOffset(scale, direction, layerId);
}
protected getLayerYOffset(scale: number, direction: number, layerId: number): number
{
if((layerId === 2) || (layerId === 3))
{
if(this._animOffsetIndex.length == 2)
{
return this._animOffsetIndex[(layerId - 2)].y;
}
}
return super.getLayerYOffset(scale, direction, layerId);
}
private getRandomAmplitudeFactor(): number
{
return ((Math.random() * 30) / 100) + 0.15;
}
}
@@ -0,0 +1,134 @@
import { IAssetLogicPlanetSystem, IVector3D, RoomObjectVariable } from '@nitrots/api';
import { Vector3d } from '@nitrots/utils';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
import { FurniturePlanetSystemVisualizationPlanetObject } from './FurniturePlanetSystemVisualizationPlanetObject';
export class FurniturePlanetSystemVisualization extends FurnitureAnimatedVisualization
{
private _planetIndex: FurniturePlanetSystemVisualizationPlanetObject[];
private _planetNameIndex: string[];
private _offsetArray: IVector3D[];
private _rootPosition: IVector3D;
constructor()
{
super();
this._offsetArray = [];
this._rootPosition = new Vector3d();
}
public dispose(): void
{
if(this._planetIndex)
{
while(this._planetIndex.length > 0)
{
const planet = this._planetIndex.shift();
planet.dispose();
}
}
this._planetIndex = null;
this._planetNameIndex = null;
}
protected updateAnimation(scale: number): number
{
if(!this._planetIndex && (this.spriteCount > 0))
{
if(!this.processPlanets()) return 0;
}
if(this._planetIndex)
{
for(const planet of this._planetIndex) planet.update(this._offsetArray, this._rootPosition, scale);
return super.updateAnimation(scale);
}
return 0;
}
protected getLayerXOffset(scale: number, direction: number, layerId: number): number
{
if(this._offsetArray[layerId])
{
return this._offsetArray[layerId].x;
}
return super.getLayerXOffset(scale, direction, layerId);
}
protected getLayerYOffset(scale: number, direction: number, layerId: number): number
{
if(this._offsetArray[layerId])
{
return this._offsetArray[layerId].y;
}
return super.getLayerYOffset(scale, direction, layerId);
}
protected getLayerZOffset(scale: number, direction: number, layerId: number): number
{
if(this._offsetArray[layerId])
{
return this._offsetArray[layerId].z;
}
return super.getLayerZOffset(scale, direction, layerId);
}
private processPlanets(): boolean
{
if(!this.object || !this.object.model) return;
const planetSystems = this.object.model.getValue<IAssetLogicPlanetSystem[]>(RoomObjectVariable.FURNITURE_PLANETSYSTEM_DATA);
if(!planetSystems) return false;
this._planetIndex = [];
this._planetNameIndex = [];
for(const planet of planetSystems)
{
const sprite = this.getSprite(planet.id);
if(sprite)
{
this.addPlanet(planet.name, planet.id, planet.parent, (planet.radius || 0), (planet.arcSpeed || 0), (planet.arcOffset || 0), (planet.height || 0));
}
}
return true;
}
private addPlanet(name: string, index: number, parentName: string, radius: number, arcSpeed: number, arcOffset: number, height: number): void
{
if(!this._planetIndex) return;
const planet = new FurniturePlanetSystemVisualizationPlanetObject(name, index, radius, arcSpeed, arcOffset, height);
const existingPlanet = this.getPlanet(parentName);
if(existingPlanet) existingPlanet.addChild(planet);
else
{
this._planetIndex.push(planet);
this._planetNameIndex.push(name);
}
}
private getPlanet(name: string): FurniturePlanetSystemVisualizationPlanetObject
{
for(const planet of this._planetIndex)
{
if(planet.name === name) return planet;
if(planet.hasChild(name)) return planet.getChild(name);
}
return null;
}
}
@@ -0,0 +1,92 @@
import { IVector3D } from '@nitrots/api';
import { Vector3d } from '@nitrots/utils';
export class FurniturePlanetSystemVisualizationPlanetObject
{
private static SYSTEM_TEMPO: number = 30;
private _name: string;
private _index: number;
private _radius: number;
private _arcSpeed: number;
private _arcOffset: number;
private _height: number;
private _position: number;
private _positionVector: IVector3D;
private _children: FurniturePlanetSystemVisualizationPlanetObject[];
constructor(name: string, index: number, radius: number, arcSpeed: number, arcOffset: number, height: number)
{
this._name = name;
this._index = index;
this._radius = radius;
this._arcSpeed = (((arcSpeed * Math.PI) * 2) / 360);
this._arcOffset = (((arcOffset * Math.PI) * 2) / 360);
this._height = height;
this._position = 0;
this._positionVector = new Vector3d(0, 0, 0);
this._children = [];
}
public dispose(): void
{
while(this._children.length > 0)
{
const child = this._children.shift();
child.dispose();
}
}
public update(offsets: IVector3D[], rootPosition: IVector3D, scale: number): void
{
this._position = (this._position + (this._arcSpeed / FurniturePlanetSystemVisualizationPlanetObject.SYSTEM_TEMPO));
offsets[this._index] = this.getPositionVector(rootPosition, scale);
for(const child of this._children) child.update(offsets, this._positionVector, scale);
}
public getPositionVector(position: IVector3D, scale: number): IVector3D
{
const cos = (this._radius * Math.cos((this._position + this._arcOffset)));
const sine = (this._radius * Math.sin((this._position + this._arcOffset)));
this._positionVector.x = ((cos - sine) * (scale / 2));
this._positionVector.y = ((((sine + cos) * (scale / 2)) * 0.5) - (this._height * (scale / 2)));
this._positionVector.z = -(Math.trunc(((4 * (cos + sine)) - 0.7)));
if(position) this._positionVector.add(position);
return this._positionVector;
}
public addChild(planetObject: FurniturePlanetSystemVisualizationPlanetObject): void
{
if(this._children.indexOf(planetObject) >= 0) return;
this._children.push(planetObject);
}
public hasChild(name: string): boolean
{
return !!this.getChild(name);
}
public getChild(name: string): FurniturePlanetSystemVisualizationPlanetObject
{
for(const child of this._children)
{
if(child.name === name) return child;
if(child.hasChild(name)) return child.getChild(name);
}
return null;
}
public get name(): string
{
return this._name;
}
}
@@ -0,0 +1,6 @@
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurniturePosterVisualization extends FurnitureAnimatedVisualization
{
}
@@ -0,0 +1,50 @@
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureQueueTileVisualization extends FurnitureAnimatedVisualization
{
private static ANIMATION_ID_ROLL: number = 3;
private static ANIMATION_ID_ROLL_ONCE: number = 2;
private static ANIMATION_ID_NORMAL: number = 1;
private static ANIMATION_DURATION: number = 15;
private _stateQueue: number[];
private _animationCounter: number;
constructor()
{
super();
this._stateQueue = [];
this._animationCounter = -1;
}
protected setAnimation(animationId: number): void
{
if(animationId === FurnitureQueueTileVisualization.ANIMATION_ID_ROLL_ONCE)
{
this._stateQueue = [];
this._stateQueue.push(FurnitureQueueTileVisualization.ANIMATION_ID_NORMAL);
this._animationCounter = FurnitureQueueTileVisualization.ANIMATION_DURATION;
}
return super.setAnimation(animationId);
}
protected updateAnimation(scale: number): number
{
if(this._animationCounter > 0) this._animationCounter--;
if(!this._animationCounter)
{
if(this._stateQueue.length) super.setAnimation(this._stateQueue.shift());
}
return super.updateAnimation(scale);
}
protected usesAnimationResetting(): boolean
{
return true;
}
}
@@ -0,0 +1,9 @@
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureResettingAnimatedVisualization extends FurnitureAnimatedVisualization
{
protected usesAnimationResetting(): boolean
{
return true;
}
}
@@ -0,0 +1,64 @@
import { Texture } from 'pixi.js';
import { DirectionalOffsetData } from '../data';
import { FurnitureBrandedImageVisualization } from './FurnitureBrandedImageVisualization';
export class FurnitureRoomBackgroundVisualization extends FurnitureBrandedImageVisualization
{
private _imageOffset: DirectionalOffsetData;
protected imageReady(texture: Texture, imageUrl: string): void
{
super.imageReady(texture, imageUrl);
if(!texture) return;
this.setImageOffset(texture.width, texture.height);
}
private setImageOffset(width: number, height: number): void
{
const offsetData = new DirectionalOffsetData();
offsetData.setDirection(1, 0, -height);
offsetData.setDirection(3, 0, 0);
offsetData.setDirection(5, -width, 0);
offsetData.setDirection(7, -width, -height);
offsetData.setDirection(4, (-width / 2), (-height / 2));
this._imageOffset = offsetData;
}
protected getLayerXOffset(scale: number, direction: number, layerId: number): number
{
if(this._imageOffset)
{
const offset = this._imageOffset.getXOffset(direction, 0);
if(offset !== undefined) return offset + this._offsetX;
}
return super.getLayerXOffset(scale, direction, layerId) + this._offsetX;
}
protected getLayerYOffset(scale: number, direction: number, layerId: number): number
{
if(this._imageOffset)
{
const offset = this._imageOffset.getYOffset(direction, 0);
if(offset !== undefined) return offset + this._offsetY;
}
return super.getLayerYOffset(scale, direction, layerId) + this._offsetY;
}
protected getLayerZOffset(scale: number, direction: number, layerId: number): number
{
return super.getLayerZOffset(scale, direction, layerId) + (-(this._offsetZ));
}
protected getLayerIgnoreMouse(scale: number, direction: number, layerId: number): boolean
{
return true;
}
}
@@ -0,0 +1,24 @@
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureScoreBoardVisualization extends FurnitureAnimatedVisualization
{
private static ONES_SPRITE: string = 'ones_sprite';
private static TENS_SPRITE: string = 'tens_sprite';
private static HUNDREDS_SPRITE: string = 'hundreds_sprite';
private static THOUSANDS_SPRITE: string = 'thousands_sprite';
protected getFrameNumber(scale: number, layerId: number): number
{
const tag = this.getLayerTag(scale, this.direction, layerId);
const animation = this.object.getState(0);
switch(tag)
{
case FurnitureScoreBoardVisualization.ONES_SPRITE: return Math.floor(animation % 10);
case FurnitureScoreBoardVisualization.TENS_SPRITE: return Math.floor((animation / 10) % 10);
case FurnitureScoreBoardVisualization.HUNDREDS_SPRITE: return Math.floor((animation / 100) % 10);
case FurnitureScoreBoardVisualization.THOUSANDS_SPRITE: return Math.floor((animation / 1000) % 10);
default: return super.getFrameNumber(scale, layerId);
}
}
}
@@ -0,0 +1,16 @@
import { RoomObjectVariable } from '@nitrots/api';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureSoundBlockVisualization extends FurnitureAnimatedVisualization
{
private _internalFrameIncreaseCounter: number = 0;
protected updateAnimations(scale: number): number
{
this._internalFrameIncreaseCounter = (this._internalFrameIncreaseCounter + this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_SOUNDBLOCK_RELATIVE_ANIMATION_SPEED));
this._frameIncrease = this._internalFrameIncreaseCounter;
this._internalFrameIncreaseCounter = (this._internalFrameIncreaseCounter - this._frameIncrease);
return super.updateAnimations(scale);
}
}
@@ -0,0 +1,12 @@
import { ColorData } from '../data';
import { FurnitureVisualization } from './FurnitureVisualization';
export class FurnitureStickieVisualization extends FurnitureVisualization
{
protected getLayerColor(scale: number, layerId: number, colorId: number): number
{
if(!this._data) return ColorData.DEFAULT_COLOR;
return this._data.getLayerColor(scale, layerId, colorId);
}
}
@@ -0,0 +1,76 @@
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureValRandomizerVisualization extends FurnitureAnimatedVisualization
{
private static ANIMATION_ID_OFFSET_SLOW1: number = 20;
private static ANIMATION_ID_OFFSET_SLOW2: number = 10;
private static ANIMATION_ID_START_ROLL: number = 31;
private static ANIMATION_ID_ROLL: number = 32;
private static ANIMATION_ID_OFF: number = 30;
private _stateQueue: number[];
private _running: boolean;
constructor()
{
super();
this._stateQueue = [];
this._running = false;
super.setAnimation(FurnitureValRandomizerVisualization.ANIMATION_ID_OFF);
}
protected setAnimation(animationId: number): void
{
if(animationId === 0)
{
if(!this._running)
{
this._running = true;
this._stateQueue = [];
this._stateQueue.push(FurnitureValRandomizerVisualization.ANIMATION_ID_START_ROLL);
this._stateQueue.push(FurnitureValRandomizerVisualization.ANIMATION_ID_ROLL);
return;
}
}
if((animationId > 0) && (animationId <= FurnitureValRandomizerVisualization.ANIMATION_ID_OFFSET_SLOW2))
{
if(this._running)
{
this._running = false;
this._stateQueue = [];
if(this.direction === 2)
{
this._stateQueue.push(FurnitureValRandomizerVisualization.ANIMATION_ID_OFFSET_SLOW1 + 5);
this._stateQueue.push(FurnitureValRandomizerVisualization.ANIMATION_ID_OFFSET_SLOW2 + 5);
}
else
{
this._stateQueue.push(FurnitureValRandomizerVisualization.ANIMATION_ID_OFFSET_SLOW1 + animationId);
this._stateQueue.push(FurnitureValRandomizerVisualization.ANIMATION_ID_OFFSET_SLOW2 + animationId);
}
this._stateQueue.push(FurnitureValRandomizerVisualization.ANIMATION_ID_OFF);
return;
}
super.setAnimation(FurnitureValRandomizerVisualization.ANIMATION_ID_OFF);
}
}
protected updateAnimation(scale: number): number
{
if(this.getLastFramePlayed(11))
{
if(this._stateQueue.length) super.setAnimation(this._stateQueue.shift());
}
return super.updateAnimation(scale);
}
}
@@ -0,0 +1,594 @@
import { AlphaTolerance, IGraphicAsset, IObjectVisualizationData, IRoomGeometry, IRoomObjectSprite, RoomObjectVariable, RoomObjectVisualizationType } from '@nitrots/api';
import { BLEND_MODES, Texture } from 'pixi.js';
import { RoomObjectSpriteVisualization } from '../RoomObjectSpriteVisualization';
import { ColorData, LayerData } from '../data';
import { FurnitureVisualizationData } from './FurnitureVisualizationData';
export class FurnitureVisualization extends RoomObjectSpriteVisualization
{
protected static DEPTH_MULTIPLIER: number = Math.sqrt(0.5);
public static TYPE: string = RoomObjectVisualizationType.FURNITURE_STATIC;
protected _data: FurnitureVisualizationData;
protected _type: string;
protected _direction: number;
protected _lastCameraAngle: number;
protected _selectedColor: number;
protected _furnitureLift: number;
protected _alphaMultiplier: number;
protected _alphaChanged: boolean;
protected _clickUrl: string;
protected _clickHandling: boolean;
protected _cacheDirection: number;
protected _cacheScale: number;
protected _cacheSize: number;
protected _layerCount: number;
protected _shadowLayerIndex: number;
protected _updatedLayers: boolean[];
protected _assetNames: string[];
protected _spriteTags: string[];
protected _spriteBlendModes: BLEND_MODES[];
protected _spriteAlphas: number[];
protected _spriteColors: number[];
protected _spriteMouseCaptures: boolean[];
protected _spriteXOffsets: number[];
protected _spriteYOffsets: number[];
protected _spriteZOffsets: number[];
private _animationNumber: number;
constructor()
{
super();
this._data = null;
this._type = null;
this._direction = 0;
this._lastCameraAngle = NaN;
this._selectedColor = 0;
this._furnitureLift = 0;
this._alphaMultiplier = 1;
this._alphaChanged = false;
this._clickUrl = null;
this._clickHandling = false;
this._cacheDirection = -1;
this._cacheScale = 0;
this._cacheSize = -1;
this._layerCount = 0;
this._shadowLayerIndex = -1;
this._updatedLayers = [];
this._assetNames = [];
this._spriteTags = [];
this._spriteBlendModes = [];
this._spriteAlphas = [];
this._spriteColors = [];
this._spriteMouseCaptures = [];
this._spriteXOffsets = [];
this._spriteYOffsets = [];
this._spriteZOffsets = [];
this._animationNumber = 0;
}
public initialize(data: IObjectVisualizationData): boolean
{
this.reset();
if(!(data instanceof FurnitureVisualizationData)) return false;
this._type = data.type;
this._data = data;
return true;
}
public dispose(): void
{
super.dispose();
this._data = null;
this._updatedLayers = null;
this._assetNames = null;
this._spriteTags = null;
this._spriteBlendModes = null;
this._spriteAlphas = null;
this._spriteColors = null;
this._spriteMouseCaptures = null;
this._spriteXOffsets = null;
this._spriteYOffsets = null;
this._spriteZOffsets = null;
}
protected reset(): void
{
super.reset();
this.setDirection(-1);
this._data = null;
this._updatedLayers = [];
this._assetNames = [];
this._spriteTags = [];
this._spriteBlendModes = [];
this._spriteAlphas = [];
this._spriteColors = [];
this._spriteMouseCaptures = [];
this._spriteXOffsets = [];
this._spriteYOffsets = [];
this._spriteZOffsets = [];
this.createSprites(0);
}
protected resetLayers(scale: number, direction: number): void
{
if((this._cacheDirection === direction) && (this._cacheScale === scale)) return;
this._updatedLayers = [];
this._assetNames = [];
this._spriteTags = [];
this._spriteBlendModes = [];
this._spriteAlphas = [];
this._spriteColors = [];
this._spriteMouseCaptures = [];
this._spriteXOffsets = [];
this._spriteYOffsets = [];
this._spriteZOffsets = [];
this._cacheDirection = direction;
this._cacheScale = scale;
this._cacheSize = this.getValidSize(scale);
this.setLayerCount(((this._data && this._data.getLayerCount(scale)) || 0) + this.getAdditionalLayerCount());
}
public update(geometry: IRoomGeometry, time: number, update: boolean, skipUpdate: boolean): void
{
if(!geometry) return;
const scale = geometry.scale;
let updateSprites = false;
if(this.updateObject(scale, geometry.direction.x)) updateSprites = true;
if(this.updateModel(scale)) updateSprites = true;
let number = 0;
if(skipUpdate)
{
this._animationNumber = (this._animationNumber | this.updateAnimation(scale));
}
else
{
number = this.updateAnimation(scale) | this._animationNumber;
this._animationNumber = 0;
}
if(updateSprites || (number !== 0))
{
this.updateSprites(scale, updateSprites, number);
this._scale = scale;
this.updateSpriteCounter++;
}
}
protected updateObject(scale: number, direction: number): boolean
{
if(!this.object) return false;
if((this.updateObjectCounter === this.object.updateCounter) && (scale === this._scale) && (this._lastCameraAngle === direction)) return false;
let offsetDirection = (this.object.getDirection().x - (direction + 135));
offsetDirection = ((((offsetDirection) % 360) + 360) % 360);
if(this._data)
{
const validDirection = this._data.getValidDirection(scale, offsetDirection);
this.setDirection(validDirection);
}
this._lastCameraAngle = direction;
this._scale = scale;
this.updateObjectCounter = this.object.updateCounter;
this.resetLayers(scale, this._direction);
return true;
}
protected updateModel(scale: number): boolean
{
const model = this.object && this.object.model;
if(!model) return false;
if(this.updateModelCounter === model.updateCounter) return false;
this._selectedColor = model.getValue<number>(RoomObjectVariable.FURNITURE_COLOR);
this._clickUrl = model.getValue<string>(RoomObjectVariable.FURNITURE_AD_URL);
this._clickHandling = ((this._clickUrl && (this._clickUrl !== '') && (this._clickUrl.indexOf('http') === 0)) || false);
this._furnitureLift = (model.getValue<number>(RoomObjectVariable.FURNITURE_LIFT_AMOUNT) || 0);
let alphaMultiplier = model.getValue<number>(RoomObjectVariable.FURNITURE_ALPHA_MULTIPLIER);
if(isNaN(alphaMultiplier)) alphaMultiplier = 1;
if(this._alphaMultiplier !== alphaMultiplier)
{
this._alphaMultiplier = alphaMultiplier;
this._alphaChanged = true;
}
this.updateModelCounter = model.updateCounter;
return true;
}
protected updateSprites(scale: number, update: boolean, animation: number): void
{
if(this._layerCount !== this.totalSprites) this.createSprites(this._layerCount);
if(update)
{
let layerId = (this.totalSprites - 1);
while(layerId >= 0)
{
this.updateSprite(scale, layerId);
layerId--;
}
}
else
{
let layerId = 0;
while(animation > 0)
{
if(animation) this.updateSprite(scale, layerId);
layerId++;
animation = (animation >> 1);
}
}
this._alphaChanged = false;
}
protected updateSprite(scale: number, layerId: number): void
{
const assetName = this.getSpriteAssetName(scale, layerId);
const sprite = this.getSprite(layerId);
if(assetName && sprite)
{
const assetData = this.getAsset(assetName, layerId);
if(assetData)
{
sprite.visible = true;
sprite.type = this._type;
sprite.texture = this.getTexture(scale, layerId, assetData);
sprite.flipH = assetData.flipH;
sprite.flipV = assetData.flipV;
sprite.direction = this._direction;
let relativeDepth = 0;
if(layerId !== this._shadowLayerIndex)
{
sprite.tag = this.getLayerTag(scale, this._direction, layerId);
sprite.alpha = this.getLayerAlpha(scale, this._direction, layerId);
sprite.color = this.getLayerColor(scale, layerId, this._selectedColor);
sprite.offsetX = (assetData.offsetX + this.getLayerXOffset(scale, this._direction, layerId));
sprite.offsetY = (assetData.offsetY + this.getLayerYOffset(scale, this._direction, layerId));
sprite.blendMode = this.getLayerBlendMode(scale, this._direction, layerId);
sprite.alphaTolerance = (this.getLayerIgnoreMouse(scale, this._direction, layerId) ? AlphaTolerance.MATCH_NOTHING : AlphaTolerance.MATCH_OPAQUE_PIXELS);
relativeDepth = this.getLayerZOffset(scale, this._direction, layerId);
relativeDepth = (relativeDepth - (layerId * 0.001));
}
else
{
sprite.offsetX = assetData.offsetX;
sprite.offsetY = (assetData.offsetY + this.getLayerYOffset(scale, this._direction, layerId));
sprite.alpha = (48 * this._alphaMultiplier);
sprite.alphaTolerance = AlphaTolerance.MATCH_NOTHING;
relativeDepth = 1;
}
sprite.relativeDepth = (relativeDepth * FurnitureVisualization.DEPTH_MULTIPLIER);
sprite.name = assetName;
sprite.libraryAssetName = this.getLibraryAssetNameForSprite(assetData, sprite);
sprite.posture = this.getPostureForAsset(scale, assetData.source);
sprite.clickHandling = this._clickHandling;
}
else
{
this.resetSprite(sprite);
}
}
else
{
if(sprite) this.resetSprite(sprite);
}
}
protected getLibraryAssetNameForSprite(asset: IGraphicAsset, sprite: IRoomObjectSprite): string
{
return asset.source;
}
protected getPostureForAssetFile(scale: number, _arg_2: string): string
{
return null;
}
private resetSprite(sprite: IRoomObjectSprite): void
{
if(!sprite) return;
sprite.texture = null;
sprite.libraryAssetName = '';
sprite.posture = '';
sprite.tag = '';
sprite.offsetX = 0;
sprite.offsetY = 0;
sprite.flipH = false;
sprite.flipV = false;
sprite.relativeDepth = 0;
sprite.clickHandling = false;
}
protected getSpriteAssetName(scale: number, layerId: number): string
{
if(!this._data || (layerId >= FurnitureVisualizationData.LAYER_LETTERS.length)) return '';
let assetName = this._assetNames[layerId];
let updated = this._updatedLayers[layerId];
if(!assetName || !assetName.length)
{
assetName = this.cacheSpriteAssetName(scale, layerId, true);
updated = (this._cacheSize !== 1);
}
if(updated) assetName += this.getFrameNumber(scale, layerId);
return assetName;
}
protected cacheSpriteAssetName(scale: number, layerId: number, cache: boolean): string
{
const type = this._type;
const size = (cache) ? this._cacheSize : this.getValidSize(scale);
let layerCode = '';
const isntIcon = (size !== 1);
if(layerId !== this._shadowLayerIndex)
{
layerCode = FurnitureVisualizationData.LAYER_LETTERS[layerId] || '';
}
else
{
layerCode = 'sd';
}
if(layerCode === '') return null;
const assetName = (this._type + ((isntIcon) ? ('_' + size + '_' + layerCode + '_' + this._direction + '_') : ('_icon_' + layerCode)));
if(cache)
{
this._assetNames[layerId] = assetName;
this._updatedLayers[layerId] = isntIcon;
}
return assetName;
}
protected getLayerTag(scale: number, direction: number, layerId: number): string
{
const existing = this._spriteTags[layerId];
if(existing !== undefined) return existing;
if(!this._data) return LayerData.DEFAULT_TAG;
const tag = this._data.getLayerTag(scale, direction, layerId);
this._spriteTags[layerId] = tag;
return tag;
}
protected getLayerBlendMode(scale: number, direction: number, layerId: number): BLEND_MODES
{
const existing = this._spriteBlendModes[layerId];
if(existing !== undefined) return existing;
if(!this._data) return LayerData.DEFAULT_BLEND_MODE;
const blendMode = this._data.getLayerBlendMode(scale, direction, layerId);
this._spriteBlendModes[layerId] = blendMode;
return blendMode;
}
protected getLayerAlpha(scale: number, direction: number, layerId: number): number
{
if(!this._alphaChanged)
{
const existing = this._spriteAlphas[layerId];
if(existing !== undefined) return existing;
}
if(!this._data) return LayerData.DEFAULT_ALPHA;
let alpha = this._data.getLayerAlpha(scale, direction, layerId);
if(this._alphaMultiplier !== null) alpha = (alpha * this._alphaMultiplier);
this._spriteAlphas[layerId] = alpha;
return alpha;
}
protected getLayerColor(scale: number, layerId: number, colorId: number): number
{
const existing = this._spriteColors[layerId];
if(existing !== undefined) return existing;
if(!this._data) return ColorData.DEFAULT_COLOR;
const color = this._data.getLayerColor(scale, layerId, colorId);
this._spriteColors[layerId] = color;
return color;
}
protected getLayerIgnoreMouse(scale: number, direction: number, layerId: number): boolean
{
const existing = this._spriteMouseCaptures[layerId];
if(existing !== undefined) return existing;
if(!this._data) return LayerData.DEFAULT_IGNORE_MOUSE;
const ignoreMouse = this._data.getLayerIgnoreMouse(scale, direction, layerId);
this._spriteMouseCaptures[layerId] = ignoreMouse;
return ignoreMouse;
}
protected getLayerXOffset(scale: number, direction: number, layerId: number): number
{
const existing = this._spriteXOffsets[layerId];
if(existing !== undefined) return existing;
if(!this._data) return LayerData.DEFAULT_XOFFSET;
const xOffset = this._data.getLayerXOffset(scale, direction, layerId);
this._spriteXOffsets[layerId] = xOffset;
return xOffset;
}
protected getLayerYOffset(scale: number, direction: number, layerId: number): number
{
if(layerId === this._shadowLayerIndex) return Math.ceil((this._furnitureLift * (scale / 2)));
const existing = this._spriteYOffsets[layerId];
if(existing !== undefined) return existing;
if(!this._data) return LayerData.DEFAULT_YOFFSET;
const yOffset = this._data.getLayerYOffset(scale, direction, layerId);
this._spriteYOffsets[layerId] = yOffset;
return yOffset;
}
protected getLayerZOffset(scale: number, direction: number, layerId: number): number
{
const existing = this._spriteZOffsets[layerId];
if(existing !== undefined) return existing;
if(!this._data) return LayerData.DEFAULT_ZOFFSET;
const zOffset = this._data.getLayerZOffset(scale, direction, layerId);
this._spriteZOffsets[layerId] = zOffset;
return zOffset;
}
protected getValidSize(scale: number): number
{
if(!this._data) return scale;
return this._data.getValidSize(scale);
}
protected setLayerCount(count: number): void
{
this._layerCount = count;
this._shadowLayerIndex = count - this.getAdditionalLayerCount();
}
protected setDirection(direction: number): void
{
if(this._direction === direction) return;
this._direction = direction;
}
protected getAdditionalLayerCount(): number
{
return 1;
}
protected updateAnimation(scale: number): number
{
return 0;
}
protected getFrameNumber(scale: number, layerId: number): number
{
return 0;
}
protected getPostureForAsset(scale: number, name: string): string
{
return null;
}
public getAsset(name: string, layerId: number = -1): IGraphicAsset
{
if(!this.asset) return null;
return this.asset.getAsset(name);
}
public getTexture(scale: number, layerId: number, asset: IGraphicAsset): Texture
{
return asset?.texture ?? null;
}
protected get direction(): number
{
return this._direction;
}
protected get data(): FurnitureVisualizationData
{
return this._data;
}
}
@@ -0,0 +1,281 @@
import { IAssetData, IAssetVisualizationData, IObjectVisualizationData } from '@nitrots/api';
import { BLEND_MODES } from 'pixi.js';
import { ColorData, LayerData, SizeData } from '../data';
export class FurnitureVisualizationData implements IObjectVisualizationData
{
public static LAYER_LETTERS: string[] = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
private _type: string = '';
private _sizes: number[] = [];
private _sizeDatas: Map<number, SizeData> = new Map();
private _lastSize: number = -1;
private _lastSizeScale: number = -1;
private _lastSizeData: SizeData = null;
private _lastSizeDataScale: number = -1;
public initialize(asset: IAssetData): boolean
{
this.reset();
if(!asset) return false;
this._type = asset.name;
if(!this.defineVisualizations(asset.visualizations))
{
this.reset();
return false;
}
return true;
}
public dispose(): void
{
if(this._sizeDatas && this._sizeDatas.size)
{
for(const size of this._sizeDatas.values()) size && size.dispose();
this._sizeDatas = null;
}
this._lastSizeData = null;
this._sizes = null;
}
private reset(): void
{
this._type = '';
if(this._sizeDatas && this._sizeDatas.size)
{
for(const size of this._sizeDatas.values()) size && size.dispose();
}
this._sizeDatas.clear();
this._sizes = [];
this._lastSizeData = null;
this._lastSizeDataScale = -1;
}
protected createSizeData(scale: number, layerCount: number, angle: number): SizeData
{
return new SizeData(layerCount, angle);
}
protected defineVisualizations(visualizations: IAssetVisualizationData[]): boolean
{
if(!visualizations) return false;
for(const visualizationId in visualizations)
{
const visualization = visualizations[visualizationId];
const layerCount = visualization.layerCount;
const angle = visualization.angle;
let size = visualization.size;
if(size < 1) size = 1;
if(this._sizeDatas.get(size)) return false;
const sizeData = this.createSizeData(size, layerCount, angle);
if(!sizeData) return false;
for(const key in visualization)
{
//@ts-ignore
const data = visualization[key];
if(!this.processVisualElement(sizeData, key, data))
{
sizeData.dispose();
return false;
}
}
this._sizeDatas.set(size, sizeData);
this._sizes.push(size);
}
this._sizes.sort();
return true;
}
protected processVisualElement(sizeData: SizeData, key: string, data: any): boolean
{
if(!sizeData || !key || !data) return false;
switch(key)
{
case 'layers':
if(!sizeData.processLayers(data)) return false;
break;
case 'directions':
if(!sizeData.processDirections(data)) return false;
break;
case 'colors':
if(!sizeData.processColors(data)) return false;
break;
}
return true;
}
public getValidSize(scale: number): number
{
if(scale === this._lastSizeScale) return this._lastSize;
const sizeIndex = this.getSizeIndex(scale);
let newScale = -1;
if(sizeIndex < this._sizes.length) newScale = this._sizes[sizeIndex];
this._lastSizeScale = scale;
this._lastSize = newScale;
return newScale;
}
private getSizeIndex(size: number): number
{
if(size <= 0) return 0;
let index = 0;
let iterator = 1;
while(iterator < this._sizes.length)
{
if(this._sizes[iterator] > size)
{
if((this._sizes[iterator] / size) < (size / this._sizes[(iterator - 1)])) index = iterator;
break;
}
index = iterator;
iterator++;
}
return index;
}
protected getSizeData(size: number): SizeData
{
if(size === this._lastSizeDataScale) return this._lastSizeData;
const sizeIndex = this.getSizeIndex(size);
if(sizeIndex < this._sizes.length) this._lastSizeData = this._sizeDatas.get(this._sizes[sizeIndex]);
else this._lastSizeData = null;
this._lastSizeDataScale = size;
return this._lastSizeData;
}
public getLayerCount(scale: number): number
{
const size = this.getSizeData(scale);
if(!size) return LayerData.DEFAULT_COUNT;
return size.layerCount;
}
public getValidDirection(scale: number, direction: number): number
{
const size = this.getSizeData(scale);
if(!size) return LayerData.DEFAULT_DIRECTION;
return size.getValidDirection(direction);
}
public getLayerTag(scale: number, direction: number, layerId: number): string
{
const size = this.getSizeData(scale);
if(!size) return LayerData.DEFAULT_TAG;
return size.getLayerTag(direction, layerId);
}
public getLayerBlendMode(scale: number, direction: number, layerId: number): BLEND_MODES
{
const size = this.getSizeData(scale);
if(!size) return LayerData.DEFAULT_BLEND_MODE;
return size.getLayerBlendMode(direction, layerId);
}
public getLayerAlpha(scale: number, direction: number, layerId: number): number
{
const size = this.getSizeData(scale);
if(!size) return LayerData.DEFAULT_ALPHA;
return size.getLayerAlpha(direction, layerId);
}
public getLayerColor(scale: number, layerId: number, colorId: number): number
{
const size = this.getSizeData(scale);
if(!size) return ColorData.DEFAULT_COLOR;
return size.getLayerColor(layerId, colorId);
}
public getLayerIgnoreMouse(scale: number, direction: number, layerId: number): boolean
{
const size = this.getSizeData(scale);
if(!size) return LayerData.DEFAULT_IGNORE_MOUSE;
return size.getLayerIgnoreMouse(direction, layerId);
}
public getLayerXOffset(scale: number, direction: number, layerId: number): number
{
const size = this.getSizeData(scale);
if(!size) return LayerData.DEFAULT_XOFFSET;
return size.getLayerXOffset(direction, layerId);
}
public getLayerYOffset(scale: number, direction: number, layerId: number): number
{
const size = this.getSizeData(scale);
if(!size) return LayerData.DEFAULT_YOFFSET;
return size.getLayerYOffset(direction, layerId);
}
public getLayerZOffset(scale: number, direction: number, layerId: number): number
{
const size = this.getSizeData(scale);
if(!size) return LayerData.DEFAULT_ZOFFSET;
return size.getLayerZOffset(direction, layerId);
}
public get type(): string
{
return this._type;
}
}
@@ -0,0 +1,51 @@
import { RoomObjectVariable } from '@nitrots/api';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureVoteCounterVisualization extends FurnitureAnimatedVisualization
{
private static ONES_SPRITE: string = 'ones_sprite';
private static TENS_SPRITE: string = 'tens_sprite';
private static HUNDREDS_SPRITE: string = 'hundreds_sprite';
private static HIDE_COUNTER_SCORE: number = -1;
protected updateObject(scale: number, direction: number): boolean
{
super.updateObject(scale, direction);
return true;
}
protected getFrameNumber(scale: number, layerId: number): number
{
const result = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_VOTE_COUNTER_COUNT);
const tag = this.getLayerTag(scale, this.direction, layerId);
switch(tag)
{
case FurnitureVoteCounterVisualization.ONES_SPRITE: return (result % 10);
case FurnitureVoteCounterVisualization.TENS_SPRITE: return ((result / 10) % 10);
case FurnitureVoteCounterVisualization.HUNDREDS_SPRITE: return ((result / 100) % 10);
default: return super.getFrameNumber(scale, layerId);
}
}
protected getLayerAlpha(scale: number, direction: number, layerId: number): number
{
const result = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_VOTE_COUNTER_COUNT);
if(result === FurnitureVoteCounterVisualization.HIDE_COUNTER_SCORE)
{
const tag = this.getLayerTag(scale, direction, layerId);
switch(tag)
{
case FurnitureVoteCounterVisualization.ONES_SPRITE:
case FurnitureVoteCounterVisualization.TENS_SPRITE:
case FurnitureVoteCounterVisualization.HUNDREDS_SPRITE:
return 0;
}
}
return super.getLayerAlpha(scale, direction, layerId);
}
}
@@ -0,0 +1,45 @@
import { RoomObjectVariable } from '@nitrots/api';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureVoteMajorityVisualization extends FurnitureAnimatedVisualization
{
private static ONES_SPRITE: string = 'ones_sprite';
private static TENS_SPRITE: string = 'tens_sprite';
private static HUNDREDS_SPRITE: string = 'hundreds_sprite';
private static HIDE_RESULTS_STATES: number[] = [-1, 1];
private static HIDE_RESULTS_VALUE: number = -1;
protected getFrameNumber(scale: number, layerId: number): number
{
const result = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_VOTE_MAJORITY_RESULT);
const tag = this.getLayerTag(scale, this.direction, layerId);
switch(tag)
{
case FurnitureVoteMajorityVisualization.ONES_SPRITE: return (result % 10);
case FurnitureVoteMajorityVisualization.TENS_SPRITE: return ((result / 10) % 10);
case FurnitureVoteMajorityVisualization.HUNDREDS_SPRITE: return ((result / 100) % 10);
default: return super.getFrameNumber(scale, layerId);
}
}
protected getLayerAlpha(scale: number, direction: number, layerId: number): number
{
const result = this.object.model.getValue<number>(RoomObjectVariable.FURNITURE_VOTE_MAJORITY_RESULT);
if(((!(FurnitureVoteMajorityVisualization.HIDE_RESULTS_STATES.indexOf(this.object.getState(0)) === -1)) || (result === FurnitureVoteMajorityVisualization.HIDE_RESULTS_VALUE)))
{
const tag = this.getLayerTag(scale, direction, layerId);
switch(tag)
{
case FurnitureVoteMajorityVisualization.ONES_SPRITE:
case FurnitureVoteMajorityVisualization.TENS_SPRITE:
case FurnitureVoteMajorityVisualization.HUNDREDS_SPRITE:
return 0;
}
}
return super.getLayerAlpha(scale, direction, layerId);
}
}
@@ -0,0 +1,6 @@
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class FurnitureWaterAreaVisualization extends FurnitureAnimatedVisualization
{
}
@@ -0,0 +1,18 @@
import { RoomObjectVariable } from '@nitrots/api';
import { FurnitureDynamicThumbnailVisualization } from './FurnitureDynamicThumbnailVisualization';
export class FurnitureYoutubeVisualization extends FurnitureDynamicThumbnailVisualization
{
protected static THUMBNAIL_URL: string = 'THUMBNAIL_URL';
protected getThumbnailURL(): string
{
if(!this.object) return null;
const furnitureData = this.object.model.getValue<{ [index: string]: string }>(RoomObjectVariable.FURNITURE_DATA);
if(furnitureData) return (furnitureData[FurnitureYoutubeVisualization.THUMBNAIL_URL] || null);
return null;
}
}
@@ -0,0 +1,172 @@
import { IGraphicAsset } from '@nitrots/api';
import { TextureUtils } from '@nitrots/utils';
import { Matrix, Sprite, Texture } from 'pixi.js';
import { FurnitureAnimatedVisualization } from './FurnitureAnimatedVisualization';
export class IsometricImageFurniVisualization extends FurnitureAnimatedVisualization
{
protected static THUMBNAIL: string = 'THUMBNAIL';
private _thumbnailAssetNameNormal: string;
private _thumbnailImageNormal: Texture;
private _thumbnailDirection: number;
private _thumbnailChanged: boolean;
protected _hasOutline: boolean;
constructor()
{
super();
this._thumbnailAssetNameNormal = null;
this._thumbnailImageNormal = null;
this._thumbnailDirection = -1;
this._thumbnailChanged = false;
this._hasOutline = false;
}
public get hasThumbnailImage(): boolean
{
return !(this._thumbnailImageNormal == null);
}
public setThumbnailImages(k: Texture): void
{
this._thumbnailImageNormal = k;
this._thumbnailChanged = true;
}
protected updateModel(scale: number): boolean
{
const flag = super.updateModel(scale);
if(!this._thumbnailChanged && (this._thumbnailDirection === this.direction)) return flag;
this.refreshThumbnail();
return true;
}
private refreshThumbnail(): void
{
if(this.asset == null) return;
if(this._thumbnailImageNormal)
{
this.addThumbnailAsset(this._thumbnailImageNormal, 64);
}
else
{
this.asset.disposeAsset(this.getThumbnailAssetName(64));
}
this._thumbnailChanged = false;
this._thumbnailDirection = this.direction;
}
private addThumbnailAsset(k: Texture, scale: number): void
{
let layerId = 0;
while(layerId < this.totalSprites)
{
if(this.getLayerTag(scale, this.direction, layerId) === IsometricImageFurniVisualization.THUMBNAIL)
{
const assetName = (this.cacheSpriteAssetName(scale, layerId, false) + this.getFrameNumber(scale, layerId));
const asset = this.getAsset(assetName, layerId);
if(asset)
{
const _local_6 = this.generateTransformedThumbnail(k, asset);
const _local_7 = this.getThumbnailAssetName(scale);
this.asset.disposeAsset(_local_7);
this.asset.addAsset(_local_7, _local_6, true, asset.offsetX, asset.offsetY, false, false);
}
return;
}
layerId++;
}
}
protected generateTransformedThumbnail(texture: Texture, asset: IGraphicAsset): Texture
{
if(this._hasOutline)
{
const container = new Sprite();
const background = new Sprite(Texture.WHITE);
background.tint = 0x000000;
background.width = (texture.width + 40);
background.height = (texture.height + 40);
const sprite = new Sprite(texture);
const offsetX = ((background.width - sprite.width) / 2);
const offsetY = ((background.height - sprite.height) / 2);
sprite.position.set(offsetX, offsetY);
container.addChild(background, sprite);
texture = TextureUtils.generateTexture(container);
}
const scale = 1.1;
const matrix = new Matrix();
const difference = (asset.width / texture.width);
switch(this.direction)
{
case 2:
matrix.a = difference;
matrix.b = (-0.5 * difference);
matrix.c = 0;
matrix.d = (difference * scale);
matrix.tx = 0;
matrix.ty = ((0.5 * difference) * texture.width);
break;
case 0:
case 4:
matrix.a = difference;
matrix.b = (0.5 * difference);
matrix.c = 0;
matrix.d = (difference * scale);
matrix.tx = 0;
matrix.ty = 0;
break;
default:
matrix.a = difference;
matrix.b = 0;
matrix.c = 0;
matrix.d = difference;
matrix.tx = 0;
matrix.ty = 0;
}
const sprite = new Sprite(texture);
sprite.setFromMatrix(matrix);
return TextureUtils.generateTexture(sprite);
}
protected getSpriteAssetName(scale: number, layerId: number): string
{
if(this._thumbnailImageNormal && (this.getLayerTag(scale, this.direction, layerId) === IsometricImageFurniVisualization.THUMBNAIL)) return this.getThumbnailAssetName(scale);
return super.getSpriteAssetName(scale, layerId);
}
protected getThumbnailAssetName(scale: number): string
{
this._thumbnailAssetNameNormal = this.getFullThumbnailAssetName(this.object.id, 64);
return this._thumbnailAssetNameNormal;
}
protected getFullThumbnailAssetName(k: number, _arg_2: number): string
{
return [this._type, k, 'thumb', _arg_2].join('_');
}
}
@@ -0,0 +1,41 @@
export * from './FurnitureAnimatedVisualization';
export * from './FurnitureAnimatedVisualizationData';
export * from './FurnitureBBVisualization';
export * from './FurnitureBadgeDisplayVisualization';
export * from './FurnitureBottleVisualization';
export * from './FurnitureBrandedImageVisualization';
export * from './FurnitureBuilderPlaceholderVisualization';
export * from './FurnitureCounterClockVisualization';
export * from './FurnitureCuboidVisualization';
export * from './FurnitureDynamicThumbnailVisualization';
export * from './FurnitureExternalImageVisualization';
export * from './FurnitureFireworksVisualization';
export * from './FurnitureGiftWrappedFireworksVisualization';
export * from './FurnitureGiftWrappedVisualization';
export * from './FurnitureGuildCustomizedVisualization';
export * from './FurnitureGuildIsometricBadgeVisualization';
export * from './FurnitureHabboWheelVisualization';
export * from './FurnitureIsometricBBVisualization';
export * from './FurnitureMannequinVisualization';
export * from './FurnitureMannequinVisualizationData';
export * from './FurnitureParticleSystem';
export * from './FurnitureParticleSystemEmitter';
export * from './FurnitureParticleSystemParticle';
export * from './FurniturePartyBeamerVisualization';
export * from './FurniturePlanetSystemVisualization';
export * from './FurniturePlanetSystemVisualizationPlanetObject';
export * from './FurniturePosterVisualization';
export * from './FurnitureQueueTileVisualization';
export * from './FurnitureResettingAnimatedVisualization';
export * from './FurnitureRoomBackgroundVisualization';
export * from './FurnitureScoreBoardVisualization';
export * from './FurnitureSoundBlockVisualization';
export * from './FurnitureStickieVisualization';
export * from './FurnitureValRandomizerVisualization';
export * from './FurnitureVisualization';
export * from './FurnitureVisualizationData';
export * from './FurnitureVoteCounterVisualization';
export * from './FurnitureVoteMajorityVisualization';
export * from './FurnitureWaterAreaVisualization';
export * from './FurnitureYoutubeVisualization';
export * from './IsometricImageFurniVisualization';