rd.rdlevel.cn/script/Extensions.js
2026-03-25 14:33:16 +08:00

1177 lines
46 KiB
JavaScript

// RhythmBase.View/Assets/AssetManager.ts
var Point = class _Point {
x = 0;
y = 0;
constructor(x, y) {
if (x !== void 0 && y !== void 0) {
this.x = x;
this.y = y;
return;
}
}
clone() {
return new _Point(this.x, this.y);
}
};
var Rect = class _Rect {
left = 0;
top = 0;
right = 0;
bottom = 0;
get x() {
return this.left;
}
set x(value) {
const diff = value - this.left;
this.left += diff;
this.right += diff;
}
get y() {
return this.top;
}
set y(value) {
const diff = value - this.top;
this.top += diff;
this.bottom += diff;
}
get width() {
return this.right - this.left;
}
set width(value) {
this.right = this.left + value;
}
get height() {
return this.bottom - this.top;
}
set height(value) {
this.bottom = this.top + value;
}
get centerX() {
return (this.left + this.right) / 2;
}
get centerY() {
return (this.top + this.bottom) / 2;
}
get location() {
let point = new Point();
point.x = this.centerX;
point.y = this.centerY;
return point;
}
set location(point) {
let w = this.width;
let h = this.height;
this.left = point.x;
this.right = this.left + w;
this.top = point.y;
this.bottom = this.top + h;
}
get isEmpty() {
return this.width <= 0 || this.height <= 0;
}
constructor(arg0, arg1, arg2, arg3) {
if (arg0 !== void 0 && arg1 !== void 0) {
if (arg2 !== void 0 && arg3 !== void 0) {
this.left = arg0;
this.top = arg1;
this.right = arg0 + arg2;
this.bottom = arg1 + arg3;
return;
}
this.right = arg0;
this.bottom = arg1;
return;
}
}
inflate(dx, dy) {
this.left -= dx;
this.right += dx;
this.top -= dy;
this.bottom += dy;
}
clone() {
return new _Rect(this.left, this.top, this.width, this.height);
}
union(rect) {
const left = Math.min(this.left, rect.left);
const top = Math.min(this.top, rect.top);
const right = Math.max(this.right, rect.right);
const bottom = Math.max(this.bottom, rect.bottom);
return new _Rect(left, top, right - left, bottom - top);
}
contains(point) {
return point.x >= this.left && point.x <= this.right && point.y >= this.top && point.y <= this.bottom;
}
};
var Color = class _Color {
red;
green;
blue;
alpha;
constructor(r, g, b, a) {
if (typeof r === "string") {
if (r.startsWith("#")) {
r = r.substring(1);
}
r = r.trim();
switch (r.length) {
case 3:
r = r.split("").map((c) => c + c).join("");
break;
case 4:
r = "ff" + r.split("").map((c) => c + c).join("");
break;
case 6:
r = "ff" + r;
break;
case 8:
break;
default:
r = "ffffffff";
}
const u = parseInt(r, 16);
this.alpha = u >> 24 & 255;
this.red = u >> 16 & 255;
this.green = u >> 8 & 255;
this.blue = u & 255;
return;
}
if (r !== void 0 && g === void 0 && b === void 0 && a === void 0) {
this.alpha = r >> 24 & 255;
this.red = r >> 16 & 255;
this.green = r >> 8 & 255;
this.blue = r & 255;
return;
}
if (r !== void 0 && g !== void 0 && b !== void 0 && a === void 0) {
this.red = r;
this.green = g;
this.blue = b;
this.alpha = 255;
return;
}
this.red = r ?? 0;
this.green = g ?? 0;
this.blue = b ?? 0;
this.alpha = a ?? 0;
}
toUint32() {
return ((this.alpha & 255) << 24 | (this.red & 255) << 16 | (this.green & 255) << 8 | this.blue & 255) >>> 0;
}
clone() {
return new _Color(this.red, this.green, this.blue, this.alpha);
}
};
var Paint = class {
color = new Color(255, 255, 255, 255);
};
var SliceInfo = class {
bounds = new Rect();
center = new Rect();
pivot = new Point();
scale = 1;
get isNinePatch() {
return !this.center.isEmpty;
}
};
var AssetManager = class _AssetManager {
static AssetFilePath = "assets.png";
static SlicesFilePath = "assets.json";
static DirectoryPath = ".";
static assetFile = null;
static slices = /* @__PURE__ */ new Map();
static _isLoaded = false;
constructor(dirpath) {
_AssetManager.DirectoryPath = dirpath;
_AssetManager.initialize();
}
static get isLoaded() {
return this._isLoaded;
}
static async loadAssetFile() {
const pngPath = _AssetManager.DirectoryPath + "/" + this.AssetFilePath;
return await new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = (e) => reject(new Error(`Failed to load asset file: ${pngPath}`));
img.src = pngPath;
});
}
static async loadSlices() {
if (this._isLoaded) {
return /* @__PURE__ */ new Map();
}
const jsonPath = _AssetManager.DirectoryPath + "/" + this.SlicesFilePath;
const response = await fetch(jsonPath);
const json = await response.json();
const slices = json["meta"]["slices"];
const sliceInfos = /* @__PURE__ */ new Map();
for (const slice of slices) {
const name = slice["name"];
const keys = slice["keys"];
const sliceInfo = new SliceInfo();
for (const key of keys) {
const bounds = key["bounds"];
sliceInfo.bounds.left = bounds["x"];
sliceInfo.bounds.top = bounds["y"];
sliceInfo.bounds.right = bounds["x"] + bounds["w"];
sliceInfo.bounds.bottom = bounds["y"] + bounds["h"];
const center = key["center"];
if (center) {
sliceInfo.center.left = center["x"];
sliceInfo.center.top = center["y"];
sliceInfo.center.right = center["x"] + center["w"];
sliceInfo.center.bottom = center["y"] + center["h"];
}
const pivot = key["pivot"];
if (pivot) {
sliceInfo.pivot.x = pivot["x"];
sliceInfo.pivot.y = pivot["y"];
}
const data = key["data"];
if (data) {
}
sliceInfos.set(name, sliceInfo);
}
}
return sliceInfos;
}
static async initialize() {
if (this._isLoaded) {
return;
}
this.assetFile = await this.loadAssetFile();
this.slices = await this.loadSlices();
this._isLoaded = true;
}
};
// RhythmBase.View/Assets/Consts.ts
var Tab = /* @__PURE__ */ function(Tab2) {
Tab2["Sounds"] = "sounds";
Tab2["Rows"] = "rows";
Tab2["Actions"] = "actions";
Tab2["Decorations"] = "decorations";
Tab2["Rooms"] = "rooms";
Tab2["Windows"] = "windows";
Tab2["Unknown"] = "unknown";
return Tab2;
}({});
var EventType = /* @__PURE__ */ function(EventType2) {
EventType2["AddClassicBeat"] = "AddClassicBeat";
EventType2["AddFreeTimeBeat"] = "AddFreeTimeBeat";
EventType2["AddOneshotBeat"] = "AddOneshotBeat";
EventType2["AdvanceText"] = "AdvanceText";
EventType2["BassDrop"] = "BassDrop";
EventType2["Blend"] = "Blend";
EventType2["CallCustomMethod"] = "CallCustomMethod";
EventType2["ChangeCharacter"] = "ChangeCharacter";
EventType2["ChangePlayersRows"] = "ChangePlayersRows";
EventType2["Comment"] = "Comment";
EventType2["CustomFlash"] = "CustomFlash";
EventType2["DesktopColor"] = "DesktopColor";
EventType2["FadeRoom"] = "FadeRoom";
EventType2["FinishLevel"] = "FinishLevel";
EventType2["Flash"] = "Flash";
EventType2["FlipScreen"] = "FlipScreen";
EventType2["FloatingText"] = "FloatingText";
EventType2["ForwardDecorationEvent"] = "ForwardDecorationEvent";
EventType2["ForwardEvent"] = "ForwardEvent";
EventType2["ForwardRowEvent"] = "ForwardRowEvent";
EventType2["HideRow"] = "HideRow";
EventType2["HideWindow"] = "HideWindow";
EventType2["InvertColors"] = "InvertColors";
EventType2["MacroEvent"] = "MacroEvent";
EventType2["MaskRoom"] = "MaskRoom";
EventType2["Move"] = "Move";
EventType2["MoveCamera"] = "MoveCamera";
EventType2["MoveRoom"] = "MoveRoom";
EventType2["MoveRow"] = "MoveRow";
EventType2["NarrateRowInfo"] = "NarrateRowInfo";
EventType2["NewWindowDance"] = "NewWindowDance";
EventType2["PaintHands"] = "PaintHands";
EventType2["PlayAnimation"] = "PlayAnimation";
EventType2["PlayExpression"] = "PlayExpression";
EventType2["PlaySong"] = "PlaySong";
EventType2["PlaySound"] = "PlaySound";
EventType2["PulseCamera"] = "PulseCamera";
EventType2["PulseFreeTimeBeat"] = "PulseFreeTimeBeat";
EventType2["ReadNarration"] = "ReadNarration";
EventType2["RenameWindow"] = "RenameWindow";
EventType2["ReorderRooms"] = "ReorderRooms";
EventType2["ReorderRow"] = "ReorderRow";
EventType2["ReorderSprite"] = "ReorderSprite";
EventType2["ReorderWindows"] = "ReorderWindows";
EventType2["SayReadyGetSetGo"] = "SayReadyGetSetGo";
EventType2["SetBackgroundColor"] = "SetBackgroundColor";
EventType2["SetBeatSound"] = "SetBeatSound";
EventType2["SetBeatsPerMinute"] = "SetBeatsPerMinute";
EventType2["SetClapSounds"] = "SetClapSounds";
EventType2["SetCountingSound"] = "SetCountingSound";
EventType2["SetCrotchetsPerBar"] = "SetCrotchetsPerBar";
EventType2["SetForeground"] = "SetForeground";
EventType2["SetGameSound"] = "SetGameSound";
EventType2["SetHandOwner"] = "SetHandOwner";
EventType2["SetHeartExplodeInterval"] = "SetHeartExplodeInterval";
EventType2["SetHeartExplodeVolume"] = "SetHeartExplodeVolume";
EventType2["SetMainWindow"] = "SetMainWindow";
EventType2["SetOneshotWave"] = "SetOneshotWave";
EventType2["SetPlayStyle"] = "SetPlayStyle";
EventType2["SetRoomContentMode"] = "SetRoomContentMode";
EventType2["SetRoomPerspective"] = "SetRoomPerspective";
EventType2["SetRowXs"] = "SetRowXs";
EventType2["SetSpeed"] = "SetSpeed";
EventType2["SetTheme"] = "SetTheme";
EventType2["SetVFXPreset"] = "SetVFXPreset";
EventType2["SetVisible"] = "SetVisible";
EventType2["SetWindowContent"] = "SetWindowContent";
EventType2["ShakeScreen"] = "ShakeScreen";
EventType2["ShakeScreenCustom"] = "ShakeScreenCustom";
EventType2["ShowDialogue"] = "ShowDialogue";
EventType2["ShowHands"] = "ShowHands";
EventType2["ShowRooms"] = "ShowRooms";
EventType2["ShowStatusSign"] = "ShowStatusSign";
EventType2["ShowSubdivisionsRows"] = "ShowSubdivisionsRows";
EventType2["SpinningRows"] = "SpinningRows";
EventType2["Stutter"] = "Stutter";
EventType2["TagAction"] = "TagAction";
EventType2["TextExplosion"] = "TextExplosion";
EventType2["Tile"] = "Tile";
EventType2["Tint"] = "Tint";
EventType2["TintRows"] = "TintRows";
EventType2["WindowResize"] = "WindowResize";
return EventType2;
}({});
var EventAttriblte = /* @__PURE__ */ function(EventAttriblte2) {
EventAttriblte2[EventAttriblte2["None"] = 0] = "None";
EventAttriblte2[EventAttriblte2["DurationEvent"] = 1] = "DurationEvent";
EventAttriblte2[EventAttriblte2["RoomEvent"] = 2] = "RoomEvent";
return EventAttriblte2;
}({});
var EventInfo = class {
defaultTab;
durationKey = "duration";
attr;
get isDurationEvent() {
return (this.attr & EventAttriblte.DurationEvent) !== 0;
}
get isRoomEvent() {
return (this.attr & EventAttriblte.RoomEvent) !== 0;
}
constructor(tab, enumAttriblte, durationKey) {
this.defaultTab = tab;
this.attr = enumAttriblte ?? EventAttriblte.None;
if (durationKey !== void 0) {
this.durationKey = durationKey;
}
}
};
var WordInfo = class {
phrase;
length;
constructor(phrase, length) {
this.phrase = phrase;
this.length = length;
}
};
var WordInfos = {
SayReaDyGetSetGoNew: new WordInfo("Rea, Dy, Get, Set, Go!", 4),
SayReaDyGetSetOne: new WordInfo("Rea, Dy, Get, Set, One!", 4),
SayGetSetGo: new WordInfo("Get, Set, Go!", 2),
SayGetSetOne: new WordInfo("Get, Set, One!", 2),
JustSayRea: new WordInfo("Rea", 0),
JustSayDy: new WordInfo("Dy", 0),
JustSayGet: new WordInfo("Get", 0),
JustSaySet: new WordInfo("Set", 0),
JustSayAnd: new WordInfo("And", 0),
JustSayGo: new WordInfo("Go!", 0),
JustSayStop: new WordInfo("Stop", 0),
JustSayAndStop: new WordInfo("And Stop!", 0),
SaySwitch: new WordInfo("Switch", 0),
SayWatch: new WordInfo("Watch", 0),
SayListen: new WordInfo("Listen", 0),
Count1: new WordInfo("1", 0),
Count2: new WordInfo("2", 0),
Count3: new WordInfo("3", 0),
Count4: new WordInfo("4", 0),
Count5: new WordInfo("5", 0),
Count6: new WordInfo("6", 0),
Count7: new WordInfo("7", 0),
Count8: new WordInfo("8", 0),
Count9: new WordInfo("9", 0),
Count10: new WordInfo("10", 0),
SayReadyGetSetGo: new WordInfo("Ready, Get, Set, Go!", 4),
JustSayReady: new WordInfo("Ready", 0)
};
var EventInfos = {
AddClassicBeat: new EventInfo(Tab.Rows),
AddFreeTimeBeat: new EventInfo(Tab.Rows),
AddOneshotBeat: new EventInfo(Tab.Rows),
AdvanceText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
BassDrop: new EventInfo(Tab.Actions),
Blend: new EventInfo(Tab.Decorations),
CallCustomMethod: new EventInfo(Tab.Actions),
ChangeCharacter: new EventInfo(Tab.Actions),
ChangePlayersRows: new EventInfo(Tab.Actions),
Comment: new EventInfo(Tab.Unknown),
CustomFlash: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
DesktopColor: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent),
FadeRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent),
FinishLevel: new EventInfo(Tab.Actions),
Flash: new EventInfo(Tab.Actions),
FlipScreen: new EventInfo(Tab.Actions),
FloatingText: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
ForwardDecorationEvent: new EventInfo(Tab.Decorations),
ForwardEvent: new EventInfo(Tab.Unknown),
ForwardRowEvent: new EventInfo(Tab.Rows),
HideRow: new EventInfo(Tab.Actions),
HideWindow: new EventInfo(Tab.Windows),
InvertColors: new EventInfo(Tab.Actions),
MacroEvent: new EventInfo(Tab.Unknown),
MaskRoom: new EventInfo(Tab.Rooms),
Move: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent),
MoveCamera: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
MoveRoom: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent),
MoveRow: new EventInfo(Tab.Rows, EventAttriblte.DurationEvent),
NarrateRowInfo: new EventInfo(Tab.Sounds),
NewWindowDance: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
PaintHands: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
PlayAnimation: new EventInfo(Tab.Decorations),
PlayExpression: new EventInfo(Tab.Actions),
PlaySong: new EventInfo(Tab.Sounds),
PlaySound: new EventInfo(Tab.Sounds),
PulseCamera: new EventInfo(Tab.Actions),
PulseFreeTimeBeat: new EventInfo(Tab.Rows),
ReadNarration: new EventInfo(Tab.Sounds),
RenameWindow: new EventInfo(Tab.Windows),
ReorderRooms: new EventInfo(Tab.Rooms),
ReorderRow: new EventInfo(Tab.Rows),
ReorderSprite: new EventInfo(Tab.Decorations),
ReorderWindows: new EventInfo(Tab.Windows),
SayReadyGetSetGo: new EventInfo(Tab.Sounds),
SetBackgroundColor: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
SetBeatSound: new EventInfo(Tab.Sounds),
SetBeatsPerMinute: new EventInfo(Tab.Sounds),
SetClapSounds: new EventInfo(Tab.Sounds),
SetCountingSound: new EventInfo(Tab.Sounds),
SetCrotchetsPerBar: new EventInfo(Tab.Sounds),
SetForeground: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
SetGameSound: new EventInfo(Tab.Sounds),
SetHandOwner: new EventInfo(Tab.Actions),
SetHeartExplodeInterval: new EventInfo(Tab.Sounds),
SetHeartExplodeVolume: new EventInfo(Tab.Sounds),
SetMainWindow: new EventInfo(Tab.Windows),
SetOneshotWave: new EventInfo(Tab.Rows),
SetPlayStyle: new EventInfo(Tab.Actions),
SetRoomContentMode: new EventInfo(Tab.Rooms),
SetRoomPerspective: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent),
SetRowXs: new EventInfo(Tab.Rows),
SetSpeed: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
SetTheme: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
SetVFXPreset: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
SetVisible: new EventInfo(Tab.Decorations),
SetWindowContent: new EventInfo(Tab.Windows, EventAttriblte.DurationEvent),
ShakeScreen: new EventInfo(Tab.Actions),
ShakeScreenCustom: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
ShowDialogue: new EventInfo(Tab.Actions),
ShowHands: new EventInfo(Tab.Actions),
ShowRooms: new EventInfo(Tab.Rooms, EventAttriblte.DurationEvent),
ShowStatusSign: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
ShowSubdivisionsRows: new EventInfo(Tab.Actions),
SpinningRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
Stutter: new EventInfo(Tab.Actions),
TagAction: new EventInfo(Tab.Actions),
TextExplosion: new EventInfo(Tab.Actions),
Tile: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent),
Tint: new EventInfo(Tab.Decorations, EventAttriblte.DurationEvent),
TintRows: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent),
WindowResize: new EventInfo(Tab.Actions, EventAttriblte.DurationEvent)
};
// RhythmBase.View/Extensions.ts
var PatchStyle = /* @__PURE__ */ function(PatchStyle2) {
PatchStyle2[PatchStyle2["Repeat"] = 0] = "Repeat";
PatchStyle2[PatchStyle2["Strentch"] = 1] = "Strentch";
return PatchStyle2;
}(PatchStyle || {});
var IconStyle = class {
Enabled;
Active = false;
Hover = false;
Scale = 2;
};
var Extensions = class {
static lineHeight = 6;
static charHeight = 8;
static iconSize = 14;
static evtag = "event_tag";
static evbarea = "event_beat_area";
static asm = new AssetManager("./rdviewAssets");
constructor() {
AssetManager.initialize();
}
static DrawSlice(canvas, src, dest, scale = 1, style = PatchStyle.Strentch, color) {
const ctx = canvas;
if (!ctx) return;
if (!AssetManager.slices.has(src)) {
return;
}
const info = AssetManager.slices.get(src);
if (dest instanceof Point) {
const destRect = new Rect(dest.x - info.pivot.x * scale, dest.y - info.pivot.y * scale, info.bounds.width * scale, info.bounds.height * scale);
if (color) {
if (color.alpha === 0) {
return destRect;
}
this.drawSliceWithColor(ctx, info, destRect, color);
} else {
this.drawSliceNormal(ctx, info, destRect);
}
return destRect;
} else {
if (info.isNinePatch) {
this.DrawNinePatch(canvas, info, dest, color, scale, style);
} else {
if (color) {
this.drawSliceWithColor(ctx, info, dest, color);
} else {
this.drawSliceNormal(ctx, info, dest);
}
}
}
}
static drawSliceNormal(ctx, info, destRect) {
const bitmap = AssetManager.assetFile;
if (!bitmap) return;
ctx.imageSmoothingEnabled = false;
ctx.drawImage(bitmap, info.bounds.x, info.bounds.y, info.bounds.width, info.bounds.height, destRect.x, destRect.y, destRect.width, destRect.height);
}
static drawSliceWithColor(ctx, info, destRect, color) {
const bitmap = AssetManager.assetFile;
if (!bitmap) return;
if (color.alpha === 0) {
return;
}
const tr = color.red / 255;
const tg = color.green / 255;
const tb = color.blue / 255;
const ta = color.alpha / 255;
ctx.save();
const tempCanvas = typeof document !== "undefined" ? document.createElement("canvas") : {};
tempCanvas.width = info.bounds.width;
tempCanvas.height = info.bounds.height;
const tempCtx = tempCanvas.getContext("2d");
tempCtx.imageSmoothingEnabled = false;
tempCtx.drawImage(bitmap, info.bounds.x, info.bounds.y, info.bounds.width, info.bounds.height, 0, 0, info.bounds.width, info.bounds.height);
const imageData = tempCtx.getImageData(0, 0, info.bounds.width, info.bounds.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
const originalAlpha = data[i + 3];
const gray = data[i] * 0.2126 + data[i + 1] * 0.7152 + data[i + 2] * 0.0722;
data[i] = gray * tr;
data[i + 1] = gray * tg;
data[i + 2] = gray * tb;
data[i + 3] = originalAlpha * ta;
}
tempCtx.putImageData(imageData, 0, 0);
ctx.imageSmoothingEnabled = false;
ctx.globalAlpha = 1;
ctx.drawImage(tempCanvas, 0, 0, info.bounds.width, info.bounds.height, destRect.x, destRect.y, destRect.width, destRect.height);
ctx.restore();
}
static DrawNinePatch(canvas, info, dest, color, scale = 1, style = PatchStyle.Strentch) {
const ctx = canvas;
if (!ctx) return;
const bitmap = AssetManager.assetFile;
if (!bitmap) return;
const srcBounds = info.bounds;
const destRect = dest;
const centerBounds = info.center;
const sx0 = srcBounds.left;
const sx3 = srcBounds.right;
const sy0 = srcBounds.top;
const sy3 = srcBounds.bottom;
const sx1 = sx0 + centerBounds.left;
const sx2 = sx0 + centerBounds.right;
const sy1 = sy0 + centerBounds.top;
const sy2 = sy0 + centerBounds.bottom;
const swLeft = sx1 - sx0;
const swCenter = sx2 - sx1;
const swRight = sx3 - sx2;
const shTop = sy1 - sy0;
const shCenter = sy2 - sy1;
const shBottom = sy3 - sy2;
const dwLeft = swLeft * scale;
let dwRight = swRight * scale;
let dwCenter = destRect.width - dwLeft - dwRight;
if (dwCenter < 0) {
const scaleX = destRect.width / Math.max(1, swLeft + swRight);
dwRight = Math.max(0, destRect.width - Math.round(swLeft * scaleX));
dwCenter = 0;
}
const dhTop = shTop * scale;
let dhBottom = shBottom * scale;
let dhCenter = destRect.height - dhTop - dhBottom;
if (dhCenter < 0) {
const scaleY = destRect.height / Math.max(1, shTop + shBottom);
dhBottom = Math.max(0, destRect.height - Math.round(shTop * scaleY));
dhCenter = 0;
}
const srcXs = [
sx0,
sx1,
sx2,
sx3
];
const srcYs = [
sy0,
sy1,
sy2,
sy3
];
const dx0 = destRect.left;
const dx1 = dx0 + dwLeft;
const dx2 = dx1 + dwCenter;
const dx3 = destRect.right;
const dy0 = destRect.top;
const dy1 = dy0 + dhTop;
const dy2 = dy1 + dhCenter;
const dy3 = destRect.bottom;
const dstXs = [
dx0,
dx1,
dx2,
dx3
];
const dstYs = [
dy0,
dy1,
dy2,
dy3
];
for (let row = 0; row < 3; row++) {
for (let col = 0; col < 3; col++) {
const sLeft = srcXs[col];
const sTop = srcYs[row];
const sRight = srcXs[col + 1];
const sBottom = srcYs[row + 1];
const sW = sRight - sLeft;
const sH = sBottom - sTop;
if (sW <= 0 || sH <= 0) continue;
const dLeft = dstXs[col];
const dTop = dstYs[row];
const dRight = dstXs[col + 1];
const dBottom = dstYs[row + 1];
const dW = dRight - dLeft;
const dH = dBottom - dTop;
if (dW <= 0 || dH <= 0) continue;
if (style === PatchStyle.Repeat) {
for (let y = dTop; y < dBottom; y += sH * scale) {
const th = Math.min(sH, (dBottom - y) / scale);
for (let x = dLeft; x < dRight; x += sW * scale) {
const tw = Math.min(sW, (dRight - x) / scale);
var sRect = new Rect(sLeft, sTop, tw, th);
var dRect = new Rect(x, y, tw * scale, th * scale);
if (color && color.alpha > 0) {
this.drawSliceWithColor(ctx, {
bounds: sRect,
pivot: new Point(0, 0),
isNinePatch: false,
center: new Rect(),
scale: 1
}, dRect, color);
} else {
this.drawSliceNormal(ctx, {
bounds: sRect,
pivot: new Point(0, 0),
isNinePatch: false,
center: new Rect(),
scale: 1
}, dRect);
}
}
}
} else {
if (color && color.alpha > 0) {
this.drawSliceWithColor(ctx, {
bounds: new Rect(sLeft, sTop, sW, sH),
pivot: new Point(0, 0),
isNinePatch: false,
center: new Rect(),
scale: 1
}, new Rect(dLeft, dTop, dW, dH), color);
} else {
ctx.imageSmoothingEnabled = false;
ctx.drawImage(bitmap, sLeft, sTop, sW, sH, dLeft, dTop, dW, dH);
}
}
}
}
}
static MeasureRDFontText(canvas, text, scale = 1) {
let len = 0;
for (let i = 0; i < text.length; i++) {
const c = text.charAt(i);
if (c === "\n") {
len = 0;
} else {
const info = AssetManager.slices.get(`char_${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
if (info) {
len += info.bounds.width * scale;
}
}
}
return len;
}
static DrawRDFontText(canvas, text, dest, color, scale = 1) {
const start = dest.clone();
const result = new Rect();
start.y -= this.lineHeight * scale;
for (let i = 0; i < text.length; i++) {
const c = text.charAt(i);
if (c === "\n") {
start.x = dest.x;
start.y += this.lineHeight * scale;
continue;
} else {
const charcode = c.charCodeAt(0).toString(16).padStart(4, "0");
const area = this.DrawSlice(canvas, `char_${charcode}`, start, scale, PatchStyle.Strentch, color);
result.union(area);
start.x += area.width * scale;
}
}
return result;
}
static DrawEventIcon(canvas, evt, dest, style) {
let destRect = new Rect();
const key = `event_${evt.type}`;
const evttype = evt.type;
const info = AssetManager.slices.get(key) ?? AssetManager.slices.get("event_Unknown") ?? (() => {
throw new Error("information not found.");
});
if (!(info instanceof SliceInfo)) {
return new Rect();
}
const pulse = "event_beat_pulse";
const hit = "event_beat_hit";
const hitf = "event_beat_hit_freeze";
const hitb = "event_beat_hit_burn";
const beatcross = "event_beat_cross";
const beatx = "event_beat_x";
const beatsynco = "event_beat_synco";
const beatline = "event_beat_line";
const beatcolor = new Color(4284539717);
const evtInfo = EventInfos[evt.type];
evt.tab = evt.tab ?? evtInfo.defaultTab;
switch (evt.type) {
case EventType.AddClassicBeat:
{
const tick = evt.tick ?? 1;
const swing = evt.swing === 0 ? 1 : evt.swing;
const hold = evt.hold ?? 0;
const syncoswing = evt.syncoSwing ?? 0;
const syncobeat = evt.syncoBeat ?? -1;
const classicbeatlength = evt.length ?? 7;
destRect = new Rect(dest.x, dest.y, this.iconSize * style.Scale * (tick * (classicbeatlength - 1 - (syncoswing ?? 0))), this.iconSize * style.Scale);
if (hold > 0) {
this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width, dest.y, this.iconSize * style.Scale * hold, this.iconSize * style.Scale), style.Scale, PatchStyle.Repeat, new Color(style.Active ? 4291839731 : 4286462352));
}
this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style);
if (style.Hover) {
for (let i = 0; i < classicbeatlength - 1; i++) {
this.DrawSlice(canvas, pulse, new Point(dest.x + this.iconSize * style.Scale * (tick * (i + i % 2 * (1 - (swing ?? 1)) - (i <= (syncobeat ?? -1) ? 0 : syncoswing ?? 0))), dest.y), style.Scale);
}
}
this.DrawSlice(canvas, hit, new Point(dest.x + style.Scale * (this.iconSize * (tick * (classicbeatlength - 1 - (syncoswing ?? 0))) - 1), dest.y), style.Scale);
}
break;
case EventType.AddFreeTimeBeat:
{
const hold = (evt.hold ?? 0) - info.bounds.width / this.iconSize;
destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * style.Scale);
this.DrawBack(canvas, destRect.clone(), this.WithState(beatcolor.clone(), style.Active, style.Enabled ?? evt.active ?? true), style);
this.DrawRDFontText(canvas, ((evt.pulse ?? 0) + 1).toString(), new Point(dest.x + 1.5 * style.Scale, dest.y + 10 * style.Scale), new Color(4294967295), style.Scale);
if ((evt.pulse ?? 0) == 6) {
this.DrawSlice(canvas, hit, new Point(dest.x, dest.y), style.Scale);
}
if (hold > 0) {
this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width, dest.y, this.iconSize * style.Scale * hold, info.bounds.height * style.Scale), style.Scale, PatchStyle.Repeat, new Color(style.Active ? 4284539717 : 4281299234));
}
}
break;
case EventType.AddOneshotBeat:
{
const tick = evt.tick ?? 1;
const interval = evt.interval ?? 1;
const loop = Math.floor(evt.loops ?? 0);
const subdiv = evt.subdivisions ?? 1;
const freezeBurnMode = evt.freezeBurnMode ?? "Wave";
const delay = freezeBurnMode === "Freezeshot" ? evt.delay ?? 0 : 0;
destRect = new Rect(dest.x, dest.y, this.iconSize * style.Scale * (loop * interval + tick + delay), this.iconSize * style.Scale);
this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style);
const subdivwidth = this.iconSize * style.Scale * (subdiv - 1) / subdiv * tick;
if (subdiv > 1) {
this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width, dest.y, subdivwidth, info.bounds.height * style.Scale), style.Scale, PatchStyle.Repeat, new Color(4279480353));
}
if (evt.skipshot ?? false) {
this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width + subdivwidth, dest.y, style.Scale * this.iconSize * interval - subdivwidth, info.bounds.height * style.Scale), style.Scale, PatchStyle.Repeat, new Color(4291115835));
}
if (style.Hover) {
for (let l = 0; l <= loop; l++) {
for (let i = 0; i < subdiv; i++) {
this.DrawSlice(canvas, pulse, new Point(dest.x + this.iconSize * style.Scale * (l * interval + i * tick / subdiv), dest.y), style.Scale);
}
}
}
for (let l = 0; l <= loop; l++) {
for (let i = 0; i < subdiv; i++) {
this.DrawSlice(canvas, hit, new Point(dest.x + style.Scale * (this.iconSize * (l * interval + delay + tick + i * tick / subdiv) - 1), dest.y), style.Scale);
}
}
const off = interval - tick;
if (freezeBurnMode !== "Wave") {
let posx = dest.x - off * style.Scale * this.iconSize;
this.DrawSlice(canvas, beatcross, new Point(posx, dest.y), style.Scale);
switch (freezeBurnMode) {
case "Freezeshot":
posx += delay * style.Scale * this.iconSize;
this.DrawSlice(canvas, beatcross, new Point(posx, dest.y), style.Scale);
for (let l = 0; l <= loop; l++) {
this.DrawSlice(canvas, hitf, new Point(dest.x + style.Scale * (this.iconSize * (l * interval + tick) - 1), dest.y), style.Scale);
}
break;
case "Burnshot":
posx -= tick * style.Scale * this.iconSize;
this.DrawSlice(canvas, beatcross, new Point(posx, dest.y), style.Scale);
for (let l = 0; l <= loop; l++) {
this.DrawSlice(canvas, hitb, new Point(dest.x + style.Scale * (this.iconSize * (l * interval + tick) - 1), dest.y), style.Scale);
}
break;
default:
break;
}
}
if (style.Active && style.Hover) {
this.DrawSlice(canvas, "event_beat_loop", new Point(destRect.right, destRect.top), style.Scale);
}
}
break;
case EventType.Comment:
{
const commentColor = new Color(evt.color);
console.log(evt.color, commentColor);
destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * style.Scale);
this.DrawBack(canvas, destRect.clone(), this.WithState(commentColor, style.Active, style.Enabled ?? evt.active ?? true), style);
this.DrawSlice(canvas, key, dest, style.Scale);
}
break;
case EventType.DesktopColor:
{
destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * 4 * style.Scale);
this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style);
const endColor = new Color(evt.endColor);
this.DrawSlice(canvas, `${key}_0`, new Point(dest.x, dest.y + info.bounds.height * style.Scale), style.Scale, PatchStyle.Strentch, endColor);
this.DrawSlice(canvas, key, new Point(dest.x, dest.y + info.bounds.height * style.Scale), style.Scale);
}
break;
case EventType.PulseFreeTimeBeat:
{
const hold = (evt.hold ?? 0) - info.bounds.width / this.iconSize;
destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * style.Scale);
this.DrawBack(canvas, destRect.clone(), this.WithState(beatcolor.clone(), style.Active, style.Enabled ?? evt.active ?? true), style);
let actionText;
switch (evt.action) {
case "Increment":
actionText = ">";
break;
case "Decrement":
actionText = "<";
break;
case "Remove":
actionText = "x";
break;
case "Custom":
default:
actionText = ((evt.customPulse ?? 0) + 1).toString();
break;
}
this.DrawRDFontText(canvas, actionText, new Point(dest.x + 1.5 * style.Scale, dest.y + 8 * style.Scale), new Color(4294967295), style.Scale);
if (evt.action === "Custom" && (evt.customPulse ?? 0) === 7) {
this.DrawSlice(canvas, hit, new Rect(dest.x - 2 * style.Scale, dest.y, 5 * style.Scale, info.bounds.height * style.Scale), style.Scale, PatchStyle.Strentch);
}
if (hold > 0) {
this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width, dest.y, this.iconSize * style.Scale * hold, info.bounds.height * style.Scale), style.Scale, PatchStyle.Repeat, new Color(style.Active ? 4291839731 : 4286462352));
}
}
break;
case EventType.ReorderRooms:
{
destRect = new Rect(dest.x, dest.y, this.iconSize * style.Scale, this.iconSize * 4 * style.Scale);
this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style);
let currentDest = dest.clone();
if (evt.order && Array.isArray(evt.order)) {
for (const r of evt.order) {
this.DrawSlice(canvas, `${key}_${r}`, currentDest.clone(), style.Scale);
currentDest.y += this.iconSize * style.Scale;
}
}
}
break;
case EventType.ReorderWindows:
{
destRect = new Rect(dest.x, dest.y, this.iconSize * style.Scale, this.iconSize * 4 * style.Scale);
this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style);
let currentDest = dest.clone();
if (evt.order && Array.isArray(evt.order)) {
for (const r of evt.order) {
this.DrawSlice(canvas, `${key}_${r}`, currentDest.clone(), style.Scale);
currentDest.y += this.iconSize * style.Scale;
}
}
}
break;
case EventType.SayReadyGetSetGo:
{
const wordInfo = WordInfos[evt.phraseToSay];
const len = wordInfo.length * evt.tick + 1;
destRect = new Rect(dest.x, dest.y, len * this.iconSize * style.Scale, this.iconSize * style.Scale);
this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style);
const stringToJion = wordInfo.phrase.split(" ");
let stringToDraw = [
stringToJion[0]
];
let lw = this.MeasureRDFontText(canvas, stringToJion[0]);
const sw = this.MeasureRDFontText(canvas, " ");
for (let i = 1; i < stringToJion.length; i++) {
const part = stringToJion[i];
const w = this.MeasureRDFontText(canvas, part);
if (lw + sw + w > (len * this.iconSize - 2) * style.Scale) {
lw = w;
stringToDraw.push(part);
} else {
lw += sw + w;
stringToDraw[stringToDraw.length - 1] += " " + part;
}
}
stringToDraw.splice(3);
const c = stringToDraw.length;
const top = dest.y + (this.iconSize - this.charHeight * c / 2) * style.Scale / 2;
for (let i = 0; i < c; i++) {
const line = stringToDraw[i];
const p = new Point(dest.x + (len * this.iconSize * style.Scale - this.MeasureRDFontText(canvas, line, style.Scale / 2)) / 2, top + (i * this.charHeight + this.lineHeight) * style.Scale / 2);
this.DrawRDFontText(canvas, line, p, new Color(4294967295), style.Scale / 2);
}
}
break;
case EventType.SetRowXs:
{
destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * style.Scale);
this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style);
const width = info.bounds.width * style.Scale / 6;
const beatxInfo = AssetManager.slices.get(beatx);
if (!beatxInfo) break;
const iconwidth = beatxInfo.bounds.width;
const s = width / iconwidth;
let left = 0;
const top = this.iconSize * style.Scale / 2 - beatxInfo.bounds.height * s / 2;
if (evt.pattern) {
const pattern = evt.pattern;
for (const p of pattern) {
const patternKey = p === "x" ? beatx : beatline;
this.DrawSlice(canvas, patternKey, new Rect(dest.x + left, dest.y + top, width, beatxInfo.bounds.height * s), style.Scale, PatchStyle.Strentch);
left += width;
}
}
if ((evt.syncoBeat ?? -1) >= 0) {
this.DrawSlice(canvas, beatsynco, new Rect(dest.x + width * (evt.syncoBeat ?? 0), dest.y + top, width, beatxInfo.bounds.height * s), style.Scale, PatchStyle.Strentch);
}
}
break;
case EventType.ShowRooms:
{
destRect = new Rect(dest.x, dest.y, this.iconSize * style.Scale, this.iconSize * 4 * style.Scale);
this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style);
if (evt.rooms && Array.isArray(evt.rooms)) {
for (let i = 0; i < 4; i++) {
const roomState = evt.rooms[i] ? "1" : "0";
this.DrawSlice(canvas, `${key}_${roomState}`, new Point(dest.x, dest.y + i * this.iconSize * style.Scale), style.Scale / 2);
}
}
}
break;
default:
destRect = new Rect(dest.x, dest.y, info.bounds.width * style.Scale, info.bounds.height * style.Scale);
this.DrawBack(canvas, destRect.clone(), this.WithState(this.ColorOf(evt.tab), style.Active, style.Enabled ?? evt.active ?? true), style);
switch (evt.type) {
case EventType.CustomFlash:
{
this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.startColor ?? 0));
this.DrawSlice(canvas, `${key}_1`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.endColor ?? 0));
}
break;
case EventType.FlipScreen:
{
let suffix = "";
const flipX = evt.flipX ?? false;
const flipY = evt.flipY ?? false;
if (flipX && flipY) {
suffix = "_2";
} else if (flipX && !flipY) {
suffix = "_1";
} else if (!flipX && flipY) {
suffix = "_0";
}
this.DrawSlice(canvas, key + suffix, dest, style.Scale);
}
break;
case EventType.FloatingText:
{
this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.color ?? 0));
this.DrawSlice(canvas, `${key}_1`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.outlineColor ?? 0));
}
break;
case EventType.MoveRoom:
{
canvas.save();
const degree = evt.angle ?? 0;
const scaleWidth = evt.scale?.width ?? 0;
const scaleHeight = evt.scale?.height ?? 0;
if (scaleWidth === 0 || scaleHeight === 0) {
canvas.restore();
break;
}
const pleft = (evt.pivot?.x ?? 0) / 100;
const ptop = 1 - (evt.pivot?.y ?? 0) / 100;
const uniform = Math.sqrt(scaleWidth * scaleWidth + scaleHeight * scaleHeight);
const w = scaleWidth / uniform;
const h = scaleHeight / uniform;
canvas.translate(dest.x + destRect.width / 2, dest.y + destRect.height / 2);
canvas.rotate(-degree * Math.PI / 180);
canvas.scale(w, h);
this.DrawSlice(canvas, key, new Point(-destRect.width / 2, -destRect.height / 2), style.Scale);
if (!(pleft < 0 || pleft > 1 || ptop < 0 || ptop > 1)) {
canvas.fillStyle = "rgb(255, 0, 0)";
canvas.fillRect((pleft - 0.5) * destRect.width - 1, (ptop - 0.5) * destRect.height - 1, 2, 2);
}
canvas.restore();
}
break;
case EventType.PaintHands:
{
this.DrawSlice(canvas, key, dest, style.Scale, PatchStyle.Strentch, new Color(evt.tintColor ?? 0));
const border = evt.border ?? "None";
if (border === "Outline") {
this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0));
} else if (border === "Glow") {
this.DrawSlice(canvas, `${key}_1`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0));
}
}
break;
case EventType.SetBackgroundColor:
{
this.DrawSlice(canvas, key, dest, style.Scale);
const bgType = evt.backgroundType ?? "Color";
if (bgType === "Color") {
this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.color ?? 0));
} else if (bgType === "Image") {
this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(4294967295));
}
}
break;
case EventType.SetCrotchetsPerBar:
{
const cpb = evt.crotchetsPerBar ?? 4;
this.DrawSlice(canvas, key, dest, style.Scale);
this.DrawRDFontText(canvas, cpb > 9 ? "-" : cpb.toString(), new Point(dest.x + 2 * style.Scale, dest.y + 7 * style.Scale), new Color(4278190080), style.Scale);
this.DrawRDFontText(canvas, "4", new Point(dest.x + 8 * style.Scale, dest.y + 12 * style.Scale), new Color(4278190080), style.Scale);
}
break;
case EventType.SetForeground:
{
this.DrawSlice(canvas, key, dest, style.Scale);
}
break;
case EventType.Tint:
{
this.DrawSlice(canvas, key, dest, style.Scale, PatchStyle.Strentch, new Color(evt.tintColor ?? 0));
const border = evt.border ?? "None";
if (border === "Outline") {
this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0));
} else if (border === "Glow") {
this.DrawSlice(canvas, `${key}_1`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0));
}
}
break;
case EventType.TintRows:
{
this.DrawSlice(canvas, key, dest, style.Scale, PatchStyle.Strentch, new Color(evt.tintColor ?? 0));
const border = evt.border ?? "None";
if (border === "Outline") {
this.DrawSlice(canvas, `${key}_0`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0));
} else if (border === "Glow") {
this.DrawSlice(canvas, `${key}_1`, dest, style.Scale, PatchStyle.Strentch, new Color(evt.borderColor ?? 0));
}
}
break;
default:
this.drawSliceNormal(canvas, info, destRect);
break;
}
break;
}
if (evtInfo.isDurationEvent) {
evt.duration = 2;
}
if (evt.duration && evt.duration > 0 && style.Active) {
const duration = evt[evtInfo.durationKey];
const durWidth = style.Scale * this.iconSize * duration - destRect.width;
const c = this.ColorOf(evt.tab);
c.alpha = style.Active ? 192 : 91;
if (durWidth > 0) {
this.DrawSlice(canvas, this.evbarea, new Rect(dest.x + destRect.width, dest.y, durWidth, destRect.height), style.Scale, PatchStyle.Repeat, c);
}
}
return destRect;
}
static ColorOf(tab) {
switch (tab) {
case "sounds":
return new Color(4292355123);
case "rows":
return new Color(4281094105);
case "actions":
return new Color(4291118003);
case "decorations":
return new Color(4278240345);
case "rooms":
return new Color(4292392978);
case "windows":
return new Color(4283479511);
default:
return new Color(4286874756);
}
}
static DrawBack(canvas, destRect, color, style) {
const outline = "event_outline";
const back = "event_back";
this.DrawSlice(canvas, outline, destRect, style.Scale, PatchStyle.Strentch, new Color(style.Active ? 4294967295 : 4289243304));
destRect.inflate(-style.Scale, -style.Scale);
this.DrawSlice(canvas, back, destRect, style.Scale, PatchStyle.Strentch, color);
}
static WithState(color, active, enabled) {
const c = enabled ? color.clone() : new Color(4286874756);
c.alpha = active ? 192 : 91;
return c;
}
};
export {
AssetManager,
Color,
Extensions,
IconStyle,
Paint,
Point,
Rect,
SliceInfo
};