shiny-cuty-excel-chiffon/data/Conductor.tjs
2024-10-22 11:38:49 -05:00

790 lines
30 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Conductor.tjs - KAG シナリオ進行処理
// Copyright (C)2001-2006, W.Dee and contributors 改変・配布は自由です
class ConductorException extends Exception
{
// ConductorException - Conductor がタグハンドラを処理中に発生した例外を
// 投げる時に使われる例外クラス
function ConductorException() { super.Exception(...); }
function finalize() { super.finalize(...); }
};
class BaseConductor extends KAGParser
{
// BaseConductor - シナリオ進行処理のベースクラス
var timer;
var oneshot;
var _interrupted = false; // 中断中か
var timerEnabled = false; // タイマが起動中か
var pendings; // 後回しにされたタグ
var inProcessing = false; // timerCallback を処理中かどうか
var reentered = false; // timerCallback 中に 再入したか
var nextTimerTick = 0; // 次にタイマーが発動されるはずの tick
function BaseConductor()
{
// コンストラクタ
super.KAGParser(...);
timer = new Timer(timerCallback, '');
// Timerの第二引数に空文字列を指定すると
// 第1引数に指定した関数を直接呼び出すようになる
oneshot = new AsyncTrigger(timerCallback, '');
// これも同様
oneshot.cached = true; // イベントのキャッシュを有効に
pendings = [];
}
function finalize()
{
// finalize()
invalidate timer;
invalidate oneshot;
super.finalize(...);
}
function clear()
{
// clear オーバーライド
pendings.clear();
super.clear();
}
function timerCallback()
{
// 次の要素を得る
nextTimerTick = timer.interval + System.getTickCount();
var obj;
try
{
if(inProcessing)
{
// 再入
reentered = true;
timer.interval = 0;
return;
}
inProcessing = true;
for(;;)
{
if(pendings.count > 0)
{
// 後回しにされたタグがある場合
obj = pendings[0];
pendings.erase(0);
}
else
{
// 後回しにされたタグがないので次のタグを得る
obj = getNextTag();
// getNextTag() の中で、pendings に追加された (iscript など)
if(pendings.count > 0)
{
pendings.add(obj);
continue;
}
}
if(obj === void)
{
// シナリオ終了
timer.enabled = false;
timerEnabled =false;
onStop();
inProcessing = false;
reentered = false;
return;
}
else
{
// onTag を呼ぶ
var step = onTag(obj);
if(step === void)
throw new Exception("onTag が void を返しました (" + obj.tagname + ")"
"( おそらくタグハンドラの戻り値を返し忘れた )");
step = int step; // step を数値に
if(step == 0)
{
// ウェイトを掛けずに次へ
timer.interval = 0;
continue;
}
else if(step < 0)
{
switch(step)
{
case -5: // いったんイベントを処理(現在のタグは後回し)
pendings.insert(0, obj);
oneshot.mode = atmAtIdle;
oneshot.trigger(); // トリガ
timer.interval = 0; // タイマは停止
inProcessing = false;
reentered = false;
return;
case -4: // いったんイベントを処理
oneshot.mode = atmAtIdle;
oneshot.trigger(); // トリガ
timer.interval = 0; // タイマは停止
inProcessing = false;
reentered = false;
return;
case -3: // 後回ししてブレーク
pendings.insert(0, obj);
timer.interval = 0; // タイマは停止
inProcessing = false;
reentered = false;
return;
case -2: // ブレーク
timer.interval = 0; // タイマは停止
inProcessing = false;
reentered = false;
return;
case -1: // シナリオ終了
timer.interval = 0;
timer.enabled = false;
timerEnabled = false;
onStop();
inProcessing = false;
reentered = false;
return;
}
}
else
{
// 次へ
if(timer.interval != step)
{
timer.interval = step;
nextTimerTick = step + System.getTickCount();
}
inProcessing = false;
reentered = false;
return;
}
}
}
inProcessing = false;
reentered = false;
}
catch(e)
{
// Debug.logAsError();
timer.enabled = false;
timerEnabled =false;
onStop();
inProcessing = false;
var msg = "エラーが発生しました\n"
"ファイル : " + curStorage + " 行 : " + (curLine+1) + "\n"
"タグ : " + (obj === void ? "不明" : obj.tagname)
+ " ( ← エラーの発生した前後のタグを示している場合もあります )\n"
+ e.message;
if((typeof e.trace) != "undefined") dm("trace : " + e.trace);
dm(msg);
throw new ConductorException(msg);
// System.inform(msg, "エラー");
}
}
function onTag()
{
// オーバーライドすること
return -1;
}
function onStop()
{
// (シナリオの)停止時に呼ばれる。
// stop() から呼ばれるわけではない。
// オーバーライドすること。
}
function startProcess(immediate = false)
{
// シナリオ進行開始
// immediate = false の場合は非同期で実行を開始するので、
// このメソッド内でタグハンドラが呼ばれることはない
// 次のイベント配信のタイミングで最初のタグハンドラが呼ばれる。
// immediate = true の場合は、このメソッド内で初回のタグハンドラが
// 処理されるため、呼び出し側はこのメソッドの実行が終わったら
// すぐに吉里吉里に制御を戻す(すべての関数から抜ける)ようにするべき。
resetInterrupt();
timer.interval = 0; // 初期インターバル
timerEnabled = true;
if(!_interrupted)
{
timer.enabled = true; // タイマー開始
if(immediate)
{
timerCallback();
}
else
{
oneshot.mode = atmExclusive;
// イベントが配信されるまで他の非同期イベントをブロック
oneshot.trigger(); // トリガ
}
}
}
function start()
{
// タイマ開始
timerEnabled = true;
timer.enabled = true;
}
function stop()
{
// タイマ停止
timer.enabled = false;
timerEnabled = false;
}
property interrupted
{
getter() { return _interrupted; }
setter(x)
{
if(!x)
{
// enable
if(timerEnabled)
{
timer.interval = 0;
timer.enabled = true;
oneshot.mode = atmExclusive;
// イベントが配信されるまで他の非同期イベントをブロック
oneshot.trigger(); // トリガ
}
}
else
{
// disable
oneshot.cancel();
timer.enabled = false;
}
_interrupted = x;
}
}
function assign(src)
{
// src の状態をこのオブジェクトにコピー
var t = timer;
var st = src.timer;
t.enabled = false;
t.interval = st.interval;
nextTimerTick = src.nextTimerTick;
if(st.enabled && st.interval != 0)
{
// タイマ interval の調整
var delta = nextTimerTick - System.getTickCount();
if(delta > 0) t.interval = delta; else t.interval = 1;
}
t.enabled = st.enabled;
timerEnabled = src.timerEnabled;
_interrupted = src._interrupted;
if(src.pendings.count > 0)
pendings.assignStruct(src.pendings);
else
pendings.clear();
super.assign(src);
}
function store()
{
// store オーバーライド
return super.store(...);
}
function restore(dic)
{
// restore オーバーライド
try{
super.restore(...);
}catch(e){
Debug.notice(e.message);
}
pendings.clear();
}
function loadScenario()
{
// loadScenario オーバーライド
pendings.clear();
super.loadScenario(...);
}
function goToLabel(l)
{
dm("■ curStorage : " + curStorage + " / curLabel : " + curLabel + " / goToLabel : " + l);
// goToLabel オーバーライド
pendings.clear();
super.goToLabel(...);
}
function enqueueTag(tag)
{
pendings.add(tag);
}
}
//ryo--
class VoiceCheckConductor extends KAGParser{
function VoiceCheckConductor(){
super.KAGParser(...);
}
function finalize(){
super.finalize(...);
}
function getTextLength(){
var count = 0;
var obj;
debugLevel = tkdlNone;
try{
while(true){
obj = getNextTag();
if(obj===void) break;
if(obj.tagname=="counttext") break;
if(obj.tagname=="scenarioend") break;
if(obj.tagname=="ch") count++;
}
}catch(e){
// dm(e.message);
}
return count;
}
function checkNextText(){
var flg = 0;
var obj;
debugLevel = tkdlNone;
try{
while(true){
obj = getNextTag();
if(obj===void) break;
if(obj.tagname=="counttext") flg = 1;
if(obj.tagname=="scenarioend") break;
if(obj.tagname=="l") break;
}
}catch(e){
// dm(e.message);
}
return flg;
}
}
class ExtasyCheckConductor extends KAGParser{
function ExtasyCheckConductor(){
super.KAGParser(...);
}
function finalize(){
super.finalize(...);
}
function getCount(){
var countM = 1;
var countF = 1;
var flagM = false;
var flagF = false;
var obj;
debugLevel = tkdlNone;
while(true){
obj = getNextTag();
if(obj===void) break;
if(obj.tagname=="extasymale"){
flagM = true;
if(flagF)break;
}
if(obj.tagname=="extasyfemale"){
flagF = true;
if(flagM)break;
}
if(obj.tagname=="extasycountcancel" || obj.tagname=="scenarioend"){
countM = -1 if(flagM==false);
countF = -1 if(flagF==false);
break;
}
if(obj.tagname=="l"){
countM++ if(flagM==false);
countF++ if(flagF==false);
}
}
kag.extasyCountMale = countM;
kag.extasyCountFemale = countF;
return void;
}
}
//--
class GetLineStrConductor extends KAGParser
{
function GetLineStrConductor(){
super.KAGParser(...);
}
function finalize(){
super.finalize(...);
}
function getLineStr(storage, label, offset)
{
// これを指定しないとjumpやcallを処理しようとするiscriptでは大丈夫か→多分大丈夫
processSpecialTags = false;
loadScenario(storage);
if(label !== void) goToLabel(label);
var targetLine = offset + curLine;
var obj;
try{
for(;;){
obj = getNextTag();
// dm("storage : " + storage + " / line : " + curLine + " / tag : " + obj.tagname);
if(obj === void) return "(´・ω・`)!";
if(curLine > targetLine){
dm("label : " + label + " / offset : " + offset + " / curLine : " + curLine + " / curLineStr : " + curLineStr);
break;
}
}
}catch(e){
dm("GetLineStrConductor : " + e.message);
}
return curLineStr;
}
}
class Conductor extends BaseConductor
{
// Conductor - シナリオ進行処理
/*const*/ var mStop = 0; // 停止
/*const*/ var mRun = 1; // 動作中
/*const*/ var mWait = 2; // 待ち
var owner;
var handlers;
var status = mStop;
var timeOutTimer;
var waitUntil = %[];
var lastTagName = ''; // 直前のタグ名
function Conductor(owner, handlers)
{
// コンストラクタ
super.BaseConductor();
ignoreCR = global.ignoreCR;
debugLevel = tkdlVerbose;
this.owner = owner;
this.handlers = handlers;
timeOutTimer = new Timer(onTimeOut, '');
}
function finalize()
{
// finalize()
invalidate timeOutTimer;
super.finalize(...);
}
function run(immediate = false)
{
// 実行の開始
// immediate=true の場合は、
// このメソッドを実行したらすぐに吉里吉里に制御を戻す
// (すべての関数から戻る)こと
status = mRun;
startProcess(immediate);
}
function sleep()
{
// 実行の停止
status = mStop;
stop();
}
function wait(until)
{
// 待ち
// until = trigger で用いるシグナル名とコールバック関数の
// 辞書配列
status = mWait;
stop();
(Dictionary.assign incontextof waitUntil)(until);
}
function waitWithTimeOut(until, timeout)
{
// 待ちを行うが、タイムアウトがある
// タイムアウト時には 'timeout' がトリガされるので
// ハンドラを定義すること。
if(timeout == 0) timeout = 1; // timeout が 0 の場合は 1 に
status = mWait;
stop();
(Dictionary.assign incontextof waitUntil)(until);
timeOutTimer.interval = timeout;
timeOutTimer.enabled = true;
}
function onTimeOut()
{
// timeOutTimer がタイムアウトした
timeOutTimer.enabled = false;
trigger('timeout'); // 自分自身で timeout をトリガする
}
function trigger(name)
{
// waitUntil 内にシグナル名 name が存在すれば、実行再開、
// 同時に waitUntil に登録されたメソッド(リスタートハンドラ)を呼ぶ
// シグナル名に _arg がついたものが waitUntil 内にあれば、
// それを引数としてハンドラに渡す
// waitUntil はクリアされる
if(status != mWait) return false;
var func = waitUntil[name];
if(func !== void)
{
var arg = waitUntil[name + '_arg'];
if(arg !== void) func(arg); else func();
(Dictionary.clear incontextof waitUntil)();
run();
return true;
}
else
{
return false;
}
}
function onTag(elm)
{
// タグの処理
var tagname = elm.tagname;
var handler = handlers[tagname];
if(handler !== void)
{
var ret = handler(elm);
lastTagName = tagname;
return ret;
}
return onUnknownTag(tagname, elm);
}
function onStop()
{
// BaseConductor.onStop オーバーライド
// 停止時に呼ばれるのでステータスを mStop にする
status = mStop;
if(owner.conductor == this) handlers.s(); // ハンドラの s (停止) を呼ぶ
}
function onScript(script, scriptname, lineofs)
{
// scirpt を実行する
try
{
Scripts.exec(script, scriptname, lineofs);
}
catch(e)
{
throw new Exception(scriptname + " の 行 " + lineofs + " から始まる"
" iscript ブロックでエラーが発生しました。"
"\n( 詳細はコンソールを参照してください )\n" + e.message);
}
return true;
}
function store()
{
// store オーバーライド
return super.store(...);
}
function restore(dic)
{
// restore オーバーライド
super.restore(...);
lastTagName = '';
}
function onScenarioLoad()
{
return owner.onConductorScenarioLoad(...);
}
function onScenarioLoaded()
{
return owner.onConductorScenarioLoaded(...);
}
function onLabel()
{
return owner.onConductorLabel(...);
}
function onJump()
{
return owner.onConductorJump(...);
}
function onCall()
{
return owner.onConductorCall(...);
}
function onReturn()
{
return owner.onConductorReturn(...);
}
function onAfterReturn()
{
return owner.onConductorAfterReturn(...);
}
function onScript()
{
return owner.onConductorScript(...);
}
function onUnknownTag()
{
return owner.onConductorUnknownTag(...);
}
}
class MultiLanguageConductor extends Conductor{
function MultiLanguageConductor(owner, handlers)
{
// コンストラクタ
super.Conductor(...);
}
function finalize()
{
super.finalize(...);
}
function getCurrentOrgFileName(){
return getOrgFileName(curStorage);
}
function restore(dic)
{
dic.storageName = getFileName(dic.storageName);
dic.storageShortName = getFileName(dic.storageShortName);
for(var i=0; i<dic.callStack.count; i++){
// 現在の言語設定に基づきファイル名を変更する
var savedStorageName = dic.callStack[i].storage;
var newStorageName = getFileName(savedStorageName);
// if(savedStorageName != newStorageName){
// 全てのファイルに対して実行した方がよい。強化パッチ用の差異によりdefeatedHscene.ksでエラーになるため
dic.callStack[i].storage = getFileName(dic.callStack[i].storage);
// ファイル名を変更したことによって発生するエラーを防止する
// 読み込んだスクリプトの該当行とorgLineStrの内容が異なっているとrestore()時にエラーになってしまうので、新しく取得してしまう)
var tempConductor = new GetLineStrConductor();
var str = tempConductor.getLineStr(dic.callStack[i].storage, dic.callStack[i].label, dic.callStack[i].offset);
dic.callStack[i].orgLineStr = str;
invalidate tempConductor;
// }
}
super.restore(...);
}
}
class SConductor extends Conductor
{
// アクションステージ用コンダクタ
var currentLine = 0;
var lineFlag = false;
function SConductor(owner, handlers)
{
// コンストラクタ
super.Conductor(...);
}
function finalize()
{
super.finalize(...);
}
function onTag(elm)
{
if(lineFlag && curLine<currentLine) return 0;
var ret = super.onTag(...);
currentLine = curLine;
lineFlag = false;
return ret;
}
function store()
{
var dic = super.store();
dic.currentLine = currentLine;
dic.status = status;
return dic;
}
function restore(dic)
{
// restore オーバーライド
super.restore(...);
if(dic.currentLine!==void) currentLine = dic.currentLine;
if(dic.status!==void) status =dic.status;
}
function onScenarioLoad()
{
super.onScenarioLoad(...);
currentLine = 0;
lineFlag = false;
}
function goToLabel()
{
super.goToLabel(...);
if(!lineFlag) currentLine = curLine;
}
}