KMXBQVJSTSU46WB6IYGNWNMXKIVAMIHILKCDQVD3E76YDR2TCZNAC
7HBFOC5MXDEVFOALYURNJZPXCGJRR5AW6ISGAGEGLTISIOURT4RAC
RB4XTDEUFAEAB4QNC6XXZUHDKVN77N3EG2NSCTQLRTQICLSEHDMAC
WNMPJOSW3767SR2TZ6I55IH5WBJD2OS2HDP3YDWCVIDMUQDRIRRQC
L4VMIGM6D5WUEBYOCXBIF6V66NRJAKOJO4FHALHIUIAGAUQUKDPAC
PZNEDCRDS5IBR7QDPHTW5HZRMQAZFIF7VB3IKWPZDC7IALHZKHWAC
33W6NM7THHPV4WL6WI2UOLGCOTFAITF2OZ3JN2SMYY2MHCGB27IQC
3UFL673QX2JG7KHTAM7DFH4BBYVHDNMXBS2RW45G3JBNFZFLSRRQC
GZRMSSTEWT3T2JERC7WCVT727X237UA6MXWVT6OSV5D5BRD4UOGQC
L72HFM6IYLNHEFEIFOQQQUAGMY2RN4POCV3Q3SMQERSQBMEZ5J3QC
RWQMSAGYY7OTRP6HVYYJUY3IOII6P5IBQEHE5NJN2V6DGIYER5OAC
FPECYSD5K4I23LPBSJW2AOILTFLJE55HQ34FMK6CKTBUOFBUL6XAC
U665HW6MTIDB6FVOODL24BOMJMOJ6ZSP664NU4T442QFLYD5CGHQC
2OZGXOFLTXALS34QEIQ2F6VT7AUWYK7FVXUUDX66GZT5I7FUNPVAC
CWCOGTXQXEQPK6O4TQFCIPDVMZD7WHOBGMIG2DTSO6BEBFEADZIQC
GIDOI5BK3WYIDEQL7SZTJPR3Q5TDQ34YHDPDCUFFH6PX4POEDSQQC
6ZGB7JZJ4EWDELXAENEHRNNJZB2EK7E7BEKNPK34MJL75DOPJNPAC
NKWFGTCM6HM35MAJAREANFQS76ALYOD7K6FT77X5HQPBCRAPXVRAC
ZDAABIZI6MPCP5DPGUN24XLSWIKQQ6LYMKIH67ORLUSFUVS5AJ5AC
AF2QOVSSTCKR26APL4PQSNUGZPPJY3IIUUHN4LJ5URL5THW2NSDQC
AZRGEBFL5YFY6PVBYGVAEUOEP5UUHVP4LLYRVMC3TAKQV6XUHXLQC
SACCO45GNBBHHTWCVMKJ64ZLGW32DM4DIKSOJF3N6U47WP4JY5HAC
HOHGBK6XI5VIWIC42IKHRO6OUNMUFUI2TXHDHMDCIPLAT7COB5TAC
GO6HOZRQC3PVIH6REZM4MYH3PGAQD5YSW3VCFJZ6ZENJLC5KDDMAC
3J7QNHQ4F2VBYCK6SWKPO3AW3YYAJZNWOW6XNSURSRDZOE2ZIGQAC
CZPLX4O4R7K3TF3NSAL5PT7NO3CUOLDY3OR332GBIYYNKMZTW24AC
DV3KM46EQREZL5Y47SDAFJQZFLEAOIBYGYZOKGLJXW2AI4MWLFGAC
HPOKB2TCHK3MTYYKXL3DE476BF3JXVSX6MSGI5NF4PSLALTS3PHQC
4CQWVYQVUFXWUZBVLT7X7YW6TVIUHAGABPLXZTC66WNQQP5BOREAC
QYHOJMYCWRCAMP6YPVGTBWSOOIDZI7Z2IMGODEA5UUJFMMYZCFCQC
MFKZYXV3EZAQCPNCFKCK5DM3O66CEGWYEUM6HZ2I2PMGVE73EYZAC
Z5I5KK7NX6RS23QAB7ISLQCM5Z6TMVZK532NPSE7CO4MNXNKVKMAC
GJGKS2YPL6XOT4CLQ2NVHUU2W7MDHYE2XC77WWRGPBCPSTWZ5GIAC
QTTO6EU2UCXVVPN724D2FUMGKJSEWTG7FXLOFNUB3IL3RVV3AVUAC
5NOOFT552GDEBDUACQZXG4TOLQSILGZEPGEJRS5BQD34TIJQ6T2QC
PSY4Y3X4ZWLXR2FEDR2W5E4SW2ASS4BPBOT4W5TDLNU2NCFZISNAC
7KT5VCNGU24M5NPW2YME3BAE3HASNPJ7Y6VEKCFEJDQKNXCP4MYAC
HGV5HTLAKXK2AEBXAAASX5AC6SDBNGT253O3NY4MYNZN3TN4S3BQC
export class PointNodeComponent {
public container: Pixi.Container;
staleProps: Props;
public state: State;
public sprite: Pixi.Sprite
public halfwayCenterSprite: Pixi.Sprite;
public centerSprite: Pixi.Sprite;
public hitArea: Pixi.IHitArea;
public tooltippableArea?: TooltippableAreaComponent
public tooltippableAreaPropsFactory: (p: Props, s: State) => TooltippableAreaComponentProps
public _children: {childClass :any, instance: any, propsFactory: Function}[] = []
public forceUpdates: {childClass :any, instance: any, propsFactory: Function}[] = []
constructor(props: Props) {
this.staleProps = props;
this.state = {
justTriedToAllocate: false,
justSpentSp: false,
justFailedToAllocate: false,
numClicks: 0
};
this.container = new Pixi.Container();
this.container.sortableChildren = true;
this.sprite = new Pixi.Sprite(props.args.pointNodeTexture);
this.sprite.anchor.x = 0.5;
this.sprite.anchor.y = 0.5;
this.sprite.zIndex = -1;
this.container.addChild(this.sprite);
this.centerSprite = new Pixi.Sprite(props.args.pointNodeTexture);
this.centerSprite.anchor.x = 0.5;
this.centerSprite.anchor.y = 0.5;
this.centerSprite.scale = PixiPointFrom(new Vector2(0.5, 0.5));
this.centerSprite.zIndex = 1;
this.centerSprite.alpha = 0; // TESTING
// this.container.addChild(this.centerSprite);
this.halfwayCenterSprite = new Pixi.Sprite(props.args.pointNodeTexture);
this.halfwayCenterSprite.anchor.x = 0.5;
this.halfwayCenterSprite.anchor.y = 0.5;
this.halfwayCenterSprite.scale = PixiPointFrom(new Vector2(0.75, 0.75));
this.halfwayCenterSprite.zIndex = 0;
// disable this sprite for now - causes a fairly significant fps hit, until we get around to holding less nodes on the page at once
this.halfwayCenterSprite.alpha = 0;
// this.container.addChild(this.halfwayCenterSprite);
this.container.interactive = true;
// NOTE(bowei): ive tested, the following 2 settings don't significantly affect FPS
this.container.buttonMode = true;
this.hitArea = new Pixi.Rectangle(
- RenderedChunkConstants.NODE_HITAREA_PX / 2,
- RenderedChunkConstants.NODE_HITAREA_PX / 2,
RenderedChunkConstants.NODE_HITAREA_PX,
RenderedChunkConstants.NODE_HITAREA_PX,
);
// note: hitarea breaks child onhover: https://github.com/pixijs/pixi.js/issues/5837
// this.container.hitArea = this.hitArea;
this.tooltippableAreaPropsFactory = (p: Props, s: State) => {
return {
args: {
markForceUpdate: this.markForceUpdate,
},
hitArea: this.hitArea,
}
}
this.tooltippableArea = new TooltippableAreaComponent(this.tooltippableAreaPropsFactory(props, this.state));
this.container.addChild(this.tooltippableArea.container);
this._children.push({
childClass: TooltippableAreaComponent,
instance: this.tooltippableArea,
propsFactory: this.tooltippableAreaPropsFactory,
});
this.renderSelf(props);
this.didMount();
}
renderSelf(props: Props) {
this.container.position = PixiPointFrom(props.position);
let tint: number;
let centerTint: number;
if (props.isSelected) {
tint = 0xBBBBFF;
centerTint = 0xBBBBFF;
} else {
tint = 0xFFFFFF;
centerTint = 0xFFFFFF;
}
if (props.isAllocated) {
tint = 0x444444;
} else {
}
let baseColor: number = 0;
if (props.pointNodeGen.resourceType === ResourceType.Nothing) {
baseColor = 0x99bbff; // blue that mixes in with bg
} else if (props.pointNodeGen.resourceType === ResourceType.Mana0) {
if (props.pointNodeGen.resourceModifier === ResourceModifier.Flat) {
baseColor = 0xeeaaaa; // pink
} else if (props.pointNodeGen.resourceModifier === ResourceModifier.Increased0) {
baseColor = 0xcc88ee; // lavender?
}
}
// switch (props.pointNodeGen.resourceType) {
// case ResourceType.Nothing:
// baseColor = 0x99bbff; // blue that mixes in with bg
// break;
// case ResourceType.Mana0:
// baseColor = 0xeeaaaa; // red
// break;
// case ResourceType.Mana1:
// baseColor = 0xbb7733; // brown?
// break;
// case ResourceType.Mana2:
// baseColor = 0x44aa44; // green
// break;
// }
this.sprite.tint = multiplyColor(baseColor, tint);
this.centerSprite.tint = multiplyColor(baseColor, centerTint);
if (props.selfPointNodeRef.pointNodeCoord.equals(Vector2.Zero)) {
this.container.scale = PixiPointFrom(new Vector2(1.25, 1.25));
}
}
updateSelf(props: Props) { }
shouldUpdate(prevProps: Props, props: Props): boolean {
for (let key of (Object.keys(prevProps) as (keyof Props)[])) {
if (key === 'delta' || key === 'args' || key === 'updaters') { continue; }
if (prevProps[key] !== props[key]) {
return true;
}
if (key === 'position') {
if (!prevProps[key].equals(props[key])) {
console.log(`chunk shouldUpdate differed in ${key}, returning true`);
return true;
} else {
continue;
}
}
if (key === 'selfPointNodeRef') {
if (prevProps[key]?.hash() !== props[key]?.hash()) {
console.log(`chunk shouldUpdate differed in ${key}, returning true`);
return true;
} else {
continue;
}
}
}
return false;
}
/** callback passed to child - since child is not a pure component, it needs to inform us of updates if otherwise we wouldnt update */
markForceUpdate = (childInstance: any) => {
this.staleProps.args.markForceUpdate(this); // mark us for update in OUR parent
for (let childInfo of this._children) {
if (childInfo.instance === childInstance) { // we found the instance in our _children array, now ensure it is in force updates array then return
if (this.forceUpdates.indexOf(childInfo) === -1) {
this.forceUpdates.push(childInfo);
}
return;
}
}
throw new Error(`Error, child ${childInstance} not found in ${this}`);
}
public didForceUpdateChild(instance: any) { }
public update(props: Props) {
// let staleState = { ...this.state };
this.updateSelf(props)
if (!this.shouldUpdate(this.staleProps, props)) {
// we think we don't need to update; however, we still need to
// update the chidlren that asked us to forcefully update them
let forceUpdates = [...this.forceUpdates];
this.forceUpdates = [];
for (let { instance, propsFactory } of forceUpdates) {
instance._update(propsFactory(props, this.state)); // why are we even calling props factory here?? theres no point... we should just tell the child to use their own stale props, like this:
// instance._forceUpdate();
// note that children can add themselves into forceupdate next tick as well, if they need to ensure they're continuously in there
this.didForceUpdateChild(instance);
}
// no need to do anything else -- stale props has not changed
return;
}
this.tooltippableArea?._update(this.tooltippableAreaPropsFactory(props, this.state));
this.renderSelf(props);
this.staleProps = props;
new Promise((resolve) => resolve(this.didUpdate()));
}
didMount() {
const { updaters } = this.staleProps; // we assume this will never change
// this.container.addListener('pointerover', (event: Pixi.InteractionEvent) => {
// this.state.pointerover = event;
// })
// this.container.addListener('pointerout', () => {
// this.state.pointerover = undefined;
// })
//
this.container.addListener("pointerdown", (event: Pixi.InteractionEvent) => {
this.state.numClicks++;
// event.stopPropagation();
// update selected to ourselves
updaters.playerUI.selectedPointNode.enqueueUpdate((prev, gameState) => {
if (prev?.pointNodeId === this.staleProps.selfPointNodeRef.pointNodeId) {
this.state.justTriedToAllocate = true;
}
return this.staleProps.selfPointNodeRef;
});
// if we tried to allocate ourselves, see if we can
updaters.playerSave.enqueueUpdate((prev, prevGameState) => {
if (this.state.justTriedToAllocate) {
this.state.justTriedToAllocate = false;
let [next, succeeded] = doTryAllocate(prev, prevGameState, this.staleProps.selfPointNodeRef);
if (succeeded) {
this.state.justSpentSp = true;
return next;
} else {
this.state.justFailedToAllocate = true;
return prev;
}
}
return prev;
});
// TODO(bowei): if we spent sp, remember to update quest status!!
updaters.enqueueUpdate((prev, prevGameState) => {
if (this.state.justSpentSp) {
this.state.justSpentSp = false;
return {
...prev,
playerSave: afterMaybeSpendingSp(prev.playerSave, prevGameState),
computed: {
...computePlayerResourceAmounts(prevGameState)
}
};
}
return prev;
})
// if we failed to allocate, shift the active tab so the player can see why
updaters.playerUI.activeTab.enqueueUpdate((prev, prevGameState) => {
if (this.state.justFailedToAllocate) {
console.log('just failed to allocate: ', this);
this.state.justFailedToAllocate = false;
return 1;
}
return prev;
});
});
}
public willUnmount() { }
public didUpdate() {
// console.log(`point node component ${this.staleProps.selfPointNodeRef.toString()} was updated`);
}
// bridge while we migrate to lifecycle handler
public _update(props: Props) { this.update(props); }
}
// const wrapped = engageLifecycle(PointNodeComponent2);
// // eslint-disable-next-line
// type wrapped = PointNodeComponent2;
// export { wrapped as PointNodeComponent };
// export type { Props as PointNodeComponentProps };
const wrapped = engageLifecycle(PointNodeComponent2);
// eslint-disable-next-line
type wrapped = PointNodeComponent2;
export { wrapped as PointNodeComponent };
export type { Props as PointNodeComponentProps };