Плагин на изменения боя. Боевая сетка (Внимание сырой)

Больше
2 ч. 11 мин. назад #132782 от Ryterator
Плагин создал мне deepseek Если вы против нейросетей как инструмента помощи в творчестве, просто не используйте этот плагин .
Пример того, что он делает.


Для установки смените окончание\расшерение файла с txt на Js.
Я не считаю нейросеть вредной в творчестве, но я сторонник общедоступности того, что было ею сделано, так как она учится и работает на открытом контенте сообщества.
Плагин предоставляется «как есть». Можете проверить его самостоятельно перед установкой. Код представлен ниже.
Code:
/*: * @target MZ * @plugindesc v5.7 Formation Grid: строгая сетка + SV/idle спрайты врагов + SV-UI построения * @author AI * * @help * ============================================================ *  Battle Formation Grid v5.7 * ============================================================ * Сетка: бойцы внутри линии стоят СТОЛБИКОМ СНИЗУ ВВЕРХ, * линии (вертикальные полосы) идут СЛЕВА НАПРАВО. * Линия 0 — фронт (слева, ближе к противнику). * * --- АВТО-ГЕНЕРАЦИЯ ЯЧЕЕК --- * Количество ячеек = partySize * partyLines. * Меняешь partySize / partyLines в параметрах плагина — * ячейки, спрайты и подписи автоматически перестраиваются. * * --- UI ПОСТРОЕНИЯ --- * Все цифры UI — прямые, в LAYOUT ниже: *   grid.originX / originY — позиция слота 0 (линия 0, низ столбика) *   grid.stepX / stepY     — шаг между линиями / бойцами в линии *   grid.cellW / cellH     — размер ячейки слота * Формула расчёта позиции слота — только в Scene_FormationGrid.slotPos. * * --- ТЕГИ СКИЛЛОВ / ПРЕДМЕТОВ (в Note) --- *  <melee>  <ranged>  <pierceLines:N> *  <aoeLine:N>  <aoeColumn:N>  <aoeCross:N> *  <coverBack>  (state) * * --- ТЕГИ ВРАГОВ (в Note врага) --- *  <svBattler:filename>                 img/sv_enemies/filename.png (9×6) *  <charSheet:filename>                 img/characters/filename.png (12×8) *  <idleSheet:filename:cols>            img/pictures/filename.png (полоса) *  <idleSheet:filename:cols:row:rows>   с указанием строки/всего строк * ============================================================ * * @command openFormation * @text Открыть построение * * @param attackIsMelee * @text Базовая «Атака» = ближняя * @type boolean * @default true * * @param enemySvMirror * @text Enemy: зеркалить SV-мобов * @type boolean * @default true * * @param partySize * @text Party: бойцов в линии * @type number * @min 1 * @max 6 * @default 3 * * @param partyLines * @text Party: линий * @type number * @min 1 * @max 6 * @default 3 * * @param partyOriginX * @text Party: Origin X * @type number * @default 540 * * @param partyOriginY * @text Party: Origin Y * @type number * @default 540 * * @param partyColSpacing * @text Party: шаг бойцов в линии * @type number * @default 80 * * @param partyRowSpacing * @text Party: шаг между линиями * @type number * @default 100 * * @param partyMirror * @text Party: Mirror * @type boolean * @default false * * @param partyFaceLeft * @text Party: смотрят влево * @type boolean * @default true * * @param enemySize * @text Enemy: бойцов в линии * @type number * @min 1 * @max 6 * @default 3 * * @param enemyLines * @text Enemy: линий * @type number * @min 1 * @max 6 * @default 3 * * @param enemyOriginX * @text Enemy: Origin X * @type number * @default 260 * * @param enemyOriginY * @text Enemy: Origin Y * @type number * @default 540 * * @param enemyColSpacing * @text Enemy: шаг бойцов в линии * @type number * @default 80 * * @param enemyRowSpacing * @text Enemy: шаг между линиями * @type number * @default 100 * * @param enemyMirror * @text Enemy: Mirror * @type boolean * @default true * * @param enemyAnimSpeed * @text Enemy: скорость idle-анимации * @type number * @min 4 * @max 120 * @default 24 */ (() => {     "use strict";     const pluginName = "BattleFormationGrid";     const raw = PluginManager.parameters(pluginName);     const clamp = (v, a, b) => isNaN(v) ? a : Math.max(a, Math.min(b, v));     const P = {         attackIsMelee:   String(raw.attackIsMelee) !== "false",         partySize:       clamp(Number(raw.partySize       || 3), 1, 6),         partyLines:      clamp(Number(raw.partyLines      || 3), 1, 6),         partyOriginX:    Number(raw.partyOriginX    || 540),         partyOriginY:    Number(raw.partyOriginY    || 540),         partyColSpacing: Number(raw.partyColSpacing || 80),         partyRowSpacing: Number(raw.partyRowSpacing || 100),         partyMirror:     String(raw.partyMirror)    === "true",         partyFaceLeft:   String(raw.partyFaceLeft)  !== "false",         enemySize:       clamp(Number(raw.enemySize       || 3), 1, 6),         enemyLines:      clamp(Number(raw.enemyLines      || 3), 1, 6),         enemyOriginX:    Number(raw.enemyOriginX    || 260),         enemyOriginY:    Number(raw.enemyOriginY    || 540),         enemyColSpacing: Number(raw.enemyColSpacing || 80),         enemyRowSpacing: Number(raw.enemyRowSpacing || 100),         enemyMirror:     String(raw.enemyMirror)    !== "false",         enemySvMirror:   String(raw.enemySvMirror) !== "True",         enemyAnimSpeed:  clamp(Number(raw.enemyAnimSpeed || 24), 4, 120)     };     // ============================================================     //  UI СЦЕНЫ ПОСТРОЕНИЯ     //  Только прямые значения: X, Y, ширина, высота, шаги.     //  Количество ячеек = partySize * partyLines (автоматически).     // ============================================================     const LAYOUT = {         // --- Сетка слотов ---         grid: {             originX: 560,       // X центра ячейки слота 0 (линия 0, позиция 0)             originY: 500,       // Y НИЗА ячейки слота 0 (ноги спрайта)             stepX:   100,       // шаг между линиями по X (вправо)             stepY:   90,        // шаг между бойцами в линии по Y (вверх)             cellW:   100,       // ширина ячейки             cellH:   90,        // высота ячейки             innerPadding: 2     // внутр. отступ рамки ячейки         },         // --- Надпись "ФРОНТ" (вертикально, побуквенно) ---         frontLabel: {             x: 460,             y: 260,             charW: 30,             charH: 26,             fontSize: 22         },         // --- Подписи линий ("Первая линия" и т.д.) ---         lineLabel: {             offsetY:  36,             w: 140,             h: 20,             fontSize: 16         },         // --- Плашка "имя + HP" над спрайтом ---         infoLabel: {             offsetY: 60,             w: 180,             h: 46,             nameFontSize: 17,             hpFontSize: 12,             hpBarH: 10,             hpBarMargin: 10,             hpBarBottomGap: 10         },         // --- Нижнее окно подсказки ---         helpWindow: { x: 40, y: 600, w: 1200, h: 70 },         // --- Левая панель "Выбор линии" ---         linePanel: { x: 40, y: 50, w: 220, h: 450, rowH: 38 },         // --- Курсор выбора слота ---         cursor: { extra: 8, thickness: 3 }     };     // ============================================================     //  УТИЛИТЫ СЛОТОВ     // ============================================================     function actorSlot(actor) {         if (!actor) return -1;         const map = $gameParty._formationSlots;         if (map) {             const key = String(actor.actorId());             if (Object.prototype.hasOwnProperty.call(map, key)) {                 return Number(map[key]);             }         }         return $gameParty.allMembers().indexOf(actor);     }     function battlerSlot(b) {         if (!b) return -1;         if (b.isActor && b.isActor()) return actorSlot(b);         return b.index();     }     // ============================================================     //  ГЕОМЕТРИЯ ДЛЯ БОЯ     // ============================================================     function gridPos(index, size, lines, ox, oy, cs, rs, mirror) {         const member = index % size;         const line   = Math.floor(index / size);         const dir    = mirror ? -1 : 1;         return {             x: Math.round(ox + line * rs * dir),             y: Math.round(oy - member * cs)         };     }     function getLineOfBattler(b) {         if (!b) return -1;         const s = battlerSlot(b);         if (s < 0) return -1;         const size = b.isActor() ? P.partySize : P.enemySize;         return Math.floor(s / size);     }     function getFrontLivingLineOfUnit(unit) {         if (!unit) return -1;         let min = Infinity;         for (const m of unit.aliveMembers()) {             const l = getLineOfBattler(m);             if (l >= 0 && l < min) min = l;         }         return min === Infinity ? -1 : min;     }     function unitLayout(unit) {         const isPartyUnit = !!unit._actors;         return {             size:  isPartyUnit ? P.partySize  : P.enemySize,             lines: isPartyUnit ? P.partyLines : P.enemyLines         };     }     function cellsOfUnit(unit) {         const { size } = unitLayout(unit);         const cells = [];         for (const m of unit.aliveMembers()) {             const s = battlerSlot(m);             if (s < 0) continue;             cells.push({                 member: m,                 memberIdx: s % size,                 line: Math.floor(s / size)             });         }         return cells;     }     function itemNote(action) { return (action.item() && action.item().note) || ""; }     function actionIsMelee(action) {         const note = itemNote(action);         if (/<ranged>/i.test(note)) return false;         if (/<melee>/i.test(note))  return true;         return P.attackIsMelee && action.isAttack();     }     function parsePierce(action) {         const m = /<pierceLines:(\d+)>/i.exec(itemNote(action));         return m ? clamp(Number(m[1]), 1, 6) : 1;     }     function parseAoeShapes(action) {         const note = itemNote(action);         const shapes = [];         const grab = (re, key) => {             const m = re.exec(note);             if (!m) return;             const n = m[1] ? clamp(Number(m[1]), 1, 36) : 36;             shapes.push({ key, n });         };         grab(/<aoeLine:(\d+)>/i,   "line");         grab(/<aoeColumn:(\d+)>/i, "column");         grab(/<aoeCross:(\d+)>/i,  "cross");         if (/<aoeLine>(?!\d)/i.test(note)   && !/<aoeLine:\d+>/i.test(note))             shapes.push({ key: "line", n: 36 });         if (/<aoeColumn>(?!\d)/i.test(note) && !/<aoeColumn:\d+>/i.test(note))             shapes.push({ key: "column", n: 36 });         if (/<aoeCross>(?!\d)/i.test(note)  && !/<aoeCross:\d+>/i.test(note))             shapes.push({ key: "cross", n: 36 });         return shapes;     }     // ============================================================     //  ПОЗИЦИИ СПРАЙТОВ В БОЮ     // ============================================================     Sprite_Actor.prototype.setActorHome = function(index) {         const battler = this._actor || this._battler;         const slot = (battler && battler.isActor && battler.isActor())             ? actorSlot(battler)             : index;         const s = slot >= 0 ? slot : index;         const p = gridPos(             s,             P.partySize, P.partyLines,             P.partyOriginX, P.partyOriginY,             P.partyColSpacing, P.partyRowSpacing,             P.partyMirror         );         this.setHome(p.x, p.y);     };     Game_Enemy.prototype.screenX = function() {         return gridPos(this.index(),             P.enemySize, P.enemyLines,             P.enemyOriginX, P.enemyOriginY,             P.enemyColSpacing, P.enemyRowSpacing,             P.enemyMirror).x;     };     Game_Enemy.prototype.screenY = function() {         return gridPos(this.index(),             P.enemySize, P.enemyLines,             P.enemyOriginX, P.enemyOriginY,             P.enemyColSpacing, P.enemyRowSpacing,             P.enemyMirror).y;     };     Game_Actor.prototype.screenX = function() {         const s = actorSlot(this);         return gridPos(             s >= 0 ? s : 0,             P.partySize, P.partyLines,             P.partyOriginX, P.partyOriginY,             P.partyColSpacing, P.partyRowSpacing,             P.partyMirror         ).x;     };     Game_Actor.prototype.screenY = function() {         const s = actorSlot(this);         return gridPos(             s >= 0 ? s : 0,             P.partySize, P.partyLines,             P.partyOriginX, P.partyOriginY,             P.partyColSpacing, P.partyRowSpacing,             P.partyMirror         ).y;     };     // ============================================================     //  ФИЛЬТР ПО ПЕРЕДНЕЙ ЛИНИИ     // ============================================================     function filterByFrontLine(action, targets) {         if (!targets || !targets.length) return targets;         if (!actionIsMelee(action)) return targets;         if (parsePierce(action) > 1) return targets;         const unit = action.isForOpponent()             ? action.opponentsUnit()             : action.friendsUnit();         const front = getFrontLivingLineOfUnit(unit);         if (front < 0) return targets;         const filtered = targets.filter(t => getLineOfBattler(t) === front);         return filtered.length ? filtered : targets;     }     const _targetsForOpponents = Game_Action.prototype.targetsForOpponents;     Game_Action.prototype.targetsForOpponents = function() {         return filterByFrontLine(this, _targetsForOpponents.call(this));     };     const _targetsForFriends = Game_Action.prototype.targetsForFriends;     Game_Action.prototype.targetsForFriends = function() {         return filterByFrontLine(this, _targetsForFriends.call(this));     };     // ============================================================     //  РАСШИРЕНИЕ ЦЕЛЕЙ: pierceLines + AoE     // ============================================================     function expandAoe(action, targets) {         if (!targets.length) return targets;         const note = itemNote(action);         const pierce = parsePierce(action);         const shapes = parseAoeShapes(action);         const hasPierce = pierce > 1 && /<pierceLines:\d+>/i.test(note);         if (!hasPierce && !shapes.length) return targets;         const unit = action.isForOpponent()             ? action.opponentsUnit()             : action.friendsUnit();         const cells = cellsOfUnit(unit);         if (!cells.length) return targets;         const result = new Set(targets);         if (hasPierce) {             const lines = [...new Set(cells.map(c => c.line))].sort((a, b) => a - b);             const activeLines = lines.slice(0, pierce);             for (const c of cells) {                 if (activeLines.includes(c.line)) result.add(c.member);             }         }         for (const t of targets) {             const tcell = cells.find(c => c.member === t);             if (!tcell) continue;             for (const shape of shapes) {                 if (shape.key === "line") {                     const group = cells.filter(c => c.line === tcell.line);                     group.sort((a, b) =>                         Math.abs(a.memberIdx - tcell.memberIdx) -                         Math.abs(b.memberIdx - tcell.memberIdx));                     group.slice(0, shape.n).forEach(c => result.add(c.member));                 } else if (shape.key === "column") {                     const group = cells.filter(c => c.memberIdx === tcell.memberIdx);                     group.sort((a, b) => a.line - b.line);                     group.slice(0, shape.n).forEach(c => result.add(c.member));                 } else if (shape.key === "cross") {                     const cross = cells.filter(c =>                         c.line === tcell.line || c.memberIdx === tcell.memberIdx);                     cross.sort((a, b) => {                         const da = Math.abs(a.memberIdx - tcell.memberIdx) +                                    Math.abs(a.line - tcell.line);                         const db = Math.abs(b.memberIdx - tcell.memberIdx) +                                    Math.abs(b.line - tcell.line);                         return da - db;                     });                     cross.slice(0, shape.n).forEach(c => result.add(c.member));                 }             }         }         return [...result];     }     const _makeTargets = Game_Action.prototype.makeTargets;     Game_Action.prototype.makeTargets = function() {         let targets = _makeTargets.call(this);         if (this._forcing || !this.subject()) return targets;         if (!targets.length) return targets;         return expandAoe(this, targets);     };     // ============================================================     //  ПРИКРЫТИЕ ТЫЛА     // ============================================================     function findCoverGuard(target) {         if (!target || !target.isActor()) return null;         if (getLineOfBattler(target) <= 0) return null;         for (const m of $gameParty.allMembers()) {             if (m === target) continue;             if (m.hp <= 0) continue;             if (getLineOfBattler(m) !== 0) continue;             if (m.states().some(s => s && /<coverBack>/i.test(s.note || ""))) return m;         }         return null;     }     const _executeHpDamage = Game_Action.prototype.executeHpDamage;     Game_Action.prototype.executeHpDamage = function(target, value) {         const guard = findCoverGuard(target);         if (guard && guard.hp > 0) { _executeHpDamage.call(this, guard, value); return; }         _executeHpDamage.call(this, target, value);     };     // ============================================================     //  СПРАЙТ АКТЁРА (SV-баттлер)     // ============================================================     function Sprite_FormationActor() { this.initialize(...arguments); }     Sprite_FormationActor.prototype = Object.create(Sprite.prototype);     Sprite_FormationActor.prototype.constructor = Sprite_FormationActor;     Sprite_FormationActor.prototype.initialize = function(actor, faceLeft) {         Sprite.prototype.initialize.call(this);         this._actor    = actor || null;         this._faceLeft = !!faceLeft;         this.anchor.x = 0.5;         this.anchor.y = 1.0;         this.z = 10;         this.loadBitmap();     };     Sprite_FormationActor.prototype.setActor = function(actor) {         if (this._actor === actor) return;         this._actor = actor || null;         this.loadBitmap();     };     Sprite_FormationActor.prototype.loadBitmap = function() {         if (!this._actor || !this._actor.battlerName()) {             this.bitmap = null; this.visible = false; return;         }         this.visible = true;         this.bitmap = ImageManager.loadSvActor(this._actor.battlerName());         this.scale.x = this._faceLeft ? 1 : -1;         this.bitmap.addLoadListener(() => this.updateFrame());         this.updateFrame();     };     Sprite_FormationActor.prototype.updateFrame = function() {         if (!this._actor || !this.bitmap || !this.bitmap.width) return;         const pw = Math.floor(this.bitmap.width  / 9);         const ph = Math.floor(this.bitmap.height / 6);         if (!pw || !ph) return;         this.setFrame(0, 1 * ph, pw, ph);     };     // ============================================================     //  СПРАЙТ «ИМЯ + HP»     // ============================================================     function Sprite_SlotInfo() { this.initialize(...arguments); }     Sprite_SlotInfo.prototype = Object.create(Sprite.prototype);     Sprite_SlotInfo.prototype.constructor = Sprite_SlotInfo;     Sprite_SlotInfo.prototype.initialize = function() {         Sprite.prototype.initialize.call(this);         this._actor = null;         const L = LAYOUT.infoLabel;         this._bitmap = new Bitmap(L.w, L.h);         this.bitmap = this._bitmap;         this.anchor.x = 0.5;         this.anchor.y = 1.0;         this.z = 15;         this.visible = false;     };     Sprite_SlotInfo.prototype.setActor = function(actor) {         this._actor = actor || null;         this.visible = !!actor;         this.refresh();     };     Sprite_SlotInfo.prototype.refresh = function() {         const b = this._bitmap; b.clear();         if (!this._actor) return;         const L = LAYOUT.infoLabel;         const w = b.width;         b.fontSize = L.nameFontSize;         b.outlineColor = "rgba(0,0,0,0.9)"; b.outlineWidth = 4;         b.textColor = "#ffffff";         b.drawText(this._actor.name(), 0, 0, w, 20, "center");         const hp = Math.max(0, this._actor.hp);         const mhp = Math.max(1, this._actor.mhp);         const ratio = Math.max(0, Math.min(1, hp / mhp));         const margin = L.hpBarMargin;         const bw = w - margin * 2;         const bh = L.hpBarH;         const bx = margin;         const by = L.h - bh - L.hpBarBottomGap;         b.fillRect(bx - 1, by - 1, bw + 2, bh + 2, "rgba(0,0,0,0.85)");         b.fillRect(bx,     by,     bw,     bh,     "rgba(40,40,40,0.9)");         const color = ratio > 0.5 ? "#3ad13a" : ratio > 0.25 ? "#e0c020" : "#e03030";         b.fillRect(bx, by, Math.floor(bw * ratio), bh, color);         b.fontSize = L.hpFontSize;         b.outlineColor = "rgba(0,0,0,0.95)"; b.outlineWidth = 3;         b.textColor = "#ffffff";         b.drawText(`${hp}/${mhp}`, 0, by - 4, w, 16, "center");     };     // ============================================================     //  ЛЕВАЯ ПАНЕЛЬ «ВЫБОР ЛИНИИ»     // ============================================================     function Window_FormationLines() { this.initialize(...arguments); }     Window_FormationLines.prototype = Object.create(Window_Base.prototype);     Window_FormationLines.prototype.constructor = Window_FormationLines;     Window_FormationLines.prototype.initialize = function(rect) {         Window_Base.prototype.initialize.call(this, rect);         this._currentLine = 0;         this.refresh();     };     Window_FormationLines.prototype.setCurrentLine = function(line) {         if (this._currentLine === line) return;         this._currentLine = line;         this.refresh();     };     Window_FormationLines.prototype.refresh = function() {         this.contents.clear();         const names = ["Первая линия", "Вторая", "Третья",                        "Четвёртая", "Пятая", "Шестая"];         const lh = LAYOUT.linePanel.rowH;         for (let i = 0; i < P.partyLines; i++) {             const label = i === 0 ? "Фронт" : (names[i] || `Линия ${i + 1}`);             this.changeTextColor(i === this._currentLine ? "#ffe66a" : "#ffffff");             this.contents.outlineColor = "rgba(0,0,0,0.9)";             this.contents.outlineWidth = 4;             this.drawText(label, 0, i * lh, this.contents.width, lh, "left");         }     };     // ============================================================     //  СЦЕНА ПОСТРОЕНИЯ     // ============================================================     function Scene_FormationGrid() { this.initialize(...arguments); }     Scene_FormationGrid.prototype = Object.create(Scene_MenuBase.prototype);     Scene_FormationGrid.prototype.constructor = Scene_FormationGrid;     Scene_FormationGrid.prototype.create = function() {         Scene_MenuBase.prototype.create.call(this);         // === АВТО: количество ячеек = partySize * partyLines ===         this._slotCount  = P.partySize * P.partyLines;         this._cursorSlot = 0;         this._pickedSlot = -1;         this._slots      = this.buildInitialSlots();         this.createGridLayer();         this.createLabelsLayer();         this.createActorSprites();         this.createInfoSprites();         this.createCursorSprite();         this.createHelpWindow();         this.createLineWindow();         this.refreshActors();         this.updateCursorPosition();     };     Scene_FormationGrid.prototype.buildInitialSlots = function() {         const slots = new Array(this._slotCount).fill(null);         const map = $gameParty._formationSlots || {};         const members = $gameParty.members();         for (const a of members) {             const key = String(a.actorId());             if (Object.prototype.hasOwnProperty.call(map, key)) {                 const s = Number(map[key]);                 if (s >= 0 && s < this._slotCount && !slots[s]) {                     slots[s] = a;                 }             }         }         let free = 0;         for (const a of members) {             if (slots.indexOf(a) >= 0) continue;             while (free < this._slotCount && slots[free]) free++;             if (free >= this._slotCount) break;             slots[free++] = a;         }         return slots;     };     // ============================================================     //  ЕДИНСТВЕННАЯ ФОРМУЛА В UI     //  Всё остальное — прямые значения из LAYOUT.grid.     //  Количество ячеек берётся из partySize/partyLines автоматически.     // ============================================================     Scene_FormationGrid.prototype.slotPos = function(slot) {         const G = LAYOUT.grid;         const member = slot % P.partySize;                 // позиция в линии (0 = низ)         const line   = Math.floor(slot / P.partySize);     // номер линии         const dir    = P.partyMirror ? -1 : 1;         return {             x: G.originX + line   * G.stepX * dir,             y: G.originY - member * G.stepY         };     };     Scene_FormationGrid.prototype.helpWindowRect = function() {         const H = LAYOUT.helpWindow;         return new Rectangle(H.x, H.y, H.w, H.h);     };     Scene_FormationGrid.prototype.createLineWindow = function() {         const L = LAYOUT.linePanel;         const rect = new Rectangle(L.x, L.y, L.w, L.h);         this._lineWindow = new Window_FormationLines(rect);         this.addChild(this._lineWindow);     };     Scene_FormationGrid.prototype.createGridLayer = function() {         const G = LAYOUT.grid;         const ip = G.innerPadding;         const cw = G.cellW;         const ch = G.cellH;         // Холст достаточно большой, чтобы ВСЕ ячейки поместились,         // даже если они выходят за Graphics.boxWidth.         let maxX = Graphics.boxWidth;         let maxY = Graphics.boxHeight;         for (let i = 0; i < this._slotCount; i++) {             const p = this.slotPos(i);             maxX = Math.max(maxX, p.x + cw);             maxY = Math.max(maxY, p.y + ch);         }         const bmp = new Bitmap(maxX, maxY);         // Все ячейки         bmp.paintOpacity = 60;         for (let i = 0; i < this._slotCount; i++) {             const p = this.slotPos(i);             bmp.fillRect(                 Math.round(p.x - cw / 2 + ip),                 Math.round(p.y - ch + ip),                 cw - ip * 2, ch - ip * 2, "white"             );         }         // Подсветка фронтовой линии         bmp.paintOpacity = 30;         for (let m = 0; m < P.partySize; m++) {             const p = this.slotPos(m);             bmp.fillRect(                 Math.round(p.x - cw / 2 + ip),                 Math.round(p.y - ch + ip),                 cw - ip * 2, ch - ip * 2, "#ffe66a"             );         }         this._gridSprite = new Sprite(bmp);         this._gridSprite.z = 1;         this.addChild(this._gridSprite);     };     Scene_FormationGrid.prototype.createLabelsLayer = function() {         const F  = LAYOUT.frontLabel;         const LL = LAYOUT.lineLabel;         const G  = LAYOUT.grid;         // === Считаем нужный размер холста заранее ===         // Чтобы вместить и ячейки, и подписи (которые выходят         // за левый/правый край ячейки на LL.w/2).         let maxX = Graphics.boxWidth;         let maxY = Graphics.boxHeight;         for (let i = 0; i < this._slotCount; i++) {             const p = this.slotPos(i);             maxX = Math.max(maxX, p.x + G.cellW / 2 + LL.w / 2 + 20);             maxY = Math.max(maxY, p.y + G.cellH + 20);         }         // плюс место под надпись "ФРОНТ" и подписи сверху         maxX = Math.max(maxX, F.x + F.charW + 20);         maxY = Math.max(maxY, F.y + F.charH * 6 + 20);         const bmp = new Bitmap(maxX, maxY);         bmp.outlineColor = "rgba(0,0,0,0.9)";         bmp.outlineWidth = 4;         // --- Надпись "ФРОНТ" побуквенно ---         const text = "ФРОНТ";         bmp.fontSize = F.fontSize;         bmp.textColor = "#ffe66a";         for (let i = 0; i < text.length; i++) {             bmp.drawText(text[i], F.x, F.y + i * F.charH,                         F.charW, F.charH, "center");         }         // --- Подписи линий ---         bmp.fontSize = LL.fontSize;         const names = ["Первая линия", "Вторая", "Третья",                     "Четвёртая", "Пятая", "Шестая"];         for (let line = 0; line < P.partyLines; line++) {             const topSlot = line * P.partySize + (P.partySize - 1);             const p = this.slotPos(topSlot);             const label = names[line] || `Линия ${line + 1}`;             bmp.textColor = line === 0 ? "#ffe66a" : "#9ad1ff";             bmp.drawText(label,                 p.x - LL.w / 2,                 p.y - G.cellH - LL.offsetY,                 LL.w, LL.h, "center");         }         this._labelsSprite = new Sprite(bmp);         this._labelsSprite.z = 5;         this.addChild(this._labelsSprite);     };     Scene_FormationGrid.prototype.createActorSprites = function() {         this._actorSprites = [];         for (let i = 0; i < this._slotCount; i++) {             const spr = new Sprite_FormationActor(null, P.partyFaceLeft);             const p = this.slotPos(i);             spr.x = p.x; spr.y = p.y; spr.visible = false;             this.addChild(spr);             this._actorSprites.push(spr);         }     };     Scene_FormationGrid.prototype.createInfoSprites = function() {         this._infoSprites = [];         for (let i = 0; i < this._slotCount; i++) {             const info = new Sprite_SlotInfo();             const p = this.slotPos(i);             info.x = p.x;             info.y = p.y - LAYOUT.infoLabel.offsetY;             this.addChild(info);             this._infoSprites.push(info);         }     };     Scene_FormationGrid.prototype.refreshActors = function() {         for (let i = 0; i < this._slotCount; i++) {             const spr = this._actorSprites[i];             const info = this._infoSprites[i];             const actor = this._slots[i];             const picked = (i === this._pickedSlot);             if (actor) {                 spr.setActor(actor); spr.visible = true;                 spr.opacity = picked ? 160 : 255;                 info.setActor(actor);                 info.opacity = picked ? 140 : 255;             } else {                 spr.visible = false;                 info.visible = false;             }         }     };     Scene_FormationGrid.prototype.createCursorSprite = function() {         const C = LAYOUT.cursor;         const G = LAYOUT.grid;         const cw = G.cellW + C.extra;         const ch = G.cellH + C.extra;         const th = C.thickness;         const bmp = new Bitmap(cw, ch);         bmp.fillRect(0, 0, cw, th, "rgba(255,230,90,0.95)");         bmp.fillRect(0, ch - th, cw, th, "rgba(255,230,90,0.95)");         bmp.fillRect(0, 0, th, ch, "rgba(255,230,90,0.95)");         bmp.fillRect(cw - th, 0, th, ch, "rgba(255,230,90,0.95)");         this._cursorSprite = new Sprite(bmp);         this._cursorSprite.anchor.x = 0.5;         this._cursorSprite.anchor.y = 0.5;         this._cursorSprite.z = 20;         this.addChild(this._cursorSprite);     };     Scene_FormationGrid.prototype.updateCursorPosition = function() {         const p = this.slotPos(this._cursorSlot);         const G = LAYOUT.grid;         this._cursorSprite.x = p.x;         this._cursorSprite.y = p.y - G.cellH / 2;         if (this._lineWindow) {             const line = Math.floor(this._cursorSlot / P.partySize);             this._lineWindow.setCurrentLine(line);         }     };     Scene_FormationGrid.prototype.createHelpWindow = function() {         const rect = this.helpWindowRect();         this._helpWindow = new Window_Help(rect);         this._helpWindow.setText(this.defaultHelpText());         this.addChild(this._helpWindow);     };     Scene_FormationGrid.prototype.defaultHelpText = function() {         return "Стрелки: перемещение по сетке   OK: взять/поставить (обмен)   Esc: выход";     };     Scene_FormationGrid.prototype.update = function() {         Scene_MenuBase.prototype.update.call(this);         if (this._cursorSprite) this.processInput();     };     Scene_FormationGrid.prototype.processInput = function() {         if (Input.isRepeated("up"))    this.moveCursor(0, -1);         if (Input.isRepeated("down"))  this.moveCursor(0,  1);         if (Input.isRepeated("left"))  this.moveCursor(-1, 0);         if (Input.isRepeated("right")) this.moveCursor( 1, 0);         if (Input.isTriggered("ok"))     this.onOk();         if (Input.isTriggered("cancel")) this.onCancel();     };     Scene_FormationGrid.prototype.moveCursor = function(dx, dy) {         let line   = Math.floor(this._cursorSlot / P.partySize);         let member = this._cursorSlot % P.partySize;         const lineDelta = P.partyMirror ? -dx : dx;         line   = (line + lineDelta + P.partyLines) % P.partyLines;         member = (member - dy + P.partySize) % P.partySize;         this._cursorSlot = line * P.partySize + member;         this.updateCursorPosition();         SoundManager.playCursor();     };     Scene_FormationGrid.prototype.onOk = function() {         if (this._pickedSlot < 0) {             if (this._slots[this._cursorSlot]) {                 this._pickedSlot = this._cursorSlot;                 SoundManager.playOk();                 this.refreshActors();                 this._helpWindow.setText("OK: поставить / обменять   Esc: отмена");             }         } else {             const a = this._pickedSlot, b = this._cursorSlot;             const tmp = this._slots[a];             this._slots[a] = this._slots[b];             this._slots[b] = tmp;             this._pickedSlot = -1;             SoundManager.playOk();             this.refreshActors();             this._helpWindow.setText(this.defaultHelpText());         }     };     Scene_FormationGrid.prototype.onCancel = function() {         if (this._pickedSlot >= 0) {             this._pickedSlot = -1;             this.refreshActors();             this._helpWindow.setText(this.defaultHelpText());             SoundManager.playCancel();         } else {             this.commitFormation();             SoundManager.playCancel();             this.popScene();         }     };     Scene_FormationGrid.prototype.commitFormation = function() {         const map = $gameParty._formationSlots || ($gameParty._formationSlots = {});         for (const k in map) delete map[k];         const ids = [];         for (let i = 0; i < this._slotCount; i++) {             const a = this._slots[i];             if (a) {                 map[String(a.actorId())] = i;                 ids.push(a.actorId());             }         }         for (const a of $gameParty.allMembers()) {             const key = String(a.actorId());             if (!Object.prototype.hasOwnProperty.call(map, key)) {                 ids.push(a.actorId());             }         }         $gameParty._actors = ids;     };     // ============================================================     //  МЕНЮ + ПЛАГИН-КОМАНДА     // ============================================================     Scene_Menu.prototype.commandFormation = function() {         if ($gameParty.size() >= 1) SceneManager.push(Scene_FormationGrid);     };     Window_MenuCommand.prototype.addFormationCommand = function() {         if (this.needsCommand("formation")) {             this.addCommand(TextManager.formation, "formation", $gameParty.size() >= 1);         }     };     PluginManager.registerCommand(pluginName, "openFormation", () => {         if (SceneManager._scene instanceof Scene_Battle) return;         SceneManager.push(Scene_FormationGrid);     });     // ============================================================     //  SV / АНИМИРОВАННЫЕ СПРАЙТЫ ВРАГОВ     // ============================================================     function parseEnemySpriteNote(note) {         const sve = /<svEnemy:\s*([^\s>]+)\s*>/i.exec(note)                 || /<svBattler:\s*([^\s>]+)\s*>/i.exec(note);         if (sve) return { mode: "svenemy", name: sve[1] };         const ch = /<charSheet:\s*([^\s>]+)\s*>/i.exec(note);         if (ch) return { mode: "char", name: ch[1] };         const idl = /<idleSheet:\s*([^\s>:]+)\s*:\s*(\d+)(?:\s*:\s*(\d+)\s*:\s*(\d+))?\s*>/i.exec(note);         if (idl) {             return {                 mode: "idle",                 name: idl[1],                 cols: Math.max(1, Number(idl[2])),                 row:  idl[3] != null ? Number(idl[3]) : 0,                 rows: idl[4] != null ? Math.max(1, Number(idl[4])) : 1             };         }         return null;     }     const _Sprite_Enemy_initMembers = Sprite_Enemy.prototype.initMembers;     Sprite_Enemy.prototype.initMembers = function() {         _Sprite_Enemy_initMembers.call(this);         this._enemySpriteMode = null;         this._enemySpriteKey  = null;         this._animFrame = 0;         this._animTimer = 0;         this._idleCols = 1;         this._idleRow = 0;         this._idleRows = 1;     };     const _Sprite_Enemy_updateBitmap = Sprite_Enemy.prototype.updateBitmap;     Sprite_Enemy.prototype.updateBitmap = function() {         const enemy = this._enemy;         if (!enemy) { return; }         const note = (enemy.enemy() && enemy.enemy().note) || "";         const cfg = parseEnemySpriteNote(note);         if (!cfg) {             if (this._enemySpriteMode !== null) {                 this._enemySpriteMode = null;                 this._enemySpriteKey  = null;                 this._battlerName = "";                 this._battlerHue  = -1;             }             _Sprite_Enemy_updateBitmap.call(this);             return;         }         const key = cfg.mode + ":" + cfg.name + ":" +                     (cfg.cols || 0) + ":" + (cfg.row || 0) + ":" + (cfg.rows || 0);         if (this._enemySpriteKey === key) return;         this._enemySpriteKey  = key;         this._enemySpriteMode = cfg.mode;         this._idleCols = cfg.cols || 1;         this._idleRow  = cfg.row  || 0;         this._idleRows = cfg.rows || 1;         this._animFrame = 0;         this._animTimer = 0;         this.scale.x = (cfg.mode === "svenemy" && P.enemySvMirror) ? -1 : 1;         let bmp;         if (cfg.mode === "svenemy")   bmp = ImageManager.loadSvEnemy(cfg.name);         else if (cfg.mode === "char") bmp = ImageManager.loadCharacter(cfg.name);         else                          bmp = ImageManager.loadPicture(cfg.name);         this.bitmap = bmp;         bmp.addLoadListener(() => {             this._bitmapLoaded = true;             this.updateFrame();         });     };     const _Sprite_Enemy_updateFrame = Sprite_Enemy.prototype.updateFrame;     Sprite_Enemy.prototype.updateFrame = function() {         if (!this._enemySpriteMode || !this.bitmap) {             _Sprite_Enemy_updateFrame.call(this);             return;         }         const bw = this.bitmap.width;         const bh = this.bitmap.height;         if (!bw || !bh) return;         if (this._enemySpriteMode === "svenemy") {             const fw = Math.floor(bw / 9);             const fh = Math.floor(bh / 6);             const f = this._animFrame % 3;             this.setFrame(f * fw, 0, fw, fh);         } else if (this._enemySpriteMode === "char") {             const fw = Math.floor(bw / 12);             const fh = Math.floor(bh / 8);             const f = this._animFrame % 3;             this.setFrame(f * fw, 4 * fh, fw, fh);         } else if (this._enemySpriteMode === "idle") {             const cols = this._idleCols;             const rows = this._idleRows;             const fw = Math.floor(bw / cols);             const fh = Math.floor(bh / rows);             const f = this._animFrame % cols;             this.setFrame(f * fw, this._idleRow * fh, fw, fh);         }     };     const _Sprite_Enemy_update = Sprite_Enemy.prototype.update;     Sprite_Enemy.prototype.update = function() {         _Sprite_Enemy_update.call(this);         if (this._enemySpriteMode) {             this._animTimer++;             if (this._animTimer >= P.enemyAnimSpeed) {                 this._animTimer = 0;                 this._animFrame = (this._animFrame + 1) % 360;             }         }     };     // ============================================================     //  ЭКСПОРТ     // ============================================================     window.BattleFormationGrid = {         config: P,         layout: LAYOUT,         scene:  Scene_FormationGrid     }; })();
!Инструкция по устранению неполадок!
Следуйте по пунктам:
1) Проверьте настройки плагина, примечания к навыкам и т.д. Всё, что вы делали.
2) Если выше не помогло, откройте VS code потом Deepseek киньте ему файл и скажите свою проблему. Патч или другие решения в файл просите скинуть целым файлом он даст вам блок кода для вставки от начала и до конца.
3) Если всё остальное не помогло мой Discord: [color=oklab(0.278878 0.00249207 -0.00875986)]1212_3949 [/color]Отвечаю где то в течение недели пишите сразу с причины обращения ЛС открыт.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Больше
2 ч. 3 мин. назад #132783 от Ryterator
Если я не так выложил можно сразу не банить первый раз выкладываю в остальном чаще смотрел..

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Больше
15 мин. назад #132784 от Dassy
Ну.. дипсик точно ничего плохого не делает, кроме передачи всего и вся партии )

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Время создания страницы: 0.107 секунд
Работает на Kunena форум