/* 文字列の出力 */ LOCAL W output_string(W fd, W len, TC *tc, W hankaku) { W err, n, pos; UH sjis; UB *buf; if (len < 1) { err = ER_OK; goto fin0; } /* 入力サイズを超えることは決してない */ buf = malloc(len); if (buf == NULL) { P(("output_string: malloc NULL\n")); err = ER_NOMEM; goto fin0; } len /= 2; pos = 0; while (len-- > 0) { switch (*tc) { case TAB: buf[pos++] = TAB; break; case LF: case CR: buf[pos++] = CR; buf[pos++] = LF; break; default: /* 言語ID */ if ((*tc & 0xff00) == 0xfe00) { LangState = *tc; break; } /* 日本語以外の言語が指定されている場合 */ if (LangState != LANGJP) { sjis = _mbcjistojms(0); buf[pos++] = sjis >> 8; buf[pos++] = sjis; break; } /* 半角化可能な物は半角で出力 */ if (hankaku) { n = zen2han(*tc, &buf[pos]); if (n > 0) { pos += n; break; } } /* 全角 */ sjis = _mbcjistojms(*tc); buf[pos++] = sjis >> 8; buf[pos++] = sjis; break; } tc++; }
bool Satori::Save(bool isOnUnload) { GetSender().next_event(); // メンバ変数を里々変数化 for (std::map<int, string>::iterator it=reserved_talk.begin(); it!=reserved_talk.end() ; ++it) variables[string("次から")+itos(it->first)+"回目のトーク"] = it->second; // 起動時間累計を設定 variables["ゴースト起動時間累計秒"] = uitos(posix_get_current_sec() - sec_count_at_load + sec_count_total,"%lu"); // (互換用) variables["ゴースト起動時間累計ミリ秒"] = uitos((posix_get_current_sec() - sec_count_at_load + sec_count_total)*1000,"%lu"); variables["ゴースト起動時間累計(ms)"] = uitos((posix_get_current_sec() - sec_count_at_load + sec_count_total)*1000,"%lu"); if ( isOnUnload ) { secure_flag = true; (void)GetSentence("OnSatoriUnload"); } string theFullPath = mBaseFolder + "satori_savedata.tmp"; std::ofstream out(theFullPath.c_str()); bool temp = GetSender().is_validated(); GetSender().validate(); GetSender().sender() << "saving " << theFullPath << "... " ; GetSender().validate(temp); if ( !out.is_open() ) { GetSender().sender() << "failed." << std::endl; return false; } string line = "*セーブデータ"; string data; out << ENCODE(line) << std::endl; for (strmap::const_iterator it=variables.begin() ; it!=variables.end() ; ++it) { string str = zen2han(it->first); if ( str[0]=='S' && aredigits(str.c_str()+1) ) { continue; } if ( str == "今回は喋らない" || str == "今回は会話時サーフェス戻し" || str == "今回は会話時サーフィス戻し" || str == "今回は自動アンカー" ) { continue; } data = it->second; replace(data,"φ","φφ"); replace(data,"(","φ("); replace(data,")","φ)"); m_escaper.unescape_for_dic(data); string line = string("$")+it->first+"\t"+data; // 変数を保存 out << ENCODE(line) << std::endl; } for (std::map<string, std::vector<Word> >::const_iterator i=mAppendedWords.begin() ; i!=mAppendedWords.end() ; ++i ) { if ( ! i->second.empty() ) { out << std::endl << ENCODE( string("@") + i->first ) << std::endl; for (std::vector<Word>::const_iterator j=i->second.begin() ; j!=i->second.end() ; ++j ) { out << ENCODE( *j ) << std::endl; } } } out.flush(); out.close(); GetSender().sender() << "ok." << std::endl; //バックアップ string realFullPath = mBaseFolder + "satori_savedata." + (fEncodeSavedata?"sat":"txt"); string realFullPathBackup = mBaseFolder + "satori_savebackup." + (fEncodeSavedata?"sat":"txt"); #ifdef POSIX unlink(realFullPathBackup.c_str()); rename(realFullPath.c_str(),realFullPathBackup.c_str()); rename(theFullPath.c_str(),realFullPath.c_str()); #else ::DeleteFile(realFullPathBackup.c_str()); ::MoveFile(realFullPath.c_str(),realFullPathBackup.c_str()); ::MoveFile(theFullPath.c_str(),realFullPath.c_str()); #endif //いらないほうを消す string delFullPath = mBaseFolder + "satori_savedata." + (fEncodeSavedata?"txt":"sat"); string delFullPathBackup = mBaseFolder + "satori_savebackup." + (fEncodeSavedata?"txt":"sat"); #ifdef POSIX unlink(delFullPath.c_str()); unlink(delFullPathBackup.c_str()); #else ::DeleteFile(delFullPath.c_str()); ::DeleteFile(delFullPathBackup.c_str()); #endif return true; }
bool Satori::system_variable_operation(string key, string value, string* result) { // mapにしようよ。 if ( key == "喋り間隔" ) { talk_interval = zen2int(value); if ( talk_interval<3 ) talk_interval=0; // 3未満は喋らない // 喋りカウント初期化 int dist = static_cast<int>(talk_interval*(talk_interval_random/100.0)); talk_interval_count = ( dist==0 ) ? talk_interval : (talk_interval-dist)+(random(dist*2)); return true; } if ( key == "喋り間隔誤差" ) { talk_interval_random = zen2int(value); if ( talk_interval_random>100 ) talk_interval_random=100; if ( talk_interval_random<0 ) talk_interval_random=0; // 喋りカウント初期化 int dist = int(talk_interval*(talk_interval_random/100.0)); talk_interval_count = ( dist==0 ) ? talk_interval : (talk_interval-dist)+(random(dist*2)); return true; } if ( key =="見切れてても喋る" ) { is_call_ontalk_at_mikire= (value=="有効"); return true; } if ( key == "今回は喋らない" ) { return_empty=(value=="有効"); return true; } if ( key == "スクリプトの一番頭" ) { header_script = value; return true; } if ( key == "呼び出し回数制限" ) { m_nest_limit = zen2int(value); if ( m_nest_limit < 0 ) { m_nest_limit = 0; } return true; } if ( key == "ジャンプ回数制限" ) { m_jump_limit = zen2int(value); if ( m_jump_limit < 0 ) { m_jump_limit = 0; } return true; } if ( key == "スコープ切り換え時" ) { append_at_scope_change = zen2han(value); return true; } if ( key == "さくらスクリプトによるスコープ切り換え時" ) { append_at_scope_change_with_sakura_script = zen2han(value); return true; } if ( key == "トーク開始時" ) { append_at_talk_start = zen2han(value); return true; } if ( key == "トーク終了時" ) { append_at_talk_end = zen2han(value); return true; } if ( key == "選択肢開始時" ) { append_at_choice_start = zen2han(value); return true; } if ( key == "選択肢終了時" ) { append_at_choice_end = zen2han(value); return true; } if ( key == "会話時サーフェス戻し" || key == "会話時サーフィス戻し" ) { if ( value == "有効" ) { surface_restore_at_talk = SR_NORMAL; } else if ( value == "強制" ) { surface_restore_at_talk = SR_FORCE; } else { surface_restore_at_talk = SR_NONE; } return true; } if ( key == "今回は会話時サーフェス戻し" || key == "今回は会話時サーフィス戻し" ) { if ( value == "有効" ) { surface_restore_at_talk_onetime = SR_NORMAL; } else if ( value == "強制" ) { surface_restore_at_talk_onetime = SR_FORCE; } else { surface_restore_at_talk_onetime = SR_NONE; } return true; } if ( key == "自動アンカー" ) { if ( value == "有効" ) { auto_anchor_enable = true; auto_anchor_enable_onetime = auto_anchor_enable; } else { auto_anchor_enable = false; auto_anchor_enable_onetime = auto_anchor_enable; } return true; } if ( key == "今回は自動アンカー" ) { if ( value == "有効" ) { auto_anchor_enable_onetime = true; } else { auto_anchor_enable_onetime = false; } return true; } if ( compare_head(key, "サーフェス加算値") && aredigits(key.c_str() + const_strlen("サーフェス加算値")) ) { int n = zen2int(key.c_str() + const_strlen("サーフェス加算値")); surface_add_value[n]= zen2int(value); variables[string()+"デフォルトサーフェス"+itos(n)] = value; next_default_surface[n] = zen2int(value); if ( !is_speaked_anybody() ) default_surface[n]=next_default_surface[n]; return true; } if ( compare_head(key, "デフォルトサーフェス") && aredigits(key.c_str() + const_strlen("デフォルトサーフェス")) ) { int n = zen2int(key.c_str() + const_strlen("デフォルトサーフェス")); next_default_surface[n]= zen2int(value); if ( !is_speaked_anybody() ) default_surface[n]=next_default_surface[n]; return true; } if ( compare_head(key, "BalloonOffset") && aredigits(key.c_str() + const_strlen("BalloonOffset")) ) { int n = stoi(key.c_str() + const_strlen("BalloonOffset")); BalloonOffset[n] = value; validBalloonOffset[n] = true; return true; } if ( key == "トーク中のなでられ反応") { insert_nade_talk_at_other_talk= (value=="有効"); return true; } if ( key == "なでられ持続秒数") { nade_valid_time_initializer = zen2int(value); return true; } if ( key == "なでられ反応回数") { nade_sensitivity = zen2int(value); return true; } if ( key == "デバッグ" ) { fDebugMode = (value=="有効"); return true; } if ( key == "Log" ) { Sender::validate(value=="有効"); return true; } if ( key == "RequestLog" ) { fRequestLog = (value=="有効"); return true; } if ( key == "OperationLog" ) { fOperationLog = (value=="有効"); return true; } if ( key == "ResponseLog" ) { fResponseLog = (value=="有効"); return true; } if ( key == "自動挿入ウェイトの倍率" ) { rate_of_auto_insert_wait= zen2int(value); rate_of_auto_insert_wait = min(1000, max(0, rate_of_auto_insert_wait)); variables["自動挿入ウェイトの倍率"] = int2zen(rate_of_auto_insert_wait); return true; } if ( key == "自動挿入ウェイトタイプ" ) { if ( value == "一般" ) { type_of_auto_insert_wait = 2; variables["自動挿入ウェイトタイプ"] = "一般"; } else if ( value == "無効" ) { type_of_auto_insert_wait = 0; variables["自動挿入ウェイトタイプ"] = "無効"; } else /* if ( value == "里々" ) */ { type_of_auto_insert_wait = 1; variables["自動挿入ウェイトタイプ"] = "里々"; } return true; } if ( key == "辞書フォルダ" ) { strvec words; split(value, ",",dic_folder); reload_flag=true; return true; } if ( key == "セーブデータ暗号化" ) { fEncodeSavedata = (value=="有効"); return true; } if ( compare_head(key,"単語群「") && compare_tail(key,"」の重複回避") ) { variables.erase(key); words.setOC( string(key.c_str()+8, key.length()-8-12), value ); return true; } if ( compare_head(key,"文「") && compare_tail(key,"」の重複回避") ) { variables.erase(key); talks.setOC( string(key.c_str()+4, key.length()-4-12), value ); return true; } if ( key == "次のトーク" ) { variables.erase(key); int count=1; while ( reserved_talk.find(count) != reserved_talk.end() ) ++count; reserved_talk[count] = value; sender << "次回のランダムトークが「" << value << "」に予\x96\xf1されました。" << endl; return true; } if ( compare_head(key,"次から") && compare_tail(key,"回目のトーク") ) { variables.erase(key); int count = zen2int( string(key.c_str()+6, key.length()-6-12) ); if ( count<=0 ) { sender << "トーク予\x96\xf1、設定値がヘンです。" << endl; } else { while ( reserved_talk.find(count) != reserved_talk.end() ) ++count; reserved_talk[count] = value; sender << count << "回後のランダムトークが「" << value << "」に予\x96\xf1されました。" << endl; } return true; } if ( key=="トーク予\x96\xf1のキャンセル" ) { if ( value=="*" ) reserved_talk.clear(); else for (map<int, string>::iterator it=reserved_talk.begin(); it!=reserved_talk.end() ; ) if ( value == it->second ) reserved_talk.erase(it++); else ++it; return true; } if ( key == "SAORI引数の計算" ) { if (value=="有効") mSaoriArgumentCalcMode = SACM_ON; else if (value=="無効") mSaoriArgumentCalcMode = SACM_OFF; else mSaoriArgumentCalcMode = SACM_AUTO; return true; } if ( key == "辞書リロード" && value=="実行") { variables.erase(key); reload_flag=true; return true; } if ( key == "手動セーブ" && value=="実行") { variables.erase(key); if ( is_dic_loaded ) { this->Save(); } return true; } if ( key == "自動セーブ間隔" ) { mAutoSaveInterval = zen2int(value); mAutoSaveCurrentCount = mAutoSaveInterval; if ( mAutoSaveInterval > 0 ) sender << "" << itos(mAutoSaveInterval) << "秒間隔で自動セーブを行います。" << endl; else sender << "自動セーブは行いません。" << endl; return true; } if ( key == "全タイマ解除" && value=="実行") { variables.erase(key); for (strintmap::const_iterator i=timer.begin();i!=timer.end();++i) variables.erase(i->first + "タイマ"); timer.clear(); return true; } if ( key == "教わること" ) { variables.erase(key); teach_genre=value; if ( result != NULL ) *result += "\\![open,teachbox]"; return true; } if ( key.size()>6 && compare_tail(key, "タイマ") ) { string name(key.c_str(), strlen(key.c_str())-6); /*if ( sentences.find(name) == sentences.end() ) { result = string("※ タイマ終了時のジャンプ先 *")+name+" がありません ※"; // セーブデータ復帰時を考慮 } else */{ int sec = zen2int(value); if ( sec < 1 ) { variables.erase(key); if ( timer.find(name)!=timer.end() ) { timer.erase(name); sender << "タイマ「" << name << "」の予\x96\xf1がキャンセルされました。" << endl; } else sender << "タイマ「" << name << "」は元から予\x96\xf1されていません。" << endl; } else { timer[name] = sec; sender << "タイマ「" << name << "」が" << sec << "秒後に予\x96\xf1されました。" << endl; } } return true; } if ( key == "引数区切り追加" && value.size()>0 ) { variables.erase(key); mDelimiters.insert(value); return true; } if ( key == "引数区切り削除" && value.size()>0 ) { variables.erase(key); mDelimiters.erase(value); return true; } if ( compare_head(key, "Value") && aredigits(key.c_str() + 5) ) { variables.erase(key); if(value!=""){ mResponseMap[string()+"Reference"+key.substr(5)] = value; }else{ mResponseMap.erase(string()+"Reference"+key.substr(5)); } return true; } return false; }
bool Satori::load(const string& iBaseFolder) { GetSender().next_event(); setlocale(LC_ALL, "Japanese"); #ifdef _WINDOWS _setmbcp(_MB_CP_LOCALE); #endif mBaseFolder = iBaseFolder; GetSender().sender() << "■SATORI::Load on " << mBaseFolder << "" << std::endl; #if POSIX // 「/」で終わっていなければ付ける。 if (mBaseFolder[mBaseFolder.size() - 1] != '/') { mBaseFolder += '/'; } #else // 「\」で終わっていなければ付ける。 if (mBaseFolder[mBaseFolder.size() - 1] != '\\') { mBaseFolder += '\\'; } #endif #ifdef _MSC_VER // 本体のあるフォルダをサーチ { TCHAR buf[MAX_PATH+1]; ::GetModuleFileName(NULL, buf, MAX_PATH); char* p = FindFinalChar(buf, DIR_CHAR); if ( p==NULL ) mExeFolder = ""; else { *(++p) = '\0'; mExeFolder = buf; } } GetSender().sender() << "本体の所在: " << mExeFolder << "" << std::endl; #endif // _MSC_VER // メンバ初期化 InitMembers(); #ifdef _MSC_VER // システムの設定を読んでおく OSVERSIONINFO ovi; ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); ::GetVersionEx(&ovi); string os; if ( ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) { if ( ovi.dwMinorVersion == 0 ) { mOSType=SATORI_OS_WIN95; os="Windows 95"; } else if ( ovi.dwMinorVersion == 10 ) { mOSType=SATORI_OS_WIN98; os="Windows 98"; } else if ( ovi.dwMinorVersion == 90 ) { mOSType=SATORI_OS_WINME; os="Windows Me"; } else { mOSType = SATORI_OS_UNDEFINED; os="undefined"; } } else { if ( ovi.dwMinorVersion == 0 ) { if ( ovi.dwMajorVersion == 4 ) { mOSType=SATORI_OS_WINNT; os="Windows NT"; } else if ( ovi.dwMajorVersion == 5 ) { mOSType=SATORI_OS_WIN2K; os="Windows 2000"; } } else { mOSType = SATORI_OS_WINXP; os="Windows XP or later"; } } GetSender().sender() << "OS種別: " << os << std::endl; if ( mOSType==SATORI_OS_WIN95 ) { is_single_monitor = true; } else { BOOL (WINAPI* pEnumDisplayMonitors)(HDC,LPRECT,MONITORENUMPROC,LPARAM); (FARPROC&)pEnumDisplayMonitors = ::GetProcAddress(::GetModuleHandle("user32.dll"), "EnumDisplayMonitors"); if ( pEnumDisplayMonitors==NULL ) { is_single_monitor = true; } else { RECT rectData[2]; memset(rectData,0,sizeof(rectData)); (*pEnumDisplayMonitors)(NULL,NULL,(MONITORENUMPROC)MonitorEnumFunc,(LPARAM)(rectData)); max_screen_rect = rectData[0]; desktop_rect = rectData[1]; RECT* rect; rect = &desktop_rect; GetSender().sender() << "プライマリデスクトップ: (" << rect->left << "," << rect->top << "," << rect->right << "," << rect->bottom << ")" << std::endl; rect = &max_screen_rect; GetSender().sender() << "仮想デスクトップ: (" << rect->left << "," << rect->top << "," << rect->right << "," << rect->bottom << ")" << std::endl; is_single_monitor = ( ::EqualRect(&max_screen_rect, &desktop_rect)!=FALSE ); GetSender().sender() << (is_single_monitor ? "モニタは一つだけと判断、見切れ判定を呼び出し元に任せます。" : "複数のモニタが接続されていると判断、見切れ判定は里々が行います。") << std::endl; } } #endif // _MSC_VER // 置換辞書読み取り strmap_from_file(replace_before_dic, mBaseFolder+"replace.txt", "\t"); strmap_from_file(replace_after_dic, mBaseFolder+"replace_after.txt", "\t"); // キャラデータ読み込み mCharacters.load(mBaseFolder + "characters.ini"); for ( inimap::const_iterator i=mCharacters.begin() ; i!=mCharacters.end() ; ++i ) { const strmap& m = i->second; strmap::const_iterator j; // 置換辞書に追加 j = m.find("popular-name"); if ( j != m.end() && j->second.size()>0 ) replace_before_dic[j->second + ":"] = string("\xff\x01") + zen2han(i->first); //0xff0x01はあとで変換 j = m.find("initial-letter"); if ( j != m.end() && j->second.size()>0 ) replace_before_dic[j->second + ":"] = string("\xff\x01") + zen2han(i->first); //0xff0x01はあとで変換 j = m.find("base-surface"); if ( j != m.end() && j->second.size()>0 ) system_variable_operation( string("サーフェス加算値") + i->first, j->second); } //for ( strmap::const_iterator j=replace_before_dic.begin() ; j!=replace_before_dic.end() ; ++j ) // cout << j->first << ": " << j->second << endl; // ランダマイズ randomize(); //------------------------------------------ // コンフィグ読み込み LoadDictionary(mBaseFolder + "satori_conf.txt", false); // 変数初期化実行 GetSentence("初期化"); // SAORI読み込み Family<Word>* f = words.get_family("SAORI"); mShioriPlugins->load(mBaseFolder); if ( f != NULL ) { std::vector<const Word*> els; f->get_elements_pointers(els); for (std::vector<const Word*>::const_iterator i=els.begin(); i!=els.end() ; ++i) { if ( (*i)->size()>0 && !mShioriPlugins->load_a_plugin(**i) ) { GetSender().sender() << "SAORI読み込み中にエラーが発生: " << **i << std::endl; } } } mShioriPlugins->load_default_entry(); talks.clear(); words.clear(); //------------------------------------------ // セーブデータ読み込み //bool oldConf = fEncodeSavedata; bool loadResult = LoadDictionary(mBaseFolder + "satori_savedata." + (fEncodeSavedata?"sat":"txt"), false); GetSentence("セーブデータ"); bool execResult = talks.get_family("セーブデータ") != NULL; if ( ! loadResult || ! execResult ) { loadResult = LoadDictionary(mBaseFolder + "satori_savebackup." + (fEncodeSavedata?"sat":"txt"), false); GetSentence("セーブデータ"); execResult = talks.get_family("セーブデータ") != NULL; } talks.clear(); reload_flag = false; if ( variables.find("ゴースト起動時間累計秒") != variables.end() ) { sec_count_total = zen2ul(variables["ゴースト起動時間累計秒"]); } else if ( variables.find("ゴースト起動時間累計ミリ秒") != variables.end() ) { sec_count_total = zen2ul(variables["ゴースト起動時間累計ミリ秒"]) / 1000; } else { sec_count_total = zen2ul(variables["ゴースト起動時間累計(ms)"]) / 1000; } variables["起動回数"] = itos( zen2int(variables["起動回数"])+1 ); // 「単語の追加」で登録された単語を覚えておく const std::map< string, Family<Word> >& m = words.compatible(); for (std::map< string, Family<Word> >::const_iterator it = m.begin() ; it != m.end() ; ++it ) { std::vector<const Word*> v; it->second.get_elements_pointers(v); for (std::vector<const Word*>::const_iterator itx = v.begin() ; itx < v.end() ; ++itx ) { mAppendedWords[it->first].push_back(**itx); } } //------------------------------------------ // 指定フォルダの辞書を読み込み int loadcount = 0; strvec::iterator i = dic_folder.begin(); if ( i==dic_folder.end() ) { loadcount += LoadDicFolder(mBaseFolder); // ルートフォルダの辞書 } else { for ( ; i!=dic_folder.end() ; ++i ) loadcount += LoadDicFolder(mBaseFolder + *i + DIR_CHAR); // サブフォルダの辞書 } is_dic_loaded = loadcount != 0; //------------------------------------------ secure_flag = true; system_variable_operation("単語群「*」の重複回避", "有効、トーク中"); system_variable_operation("文「*」の重複回避", "有効"); //system_variable_operation("単語群「季節の食べ物」の重複回避", "有効、トーク中"); GetSentence("OnSatoriLoad"); on_loaded_script = GetSentence("OnSatoriBoot"); diet_script(on_loaded_script); GetSender().sender() << "loaded." << std::endl; GetSender().flush(); return true; }
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; }