Example #1
0
string	Satori::UnKakko(const char* p,bool for_calc,bool for_non_talk)
{
	assert(p!=NULL);
	string	result;
	while ( p[0] != '\0' ) {
		string c=get_a_chr(p);
		result += (c=="(") ? KakkoSection(p,for_calc,for_non_talk) : c;
	}
	return	result;
}
Example #2
0
bool	Satori::Translate(string& ioScript) {

	if ( ioScript.empty() )
		return	false;

	const bool is_OnTranslate = (mRequestID=="OnTranslate");

	// さくらスクリプトとそれ以外を分割して処理を加える
	vector<string>	vec;
	string	acum;
	bool	content=false;	// 文に中身があるのか
	bool	is_first_question = true; // 選択分岐記録の消去処理用。
	int	last_speaker=0;
	const char* p = ioScript.c_str();
	while (*p) {
		string	c=get_a_chr(p);	// 全角半角問わず一文字取得し、pを一文字すすめる
		
		if ( c=="\\" || c=="%" ) {
			if (*p=='\\'||*p=='%') {	// エスケープされた\, %
				acum += c + *p++;
				continue;
			}
			
			const char*	start=p;
			string	cmd="",opt="";
	
			while (!_ismbblead(*p) && (isalpha(*p)||isdigit(*p)||*p=='!'||*p=='*'||*p=='&'||*p=='?'||*p=='_'))
				++p;
			cmd.assign(start, p-start);
	
			if (*p=='[') {
				const char* opt_start = ++p;
				while (*p!=']') {
					if (p[0]=='\\' && p[1]==']')	// エスケープされた]
						++p;
					p += _ismbblead(*p) ? 2 : 1;
				}
				opt.assign(opt_start, p++ -opt_start);
			}
			
			// 選択分岐ラベルに対する特殊処理
			if ( !is_OnTranslate && 
				cmd=="q" && opt!="" && count(opt, ",")>0 && 
				mRequestID!="OnHeadlinesense.OnFind") {

				// 選択分岐があるスクリプトであれば、その初回で選択分岐記録をクリア
				if ( is_first_question ) {
					question_record.clear();	
					is_first_question = false;
				}

				// 選択分岐を記録
				{
					strvec	vec;
					split(opt, ",", vec);
					if ( vec.size()==1 )	// countとsplitの罠。
						vec.push_back("");	// 
					string	label=vec[0], id=vec[1];

					if ( false == compare_head(id, "On") )
					{ 
						// Onで始まるものはOnChoiceSelectを経由されないため、対象外とする

						int	count = question_record.size()+1;
						question_record[id] = pair<int,string>(count, label);

						// ラベルIDに書き戻し
						opt = label+","+id+byte1_dlmt+label+byte1_dlmt+itos(count);
						for (int i=2;i<vec.size();++i)
							opt += string(",") + vec[i];
					}
				}
			}
			else if ( cmd=="0" || cmd=="h" ) { last_speaker=0; }
			else if ( cmd=="1" || cmd=="u" ) { last_speaker=1; }
			else if ( cmd=="p" && aredigits(opt) ) {
				last_speaker=stoi(opt);
				if ( mIsMateria || last_speaker<=1 ) {
					cmd = (opt=="0") ? "0" : "1";
					opt = "";
				}
			}
			else if ( cmd=="s" && !opt.empty() ) {
				last_talk_exiting_surface[last_speaker]=stoi(opt);
			}
			else if ( cmd.size()==2 && cmd[0]=='s' && isdigit(cmd[1]) ) {
				last_talk_exiting_surface[last_speaker]=cmd[1]-'0';
			}
						
			if ( !acum.empty() )
				vec.push_back(acum);

			if ( opt=="" )
				vec.push_back(c + cmd);
			else
				vec.push_back(c + cmd + "[" + opt + "]");
			acum="";

			static	set<string>	nc_cmd;	// 有効と数えないさくらスクリプト群
			static	bool	initialized=false;
			if (!initialized) {
				initialized=true;
				nc_cmd.insert("0"); nc_cmd.insert("1"); nc_cmd.insert("h"); nc_cmd.insert("u"); nc_cmd.insert("p");
				nc_cmd.insert("n"); nc_cmd.insert("w"); nc_cmd.insert("_w"); nc_cmd.insert("e");
			}
			if ( nc_cmd.find(cmd)==nc_cmd.end() )
				content = true;

		}
		else {
			content = true;
			acum += c;
		}
	}
	if ( !acum.empty() )
		vec.push_back(acum);

	if (!content)
		return	false;	// 中身の無いスクリプト(実行してもしなくても一緒)と判断。

	ioScript="";

	for (vector<string>::iterator i=vec.begin() ; i!=vec.end() ; ++i) {
		if ( i->at(0)!='\\' && i->at(0)!='%' ) {
			// さくらスクリプト以外の文への処理

			// アンカー挿入
			if ( !is_OnTranslate )
				for ( set<string>::iterator j=anchors.begin() ; j!=anchors.end() ; ++j )
					replace(*i, *j, string("\\_a[")+*j+"]"+*j+"\\_a");
		}
		ioScript += *i;
	}


	// 事後置き換え辞書を適用
	if ( !is_OnTranslate )
		for ( strmap::iterator di=replace_after_dic.begin() ; di!=replace_after_dic.end() ; ++di )
			replace(ioScript, di->first, di->second);

	diet_script(ioScript);	// ラストダイエット

	// エスケープしてあった文字を戻す
	m_escaper.unescape(ioScript);

	return	true;
}
Example #3
0
// 文章の中で ( を見つけた場合、pが ( の次の位置まで進められた上でこれが実行される。
// pはこの内部で ) の次の位置まで進められる。
// 返値はカッコの解釈結果。
string	Satori::KakkoSection(const char*& p,bool for_calc,bool for_non_talk)
{
	string	thePluginName = "";
	string  theDelimiter = "";
	bool specialFlag = false;
	const char *pp=0;
	strvec	theArguments;
	string	kakko_str;

	if ( for_calc ) {
		for_non_talk = true;
	}
	for ( set<string>::iterator it = special_commands.begin(); it != special_commands.end(); ++it) {
		if ( strncmp(it->c_str(), p, it->size()) == 0 ) {
			pp = p + it->size();
			string c = get_a_chr(pp);
			//引数がない場合はスペシャルフォームにする必要はない。
			if ( mDelimiters.find(c) != mDelimiters.end() ){
				specialFlag = true;
				theDelimiter = c;
				thePluginName = it->c_str();
				break;
			}
		}
	}

	if( specialFlag ) {
		assert(pp);
		int level = 0;
		const char *p_start = pp;
		while( true ){
			if ( *pp == '\0' ){
				return string("("); // 閉じカッコが無かった
			}
			string c = get_a_chr(pp);
			if ( c == "(" ) {
				level++;
			}
			if ( c == ")" ) {
				level--;
			}
			if ( level < 0 ) {
				theArguments.push_back( string(p_start, pp-p_start-2) );
				break;
			}
			if ( level == 0 ) {
				if ( c == theDelimiter ) {
					theArguments.push_back( string(p_start, pp-p_start-c.size()) );
					p_start = (char *)pp;
				}
			}
		}
		p = pp;
		return special_call(thePluginName, theArguments, for_calc, for_non_talk, secure_flag);
	}
	else {
		while (true) {
			if ( p[0] == '\0' )
				return	string("(") + kakko_str;	// 閉じカッコが無かった
			
			string c = get_a_chr(p);
			if ( c==")" )
				break;
			else if ( c=="(" ) {
				kakko_str += KakkoSection(p,false,for_non_talk); //内側の括弧は0に置き換えしない
			}
			else
				kakko_str += c;
		}	
		string	result;
		if ( Call(kakko_str, result, for_calc, for_non_talk) )
			return	result;
		if ( for_calc )
			return	string("0");
		else
			return	string("(") + kakko_str + ")";
	}
}
Example #4
0
int Satori::SentenceToSakuraScriptInternal(const strvec &vec,string &result,string &jump_to,ptrdiff_t &ip)
{
    // 再帰管理
    static	int nest_count=0;
    ++nest_count;
    //DBG(sender << "enter SentenceToSakuraScriptInternal, nest-count: " << nest_count << ", vector_size: " << vec.size() << endl);

    if ( m_nest_limit > 0 && nest_count > m_nest_limit ) {
        sender << "呼び出し回数超過" << endl;
        --nest_count;
        return 0;
    }

    static const int basewait=3;

    strvec::const_iterator it = vec.begin();
    std::advance(it,ip);

    for ( ; it != vec.end() ; ++it) {
        const char*	p = it->c_str();
        //DBG(sender << nest_count << " '" << p << "'" << endl);

        if ( it==vec.begin() && strncmp(p, "→", 2)==0 ) {
            p+=2;
            updateGhostsInfo();	// ゴースト情報を更新

            if ( ghosts_info.size()>=2 ) {	// そもそも自分以外にゴーストはいるのか。
                string	temp = p;
                vector<strmap>::iterator i=ghosts_info.begin();
                ++i; // 自分は飛ばす
                for ( ; i!=ghosts_info.end() ; ++i ) {
                    string	name = (*i)["name"];
                    sender << "ghost: " << name <<endl;
                    if ( compare_head(temp, name) ) {// 相手を特定
                        mCommunicateFor = name;
                        p += mCommunicateFor.size();
                        break;
                    }
                }


                if ( i==ghosts_info.end() ) {	// 特定しなかった場合
                    // ランダム
                    //int n = random(ghosts_info.size()-1))+1;
                    //assert( n>=1 && n < ghosts_info.size());
                    mCommunicateFor = (ghosts_info[1])["name"];

                    // あかん、隣で起動している〜〜にならん
                }
            }
        }

        // 選択肢	\q?[id,string]
        if ( strncmp(p, "_", 2)==0 ) {
            if ( strlen(p)>1023 )
                continue;
            char	buf[1024];
            strncpy(buf, p+2, sizeof(buf) / sizeof(buf[0]));

            char*	choiced = buf;
            char*	id = (char*)strstr_hz(buf, "\t"); // 選択肢ラベルとジャンプ先の区切り

            result += append_at_choice_start;
            if ( id == NULL ) {
                string	str=UnKakko(choiced);
                //result += string("\\q")+itos(question_num++)+"["+str+"]["+str+"]";
                result += "\\q["+str+","+str+"]";
            } else {
                *id++='\0';
                while ( *id=='\t' ) ++id; // 選択肢ラベルとジャンプ先の区切り
                //result += string("\\q")+itos(question_num++)+"["+UnKakko(id)+"]["+UnKakko(choiced)+"]";
                result += "\\q["+UnKakko(choiced)+","+UnKakko(id)+"]";
            }
            result += append_at_choice_end;

            continue;
        }

        // ちょっと微妙な存在意義。
        if ( strncmp(p, "\\s", 2)==0 ) {
            if ( !is_speaked(speaker) ) {
                if ( surface_changed_before_speak.find(speaker) == surface_changed_before_speak.end() ) {
                    surface_changed_before_speak.insert(map<int,bool>::value_type(speaker,is_speaked_anybody()) );
                }
            }
        }

        // ジャンプ
        if ( strncmp(p, ">", 2)==0 || strncmp(p, "≫", 2)==0 ) {
            strvec	words;
            split(p+2, "\t", words, 2); // ジャンプ先とジャンプ条件の区切り

            if ( words.size()>=2 ) {
                string	r;
                if ( !calculate(words[1], r) )
                    break;
                if ( zen2int(r) == 0 ) {
                    sender << "*計算結果が0だったため、続行します。" << endl;
                    continue;
                }
            }

            if ( words.size() >= 1 ) {
                jump_to = UnKakko(words[0].c_str(),false,true);
            }
            else {
                jump_to.erase();
            }

            if ( strncmp(p, "≫", 2)==0 ) {
                ip = std::distance(vec.begin(),it) + 1;
                --nest_count;
                return 2;
            }
            else {
                ip = std::distance(vec.begin(),it) + 1;
                --nest_count;
                return 1;
            }
        }

        // 変数を設定
        if ( strncmp(p, "$", 2)==0 ) {
            const char* v;
            string	value;
            bool	do_calc=false;
            p+=2;
            if ( (v=strstr_hz(p, "\t"))!=NULL ) { // 変数名と変数に設定する内容の区切り
                value = UnKakko(v+1,false,true);
            }
            else if ( (v=strstr_hz(p, "="))!=NULL || (v=strstr_hz(p, "="))!=NULL ) {
                value = UnKakko(v+((*v=='=') ? 1 : 2),false,true);
                do_calc=true;
            }
            else {
                //v = p+strlen(p);
                //value="";
                result += "\\n※ $による変数代入文には、タブによる区切りか、=による計算式が必要です ※\\n\\n[half]'" + value +"'";
                break;
            }

            string	key(p, v-p);
            key = UnKakko(key.c_str(),false,true);

            if ( key=="" ) {
                result += "$"; // $そのまま表示
                speaked_speaker.insert(speaker);
            }
            else if ( aredigits(zen2han(key)) ) {
                sender << "$" << key << " 数字のみの変数名は扱えません." << endl;
                erase_var(key);	// 存在抹消
            }
            else if ( value=="" ) {
                sender << "$" << key << "/cleared." << endl;
                erase_var(key);	// 存在抹消
                system_variable_operation(key, "", &result);//存在抹消したものがシステム変数かも!
            }
            else {
                bool isOverwritten;
                bool isSysValue;

                // "0"は代入先を先に参照する時、エラーを返さないように。
                string *pstr = GetValue(key,isSysValue,true,&isOverwritten,"0");

                if ( do_calc ) {
                    if ( !calculate(value, value) )
                        break;
                    if ( aredigits(value) ) {
                        value = int2zen(stoi(value));
                    }
                }

                sender << "$" << key << "=" << value << "/" <<
                       (isOverwritten ? "written." : "overwritten.")<< endl;

                if ( pstr ) {
                    *pstr = value;
                }
                system_variable_operation(key, value, &result);
            }
            continue;
        }

        // 通常処理
        while ( p[0] != '\0' ) {
            string	c=get_a_chr(p);	// 全角半角問わず一文字取得し、pを一文字すすめる

            if ( c=="(" ) {	// 何かを取得・挿入
                character_wait_exec;
                result += KakkoSection(p);
            }
            else if ( c=="\xff" ) {	//内部特殊表現
                c=get_a_chr(p);
                if ( c=="\x01" ) { //0xff0x01=スコープ切り替え 後に半角数値が1文字続く
                    c=get_a_chr(p);
                    int speaker_tmp = stoi(c.c_str());
                    if ( is_speaked(speaker) && speaker != speaker_tmp ) {
                        result += append_at_scope_change;
                        chars_spoken += 2;
                    }
                    speaker = speaker_tmp;
                    character_wait_clear(2);
                    if ( speaker == 0 ) {
                        result += "\\0";
                    }
                    else if ( speaker == 1 ) {
                        result += "\\1";
                    }
                    else {
                        result += "\\p[" + c + "]";
                    }
                }
            }
            else if ( c==":" ) {	// スコープ切り替え - ここは二人を想定。
                if ( is_speaked(speaker) ) {
                    result += append_at_scope_change;
                    chars_spoken += 2;
                }
                speaker = (speaker==0) ? 1 : 0;
                character_wait_clear(2);
                result += (speaker ? "\\1" : "\\0");
            }
            else if ( c=="\\" || c=="%" ) {	// さくらスクリプトの解釈、というか解釈のスキップ。

                if (*p=='\\'||*p=='%') {	// エスケープされた\, %
                    result += c + *p++;
                    continue;
                }

                const char*	start=p;
                string	cmd="",opt="";

                while (!_ismbblead(*p) && (isalpha(*p)||isdigit(*p)||*p=='!'||*p=='-'||*p=='*'||*p=='&'||*p=='?'||*p=='_'))
                    ++p;
                cmd.assign(start, p-start);

                if ( cmd == "_?" || cmd == "_!" ) { //エスケープ処理 この間に自動タグ挿入はしない
                    const char* e1 = strstr(p,"\\_?");
                    if ( ! e1 ) {
                        e1 = strstr(p,"\\_!");
                    }

                    if ( e1 ) {
                        character_wait_exec;
                        result += c;
                        result += cmd;

                        opt.assign(p,e1-p+3);
                        opt = UnKakko(opt.c_str());

                        p = e1 + 3; //endtag

                        result += opt;
                        continue;
                    }
                }

                if (*p=='[') {
                    const char* opt_start = ++p;
                    while (*p!=']') {
                        if (p[0]=='\\' && p[1]==']')	// エスケープされた]
                            ++p;
                        p += _ismbblead(*p) ? 2 : 1;
                    }
                    opt.assign(opt_start, p++ -opt_start);
                    opt=UnKakko(opt.c_str());
                }

                if ( cmd=="n" ) {
                    // 改行
                    character_wait_clear(2);
                }
                else if ( ( (cmd=="0" || cmd=="h") && speaker==1) || ( (cmd=="1" || cmd=="u") && speaker==0) ) {
                    // スコープ切り替え
                    if ( is_speaked(speaker) ) {
                        result += append_at_scope_change_with_sakura_script;
                        chars_spoken += 2;
                    }
                    speaker = stoi(cmd);
                    character_wait_clear(2);
                }
                else if ( cmd=="p" && aredigits(opt) ) {
                    int spktmp = stoi(opt);
                    if ( speaker != spktmp ) {
                        // スコープ切り替えonSSP/CROW
                        if ( is_speaked(speaker) ) {
                            result += append_at_scope_change_with_sakura_script;
                            chars_spoken += 2;
                        }
                        speaker = spktmp;
                        character_wait_clear(2);
                    }
                }
                else if ( cmd=="s" ) {
                    //サーフィス切り替えの前にウェイトは済ませておくこと
                    character_wait_exec;
                }
                else if ( cmd=="_q" ) {
                    if ( ! is_quick_section ) { //これからクイックセクションなのでウエイトを全部消化
                        character_wait_exec;
                    }
                    is_quick_section = ! is_quick_section;
                }

                if ( opt!="" ) {
                    //sender << "ss_cmd: " << c << "," << cmd << "," << opt << endl;
                    result += c + cmd + "[" + opt + "]";
                } else {
                    //sender << "ss_cmd: " << c << "," << cmd << endl;
                    result += c + cmd;
                }


                //result += string(start, p-start);
            }
            else {	// 通常の一文字
                character_wait_exec;

                speaked_speaker.insert(speaker);
                result += c;
                chars_spoken += c.size();
                if ( c=="。" || c=="、" ) {
                    character_wait_clear(c=="、"?1:2);
                }
            }

        }
        character_wait_clear(2);
        result += "\\n";
    }

    //DBG(sender << "leave SentenceToSakuraScriptInternal, nest-count: " << nest_count << endl);
    --nest_count;
    return 0;
}