レンタルwiki用ダイスボット案

オンラインでキャンペーン的なことをやっていると、
ゲーム中に出てきたNPCなどの設定をwikiで記録しておくと、何かと便利です。


仲間内でよく使ってるのが、無料の@wiki
「ここでダイスも振れればいいのに」という要望があったので、検討してみました。


普通のwikiならプラグインを作って・・・となるところですが、レンタルサービスなので、自作のプラグインを入れられません。

考えた結果、「フォーム送信前に、書き込みからダイスを抽出・変換するJavascript」という案が浮かびました。


設定や環境次第では、その他のレンタル掲示板/wiki/チャットなどにも応用が利きそうですが、
ジャストアイディアを形にしただけの段階なので、仕様検討の余地が大きそうです



@wikiは、管理人のみ編集可能なページで、Javasciptを記述する事ができます。

これと、コメントプラグインを組み合わせます。


指定のコメント欄に

成長のダイス振ります [2d6]

と書いて送信すると、 [2d6] の部分をダイスロールに変換して入力内容を書き換えます。

成長のダイス振ります [2d6] = (2,6) = 8

その直後にサーバに送信して、コメント投稿完了・・・という流れで動作します。


ダイスに対するズルは、以下の理由で防止できると考えてます*1

  1. 投稿したコメント(ダイス結果)を手動で書き換えると、wiki仕様で履歴が残る。
  2. ダイスを振った結果と同じように手入力して投稿すると、[2d6] = (3,4) = (2,6) = 8 のような不自然な表示になる。

基本的に、登録済みメンバー内輪で使う機能、という前提なので多少セキュリティは甘くても良いと思ってますが、
まだ、仕様改善の余地は多いです。


また根本的に、別の方法もないか、とも考えています。


*参考:試しに作ったソース*2

embedDiceBot = new function()
{
	// 設定
	var columnNumber = 2; // ダイス変換を行うカラムは何個目か
	var formNumber = 3; // ダイス変換を行うフォームはソース中の何番目か

	function diceInit() {
		// dice pattern
		dicePattern = new RegExp(/([\s\S]*)\[(\d+)(d)(\d+)([\d-+]+)?\]([\s\S]*)/i);

		columnNumber = columnNumber -1;
		formNumber = formNumber -1;
		targetForm = document.forms[formNumber];
		targetColumn = document.forms[formNumber].elements[columnNumber];

		result = [];
		sum = 0;
	}

	function pickupDice(diceArr) {
		preMsg = diceArr[1];
		diceNum = diceArr[2];
		diceNumber = diceArr[4];
		revision = diceArr[5];
		if (revision==undefined) {
			revision = '';
		}
		afterMsg = diceArr[6];

		if (diceNum<1) {
			alert('ダイスを何個振るか、1以上で指定してください');
			return false;
		}

		if (diceNumber<2) {
			alert('d2以下のダイスはありません');
			return false;
		}

		return true;
	}

	function diceGenerater(number){
		return Math.round(Math.random()*(number-1))+1;
	}

	function diceRoll() {
		for (var i=0; i<diceNum; i++) {
			result.push(diceGenerater(diceNumber));
			sum += result[i]
		}

		return result;
	}

	function revisionSum() {
		if (revision) {
			if (revision.match(/[-+]{2,}/)) {
				alert('+−が連続しています。');
				sum += revision;
				return false;
			}

			var revs = revision.match(/([-+])(\d+)/g);
			for (var j=0; j<revs.length; j++) {
				var op = revs[j].substr(0,1);
				var rev = revs[j].substr(1);
				if (op=='+') {
					sum = eval(sum) + eval(rev);
				} else if (op=='-') {
					sum = eval(sum) - eval(rev);
				} else {
					alert('式が正しくありません。');
					sum += revision;
					return false;
				}
			}
		}

		return sum;
	}

	function outputDiceResult() {
		return preMsg+'['+diceNum+dice[3]+diceNumber+revision+'] = ('
			+result.join(',')+') = '
			+sum
			+' '+afterMsg;
	}

	window.onload = function (){
		// Init
		diceInit();

		targetForm.onsubmit = function diceConvert() {
			var comment = targetColumn.value;

			if (comment!='' || comment==undefined) {
				dice = comment.match(dicePattern);

				if (dice!=null) {
					if (pickupDice(dice)==false) {
						return false;
					}

					// DiceRoll
					diceRoll();
					revisionSum();

					// output
					var convert = outputDiceResult();
					this.elements[1].value = convert;
				}

				return true;
			} else {
				return false;
			}

			return false;
		}
	}
}

*1:wiki機能依存

*2:フォームの位置などの設定は@wiki仕様