// ==UserScript== // @name UrMortal // @namespace http://tampermonkey.net/ // @version 2.3 // @description MortalReviewer(KillerDucky)のGUIを変更し、悪手率を表示します。 // @match https://mjai.ekyu.moe/killerducky/?data=* // @grant none // @downloadURL https://update.greasyfork.icu/scripts/516625/UrMortal.user.js // @updateURL https://update.greasyfork.icu/scripts/516625/UrMortal.meta.js // ==/UserScript== (function() { 'use strict'; // テキスト画像変更 const replacementTextForUun = 'うーん...';//テキストを「うーん...」から変更します。 const replacementTextForAkan = 'アカン!';//テキストを「アカン!」から変更します。 const newImageURL = 'https://mjai.ekyu.moe/killerducky/media/rustferris.png';//画像を変更します。 const images = document.querySelectorAll('img.killer-call-img[src="media/rustferris.png"]'); images.forEach(img => { img.src = newImageURL; }); const observer = new MutationObserver(() => { const textElements = document.querySelectorAll('text[fill="hsla(190, 0%, 100%, 0.70)"]'); textElements.forEach(textElement => { if (textElement.textContent === 'うーん...') { textElement.textContent = replacementTextForUun; } else if (textElement.textContent === 'アカン!') { textElement.textContent = replacementTextForAkan; } }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); (async function() { 'use strict'; // ヘルプボタンとダイアログの要素を取得 const aboutModal = document.getElementById('about-modal'); const aboutButton = document.getElementById('about'); // URLからJSONファイル名を抽出し、JSONデータのURLを動的に作成 const pathMatch = window.location.href.match(/data=(?:%2F|\/)report(?:%2F|\/)([a-zA-Z0-9]+\.json)/); if (!pathMatch) { console.error("JSONファイルパスが見つかりませんでした。"); return; } const jsonUrl = `https://mjai.ekyu.moe/report/${pathMatch[1]}`; if (aboutModal && aboutButton) { aboutButton.addEventListener('click', async () => { try { // JSONデータをフェッチ const response = await fetch(jsonUrl); if (!response.ok) { throw new Error(`HTTPエラー: ${response.status}`); } const data = await response.json(); let matchRate = ''; let rating = ''; let mistakeCount = 0; let totalEntries = 0; let mortalengine = ''; // engineのデータを格納する変数 let modeltag = ''; // model_tagのデータを格納する変数 let version = ''; // versionのデータを格納する変数 let temperature = ''; // temperatureのデータを格納する変数 // engineのデータを取得 if (data.engine) { mortalengine = data.engine; // engineの値をmortalengineに格納 } // model_tagのデータを取得 if (data.review && data.review.model_tag) { modeltag = data.review.model_tag; // model_tagの値をmodeltagに格納 } // versionのデータを取得 if (data.version) { version = data.version; // versionの値をversionに格納 } // temperatureのデータを取得 if (data.review && data.review.temperature) { temperature = data.review.temperature; // temperatureの値をtemperatureに格納 } // 一致率とレーティングの取得と計算 if (data.review) { const totalReviewed = data.review.total_reviewed; const totalMatches = data.review.total_matches; matchRate = Math.ceil((totalMatches / totalReviewed) * 1000) / 10; // 小数点第1位まで rating = Math.ceil(data.review.rating * 1000) / 10; // レーティングを100倍し小数点第1位 } // 悪手率を計算 data.review.kyokus.forEach(kyoku => { kyoku.entries.forEach(entry => { if (!entry.is_equal) { const actualPai = entry.actual.pai; const lowProbActions = entry.details.filter(detail => detail.action.pai === actualPai && detail.prob <= 0.05 ); if (lowProbActions.length > 0) { mistakeCount++; } } totalEntries++; }); }); const mistakeRate = Math.ceil((mistakeCount / totalEntries) * 1000) / 10; // 小数点第1位まで // 色とスタイルを条件に応じて設定 const matchRateStyle = matchRate >= 80 ? "color: gold;" : ""; const ratingStyle = rating >= 90 ? "color: gold;" : ""; const mistakeRateStyle = mistakeRate <= 5 ? "color: gold;" : ""; // 数値を太字、透明な背景にするためのスタイル(一致率、レーティング、悪手率用) const cellStyle = "background-color: transparent; font-weight: bold; text-align: center; border: none;"; // 通常のセル(一致回数 / 打牌選択回数と悪手回数 / 打牌選択回数) const normalCellStyle = "text-align: center; border: 1px solid #ccc;"; // 一致率、レーティング、悪手率をテーブルセル表示し、次の行に 一致回数 / 打牌選択回数 と 悪手回数 / 打牌選択回数 を追加 aboutModal.innerHTML = `
`; // ダイアログを表示 aboutModal.showModal(); } catch (error) { console.error("JSONデータの取得または処理中にエラーが発生しました:", error); } }); } })();