//============================================================================= // RPG Maker MZ - SceneLewdStatus // // Copyright 2024 Panzer-IV. All rights reserved. // This source code or any portion thereof must not be // reproduced or used without licensed in any manner whatsoever. //============================================================================= /*: * @target MZ * @plugindesc みんぱぶエロステ画面プラグイン * @author 四号戦車 * @base PluginCommonBase * @base DebugSwitch * @base TextResource * @base PluginUtils * @orderAfter PluginCommonBase * @orderAfter DebugSwitch * @orderAfter TextResource * @orderAfter PluginUtils * * @param bgm * @text シーンのBGM * @desc シーン中再生するBGMを指定します。 * @type file * @dir audio/bgm * @default * * @param lewdLevel1 * @text 勇者レベル * @desc エロステ値を管理する変数を指定して下さい。 * @type variable * @default 0 * * @param lewdLevel2 * @text 娼婦レベル * @desc エロステ値を管理する変数を指定して下さい。 * @type variable * @default 0 * * @param playerActor * @text プレイヤー * @desc レベル表示するプレイヤーを指定します * @type actor * @default 0 * * @param lewdStage * @text エロステ段階の変数 * @desc エロステ段階を管理する変数を指定してください * @type variable * @default 0 * * @param comment * @text 備考欄 * @desc プラグイン側では使用しません。 * メモ欄としてお使いください。 * @type multiline_string * @default * * @requiredAssets img/system/lewd_status/background * @requiredAssets img/system/lewd_status/back_button * @requiredAssets img/system/lewd_status/frame * @requiredAssets img/system/lewd_status/body_mask * @requiredAssets img/system/lewd_status/body/stage_1 * @requiredAssets img/system/lewd_status/body/stage_2 * @requiredAssets img/system/lewd_status/body/stage_3 * @requiredAssets img/system/lewd_status/body/stage_4 * @requiredAssets img/system/lewd_status/body_background * * @help SceneLewdStatus.js * * Version: 0.0.2 * * エロステ画面プラグイン * * @command startScene * @text エロステ画面表示 * @desc エロステ画面を表示します * */ (() => { "use strict"; //======================================================================== // プラグイン定義 //======================================================================== const pluginName = "SceneLewdStatus"; const script = document.currentScript; const param = PluginUtils.reparseParameter(script); //======================================================================== // 定数定義 //======================================================================== const UI_AREA_X = 7; const UI_AREA_Y = 0; const LEWD_LEVEL_WIDTH = 260; const LEWD_LEVEL_HEIGHT = 58; const LEWD_LEVEL_MERGIN = 12; const TITLE_TEXT = "0900-003-n003-0"; // 画面タイトル const SYSTEM_LEWD_VALUE1 = "0900-030-n030-0"; // ゲージタイトル(勇者レベル) const SYSTEM_LEWD_VALUE2 = "0900-031-n031-0"; // ゲージタイトル(娼婦レベル) const SYSTEM_TOTAL_LEBEL = "0900-033-n033-0"; // ラベル(総合レベル) const ITEM_WIDTH = 518; const ITEM_HEIGHT = 60; const ITEM_MERGIN = 8; const CONTENT_AREA_WIDTH = 682; const CONTENT_AREA_HEIHGT = 670; const DESCRIPTION_LINE_HEIGHT = 40; const DESCRIPTION_MERGIN = 18; const CONTENT_LINE_WIDTH = 3; const CONTENT_TOP = 134; //======================================================================== // 定数定義(ゲーム固有) //======================================================================== const State = { PUSSY: { // おまんこ name: 'PUSSY', label: '0900-011-n011-0', texts: [ "0910-001-n001-0", "0910-002-n002-0", "0910-003-n003-0", "0910-004-n004-0", ], position: new Point(-415, 434), }, BREASTS: { // おっぱい name: 'BREASTS', label: '0900-012-n012-0', texts: [ "0920-001-n001-0", "0920-002-n002-0", "0920-003-n003-0", "0920-004-n004-0", ], position: new Point(-436, 332), }, BUTT: { // お尻 name: 'BUTT', label: '0900-013-n013-0', texts: [ "0930-001-n001-0", "0930-002-n002-0", "0930-003-n003-0", "0930-004-n004-0", ], position: new Point(-524, 516), }, MOUTH: { // おクチ name: 'MOUTH', label: '0900-014-n014-0', texts: [ "0940-001-n001-0", "0940-002-n002-0", "0940-003-n003-0", "0940-004-n004-0", ], position: new Point(-470, 0), }, WOMB: { // 子宮 name: 'WOMB', label: '0900-017-n017-0', texts: [ "0950-001-n001-0", "0950-002-n002-0", "0950-003-n003-0", "0950-004-n004-0", ], position: new Point(-407, 525), }, MIND: { // 精神 name: 'MIND', label: '0900-018-n018-0', texts: [ "0960-001-n001-0", "0960-002-n002-0", "0960-003-n003-0", "0960-004-n004-0", ], position: new Point(-440, 320), }, }; //======================================================================== // クラス定義 (SceneLewdStatus) //======================================================================== class SceneLewdStatus extends Scene_Base { constructor() { super(); this.images = {}; this.isImageLoaded = false; this.runOnExit = false; this.interpreter = null; this._state = null; this.stateSprite = {}; this.currentStage = null; } create() { super.create(); this.createWindowLayer(); let promises = [ ImageManager.loadSystemAsync("lewd_status/background"), ImageManager.loadSystemAsync("lewd_status/back_button"), ImageManager.loadSystemAsync("lewd_status/frame"), ImageManager.loadSystemAsync("lewd_status/body_mask"), ImageManager.loadSystemAsync("lewd_status/body/stage_1"), ImageManager.loadSystemAsync("lewd_status/body/stage_2"), ImageManager.loadSystemAsync("lewd_status/body/stage_3"), ImageManager.loadSystemAsync("lewd_status/body/stage_4"), ImageManager.loadSystemAsync("lewd_status/body_background"), ]; const bgBitmap = new Bitmap(Graphics.width, Graphics.height); bgBitmap.fillAll('#000000'); this.blackBackground = new Sprite(bgBitmap); this.blackBackground.setFrame(0, 0, Graphics.width, Graphics.height); this.blackBackground.zIndex = 0; this.addChild(this.blackBackground); Promise.all(promises).then(images => { this.createDisplayObjects(images); this.isImageLoaded = true; }); } createDisplayObjects(images) { this.background = new Sprite(images[0]); this.background.zIndex = 1; this.addChild(this.background); this.baseSprites = this.createSprites(images); this.content = this.createContentSprite(images, images[2].width, images[2].height); if (!!this.content) { this.content.move(UI_AREA_X, UI_AREA_Y); this.content.zIndex = 100; this.addChild(this.content); } this.window = this.createMessageWindow(); this.addWindow(this.window); this.sortChildren(); } createSprites(images) { const sprites = []; const uiWidth = images[2].width; const uiHeight = images[2].height; const frame = new Sprite(new Bitmap(uiWidth, uiHeight)); const frameBitmap = frame.bitmap; frameBitmap.blt(images[2], 0, 0, uiWidth, uiHeight, 0, 0); frameBitmap.textColor = '#FFFFFF'; frameBitmap.fontFace = 'genkai-mincho'; frameBitmap.outlineWidth = 0; frameBitmap.fontSize = 64; frameBitmap.drawText(TextResource.getText(TITLE_TEXT), 52, 46, 1200, 64, 'left'); frame.move(7, 0); frame.zIndex = 60; this.addChild(frame); sprites.push(frame); const backButtonArea = new Sprite_InputHandle(); backButtonArea.bitmap = images[1]; backButtonArea.setFrame(0, 0, 72, 72); backButtonArea.addEnterListener(() => { if (this.handleBackButtonClicked()) { if (!this.runOnExit && !this.isBusy()) { this._exit(); } } }); backButtonArea.move(1830, 990); backButtonArea.zIndex = 3; this.addChild(backButtonArea); sprites.push(backButtonArea); const bar1 = this.createLewdGauge(param.lewdLevel1, SYSTEM_LEWD_VALUE1); bar1.move(902, 846); bar1.zIndex = 100; this.addChild(bar1); sprites.push(bar1); const bar2 = this.createLewdGauge(param.lewdLevel2, SYSTEM_LEWD_VALUE2); bar2.move(902, 918); bar2.zIndex = 100; this.addChild(bar2); sprites.push(bar2); const level = $gameActors.actor(param.playerActor).level; const levelTextBitmap = new Bitmap(918, 50); levelTextBitmap.textColor = '#FFFFFF'; levelTextBitmap.fontFace = 'MPLUS1Code-Regular'; levelTextBitmap.outlineWidth = 0; levelTextBitmap.fontSize = 40; levelTextBitmap.drawText(TextResource.getText(SYSTEM_TOTAL_LEBEL), 0, 0, 230, levelTextBitmap.height, 'left'); levelTextBitmap.drawText(level, 818, 0, 100, levelTextBitmap.height, 'right'); const levelText = new Sprite(levelTextBitmap); levelText.move(902, 986); levelText.zIndex = 100; this.addChild(levelText); sprites.push(levelText); return sprites; } createContentSprite(images, width, height) { const content = new Sprite(new Bitmap(width, height)); const charaBackGround = new Sprite(images[8]); charaBackGround.move(1265, 33); charaBackGround.zIndex = 1; content.addChild(charaBackGround); const chMask = new Sprite(images[3]); this.character = new Sprite_Scrollable(images[3].width, images[2].height, chMask); this.leveledCharacters = [ 0, 1, 2, 3 ].map(index => { const chImageSprite = new Sprite(images[index + 4]); chImageSprite.zIndex = 1; chImageSprite.hide(); this.character.addChild(chImageSprite); return chImageSprite; }); this.character.enableLimit(false); this.character.enableInput(false); this.character.zIndex = 3; this.character.move(1265, 33); content.addChild(this.character); this.stateMenuArea = new Sprite_Scrollable(ITEM_WIDTH, CONTENT_AREA_HEIHGT); this.stateMenuArea.enableScroll(false); this.stateMenus = this.createMenuSprite(Object.values(State)).map(sprite => { this.stateMenuArea.addChild(sprite); return sprite; }); this.stateMenuArea.move(39, CONTENT_TOP); this.stateMenuArea.zIndex = 2; content.addChild(this.stateMenuArea); this.descriptionArea = this.createDescriptionFrame(); const descriptionEntries = Object.values(State).map(state => { return [ state.name, { state: state.name, sprites: [ 1, 2, 3, 4 ].map(level => { const sprite = this.createDescriptionText(state, level); sprite.hide(); this.descriptionArea.addChild(sprite); return sprite; }), } ]; }); this.descriptions = Object.fromEntries(descriptionEntries); this.descriptionArea.move(574, CONTENT_TOP); this.descriptionArea.zIndex = 2; content.addChild(this.descriptionArea); this.setState(State.PUSSY.name); return content; } createMenuSprite(itemNames) { return itemNames.map((item, index) => { const sprite = new Sprite_StatusItem(item.name, item.label, ITEM_WIDTH, ITEM_HEIGHT); sprite.move(0, (ITEM_HEIGHT + ITEM_MERGIN) * index); return sprite; }); } createDescriptionFrame() { const areaSprite = new Sprite_Scrollable(CONTENT_AREA_WIDTH, CONTENT_AREA_HEIHGT); const frameSprite = new Sprite(new Bitmap(CONTENT_AREA_WIDTH, CONTENT_AREA_HEIHGT)); const frameBitmap = frameSprite.bitmap; const lw = CONTENT_LINE_WIDTH; frameBitmap.fillAll('#FFFFFF'); frameBitmap.clearRect(lw, lw, CONTENT_AREA_WIDTH - (lw * 2), CONTENT_AREA_HEIHGT - (lw * 2)); frameSprite.zIndex = 2; areaSprite.addChild(frameSprite); return areaSprite; } createDescriptionText(state, level) { const index = level - 1; const text = TextResource.getText(state.texts[index]); const lines = PluginUtils.splitText(text, 23); const width = CONTENT_AREA_WIDTH - (DESCRIPTION_MERGIN * 2); const height = (lines.length * DESCRIPTION_LINE_HEIGHT); const bitmap = new Bitmap(width, height); bitmap.textColor = '#FFFFFF'; bitmap.fontFace = 'NotoSerifCJKjp-Bold'; bitmap.outlineWidth = 0; bitmap.fontSize = 28; lines.forEach((line, index) => { const y = (DESCRIPTION_LINE_HEIGHT * index); bitmap.drawText(line, 0, y, width, DESCRIPTION_LINE_HEIGHT, 'left'); }) const sprite = new Sprite(bitmap); sprite.move(DESCRIPTION_MERGIN, (DESCRIPTION_MERGIN / 2)); sprite.zIndex = 1; return sprite; } createMessageWindow() { const rect = new Rectangle(0, 0, 840, 248); const window = new Window_LewdLevel(rect); window.setLewdLevelListener(this.setLewdStage.bind(this)); const currentLewdStage = Math.max(PluginUtils.getVariables(param.lewdStage) || 1, 1); this.setLewdStage(currentLewdStage); return window; } createWindowLayer() { this._windowLayer = new WindowLayer(); this._windowLayer.x = 7; this._windowLayer.y = 826; this._windowLayer.zIndex = 500; this.addChild(this._windowLayer); } createLewdGauge(bindingVariable, label) { const sprite = new Sprite(new Bitmap(1000, 54)); const bitmap = sprite.bitmap; bitmap.textColor = '#FFFFFF'; bitmap.fontFace = 'MPLUS1Code-Regular'; bitmap.fontSize = 40; bitmap.outlineWidth = 0; const labelWidth = 230; const countWidth = 68; const textHeight = 50; const labelY = (bitmap.height - textHeight) / 2; const barWidth = 620; const mergin = 10; bitmap.drawText(TextResource.getText(label), 0, labelY, labelWidth, textHeight, 'left'); const lewdCount = PluginUtils.getVariables(bindingVariable) || 0; bitmap.drawText(lewdCount, labelWidth + barWidth, labelY, countWidth, textHeight, 'right'); const bar = new Sprite_ProgressBar(barWidth, 54, 99); bar.lineWidth = 6; bar.bind(bindingVariable); bar.setProgressGradation([ new GradientPoint(0, '#CACACA'), new GradientPoint(100, '#CACACA'), ]); bar.zIndex = 3; bar.move(labelWidth + mergin, 0); sprite.addChild(bar); return sprite; } setBloking(enable) { if (enable !== this.isTouchBlocking) { if (enable) { this.onStartBlocking(); } else { this.onEndBlocking(); } this.isTouchBlocking = enable; } } setState(value) { if (State.hasOwnProperty(value)) { if (value !== this._state) { const point = State[value].position; this.character.smoothScrollTo(point.x, point.y, 6); Object.values(this.descriptions).forEach(description => { description.sprites.forEach((sprite, index) => { sprite.visible = (description.state === value && this.currentStage === (index + 1)); }); }); this.stateMenus.forEach((sprite, index) => { if (sprite.getName() === value) { sprite.setFocus(true); this.stateindex = index; } else { sprite.setFocus(false); } }); this._state = value; } } else { Logger.w(`[SceneLewdStatus] invalid state: state = ${value}`); } } setLewdStage(value) { const stage = Number(value).clamp(1, 4); if (this.currentStage !== stage) { Object.values(this.descriptions).forEach(description => { description.sprites.forEach((sprite, index) => { sprite.visible = (description.state === this._state && stage === (index + 1)); }); }); this.leveledCharacters.forEach((sprite, index) => { sprite.visible = (stage === (index + 1)); }); this.currentStage = stage; } } onExit() { // for overload } onStartBlocking() { // for overload } onEndBlocking() { // for overload } handleBackButtonClicked() { // for overload return true; } start() { super.start(); if (!!this.bgm && this.bgm !== '') { AudioManager.playBgm({ name: this.bgm, volume: 100, pitch: 100, pan: 0, pos: 0, }); } } stop() { super.stop(); if (!!this.bgm && this.bgm !== '') { AudioManager.stopBgm(); } } update() { super.update(); if (!this.isActive()) { return; } if (!this.runOnExit && !this.isBusy()) { this.processInput(); } } processInput() { if ((Input.isRepeated("cancel") || TouchInput.isCancelled()) && !this.runOnExit) { this._exit(); } else if (Input.isRepeated(InputClass.INPUT_CLASS_UP)) { this.moveStateFocus((this.stateindex < 0) ? 0 : -1); } else if (Input.isRepeated(InputClass.INPUT_CLASS_DOWN)) { this.moveStateFocus((this.stateindex < 0) ? 0 : 1); } else if (TouchInput.isHovered()) { this.processStatus(); } } processStatus() { if (this.stateMenuArea.isTouchedInsideFrame()) { const focusedIndex = this.stateMenus.findIndex(sprite => sprite.isHovered()); if (focusedIndex >= 0) { this.updateStateFocusIndex(focusedIndex, true); } } } moveStateFocus(moveIndex) { const index = Number((this.stateindex >= 0) ? this.stateindex + moveIndex : 0); if (index >= 0 && index < this.stateMenus.length) { this.updateStateFocusIndex(index, false); } } updateStateFocusIndex(index, fromTouch) { if (index >= 0 && this.stateindex !== index) { this.stateMenus.forEach((s, i) => s.setFocus(i === index)); this.stateindex = index; this.setState(this.stateMenus[index].getName()); SoundManager.playCursor(); return true; } return false; } _exit() { this.runOnExit = true; SoundManager.playCancel(); this.onExit(); // this.fadeOutAll(); this._updateInput(); this._exitScene(); } _exitScene() { SceneManager.pop(); } _updateInput() { Input.update(); TouchInput.update(); } } window.SceneLewdStatus = SceneLewdStatus; //======================================================================== // クラス定義 (Window_LewdLevel) //======================================================================== class Window_LewdLevel extends Window_Base { constructor(rect) { super(rect); this.move(rect.x, rect.y, rect.width, rect.height); this._frame this._modeListener = null; this._lewdLevelListener = null; } createContents() { super.createContents(); const bitmap = this.contents; bitmap.textColor = '#FFFFFF'; bitmap.fontFace = 'NotoSerifCJKjp-Black'; bitmap.fontSize = 40; bitmap.outlineWidth = 0; const textWidth = 804; const x = (bitmap.width - textWidth) / 2; bitmap.drawText(TextResource.getText('0900-005-n005-0'), x, 6, textWidth, 50, 'center'); const labels = [ '0900-006-n006-0', '0900-007-n007-0', '0900-008-n008-0', '0900-009-n009-0', ]; const maxLewdStage = Math.max(PluginUtils.getVariables(param.lewdStage) || 1, 1) - 1; const areaSprite = new Sprite(); this.stages = labels.map((label, index) => { const sprite = new Sprite_LewdLevel(label, index + 1); const x = (index % 3) * (LEWD_LEVEL_WIDTH + LEWD_LEVEL_MERGIN); const y = Math.trunc(index / 3) * (LEWD_LEVEL_HEIGHT + LEWD_LEVEL_MERGIN); sprite.setActive(index <= maxLewdStage); sprite.move(x, y); areaSprite.addChild(sprite); return sprite; }); const bounds = areaSprite.getBounds(); areaSprite.move((this.width - bounds.width) / 2, 84); this.addChild(areaSprite); this.updateFocusIndex(maxLewdStage, false); } setDrugAcitive(active) { this.stages[this.stages.length - 1].setActive(active); } setModeListener(listener) { if (!!listener && typeof listener === 'function') { this._modeListener = listener; } } setLewdLevelListener(listener) { if (!!listener && typeof listener === 'function') { this._lewdLevelListener = listener; } } update() { super.update(); this.processInput(); } processInput() { if (Input.isTriggered(InputClass.INPUT_CLASS_LEFT)) { for (let i = 1; (this.index - i) >= 0; i++) { const index = Number(this.index - i).clamp(0, this.stages.length); if (this.stages[index].isActive()) { this.updateFocusIndex(index, false); break; } } } else if (Input.isTriggered(InputClass.INPUT_CLASS_RIGHT)) { for (let i = 1; (this.index + i) < this.stages.length; i++) { const index = Number(this.index + i).clamp(0, this.stages.length); if (this.stages[index].isActive()) { this.updateFocusIndex(index, false); break; } } } else if (TouchInput.isHovered()) { const focusedIndex = this.stages.findIndex(sprite => { return sprite.isHovered() && sprite.isActive(); }); if (focusedIndex >= 0) { this.updateFocusIndex(focusedIndex, true); } } } updateFocusIndex(index, fromTouch) { if (index >= 0 && this.index !== index) { this.stages.forEach((s, i) => { if (i === index) { s.setFocus(true); const level = s.getLevel(); if (level < 0) { this._fireModeChange(Mode.DRAG); } else { if (this.index >= 0 && this.stages[this.index].getLevel() < 0) { this._fireModeChange(Mode.STATUS); } this._fireLewdLevelChanged(level); } } else { s.setFocus(false); } }); this.index = index; SoundManager.playCursor(); return true; } return false; } _fireModeChange(newMode) { if (!!this._modeListener && typeof this._modeListener === 'function') { this._modeListener(newMode); } } _fireLewdLevelChanged(newLevel) { if (!!this._lewdLevelListener && typeof this._lewdLevelListener === 'function') { this._lewdLevelListener(newLevel); } } } //======================================================================== // クラス定義 (Sprite_StatusItem) //======================================================================== class Sprite_StatusItem extends Sprite_InputHandle { constructor(name, label, width, height) { super(); this.setFrame(0, 0, width, height); this._name = name; this._focus = false; this.bg = new Sprite(new Bitmap(width, height)); const bgBitmap = this.bg.bitmap; bgBitmap.fillAll('#FFFFFF'); this.bg.zIndex = 0; this.bg.opacity = PluginUtils.percent(255, 70); this.addChild(this.bg); const textSprite = this.createLabelSprite(label); textSprite.move((this.width - textSprite.width) / 2, (this.height - textSprite.height) / 2); textSprite.zIndex = 1; this.addChild(textSprite); this.setFocus(false); } createLabelSprite(label) { const title = new Bitmap(494, 40); title.textColor = '#FFFFFF'; title.fontFace = 'NotoSerifCJKjp-Bold'; title.outlineWidth = 0; title.fontSize = 28; title.drawText(TextResource.getText(label), 0, 0, 494, 40, 'left'); return new Sprite(title); } getName() { return this._name; } normalColor() { return 0x000000; } focusedColor() { return 0xCACACA; } setFocus(focus) { this.bg.tint = focus ? this.focusedColor() : this.normalColor(); this._focus = focus; } isFocused() { return this._focus; } } //======================================================================== // クラス定義 (Sprite_LewdLevel) //======================================================================== class Sprite_LewdLevel extends Sprite_StatusItem { constructor(label, level) { super(String(level), label, LEWD_LEVEL_WIDTH, LEWD_LEVEL_HEIGHT); this._level = level; this._active = true; } getLevel() { return Number(this.getName()); } normalColor() { return 0x444444; } setActive(value) { this.opacity = value ? 255 : 40; this._active = value; } isActive() { return this._active; } createLabelSprite(label) { const title = new Bitmap(LEWD_LEVEL_WIDTH, LEWD_LEVEL_HEIGHT); title.textColor = '#FFFFFF'; title.fontFace = 'NotoSerifCJKjp-Bold'; title.outlineWidth = 0; title.fontSize = 36; title.drawText(TextResource.getText(label), 0, 0, LEWD_LEVEL_WIDTH, LEWD_LEVEL_HEIGHT, 'center'); return new Sprite(title); } } //======================================================================== // プラグインコマンド //======================================================================== PluginManagerEx.registerCommand(script, 'startScene', args => { SceneManager._scene.fadeOutAll(); SceneManager.push(SceneLewdStatus); }); })();