msagent.js/web: Implement animation branching

This commit is contained in:
Lily Tsuru 2024-11-26 22:18:00 -05:00
parent 883ef7357c
commit 74743a1824
2 changed files with 51 additions and 5 deletions

View file

@ -92,7 +92,10 @@ export class AcsAnimationFrameInfo {
soundIndex = 0; soundIndex = 0;
frameDuration = 0; // The duration of the frame in (1/100)th seconds. frameDuration = 0; // The duration of the frame in (1/100)th seconds.
nextFrame = 0; // -2 = animation has ended (although, I imagine this could be detected in better ways!)
// Index of frame to go to when exiting a branch
// -2 = animation has ended/no exit? idk (although, I imagine this could be detected in better ways!)
branchExitFrameIndex = 0;
branchInfo: AcsBranchInfo[] = []; branchInfo: AcsBranchInfo[] = [];
overlayInfo: AcsOverlayInfo[] = []; overlayInfo: AcsOverlayInfo[] = [];
@ -106,7 +109,7 @@ export class AcsAnimationFrameInfo {
info.soundIndex = buffer.readS16LE(); info.soundIndex = buffer.readS16LE();
info.frameDuration = buffer.readU16LE(); info.frameDuration = buffer.readU16LE();
info.nextFrame = buffer.readS16LE(); info.branchExitFrameIndex = buffer.readS16LE();
info.branchInfo = buffer.readCountedList(() => { info.branchInfo = buffer.readCountedList(() => {
return AcsBranchInfo.read(buffer); return AcsBranchInfo.read(buffer);

View file

@ -1,4 +1,4 @@
import { BufferStream, SeekDir, imageDrawToBuffer } from '@msagent.js/core'; import { AcsBranchInfo, BufferStream, SeekDir, imageDrawToBuffer } from '@msagent.js/core';
import { AcsData } from '@msagent.js/core'; import { AcsData } from '@msagent.js/core';
import { ContextMenu, ContextMenuItem } from './contextmenu.js'; import { ContextMenu, ContextMenuItem } from './contextmenu.js';
import { AcsAnimation, AcsAnimationFrameInfo } from '@msagent.js/core'; import { AcsAnimation, AcsAnimationFrameInfo } from '@msagent.js/core';
@ -6,8 +6,6 @@ import { AcsImageEntry } from '@msagent.js/core';
import { Point, Size } from '@msagent.js/core'; import { Point, Size } from '@msagent.js/core';
import { wordballoonDrawImage, wordballoonDrawText } from './wordballoon.js'; import { wordballoonDrawImage, wordballoonDrawText } from './wordballoon.js';
function randint(min: number, max: number) { function randint(min: number, max: number) {
return Math.floor(Math.random() * (max - min) + min); return Math.floor(Math.random() * (max - min) + min);
} }
@ -42,6 +40,51 @@ class AgentAnimationState {
nextFrame() { nextFrame() {
requestAnimationFrame(() => { requestAnimationFrame(() => {
if (this.cancelled) return; if (this.cancelled) return;
// Handle animation branching, if it is required
let bi = this.anim.frameInfo[this.frameIndex].branchInfo;
if (bi.length != 0) {
let biCopy = [...bi];
// This happens more often then you'd think, but this basically handles
// a branch that will always be taken.
//
// This is often used for looping from my understanding?
if (bi.length == 1 && bi[0].branchFrameProbability == 100) {
this.frameIndex = bi[0].branchFrameIndex;
} else {
let probabilityOnlyList = bi.map((bii) => bii.branchFrameProbability);
let totalProbability = probabilityOnlyList.reduce((sum, pro) => {
return sum + pro;
});
// Handles the off chance that there is a branch info list that sums less than 100%.
// (Office Logo 'Idle3', Victor has a couple, ...)
//
// I'm not entirely sure the correct action in this case but I just
// have this do nothing.
if (totalProbability != 100) {
let nothingBranchItem = new AcsBranchInfo();
nothingBranchItem.branchFrameIndex = this.frameIndex;
nothingBranchItem.branchFrameProbability = 100 - totalProbability;
biCopy.push(nothingBranchItem);
}
// Pick a random branch
let randProbability = randint(0, 100);
let cumulativeProbability = 0;
for (const branchItem of biCopy) {
cumulativeProbability += branchItem.branchFrameProbability;
if (randProbability < cumulativeProbability) {
//console.log('picked', branchItem);
this.frameIndex = branchItem.branchFrameIndex;
break;
}
}
}
}
this.char.drawAnimationFrame(this.anim.frameInfo[this.frameIndex++]); this.char.drawAnimationFrame(this.anim.frameInfo[this.frameIndex++]);
if (this.frameIndex >= this.anim.frameInfo.length) { if (this.frameIndex >= this.anim.frameInfo.length) {