import { createElementEvent } from "./rdtkview.js"; function loadRDView() { window.RDViewRender = RDViewRender; } class Color { constructor(red, green, blue, alpha) { this.red = red; this.green = green; this.blue = blue; this.alpha = alpha; } ; } var EventCondition; (function (EventCondition) { EventCondition["true"] = "true"; EventCondition["false"] = "false"; EventCondition["both"] = "both"; })(EventCondition || (EventCondition = {})); class RDViewWindow { constructor() { this.Row = 4; this.Column = 8; this.Scale = 1; } } class RDEvent { constructor() { this.Name = ""; this.PrefixTab = undefined; this.Properties = []; this.Style = { Beat: 0, Y: 0 }; } } class RDStyle { constructor() { this.Beat = 0; this.Y = 0; } } class RDGroup { constructor() { this.Width = 1; this.Height = 1; this.Outline = new Color(255, 0, 0, 255); this.Style = new RDStyle(); this.ClickStyle = new RDStyle(); this.Children = []; } } function RDViewRender(lang, code) { const view = new RDViewWindow(); var objs = []; try { objs = ReadObjs(code); } catch (error) { return ErrorElement(`${error}`); } const args = lang.split(/\s+/g); if (1 < args.length && args.length <= 4) { if (args[1]) { view.Column = parseInt(args[1]); } if (args[2]) { view.Row = parseInt(args[2]); } if (args[3]) { view.Scale = parseFloat(args[3]); } } return ConstructObjs(view, objs); } function ErrorElement(message = "") { const el = document.createElement("div"); el.className = "rdtk-error"; el.textContent = message; return el; } function PrefixToTab(prefix) { switch (prefix) { case "es": return "Sounds"; case "eb": return "Rows"; case "ea": return "Actions"; case "ed": return "Sprites"; case "er": return "Rooms"; case "ec": return "Unknown"; default: return undefined; } } function ReadObjs(line) { const objs = []; var reader = new Reader(line); while (!reader.IsEnd()) { var event; var name = ""; var prefix = ""; try { name = reader.ReadSymbol(); if (reader.TestRead('.', false)) { prefix = name; name = reader.ReadSymbol(); } } catch (e) { name = ""; } if (name.toLowerCase() === 'g') { event = new RDGroup(); } else { const ev = new RDEvent(); ev.Name = name; ev.PrefixTab = PrefixToTab(prefix); event = ev; } if (event instanceof RDEvent) { try { event.Style.Beat = reader.ReadFloat(); } catch (e) { } try { event.Style.Y = reader.ReadInt(); } catch (e) { } if (reader.TestPeek('[')) { const pairString = reader.ReadQuoted('[', ']'); const keyvalues = new Reader(pairString, reader).ReadPairs(); ReadProperties(reader, event, keyvalues); } reader.TestRead(';', true); } else if (event instanceof RDGroup) { try { event.Style.Beat = reader.ReadFloat(); } catch (e) { } try { event.Style.Y = reader.ReadInt(); } catch (e) { } try { event.Width = reader.ReadFloat(); } catch (e) { } try { event.Height = reader.ReadInt(); } catch (e) { } try { event.Outline = reader.ReadColor(); } catch (e) { } if (reader.TestPeek('[')) { const pairString = reader.ReadQuoted('[', ']'); const keyvalues = new Reader(pairString, reader).ReadPairs(); ReadProperties(reader, event, keyvalues); } if (reader.TestPeek('{')) { const pairString = reader.ReadQuoted('{', '}'); const objs2 = ReadObjs(pairString); event.Children = objs2; } reader.TestRead(';', true); } objs.push(event); } return objs; } function IsEmptyOrSpace(string) { return (string) ? /\s/.test(string) : false; } class Reader { constructor(string, reader = undefined) { this.position = 0; this.line = 0; this.offl = 0; this.offp = 0; this.string = string; if (reader) { this.offl = reader.line; this.offp = reader.position; } } ; IsEnd() { this.JumpSpace(); return this.position >= this.string.length; } JumpSpace() { while (IsEmptyOrSpace(this.string[this.position])) { if (this.string[this.position] === '\n') { this.line++; } this.position++; } } Peek() { this.JumpSpace(); return this.string[this.position]; } TestPeek(str, allowThrow = false) { this.JumpSpace(); var c = this.string.substring(this.position, this.position + str.length); if (c === str) { return true; } else { if (allowThrow) { throw new Error(`Expecting a string '${str}' but got '${c}': ${this.GetPositionDescription()}.`); } else { return false; } } } TestRead(str, allowThrow = false) { this.JumpSpace(); var c = this.string.substring(this.position, this.position + str.length); if (c === str) { this.position++; return true; } else { if (allowThrow) { throw new Error(`Expecting a char '${str}' but got '${c}': ${this.GetPositionDescription()}.`); } else { return false; } } } ReadChar() { var c = this.string[this.position]; if (c === '\n') { this.line++; } this.position++; return c; } ReadSymbol() { var _a; this.JumpSpace(); var name = (_a = this.string.substring(this.position).match(/^\w+/)) === null || _a === void 0 ? void 0 : _a[0]; if (name) { this.position += name.length; return name; } throw new Error(`Expecting a key but missing: ${this.GetPositionDescription()}.`); } ReadColor() { var _a; this.JumpSpace(); var color = (_a = this.string.substring(this.position).match(/^#[0-9A-Fa-f]{3}([0-9A-Fa-f]{1}([0-9A-Fa-f]{2}([0-9A-Fa-f]{2})?)?)?/)) === null || _a === void 0 ? void 0 : _a[0].substring(1); if (!color) { throw new Error(`Expecting a color but missing: ${this.GetPositionDescription()}`); } var result; switch (color.length) { case 3: result = new Color(parseInt(color.substring(0, 1), 16) * 16, parseInt(color.substring(1, 2), 16) * 16, parseInt(color.substring(2, 3), 16) * 16, 255); break; case 4: result = new Color(parseInt(color.substring(0, 1), 16) * 16, parseInt(color.substring(1, 2), 16) * 16, parseInt(color.substring(2, 3), 16) * 16, parseInt(color.substring(3, 4), 16) * 16); break; case 6: result = new Color(parseInt(color.substring(0, 2), 16), parseInt(color.substring(2, 4), 16), parseInt(color.substring(4, 6), 16), 255); break; case 8: result = new Color(parseInt(color.substring(0, 2), 16), parseInt(color.substring(2, 4), 16), parseInt(color.substring(4, 6), 16), parseInt(color.substring(6, 8), 16)); break; default: result = new Color(255, 0, 0, 255); break; } this.position += color.length + 1; return result; } ReadInt() { var _a; this.JumpSpace(); var name = (_a = this.string.substring(this.position).match(/^[+-]?[0-9]+/)) === null || _a === void 0 ? void 0 : _a[0]; if (name) { this.position += name.length; return parseInt(name); } throw new Error(`Expecting an int but missing: ${this.GetPositionDescription()}.`); } ReadFloat() { var _a; this.JumpSpace(); var name = (_a = this.string.substring(this.position).match(/^[+-]?([0-9]*[.])?[0-9]+/)) === null || _a === void 0 ? void 0 : _a[0]; if (name) { this.position += name.length; return parseFloat(name); } throw new Error(`Expecting a float but missing: ${this.GetPositionDescription()}.`); } ReadPairs(separator = ',', equals = '=') { var pairs = []; var flag = !this.IsEnd(); while (flag) { if (this.IsEnd()) { break; } const index = this.position + this.offp; const name = this.ReadSymbol(); this.TestRead(equals, true); const value = this.ReadWhileNotEnd([separator]); pairs.push({ Key: name, Value: value, Index: index }); if (flag = !this.IsEnd()) { this.TestRead(separator, true); } } return pairs; } ReadWhileNotEnd(ends = [',', ']']) { var str = ''; while (!(this.position >= this.string.length) && !ends.find(i => this.string.startsWith(i, this.position))) { str += this.string[this.position]; this.position++; } return str.trim(); } ReadQuoted(left, right) { this.JumpSpace(); var level = 0; var result = ''; if (this.string.startsWith(left, this.position)) { level++; this.position += left.length; } else { throw new Error(`Cannot find the left half "${left}": ${this.GetPositionDescription()}`); } while (!(this.position >= this.string.length) && level > 0) { if (this.string.startsWith(left, this.position)) { level++; this.position += left.length; result += left; } if (this.string.startsWith(right, this.position)) { level--; this.position += right.length; if (level === 0) { return result; } else { result += right; } } result += this.string[this.position]; this.position++; } throw new Error(`Cannot find the right half "${right}": ${this.GetPositionDescription()}`); } GetPositionDescription(position = undefined) { const s = this.string.split('\n'); var curp = this.offp; var line = this.offl; if (position !== undefined) { while (curp + s[line].length + 1 < position - this.offp) { curp += s[line].length + 1; line += 1; } } else { curp += s.slice(0, this.line).reduce((sum, i) => sum + i.length + 1, 0); line += this.line; position = this.position; } return `
at "${s[line]}".`; } } function FindValue(pairs, key) { const finded = pairs.find(i => i.Key === key); if (finded) { return finded; } return undefined; } function ReadProperties(reader, event, pairs) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; if (event instanceof RDGroup) { var value; if (value = FindValue(pairs, "hue")) { event.Style.Hue = parseFloat(value.Value); } if (value = FindValue(pairs, "brightness")) { event.Style.Brightness = parseFloat(value.Value); } if (value = FindValue(pairs, "grayscale")) { event.Style.Grayscale = parseFloat(value.Value); } if (value = FindValue(pairs, "opacity")) { event.Style.Opacity = parseFloat(value.Value); } if (value = FindValue(pairs, "offset")) { reader = new Reader(value.Value); (_a = event.ClickStyle) !== null && _a !== void 0 ? _a : (event.ClickStyle = new RDStyle()); try { event.ClickStyle.Beat = reader.ReadFloat(); } catch (e) { } try { event.ClickStyle.Y = reader.ReadInt(); } catch (e) { } try { event.ClickOutline = reader.ReadColor(); } catch (e) { } } if (value = FindValue(pairs, "offset_hue")) { (_b = event.ClickStyle) !== null && _b !== void 0 ? _b : (event.ClickStyle = new RDStyle()); event.ClickStyle.Hue = parseFloat(value.Value); } if (value = FindValue(pairs, "offset_brightness")) { (_c = event.ClickStyle) !== null && _c !== void 0 ? _c : (event.ClickStyle = new RDStyle()); event.ClickStyle.Brightness = parseFloat(value.Value); } if (value = FindValue(pairs, "offset_grayscale")) { (_d = event.ClickStyle) !== null && _d !== void 0 ? _d : (event.ClickStyle = new RDStyle()); event.ClickStyle.Grayscale = parseFloat(value.Value); } if (value = FindValue(pairs, "offset_opacity")) { (_e = event.ClickStyle) !== null && _e !== void 0 ? _e : (event.ClickStyle = new RDStyle()); event.ClickStyle.Opacity = parseFloat(value.Value); } } else if (event instanceof RDEvent) { for (const pair of pairs) { const key = pair.Key; const value = pair.Value; switch (key) { case "if": if (["true", "false", "both"].find(i => i === value)) { event.Condition = value === "true" ? EventCondition.true : value === "false" ? EventCondition.false : EventCondition.both; } else { throw new Error(`Expecting "true", "false" or "both", but find "${value}".`); } break; case "tag": event.Tag = value === "true"; break; case "hue": event.Style.Hue = parseFloat(value); break; case "brightness": event.Style.Brightness = parseFloat(value); break; case "grayscale": event.Style.Grayscale = parseFloat(value); break; case "opacity": event.Style.Opacity = parseFloat(value); break; case "offset": { const offsetReader = new Reader(value); (_f = event.ClickStyle) !== null && _f !== void 0 ? _f : (event.ClickStyle = new RDStyle()); try { event.ClickStyle.Beat = offsetReader.ReadFloat(); } catch (e) { } try { event.ClickStyle.Y = offsetReader.ReadInt(); } catch (e) { } break; } case "offset_hue": (_g = event.ClickStyle) !== null && _g !== void 0 ? _g : (event.ClickStyle = new RDStyle()); event.ClickStyle.Hue = parseFloat(value); break; case "offset_brightness": (_h = event.ClickStyle) !== null && _h !== void 0 ? _h : (event.ClickStyle = new RDStyle()); event.ClickStyle.Brightness = parseFloat(value); break; case "offset_grayscale": (_j = event.ClickStyle) !== null && _j !== void 0 ? _j : (event.ClickStyle = new RDStyle()); event.ClickStyle.Grayscale = parseFloat(value); break; case "offset_opacity": (_k = event.ClickStyle) !== null && _k !== void 0 ? _k : (event.ClickStyle = new RDStyle()); event.ClickStyle.Opacity = parseFloat(value); break; default: event.Properties.push(pair); } } } } const CELL_SIZE = 28; const RDTK_SCALE = 2; const NUMERIC_KEYS = new Set([ "tick", "swing", "hold", "pulse", "customPulse", "interval", "delay", "loop", "subdivision", "crotchetsPerBar", "syncoBeat", "duration", "angle", "bpm", "beatsPerMinute", "volume", "speed", "startOpacity", "endOpacity", "subdivOffset", ]); const SAY_PHRASES = new Set([ "SayReaDyGetSetGoNew", "SayReaDyGetSetOne", "SayGetSetGo", "SayGetSetOne", "JustSayRea", "JustSayDy", "JustSayGet", "JustSaySet", "JustSayAnd", "JustSayGo", "JustSayStop", "JustSayAndStop", "SaySwitch", "SayWatch", "SayListen", "Count1", "Count2", "Count3", "Count4", "Count5", "Count6", "Count7", "Count8", "Count9", "Count10", "SayReadyGetSetGo", "JustSayReady", ]); function CoerceValue(key, value) { if (value === "true") { return true; } if (value === "false") { return false; } if (NUMERIC_KEYS.has(key) && /^[+-]?(\d+(\.\d+)?|\.\d+)$/.test(value)) { return Number(value); } return value; } function ToRDtkObject(ev) { const obj = { type: ev.Name }; let tab = undefined; for (const pair of ev.Properties) { let key = pair.Key; const value = pair.Value; if (key === "tab") { tab = value; continue; } if (key === "tag") { continue; } if (ev.Name === "AddOneshotBeat" && key === "type") { const types = value.split(/\s+/).filter(i => i.length > 0); for (const t of types) { switch (t) { case "freezeshot": obj.freezeBurnMode = "Freezeshot"; break; case "burnshot": obj.freezeBurnMode = "Burnshot"; break; case "skipshot": obj.skipshot = true; break; } } continue; } if (ev.Name === "AddOneshotBeat" && key === "hold") { obj.hold = !(value === "false" || value === "0" || value === "0.0"); continue; } if (key === "rowxs") { key = "pattern"; } else if (ev.Name === "AddOneshotBeat" && key === "loop") { key = "loops"; } else if (ev.Name === "AddOneshotBeat" && key === "subdivision") { key = "subdivisions"; } if (ev.Name === "SayReadyGetSetGo" && key === "phraseToSay") { if (SAY_PHRASES.has(value)) { obj.phraseToSay = value; } continue; } obj[key] = CoerceValue(key, value); } if (tab !== undefined) { obj.tab = tab; } else if (ev.PrefixTab !== undefined) { obj.tab = ev.PrefixTab; } if (ev.Tag === true) { obj.tag = true; } return obj; } function ConstructObjs(view, objs) { const content = document.createElement("div"); content.className = "RDViewContent"; content.style.setProperty("--column", `${view.Column}`); content.style.setProperty("--row", `${view.Row}`); content.style.setProperty("--scale", `${view.Scale}`); const canvas = document.createElement("div"); canvas.className = "RDView rdtk-rdview"; canvas.style.setProperty("--column", `${view.Column}`); canvas.style.setProperty("--row", `${view.Row}`); canvas.style.setProperty("--scale", `${view.Scale}`); for (const obj of objs) { const node = BuildObject(obj); if (node) { canvas.appendChild(node); } } content.appendChild(canvas); return content; } function BuildObject(obj) { return obj instanceof RDGroup ? BuildGroup(obj) : BuildEvent(obj); } function BuildEvent(ev) { var _a, _b, _c, _d; const wrapper = document.createElement("div"); wrapper.className = "rdtk-event"; wrapper.style.left = `${ev.Style.Beat * CELL_SIZE}px`; wrapper.style.top = `${ev.Style.Y * CELL_SIZE}px`; const state = { enabled: true, active: false, hover: false, scale: RDTK_SCALE, showDuration: false }; const rdobj = ToRDtkObject(ev); const inner = rdobj ? createElementEvent(rdobj, state) : null; if (inner) { inner.style.position = "absolute"; inner.style.left = "0px"; inner.style.top = "0px"; wrapper.appendChild(inner); } else { wrapper.classList.add("rdtk-unknown"); wrapper.textContent = ev.Name || "unknown"; } ApplyFilter(wrapper, ev.Style); if (ev.Condition !== undefined) { const condition = document.createElement("div"); condition.className = `rdtk-condition condition-${ev.Condition}`; wrapper.appendChild(condition); } const offsetBeat = (_b = (_a = ev.ClickStyle) === null || _a === void 0 ? void 0 : _a.Beat) !== null && _b !== void 0 ? _b : 0; const offsetY = (_d = (_c = ev.ClickStyle) === null || _c === void 0 ? void 0 : _c.Y) !== null && _d !== void 0 ? _d : 0; const hasOffset = offsetBeat !== 0 || offsetY !== 0; function setState(hover, active) { state.hover = hover; state.active = active; inner === null || inner === void 0 ? void 0 : inner.onStateChange(state); wrapper.classList.toggle("hover", hover); wrapper.classList.toggle("active", active); wrapper.style.transform = (active && hasOffset) ? `translate(${offsetBeat * CELL_SIZE}px, ${offsetY * CELL_SIZE}px)` : ""; ApplyFilter(wrapper, active && ev.ClickStyle ? ev.ClickStyle : ev.Style); } wrapper.addEventListener("mouseover", (e) => { if (!wrapper.contains(e.relatedTarget)) { setState(true, state.active); } }); wrapper.addEventListener("mouseout", (e) => { if (!wrapper.contains(e.relatedTarget)) { setState(false, false); } }); wrapper.addEventListener("mousedown", () => setState(true, true)); wrapper.addEventListener("mouseup", () => setState(state.hover, false)); wrapper.__setRDtkState = setState; return wrapper; } function BuildGroup(grp) { var _a, _b, _c, _d; const wrapper = document.createElement("div"); wrapper.className = "rdtk-group"; wrapper.style.left = `${grp.Style.Beat * CELL_SIZE}px`; wrapper.style.top = `${grp.Style.Y * CELL_SIZE}px`; wrapper.style.width = `${grp.Width * CELL_SIZE}px`; wrapper.style.height = `${grp.Height * CELL_SIZE}px`; wrapper.style.outlineColor = ToHex(grp.Outline); ApplyFilter(wrapper, grp.Style); for (const child of grp.Children) { const node = BuildObject(child); if (node) { wrapper.appendChild(node); } } const offsetBeat = (_b = (_a = grp.ClickStyle) === null || _a === void 0 ? void 0 : _a.Beat) !== null && _b !== void 0 ? _b : 0; const offsetY = (_d = (_c = grp.ClickStyle) === null || _c === void 0 ? void 0 : _c.Y) !== null && _d !== void 0 ? _d : 0; const hasOffset = offsetBeat !== 0 || offsetY !== 0; function setState(hover, active) { var _a; wrapper.classList.toggle("hover", hover); wrapper.classList.toggle("active", active); wrapper.style.transform = (active && hasOffset) ? `translate(${offsetBeat * CELL_SIZE}px, ${offsetY * CELL_SIZE}px)` : ""; wrapper.style.outlineColor = active ? ToHex((_a = grp.ClickOutline) !== null && _a !== void 0 ? _a : grp.Outline) : ToHex(grp.Outline); ApplyFilter(wrapper, active && grp.ClickStyle ? grp.ClickStyle : grp.Style); } wrapper.addEventListener("mouseover", (e) => { if (!wrapper.contains(e.relatedTarget)) { setState(true, false); } }); wrapper.addEventListener("mouseout", (e) => { if (!wrapper.contains(e.relatedTarget)) { setState(false, false); } }); wrapper.addEventListener("mousedown", () => setState(true, true)); wrapper.addEventListener("mouseup", () => setState(true, false)); wrapper.__setRDtkState = setState; return wrapper; } function ApplyFilter(el, style) { const parts = []; if (style.Hue !== undefined) { parts.push(`hue-rotate(${style.Hue}deg)`); } if (style.Brightness !== undefined) { parts.push(`brightness(${style.Brightness}%)`); } if (style.Grayscale !== undefined) { parts.push(`grayscale(${style.Grayscale}%)`); } if (style.Opacity !== undefined) { parts.push(`opacity(${style.Opacity}%)`); } el.style.filter = parts.join(" "); } function ToHex(color) { const hex = parseInt(color.red.toFixed(0)).toString(16).padStart(2, '0') + parseInt(color.green.toFixed(0)).toString(16).padStart(2, '0') + parseInt(color.blue.toFixed(0)).toString(16).padStart(2, '0') + parseInt(color.alpha.toFixed(0)).toString(16).padStart(2, '0'); return '#' + hex; } window.loadRDView = loadRDView;