Mercurial > otakunoraifu
annotate scn2k/scn2k_text.cc @ 40:651237260724
* Center button-type selects
| author | thib |
|---|---|
| date | Wed, 18 Mar 2009 16:44:49 +0000 |
| parents | de29c4d2d043 |
| children | 01aa5ddf7dc8 |
| rev | line source |
|---|---|
| 0 | 1 /* |
| 2 TODO: | |
| 3 日付のラベルが画面切り替え時に欠けるのを修正 | |
| 4 画像効果 : 人間の入れ換わりなど | |
| 5 kcursor の操作を WidText クラスに任せる | |
| 6 WidText クラスには新たに以下の操作を加える | |
| 7 ・ウェイト終了後、クリアなしに新たなテキストを追加、新たにstart-waitする | |
| 8 ・文字の描画 (Start) と Wait(カーソル表示待ち)の分離。 | |
| 9 Start すると文字を描画開始する。クリックで全描画。 | |
| 10 Flush するとバッファ内の文字をすべて描画する | |
| 11 Wait すると全描画後、クリックされるまでカーソルを表示するまで待つ | |
| 12 TextImpl 側の状態としては Wait のみを持つ (PREPAREに戻るのを待つ) | |
| 13 ただし、Skip の権利はどっちがもつ?(現状は?) | |
| 14 | |
| 15 GrpObj: NextObj と GrpObj を分離。CreateObj は現状通り、Visible=1 時に行う。 | |
| 16 それぞれ num=0 (screen) の枝leaf として実装。delete時は親のdeleteのみを | |
| 17 行い、子はGrpObjの実体だけを削除する | |
| 18 Visible 後のhide は実際に hide とする | |
| 19 ExecReservedCmd() はなくせるはず。Delete() もなくなる。 | |
| 20 カノギ:ReBlit() がうまくいかないせいで名前ウィンドウが消えた時の背景がなくなる | |
| 21 | |
| 22 くら:回想表示 | |
| 23 SEL画像効果 | |
| 24 DONE: | |
| 25 ともよのテキストウィンドウ実装、ボタン実装 | |
| 26 shake の画像効果 | |
| 27 オブジェクト内のテキスト色の実装 | |
| 28 画像効果の改善 | |
| 29 */ | |
| 30 | |
| 31 /* | |
| 32 * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno | |
| 33 * All rights reserved. | |
| 34 * | |
| 35 * Redistribution and use in source and binary forms, with or without | |
| 36 * modification, are permitted provided that the following conditions | |
| 37 * are met: | |
| 38 * 1. Redistributions of source code must retain the above copyright | |
| 39 * notice, this list of conditions and the following disclaimer. | |
| 40 * 2. Redistributions in binary form must reproduce the above copyright | |
| 41 * notice, this list of conditions and the following disclaimer in the | |
| 42 * documentation and/or other materials provided with the distribution. | |
| 43 * 3. The name of the author may not be used to endorse or promote products | |
| 44 * derived from this software without specific prior written permission. | |
| 45 * | |
| 46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
| 47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
| 48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
| 49 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 50 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
| 51 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| 55 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 56 */ | |
| 57 | |
| 58 #include"window/event.h" | |
| 59 #include"window/picture.h" | |
| 60 #include"window/widget.h" | |
| 61 #include"system/file.h" | |
| 62 #include"system/system_config.h" | |
| 63 #include"scn2k.h" | |
| 64 | |
| 65 #include<string> | |
| 66 using namespace std; | |
| 67 | |
| 68 // kanji conv : デバッグ表示用 | |
| 69 void kconv(const unsigned char* src, unsigned char* dest); | |
| 70 void kconv_rev(const unsigned char* src, unsigned char* dest); | |
| 71 string kconv(const string& s); | |
| 72 string kconv_rev(const string& s); | |
| 73 // render.cc | |
| 74 void DSurfaceFillA(Surface* src, const Rect& rect, int r, int g, int b, int a); // テキストウィンドウ背景の設定 | |
| 75 void DSurfaceMove(Surface* src_o, const Rect& srcrect, Surface* dst_o, const Rect& dstrect); // コピー | |
| 76 | |
| 77 /**************************************************************:: | |
| 78 ** | |
| 79 ** TextImpl(interface) | |
| 80 */ | |
| 81 struct TimerAtom { | |
| 82 int from; | |
| 83 int to; | |
| 84 unsigned int start_time; | |
| 85 unsigned int total_time; | |
| 86 }; | |
| 87 | |
| 88 struct TextWindow { | |
| 89 /* @@@ : SetWindowColor での surface 再設定に注意 */ | |
| 90 WidText* wid; | |
| 91 bool name_visible; | |
| 92 WidLabel* name; | |
| 93 PicContainer* name_container; | |
| 94 PicBase* face; | |
| 95 PicBase* face_pics[8]; | |
| 96 TextWindow(PicContainer& parent, Event::Container& event, int window_no, const AyuSysConfig& config, void* callback); | |
| 97 ~TextWindow() { | |
| 98 if (name_container) delete name_container; | |
| 99 int i; for (i=0; i<8; i++) { | |
| 100 if (face_pics[i]) delete face_pics[i]; | |
| 101 } | |
| 102 if (wid) delete wid; | |
| 103 } | |
| 104 Rect WakuSize(PicContainer& pic, int waku_no, const AyuSysConfig& config); | |
| 105 void MakeWaku(PicContainer& pic, Event::Container& event, int waku_no,int window_no, bool* use_btn, const AyuSysConfig& config, void* callback); | |
| 106 void show(void) { | |
| 107 wid->show(); | |
| 108 if (name_container && name_visible) name_container->show(); | |
| 109 if (face) face->show(); | |
| 110 } | |
| 111 void hide(void) { | |
| 112 wid->hide(); | |
| 113 if (name_container) name_container->hide(); | |
| 114 if (face) face->hide(); | |
| 115 } | |
| 116 void ShowFace(const char* path) { | |
| 117 if (!face) return; | |
| 118 face->SetSurface( path, 0,0); | |
| 119 } | |
| 120 void ResetFace(void) { | |
| 121 if (!face) return; | |
| 122 face->SetSurface( (Surface*)0, 0,0); | |
| 123 } | |
| 124 void StartText(const TextStream& _stream) { | |
| 125 wid->Clear(); | |
| 126 wid->stream = _stream; | |
| 127 if (name_container) { | |
| 128 char namestr[1024]; | |
| 129 namestr[0] = 0; | |
| 130 wid->stream.RemoveName(namestr, 1024); | |
| 131 if (namestr[0] == 0) { | |
| 132 name_container->hide(); | |
| 133 } else { | |
| 134 if (name) { | |
| 135 name_container->show_all(); | |
| 136 name->SetText(namestr); | |
| 137 } | |
| 138 } | |
| 139 } | |
| 140 wid->Start(); | |
| 141 } | |
| 142 void SetName(const char* n) { | |
| 143 if (name_container && name) { | |
| 144 if (n[0]) { | |
| 145 name_container->show(); | |
| 146 name->SetText(n); | |
| 147 name_visible = true; | |
| 148 } else { | |
| 149 name_container->hide(); | |
| 150 name_visible = false; | |
| 151 } | |
| 152 } | |
| 153 } | |
| 154 }; | |
| 155 | |
| 156 class TextImpl { | |
| 157 private: | |
| 158 public: | |
| 159 TextWindow* text; | |
| 160 typedef enum {NORMAL=0, WAIT_TEXT=1, WAIT=2, WAIT_CLICK=3, WAIT_ABORT=4, WAIT_CLICK_MOUSEPOS = 5, WAIT_CLICK_MOUSEPOSEND_L = 6, WAIT_CLICK_MOUSEPOSEND_R = 7, | |
| 161 WAIT_SELECT_INBOX = 10, WAIT_SELECT_OUTBOX=11, WAIT_SELECT_VALUE = 12, | |
| 162 WAIT_EXTRN_MASK = 64, SAVEMASK = 128, LOADMASK = 256, SKIPMASK = 512, | |
| 163 CLEARSCR_MASK = 1024, STATSAVE_MASK = 2048, CLEARSCR_WAIT_MASK=(1<<12), | |
| 164 SKIPEND_MASK = (1<<13), BACKLOG_MASK=(1<<14), BACKLOG_MASK_FWD=(1<<15), BACKLOG_MASK_KOE=(1<<16), BACKLOG_WAIT_MASK=(1<<17), | |
| 165 ALLMASK = (CLEARSCR_MASK | WAIT_EXTRN_MASK | SAVEMASK | LOADMASK | SKIPMASK | BACKLOG_MASK | BACKLOG_MASK_FWD | BACKLOG_MASK_KOE | BACKLOG_WAIT_MASK | STATSAVE_MASK | CLEARSCR_WAIT_MASK | SKIPEND_MASK) | |
| 166 } Status; | |
| 167 Status status, status_saved, status_mask; | |
| 168 private: | |
| 169 std::string ruby_text; | |
| 170 bool ruby_text_flag; | |
| 171 unsigned int wait_time; | |
| 172 unsigned int old_time; | |
| 173 unsigned int base_time; | |
| 174 int text_window_number; | |
| 175 bool text_parsing; | |
| 176 TextStream text_stream; | |
| 177 SkipMode skip_mode; | |
| 178 int save_selectcount; | |
| 179 | |
| 180 std::map<int, TimerAtom> timer_var; | |
| 181 std::vector<WidTextButton*> selects; | |
| 182 std::vector<int> sel_backlog_pos; | |
| 183 string replace_name[26]; | |
| 184 string replace_name2[26]; | |
| 185 PicContainer* sel_widget; | |
| 186 PicWidget* backlog_widget; | |
| 187 | |
| 188 vector<BacklogItem>& backlog; | |
| 189 BacklogItem& backlog_item; | |
| 190 BacklogItem cur_backlog_item; | |
| 191 BacklogItem drawn_backlog_item; | |
| 192 | |
| 193 public: | |
| 194 PicContainer& parent; | |
| 195 Event::Container& event; | |
| 196 AyuSysConfig& config; | |
| 197 private: | |
| 198 TextWindow* widgets[32]; | |
| 199 WidTimeCursor* kcursor; | |
| 200 Surface* sel_bg1; | |
| 201 Surface* sel_bg2; | |
| 202 Rect sel_bg_rect; | |
| 203 | |
| 204 void SetCursor(int num); | |
| 205 VarInfo wait_savedvar[2]; | |
| 206 | |
| 207 public: | |
| 208 void AddText(const char* str); | |
| 209 | |
| 210 static void PressFuncSkip(void* pointer, WidButton* from); | |
| 211 static void PressFuncLoad(void* pointer, WidButton* from); | |
| 212 static void PressFuncSave(void* pointer, WidButton* from); | |
| 213 static void PressFuncBacklog(void* pointer, WidButton* from); | |
| 214 static void PressFuncBacklogFwd(void* pointer, WidButton* from); | |
| 215 private: | |
| 216 static void PressFuncButton(void* pointer, WidButton* from); | |
| 217 static bool PressFunc(int x, int y, void* pointer); | |
| 218 | |
| 219 public: | |
| 220 TextImpl(Event::Container& _event, PicContainer& _parent, AyuSysConfig& config, vector<BacklogItem>& parent_backlog, BacklogItem& parent_backlog_item); | |
| 221 ~TextImpl(); | |
| 222 void InitWindow(void); | |
| 223 void SetWindowColor(int r, int g, int b, int a, bool is_transparent); | |
| 224 void SetTextSpeed(int new_speed); | |
| 225 void SetTextWait(int new_wait); | |
| 226 void CreateSelect(Cmd& cmd); | |
| 227 void Exec(Cmd& cmd); | |
| 228 bool Wait(unsigned int current_time, Cmd& cmd); | |
| 229 void hide(void); | |
| 230 void show(void) { show(text_window_number); } | |
| 231 void show(int num); | |
| 232 void DrawBacklog(BacklogItem& item, Cmd& cmd); | |
| 233 void Save(std::string& str, bool select_save); | |
| 234 void Load(const char* str); | |
| 235 void SetSkipMode(SkipMode _mode); | |
| 236 void CreateSelBG(void); | |
| 237 }; | |
| 238 | |
| 239 /**************************************************************:: | |
| 240 ** | |
| 241 ** TextImpl(implementation) | |
| 242 */ | |
| 243 TextImpl::TextImpl(Event::Container& _event, PicContainer& _parent, AyuSysConfig& _config, vector<BacklogItem>& parent_backlog, BacklogItem& parent_backlog_item) : | |
| 244 text(0),status(TextImpl::NORMAL), status_saved(TextImpl::NORMAL), status_mask(TextImpl::NORMAL), ruby_text_flag(false), | |
| 245 old_time(0), base_time(0), text_window_number(0), text_parsing(false), skip_mode(SKIP_NO), save_selectcount(0), sel_widget(0), | |
| 246 backlog_widget(0), backlog(parent_backlog), backlog_item(parent_backlog_item), parent(_parent), event(_event), config(_config), | |
| 247 kcursor(0), sel_bg1(0), sel_bg2(0), sel_bg_rect(0,0,0,0) { | |
| 248 int i; | |
| 249 for (i=0; i<32; i++) { | |
| 250 widgets[i] = 0; | |
| 251 } | |
| 252 text_stream.kanji_type = TextStream::sjis; | |
| 253 event.RegisterGlobalPressFunc(&PressFunc, (void*)this); | |
| 254 } | |
| 255 | |
| 256 TextImpl::~TextImpl() { | |
| 257 if (sel_widget) delete sel_widget; | |
| 258 int i; | |
| 259 for (i=0; i<32; i++) { | |
| 260 if (widgets[i]) delete widgets[i]; | |
| 261 } | |
| 262 if (backlog_widget) delete backlog_widget; | |
| 263 if (sel_bg1) parent.Root().DeleteSurface(sel_bg1); | |
| 264 if (sel_bg2) parent.Root().DeleteSurface(sel_bg2); | |
| 265 event.DeleteGlobalPressFunc(&PressFunc, (void*)this); | |
| 266 } | |
| 267 | |
| 268 bool TextImpl::PressFunc(int x, int y, void* pointer) { | |
| 269 TextImpl* t = (TextImpl*)pointer; | |
| 270 if (t->status == WAIT_CLICK) { | |
| 271 t->status = WAIT_ABORT; | |
| 272 } else if (t->status == WAIT_CLICK_MOUSEPOS) { | |
| 273 t->status = WAIT_CLICK_MOUSEPOSEND_L; | |
| 274 } else if (t->status_mask & CLEARSCR_WAIT_MASK) { | |
| 275 t->status_mask = Status(t->status_mask & (~CLEARSCR_WAIT_MASK)); | |
| 276 if (t->text) t->text->show(); | |
| 277 if (t->kcursor) { | |
| 278 if (t->status == WAIT_TEXT) t->kcursor->show(); | |
| 279 } | |
| 280 if (t->sel_widget) t->sel_widget->show(); | |
| 281 if (t->backlog_widget) t->backlog_widget->show(); | |
| 282 } else if (t->status_mask & BACKLOG_WAIT_MASK) { | |
| 283 t->status_mask = Status(t->status_mask | BACKLOG_MASK_KOE); | |
| 284 } else if ( (t->skip_mode & SKIP_TEXT) && (!(t->skip_mode & SKIP_IN_MENU)) ) { | |
| 285 if (t->status == WAIT_SELECT_INBOX) ; | |
| 286 else if (t->status == WAIT_SELECT_OUTBOX) ; | |
| 287 else if (t->status == WAIT_SELECT_VALUE) ; | |
| 288 else t->status_mask = Status(t->status_mask | SKIPEND_MASK); | |
| 289 } | |
| 290 return true; // event not deleted | |
| 291 } | |
| 292 void TextImpl::PressFuncButton(void* pointer, WidButton* from) { | |
| 293 TextImpl* t = (TextImpl*)pointer; | |
| 294 if (t->status != WAIT_SELECT_INBOX && t->status != WAIT_SELECT_OUTBOX) return; | |
| 295 vector<WidTextButton*>::iterator it; | |
| 296 int sel = 0; | |
| 297 for (it=t->selects.begin(); it != t->selects.end(); it++, sel++) { | |
| 298 if (from == *it) break; | |
| 299 } | |
| 300 if (it == t->selects.end()) { | |
| 301 fprintf(stderr,"TextImpl::PressFuncButton: Cannot find select widget\n"); | |
| 302 return; | |
| 303 } | |
| 304 t->status = Status(WAIT_SELECT_VALUE + sel); | |
| 305 return; | |
| 306 } | |
| 307 | |
| 308 void TextImpl::SetSkipMode(SkipMode _mode) { | |
| 309 if ( (skip_mode & SKIP_IN_MENU) && (_mode & SKIP_IN_MENU) == 0) { | |
| 310 if (status_mask & BACKLOG_WAIT_MASK) { // backlog mode から復帰 | |
| 311 status_mask = Status(status_mask & (~(BACKLOG_MASK|BACKLOG_MASK_FWD|BACKLOG_MASK_KOE|BACKLOG_WAIT_MASK))); | |
| 312 text->wid->Clear(); | |
| 313 if (status == WAIT_TEXT && text != 0) { | |
| 314 text->StartText(text_stream); | |
| 315 text->ShowFace(backlog_item.face.c_str()); | |
| 316 text->wid->Flush(); | |
| 317 if (kcursor) kcursor->show(); | |
| 318 } | |
| 319 drawn_backlog_item.Clear(); | |
| 320 } | |
| 321 if (text) text->wid->activate(); | |
| 322 if (sel_widget) { | |
| 323 sel_widget->show(); | |
| 324 if (kcursor) kcursor->hide(); | |
| 325 } | |
| 326 if (backlog_widget) backlog_widget->show(); | |
| 327 if (status_mask & STATSAVE_MASK) { | |
| 328 status_mask = Status(status_mask & (~STATSAVE_MASK)); | |
| 329 status = status_saved; | |
| 330 } | |
| 331 } else if ( (skip_mode & SKIP_IN_MENU) == 0 && (_mode & SKIP_IN_MENU) ) { | |
| 332 if (text) text->wid->deactivate(); | |
| 333 if (sel_widget) sel_widget->hide(); | |
| 334 if (backlog_widget) backlog_widget->hide(); | |
| 335 } | |
| 336 skip_mode = _mode; | |
| 337 } | |
| 338 | |
| 339 /* hash_map が欲しい……*/ | |
| 340 #include<map> | |
| 341 #include<list> | |
| 342 struct SaveFaceHash { // バックログセーブ時の顔画像管理を行う | |
| 343 map<string, int> facetonum; | |
| 344 typedef pair<string,int> Node; | |
| 345 typedef list<Node> List; | |
| 346 List container; | |
| 347 int id_max; | |
| 348 static int size_max; | |
| 349 SaveFaceHash() : id_max(0) { | |
| 350 } | |
| 351 void NewNode(string face, int face_id) { | |
| 352 facetonum[face] = face_id; | |
| 353 container.push_front(Node(face, face_id)); | |
| 354 if (container.size() > size_max) { | |
| 355 Node remove = container.back(); | |
| 356 container.pop_back(); | |
| 357 facetonum.erase(remove.first); | |
| 358 } | |
| 359 } | |
| 360 int Add(string face) { | |
| 361 int id; int ret = -1; | |
| 362 int i; List::iterator it; | |
| 363 if (face.empty()) return -1; | |
| 364 if (facetonum.find(face) == facetonum.end()) { | |
| 365 id = ++id_max; | |
| 366 NewNode(face, id); | |
| 367 ret = -1; | |
| 368 } else { | |
| 369 id = facetonum[face]; | |
| 370 for (i=0, it=container.begin(); it != container.end(); i++, it++) { | |
| 371 if (it->second == id) { | |
| 372 ret = i; | |
| 373 Node n = *it; | |
| 374 container.erase(it); | |
| 375 container.push_front(n); | |
| 376 break; | |
| 377 } | |
| 378 } | |
| 379 } | |
| 380 return ret; | |
| 381 } | |
| 382 string Get(int num) { | |
| 383 if (num < 0) return ""; | |
| 384 List::iterator it = container.begin(); | |
| 385 for (; it != container.end(); it++) { | |
| 386 if (num == 0) return it->first; | |
| 387 num--; | |
| 388 } | |
| 389 return ""; | |
| 390 } | |
| 391 }; | |
| 392 int SaveFaceHash::size_max = 20; | |
| 393 | |
| 394 void TextImpl::Save(string& str, bool rollback_save) { | |
| 395 char buf[1024]; | |
| 396 str = "\n"; | |
| 397 str += "[TextImpl Window]\n"; | |
| 398 sprintf(buf, "TextImplWindow=%d\n",text_window_number); | |
| 399 str += buf; | |
| 400 if (rollback_save) { | |
| 401 ++save_selectcount; | |
| 402 BacklogItem save_item; | |
| 403 save_item.SetSavepos(save_selectcount); | |
| 404 backlog.push_back(save_item); | |
| 405 } | |
| 406 sprintf(buf, "SaveSelectCount=%d\n",save_selectcount); | |
| 407 | |
| 408 str += buf; | |
| 409 int i; | |
| 410 for (i=0; i<26; i++) { | |
| 411 if (replace_name2[i].empty()) continue; | |
| 412 sprintf(buf, "RName.%c=%s\n",i+'A',replace_name2[i].c_str()); | |
| 413 str += buf; | |
| 414 } | |
| 415 int cnt = 0; | |
| 416 vector<BacklogItem>::iterator it; | |
| 417 it = backlog.begin(); | |
| 418 if (!rollback_save) { | |
| 419 SaveFaceHash face_log; | |
| 420 do { | |
| 421 int cur_scn = -1; int cur_pos = -1; | |
| 422 sprintf(buf, "Backlog.%d=",++cnt); | |
| 423 str += buf; | |
| 424 for (; it != backlog.end(); it++) { | |
| 425 buf[0] = 0; int buflen = 0; | |
| 426 if (it->scn == -1) continue; | |
| 427 if (it->pos == -1 && it->scn != 0) continue; | |
| 428 | |
| 429 buf[buflen++] = ';'; | |
| 430 if (it->scn == 0 && it->pos == -1) { | |
| 431 buflen += snprintf(buf+buflen, 1000-buflen, "\"%s\".", it->text.Save().c_str()); | |
| 432 } else { | |
| 433 if (cur_scn != -1 && cur_scn != it->scn) break; // scn change | |
| 434 if (cur_pos != -1 && cur_pos/5000 != it->pos/5000) break; // pos exceeded | |
| 435 if (!it->text.container.empty()) { | |
| 436 buflen += snprintf(buf+buflen, 1000-buflen, "\"%s\"", it->text.Save().c_str()); | |
| 437 } | |
| 438 if (cur_scn == -1) { // scene change | |
| 439 buflen += snprintf(buf+buflen, 1000-buflen, ":%d:%d",it->scn,it->pos); | |
| 440 cur_scn = it->scn; | |
| 441 } else { | |
| 442 buflen += snprintf(buf+buflen, 1000-buflen, "%d",it->pos); | |
| 443 } | |
| 444 cur_pos = it->pos; | |
| 445 } | |
| 446 if (it->koe != -1) | |
| 447 buflen += snprintf(buf+buflen, 1000-buflen, ",%d",it->koe); | |
| 448 if (!it->face.empty()) { | |
| 449 if (it->koe == -1) buf[buflen++] = ','; | |
| 450 int face_num = face_log.Add(it->face); | |
| 451 if (face_num >= 0 && face_num < 20) | |
| 452 buflen += snprintf(buf+buflen, 1000-buflen, ",%c", 'A'+face_num); | |
| 453 else | |
| 454 buflen += snprintf(buf+buflen, 1000-buflen, ",\"%s\"", it->face.c_str()); | |
| 455 } | |
| 456 buf[buflen++] = '\0'; | |
| 457 if (buflen >= 1000) { // 万が一、バックログ1アイテムの大きさが 1000byte を越えるとき | |
| 458 fprintf(stderr,"Fatal : Cannot save backlog crrectly; Please send bug report to the author.\n"); | |
| 459 } else str += buf; | |
| 460 } | |
| 461 str += "\n"; | |
| 462 } while(it != backlog.end()); | |
| 463 } | |
| 464 return; | |
| 465 } | |
| 466 void TextImpl::Load(const char* str) { | |
| 467 if (text) text->wid->Clear(); | |
| 468 hide(); | |
| 469 text_window_number = 0; | |
| 470 save_selectcount = 0; | |
| 471 if (sel_widget) { | |
| 472 selects.clear(); | |
| 473 sel_backlog_pos.clear(); | |
| 474 delete sel_widget; | |
| 475 sel_widget = 0; | |
| 476 } | |
| 477 if (backlog_widget) { | |
| 478 delete backlog_widget; | |
| 479 backlog_widget = 0; | |
| 480 } | |
| 481 status = NORMAL; | |
| 482 status_mask = NORMAL; | |
| 483 status_saved = NORMAL; | |
| 484 text_parsing = false; | |
| 485 text_stream.Clear(); | |
| 486 // backlog.clear(); | |
| 487 vector<BacklogItem> new_backlog; | |
| 488 backlog_item.Clear(); | |
| 489 cur_backlog_item.Clear(); | |
| 490 drawn_backlog_item.Clear(); | |
| 491 | |
| 492 str = strstr(str, "\n[TextImpl Window]\n"); | |
| 493 | |
| 494 if (str) { | |
| 495 SaveFaceHash face_log; | |
| 496 str += strlen("\n[TextImpl Window]\n"); | |
| 497 const char* strend = str; | |
| 498 do { | |
| 499 str = strend; | |
| 500 | |
| 501 strend = strchr(str, '\n'); | |
| 502 if (strend == 0) strend = str + strlen(str); | |
| 503 else strend++; | |
| 504 | |
| 505 if (str[0] == '[') break; // next section | |
| 506 if (strncmp(str, "TextImplWindow=",15) == 0) { | |
| 507 str += 15; | |
| 508 sscanf(str, "%d", &text_window_number); | |
| 509 } else if (strncmp(str, "SaveSelectCount=",16) == 0) { | |
| 510 str += 16; | |
| 511 sscanf(str, "%d", &save_selectcount); | |
| 512 } else if (strncmp(str, "RName.", 6) == 0) { | |
| 513 int n = str[6]-'A'; | |
| 514 if (n >= 0 && n < 26 && str[7] == '=') { | |
| 515 const char* s = strchr(str, '\n'); | |
| 516 int len = -1; | |
| 517 if (s) len = s-(str+8); | |
| 518 if (len > 0) { | |
| 519 replace_name2[n].assign(str+8, len); | |
| 520 } | |
| 521 } | |
| 522 } else if (strncmp(str, "Backlog.", 8) == 0) { | |
| 523 int cur_scn = -1; | |
| 524 int n = -1; | |
| 525 sscanf(str+8, "%d", &n); /* not used */ | |
| 526 const char* next_str = strchr(str, ';'); | |
| 527 while(next_str != 0 && next_str < strend) { | |
| 528 str = next_str + 1; | |
| 529 next_str = strchr(str, ';'); | |
| 530 if (next_str == 0) next_str = strend; | |
| 531 | |
| 532 BacklogItem item; | |
| 533 if (str[0] == '"') { | |
| 534 const char* send = strchr(str+1, '"'); | |
| 535 if (send == 0 || send > next_str) continue; | |
| 536 string tmp_str; tmp_str.assign(str+1, send-str-1); | |
| 537 item.DeleteTextPos(); | |
| 538 item.text.Load(tmp_str); | |
| 539 str = send + 1; | |
| 540 } | |
| 541 if (str[0] == '.') { | |
| 542 item.DeleteTextPos(); | |
| 543 str++; | |
| 544 } else if (str[0] == ':') { | |
| 545 sscanf(str, ":%d:%d", &item.scn, &item.pos); | |
| 546 cur_scn = item.scn; | |
| 547 | |
| 548 } else { | |
| 549 item.scn = cur_scn; | |
| 550 sscanf(str, "%d", &item.pos); | |
| 551 } | |
| 552 str = strchr(str, ','); | |
| 553 if (str == 0 || str > next_str) goto backlog_store; | |
| 554 str++; | |
| 555 if (str[0] == ';' || str[0] == ',') | |
| 556 item.koe = -1; | |
| 557 else | |
| 558 sscanf(str, "%d", &item.koe); | |
| 559 str = strchr(str, ','); | |
| 560 if (str == 0 || str > next_str) goto backlog_store; | |
| 561 str++; | |
| 562 if (*str == '"') { | |
| 563 const char* send = strchr(str+1, '"'); | |
| 564 if (send) { | |
| 565 item.face.assign(str+1, send-str-1); | |
| 566 } | |
| 567 } else if (*str >= 'A' && *str <= 'Z') { | |
| 568 item.face = face_log.Get(*str - 'A'); | |
| 569 } | |
| 570 face_log.Add(item.face); | |
| 571 backlog_store: | |
| 572 new_backlog.push_back(item); | |
| 573 } | |
| 574 } | |
| 575 } while (*strend != 0); | |
| 576 } | |
| 577 if (new_backlog.empty() && (!backlog.empty())) { // empty なら save_selectcount まで backlog を巻き戻す | |
| 578 vector<BacklogItem>::iterator it = backlog.end(); | |
| 579 do { | |
| 580 it--; | |
| 581 if (it->scn == BacklogItem::SaveSelect && it->pos == save_selectcount) { | |
| 582 // Save 位置を見つけたらそれ以降を erase | |
| 583 backlog.erase(it, backlog.end()); | |
| 584 break; | |
| 585 } | |
| 586 } while(it != backlog.begin()); | |
| 587 --save_selectcount; | |
| 588 } else { | |
| 589 backlog.swap(new_backlog); | |
| 590 } | |
| 591 // backlog.clear(); | |
| 592 return; | |
| 593 } | |
| 594 | |
| 595 void TextImpl::hide(void) { | |
| 596 if (text) text->hide(); | |
| 597 if (kcursor) kcursor->hide(); | |
| 598 text = 0; | |
| 599 } | |
| 600 void TextImpl::show(int num) { | |
| 601 if (num != text_window_number) { | |
| 602 hide(); | |
| 603 if (num >= 0 && num < 32 && widgets[num] != 0) { | |
| 604 text_window_number = num; | |
| 605 } | |
| 606 } | |
| 607 text = widgets[text_window_number]; | |
| 608 text->show(); | |
| 609 if (kcursor) { | |
| 610 int kx, ky, d; | |
| 611 char key[1024]; | |
| 612 sprintf(key, "#WINDOW.%03d.KEYCUR_MOD", text_window_number); | |
| 613 config.GetParam(key, 3, &d, &kx, &ky); | |
| 614 // 正しくない気がする | |
| 615 kx += text->wid->Pic()->PosX(); | |
| 616 ky += text->wid->Pic()->PosY(); | |
| 617 // 微妙に下にする | |
| 618 ky += 8; | |
| 619 kcursor->Pic()->Move(kx, ky); | |
| 620 } | |
| 621 } | |
| 622 void TextImpl::DrawBacklog(BacklogItem& item, Cmd& cmd) { | |
| 18 | 623 show(); |
| 0 | 624 text->wid->deactivate(); |
| 625 status_mask = Status(status_mask | BACKLOG_WAIT_MASK); | |
| 626 drawn_backlog_item = item; | |
| 627 if (item.text.container.empty()) { | |
| 628 // cmd から text 内容を再構成 | |
| 629 TextStream saved_text = text_stream; | |
| 630 text_stream.Clear(); | |
| 631 AddText(cmd.Str(cmd.args[0])); | |
| 632 item.text = text_stream; | |
| 633 text_stream = saved_text; | |
| 634 } | |
| 18 | 635 item.text.InsertColor(0, item.text.container.size(), 0xff,0xff,0); |
| 17 | 636 text->StartText(item.text); |
| 0 | 637 text->wid->Flush(); |
| 638 if (item.face.empty()) text->ResetFace(); | |
| 639 else text->ShowFace(item.face.c_str()); | |
| 640 if (kcursor) kcursor->hide(); | |
| 641 } | |
| 642 | |
| 643 void TextImpl::CreateSelBG(void) { | |
| 644 if (sel_bg1 != 0 || sel_bg2 != 0) return; | |
| 645 | |
| 646 const char* btnfile1 = config.GetParaStr("#SELBTN.000.NAME"); | |
| 647 const char* btnfile2 = config.GetParaStr("#SELBTN.000.BACK"); | |
| 648 char path[1024]; | |
| 649 strcpy(path, btnfile1); | |
| 650 sel_bg1 = parent.Root().NewSurface(path); | |
| 651 if (sel_bg1 == 0) { | |
| 652 sprintf(path,"%s.g00",btnfile1); | |
| 653 sel_bg1 = parent.Root().NewSurface(path); | |
| 654 } | |
| 655 strcpy(path, btnfile2); | |
| 656 sel_bg2 = parent.Root().NewSurface(path); | |
| 657 if (sel_bg2 == 0) { | |
| 658 sprintf(path,"%s.g00",btnfile2); | |
| 659 sel_bg2 = parent.Root().NewSurface(path); | |
| 660 } | |
| 661 sel_bg_rect = Rect(0,0,0,0); | |
| 662 if (sel_bg1) sel_bg_rect.join(Rect(*sel_bg1)); | |
| 663 if (sel_bg2) sel_bg_rect.join(Rect(*sel_bg2)); | |
| 664 return; | |
| 665 } | |
| 666 | |
| 667 void TextImpl::CreateSelect(Cmd& cmd) { | |
| 668 char key[1024]; | |
| 669 sprintf(key, "#WINDOW.%03d.SELCOM_USE",text_window_number); | |
| 670 int sel_type = 0; | |
|
38
658272d883ed
* Support (more or less) button style selects (fuuko's ones)
thib
parents:
18
diff
changeset
|
671 if (cmd.cmd3 == 1) config.GetParam(key, 1, &sel_type); |
|
658272d883ed
* Support (more or less) button style selects (fuuko's ones)
thib
parents:
18
diff
changeset
|
672 else if (cmd.cmd3 == 3) sel_type = 0; |
| 0 | 673 |
| 674 int sel_size = cmd.args.size() / 2; | |
| 675 int i; | |
| 676 // cur_backlog_item に次にbacklogに入るべき内容を作成 | |
| 677 // CreateSelect() 後、SAVEPOINT なので現在のbacklogの内容(前のメッセージ)が | |
| 678 // backlog に代入される。その後、backlog_item に cur_backlog_item の内容がセットされる(Wait()内) | |
| 679 char backlog_sel_text[11] = {0x81,0x69,0x91,0x49,0x91,0xf0,0x8e,0x88,0x81,0x6a,0x00}; | |
| 680 cur_backlog_item.Clear(); | |
| 681 cur_backlog_item.AddTextPos(cmd); | |
| 682 cur_backlog_item.text.Add(backlog_sel_text); | |
| 683 cur_backlog_item.text.AddReturn(); | |
| 684 sel_backlog_pos.clear(); | |
| 685 for (i=0; i<sel_size; i++) { | |
| 686 sel_backlog_pos.push_back(cur_backlog_item.text.container.size()); | |
| 687 cur_backlog_item.text.Add(cmd.Str(cmd.args[i*2])); | |
| 688 cur_backlog_item.text.AddReturn(); | |
| 689 } | |
| 690 sel_backlog_pos.push_back(cur_backlog_item.text.container.size()); | |
| 691 | |
| 692 if (sel_type == 0) { // Princess Bride: 選択ウィンドウを別表示 | |
| 693 External_select: | |
| 694 CreateSelBG(); | |
| 695 hide(); // なので、テキストウィンドウは消去 | |
| 40 | 696 int baseposx, baseposy, repposx, repposy, centerx, centery; |
| 0 | 697 int mojisize, col1, col2; |
| 40 | 698 config.GetParam("#SELBTN.000.CENTERING", 2, ¢erx, ¢ery); |
| 0 | 699 config.GetParam("#SELBTN.000.BASEPOS", 2, &baseposx, &baseposy); |
| 700 config.GetParam("#SELBTN.000.REPPOS", 2, &repposx, &repposy); | |
| 701 config.GetParam("#SELBTN.000.MOJISIZE", 1, &mojisize); | |
| 702 config.GetParam("#SELBTN.000.MOJIDEFAULTCOL", 1, &col1); | |
| 703 config.GetParam("#SELBTN.000.MOJISELECTCOL", 1, &col2); | |
| 704 if (col1 == col2) col2 = 1; // CLANNAD でとりあえず。 | |
| 705 int r, g, b; | |
| 706 sprintf(key, "#COLOR_TABLE.%03d", col1); | |
| 707 config.GetParam(key, 3, &r, &g, &b); | |
| 708 Color fore(r,g,b); | |
| 709 sprintf(key, "#COLOR_TABLE.%03d", col2); | |
| 710 config.GetParam(key, 3, &r, &g, &b); | |
| 711 Color seled(r,g,b); | |
| 712 | |
| 713 /* ウィジット作成 */ | |
| 714 /* ウィンドウ背景の大きさを求める */ | |
| 715 if (baseposx == 0 && sel_bg_rect.width() != 0) | |
| 716 baseposx = (parent.Width()-sel_bg_rect.width()) / 2; // ボタン位置をセンタリング | |
| 40 | 717 if (centerx) |
| 718 baseposx = (parent.Width()-sel_bg_rect.width()-sel_size*repposx) / 2; | |
| 719 if (centery) | |
| 720 baseposy = (parent.Height()-sel_bg_rect.height()-sel_size*repposy) / 2; | |
| 0 | 721 |
| 722 sel_widget = parent.create_node( Rect(0, 0, parent.Width(), parent.Height()),0); | |
| 723 | |
| 724 for (i=0; i<sel_size; i++) { | |
| 725 PicBase* p; | |
| 726 // 背景作成 | |
| 727 if (sel_bg2) { | |
| 728 p = sel_widget->create_node(Rect(baseposx, baseposy, baseposx+sel_bg_rect.width(), baseposy+sel_bg_rect.height()),0); | |
| 729 p->SetSurface(sel_bg2, 0, 0); | |
| 730 } | |
| 731 if (sel_bg1) { | |
| 732 p = sel_widget->create_node(Rect(baseposx, baseposy, baseposx+sel_bg_rect.width(), baseposy+sel_bg_rect.height()),0); | |
| 733 p->SetSurface(sel_bg1, 0, 0); | |
| 734 } | |
| 735 /* ボタン作成 */ | |
| 736 const char* str = cmd.Str(cmd.args[i*2]); | |
| 737 int value = cmd.args[i*2+1].value; | |
| 738 while(selects.size() <= value) selects.push_back(0); // vector の大きさを広げる | |
| 739 | |
| 740 kconv( (const unsigned char*)str, (unsigned char*)key); | |
| 741 selects[value] = new WidTextButton(event, sel_widget, key, mojisize, WidTextButton::CENTER, | |
| 742 Rect(baseposx, baseposy, baseposx+sel_bg_rect.width(), baseposy+sel_bg_rect.height()), 1, fore, seled, Color(0,0,0,0)); | |
| 743 selects[value]->press_func = &PressFuncButton; | |
| 744 selects[value]->press_pointer = (void*)this; | |
| 745 | |
| 746 baseposx += repposx; | |
| 747 baseposy += repposy; | |
| 748 } | |
| 749 sel_widget->show_all(); | |
| 750 status = WAIT_SELECT_OUTBOX; | |
| 751 } else { // CLANNAD: テキストウィンドウ内に選択肢表示 | |
| 752 int mojisize; | |
| 753 config.GetParam("#SELBTN.000.MOJISIZE", 1, &mojisize); | |
| 754 Color fore(0xff,0xff,0xff); | |
| 755 Color seled(0xff,0xff,0xff); | |
| 756 | |
| 757 show(); | |
| 758 if (text == 0) goto External_select; // テキスト・ウィンドウを表示できなければ外部選択肢にする | |
| 759 text->wid->Clear(); | |
| 760 if (kcursor) kcursor->hide(); | |
| 761 /* ウィジット作成 : テキスト表示範囲と同じ*/ | |
| 762 int posx = text->wid->pictext->PosX(); | |
| 763 int posy = text->wid->pictext->PosY(); | |
| 764 int sel_w = text->wid->pictext->Width(); | |
| 765 int sel_h = text->wid->pictext->Height(); | |
| 766 sel_widget = text->wid->PicNode()->create_node(Rect(posx, posy, posx+sel_w, posy+sel_h), 0); | |
| 767 | |
| 768 int sel_y = 0; | |
| 769 for (i=0; i<sel_size; i++) { | |
| 770 PicBase* p; | |
| 771 /* ボタン作成 */ | |
| 772 const char* str = cmd.Str(cmd.args[i*2]); | |
| 773 int value = cmd.args[i*2+1].value; | |
| 774 while(selects.size() <= value) selects.push_back(0); // vector の大きさを広げる | |
| 775 | |
| 776 kconv( (const unsigned char*)str, (unsigned char*)key); | |
| 777 selects[value] = new WidTextButton(event, sel_widget, key, mojisize, WidTextButton::Attribute(WidTextButton::REVERSE | WidTextButton::NOPADDING), | |
| 778 Rect(0, sel_y, sel_w, sel_y), 1, fore, seled, Color(0,0,0,0)); | |
| 779 selects[value]->press_func = &PressFuncButton; | |
| 780 selects[value]->press_pointer = (void*)this; | |
| 781 | |
| 782 sel_y += selects[value]->Pic()->Height() + 1; | |
| 783 } | |
| 784 sel_widget->show_all(); | |
| 785 status = WAIT_SELECT_INBOX; | |
| 786 } | |
| 787 } | |
| 788 | |
| 789 void TextImpl::AddText(const char* str_o) { | |
| 790 char str[10001]; | |
| 791 if (text == 0) return; | |
| 792 /* まず、replace string を変換 */ | |
| 793 int i; | |
| 794 int cnt = 0; | |
| 795 /* * = 81 96 A-Z = 0x82 [0x60-0x79] */ | |
| 796 /* % = 81 93 A-Z = 0x82 [0x60-0x79] */ | |
| 797 for (i=0; cnt<10000 && str_o[i] != 0; i++) { | |
| 798 if (str_o[i] < 0) { | |
| 799 if ( (unsigned char)str_o[i] == 0x81 && (unsigned char)str_o[i+1] == 0x96 && (unsigned char)str_o[i+2] == 0x82) { | |
| 800 int c = str_o[i+3]; | |
| 801 if (c >= 0x60 && c <= 0x79 && replace_name[c-0x60].length() != 0) { // 名前変換 | |
| 802 i += 3; | |
| 803 strcpy(str+cnt, replace_name[c-0x60].c_str()); | |
| 804 cnt += replace_name[c-0x60].length(); | |
| 805 continue; | |
| 806 } | |
| 807 } else if ( (unsigned char)str_o[i] == 0x81 && (unsigned char)str_o[i+1] == 0x93 && (unsigned char)str_o[i+2] == 0x82) { | |
| 808 int c = str_o[i+3]; | |
| 809 if (c >= 0x60 && c <= 0x79 && replace_name2[c-0x60].length() != 0) { // 名前変換2 | |
| 810 i += 3; | |
| 811 strcpy(str+cnt, replace_name2[c-0x60].c_str()); | |
| 812 cnt += replace_name2[c-0x60].length(); | |
| 813 continue; | |
| 814 } | |
| 815 } | |
| 816 str[cnt++] = str_o[i++]; | |
| 817 } | |
| 818 str[cnt++] = str_o[i]; | |
| 819 } | |
| 820 str[cnt] = 0; | |
| 821 str[10000] = 0; | |
| 822 char* str_top = str; | |
| 823 | |
| 824 for (char* s = str_top; *s != 0; s++) { | |
| 825 // if (*(unsigned char*)s == 0xa1 && *(unsigned char*)(s+1) == 0xda) { /* euc */ | |
| 826 if (*(unsigned char*)s == 0x81 && *(unsigned char*)(s+1) == 0x79) { /* sjis */ | |
| 827 // 名前 | |
| 828 *s = 0; | |
| 829 if (s != str_top) text_stream.Add(str_top); | |
| 830 s += 2; | |
| 831 char* name_top = s; | |
| 832 for (; *s != 0; s++) { | |
| 833 // if (*(unsigned char*)s == 0xa1 && *(unsigned char*)(s+1) == 0xdb) { /* euc */ | |
| 834 if (*(unsigned char*)s == 0x81 && *(unsigned char*)(s+1) == 0x7a) { /* sjis */ | |
| 835 *s = 0; | |
| 836 s += 2; | |
| 837 text_stream.AddName(name_top); | |
| 838 break; | |
| 839 } | |
| 840 if (*s < 0 && s[1] != 0) s++; // 全角文字なら2字飛ばす | |
| 841 } | |
| 842 str_top = s; | |
| 843 } | |
| 844 if (*s == 0x0a) { | |
| 845 *s = 0; | |
| 846 text_stream.Add(str_top); | |
| 847 text_stream.AddReturn(); | |
| 848 str_top = s; | |
| 849 } else if (*s < 0 && s[1] != 0) s++; | |
| 850 } | |
| 851 text_stream.Add(str_top); | |
| 852 return; | |
| 853 } | |
| 854 | |
| 855 void TextImpl::Exec(Cmd& cmd) { | |
| 856 if (cmd.cmd_type == CMD_TEXT) { | |
| 857 if (text == 0) { | |
| 858 show(); | |
| 859 } | |
| 860 if (cmd.args.size() != 1) return; | |
| 861 if (ruby_text_flag) { | |
| 862 ruby_text = cmd.Str(cmd.args[0]); | |
| 863 ruby_text_flag = 0; | |
| 864 cmd.clear(); | |
| 865 return; | |
| 866 } | |
| 867 cur_backlog_item.AddTextPos(cmd); | |
| 868 AddText(cmd.Str(cmd.args[0])); | |
| 869 char debug[1024]; | |
| 870 kconv( (unsigned char*)cmd.Str(cmd.args[0]), (unsigned char*)debug); | |
| 871 eprintf("text: %s\n",debug); | |
| 872 if (text_parsing) | |
| 873 cmd.clear(); | |
| 874 else | |
| 875 cmd.cmd_type = CMD_SAVEPOINT; | |
| 876 text_parsing = true; /* テキスト待ち直後のテキスト位置=セーブ位置 */ | |
| 877 return; | |
| 878 } | |
| 879 if (cmd.cmd_type != CMD_OTHER) return; | |
| 880 /* テキストウィンドウを消去するコマンド類をチェックする */ | |
| 881 if (cmd.cmd1 == 1 && cmd.cmd2 == 0x21) { | |
| 882 if (cmd.cmd3 == 0x49 || cmd.cmd3 == 0x4b || cmd.cmd3 == 0x4c) { | |
| 883 if (text) text->ResetFace(); | |
| 884 cur_backlog_item.face = ""; | |
| 885 hide(); | |
| 886 } | |
| 887 } | |
| 888 if (cmd.cmd1 == 1 && cmd.cmd2 == 0x17 && cmd.cmd3 == 0 && cmd.cmd4 == 1) { | |
| 889 // PlayKoe ; 声出力コマンドをチェックする */ | |
| 890 cur_backlog_item.koe = cmd.args[0].value; | |
| 891 } | |
| 892 if (cmd.cmd1 == 0 && cmd.cmd2 == 3 && cmd.cmd3 == 0x97) { // いいのかなー | |
| 893 | |
| 894 if (text) { | |
| 895 text->ResetFace(); | |
| 896 text->wid->Clear(); | |
| 897 } | |
| 898 cur_backlog_item.face = ""; | |
| 899 text_stream.Clear(); | |
| 900 hide(); | |
| 901 } | |
| 902 if (cmd.cmd1 == 0 && cmd.cmd2 == 3) { | |
| 903 if (cmd.cmd3 == 0x11) { // テキスト表示、クリック待ち | |
| 904 if (text) { | |
| 905 eprintf("start\n"); | |
| 906 text->StartText(text_stream); | |
| 907 if (skip_mode & SKIP_TEXT) text->wid->Flush(); | |
| 908 else if (kcursor) kcursor->show(); | |
| 909 status = WAIT_TEXT; | |
| 910 text_parsing = false; | |
| 911 } | |
| 912 backlog_item = cur_backlog_item; | |
| 913 if (cur_backlog_item.scn == 0 && cur_backlog_item.pos == -1) backlog_item.text = text_stream; | |
| 914 cur_backlog_item.Clear(); | |
| 915 | |
| 916 cmd.clear(); | |
| 917 cmd.cmd_type = CMD_WAITFRAMEUPDATE; // 画像描画に戻る(skip時にテキストが描画されやすくするため) | |
| 918 // これだと1フレーム1テキストしか表示されなくなるので注意 | |
| 919 } else if (cmd.cmd3 == 3 || cmd.cmd3 == 0xc9) { // リターン挿入 | |
| 920 text_stream.AddReturn(); | |
| 921 cur_backlog_item.DeleteTextPos(); | |
| 922 cmd.clear(); | |
| 923 } else if (cmd.cmd3 == 0x3e8 || cmd.cmd3 == 0x3e9) { // 顔グラフィック変更 | |
| 924 if (text == 0) { | |
| 925 show(); | |
| 926 } | |
| 927 if (cmd.cmd3 == 0x3e8) { | |
| 928 string s = cmd.Str(cmd.args[0]); | |
| 929 s += ".g00"; | |
| 930 if (text) text->ShowFace(s.c_str()); | |
| 931 cur_backlog_item.face = s; | |
| 932 cmd.cmd_type = CMD_SAVECMD_ONCE; | |
| 933 } else if (cmd.cmd3 == 0x3e9) { // 顔グラフィック消去 | |
| 934 if (text) text->ResetFace(); | |
| 935 cur_backlog_item.face = ""; | |
| 936 cmd.cmd_type = CMD_SAVECMD_ONCE; | |
| 937 } | |
| 938 } else if (cmd.cmd3 == 0x78) { // ルビ関連 | |
| 939 if (text == 0) { | |
| 940 show(); | |
| 941 } | |
| 942 if (cmd.cmd4 == 1) { | |
| 943 ruby_text_flag = true; | |
| 944 eprintf("SetRubyTextImpl."); | |
| 945 cmd.clear(); | |
| 946 } else if (cmd.cmd4 == 0) { | |
| 947 if (ruby_text.length() == 0) { // ルビを振るテキストがない | |
| 948 eprintf("Cannot find ruby text.\n"); | |
| 949 return; | |
| 950 } | |
| 951 if (cmd.args.size() != 1) return; | |
| 952 char debug1[1024], debug2[1024]; | |
| 953 kconv( (unsigned char*)ruby_text.c_str(), (unsigned char*)debug1); | |
| 954 kconv( (unsigned char*)cmd.Str(cmd.args[0]), (unsigned char*)debug2); | |
| 955 eprintf("SetRuby. %s, %s",debug1, debug2); | |
| 956 text_stream.AddRuby(ruby_text.c_str(), cmd.Str(cmd.args[0])); | |
| 957 cur_backlog_item.DeleteTextPos(); | |
| 958 cmd.clear(); | |
| 959 } | |
| 960 } else if (cmd.cmd3 == 0x66) { // テキストウィンドウの形 | |
| 961 if (cmd.cmd4 == 0) { | |
| 962 eprintf("set text window <- %d\n",cmd.args[0].value); | |
| 963 if (text) show(cmd.args[0].value); | |
| 964 else text_window_number = cmd.args[0].value; | |
| 965 } else if (cmd.cmd4 == 1) { // default value | |
| 966 eprintf("set text window <- default\n"); | |
| 967 if (text) show(0); | |
| 968 else text_window_number = 0; | |
| 969 } | |
| 970 cmd.clear(); | |
| 971 } else if (cmd.cmd3 == 0x67) { // テキストウィンドウ表示? | |
| 972 show(); | |
| 973 // 表示の際はテキストをクリアしない? | |
| 974 // if (text) text->wid->Clear(); | |
| 975 // text_stream.Clear(); | |
| 976 cmd.clear(); | |
| 977 } else if (cmd.cmd3 == 0x68) { // テキスト表示? | |
| 978 // 全テキスト表示 | |
| 979 if (text) { | |
| 980 text->StartText(text_stream); | |
| 981 text->wid->Flush(); | |
| 982 } | |
| 983 cmd.clear(); | |
| 984 } else if (cmd.cmd3 == 0x98) { // テキストウィンドウクリア? | |
| 985 show(); | |
| 986 if (text) text->wid->Clear(); | |
| 987 text_stream.Clear(); | |
| 988 cmd.clear(); | |
| 989 } | |
| 990 } else if (cmd.cmd1 == 0 && cmd.cmd2 == 2 && (cmd.cmd3 == 1 || cmd.cmd3 == 3) && cmd.cmd4 == 0) { | |
| 991 // 選択肢 | |
| 992 CreateSelect(cmd); | |
| 39 | 993 //FIXME: Check if it's really clean |
| 994 if (text_parsing) { | |
| 995 show(); | |
| 996 text->StartText(text_stream); | |
| 997 if (skip_mode & SKIP_TEXT) text->wid->Flush(); | |
| 998 else if (kcursor) kcursor->hide(); | |
| 999 text_parsing = false; | |
| 1000 text_stream.Clear(); | |
| 1001 } | |
| 0 | 1002 cmd.cmd_type = CMD_ROLLBACKPOINT; /* 選択肢はセーブ位置 / シナリオ巻き戻し位置 */ |
| 1003 // cmd.clear(); | |
| 1004 } else if (cmd.cmd1 == 0 && cmd.cmd2 == 4) { | |
| 1005 if (cmd.cmd3 == 0x44c) { // テキストスキップ開始 | |
| 1006 status_mask = Status(SKIPMASK | status_mask); | |
| 1007 cmd.clear(); | |
| 1008 } else if (cmd.cmd3 == 0x3e8) { // ウィンドウ消去 | |
| 1009 status_mask = Status(CLEARSCR_MASK | status_mask); | |
| 1010 cmd.clear(); | |
| 1011 } | |
| 1012 } else if (cmd.cmd1 == 1 && cmd.cmd2 == 0x04) { | |
| 1013 /* ウェイト関連命令 */ | |
| 1014 if (cmd.cmd3 == 0x64 || cmd.cmd3 == 0x6f || cmd.cmd3 == 0x79) { | |
| 1015 eprintf("wait %dmsec\n",cmd.args[0].value); | |
| 1016 if (cmd.cmd3 == 0x64 && text) { | |
| 1017 /* 0x64 だと文字描画中の待ちに使うことがある */ | |
| 1018 text->StartText(text_stream); | |
| 1019 text->wid->Flush(); | |
| 1020 } | |
| 1021 if (cmd.cmd3 == 0x6f || cmd.cmd3 == 0x79) wait_time = base_time + cmd.args[0].value; | |
| 1022 else wait_time = old_time + cmd.args[0].value; | |
| 1023 status = WAIT; | |
| 1024 cmd.cmd_type = CMD_WAITFRAMEUPDATE; // 画像描画に戻る(skip時にテキストが描画されやすくするため) | |
| 1025 } else if (cmd.cmd3 == 0x65 || cmd.cmd3 == 0x70) { | |
| 1026 eprintf("wait %dmsec(click stop)\n",cmd.args[0].value); | |
| 1027 if (cmd.cmd3 == 0x70) wait_time = base_time + cmd.args[0].value; | |
| 1028 else wait_time = old_time + cmd.args[0].value; | |
| 1029 status = WAIT_CLICK; | |
| 1030 cmd.cmd_type = CMD_WAITFRAMEUPDATE; // 画像描画に戻る(skip時にテキストが描画されやすくするため) | |
| 1031 } else if (cmd.cmd3 == 0x83) { | |
| 1032 /* マウスがクリックされるまで待つ */ | |
| 1033 eprintf("wait and get mouse pos at click\n"); | |
| 1034 wait_time = old_time + 1000 * 1000; | |
| 1035 status = WAIT_CLICK_MOUSEPOS; | |
| 1036 wait_savedvar[0] = cmd.args[0]; | |
| 1037 wait_savedvar[1] = cmd.args[1]; | |
| 1038 cmd.clear(); | |
| 1039 } else if (cmd.cmd3 == 0x1fe) { | |
| 1040 eprintf("get timer value[%d]\n",cmd.args[0].value); | |
| 1041 if (timer_var.find(cmd.args[0].value) == timer_var.end()) { | |
| 1042 cmd.SetSysvar(0); | |
| 1043 } else { | |
| 1044 TimerAtom& atom = timer_var[cmd.args[0].value]; | |
| 1045 if (atom.total_time <= 0) atom.total_time = 1; | |
| 1046 int cur_tm = old_time - atom.start_time; | |
| 1047 if (cur_tm < 0) cur_tm = atom.total_time; // エラーなら最終時間に合わせる | |
| 1048 if (cur_tm > atom.total_time) cur_tm = atom.total_time; | |
| 1049 // use 'long long'(64bit) or 'double'(80bit) type, since total_time, to and from is 32 bit. | |
| 1050 int v = atom.from + (long long)(atom.to-atom.from)*cur_tm/int(atom.total_time); | |
| 1051 cmd.SetSysvar(v); | |
| 1052 } | |
| 1053 /* From rldev-1.40, reallive.kfn | |
| 1054 0x72 fun Timer (store) <1:Sys:00114, 1> ('counter') () | |
| 1055 0x73 fun CmpTimer (store) <1:Sys:00115, 1> ('time') ('time', 'counter') | |
| 1056 0x74 fun SetTimer <1:Sys:00116, 1> ('time') ('time', 'counter') | |
| 1057 | |
| 1058 0x78 fun ResetExTimer <1:Sys:00120, 1> ('counter') () | |
| 1059 0x79 fun timeEx <1:Sys:00121, 1> ('time') ('time', 'counter') | |
| 1060 0x7a fun timeExC (store) <1:Sys:00122, 1> ('time') ('time', 'counter') | |
| 1061 0x7b fun timeExC2 (store) <1:Sys:00123, 1> ('time') ('time', 'counter') // UNDOCUMENTED | |
| 1062 0x7c fun ExTimer (store) <1:Sys:00124, 1> ('counter') () | |
| 1063 0x7d fun CmpExTimer (store) <1:Sys:00125, 1> ('time') ('time', 'counter') | |
| 1064 0x7e fun SetExTimer <1:Sys:00126, 1> ('time') ('time', 'counter') | |
| 1065 */ | |
| 1066 | |
| 1067 } else if (cmd.cmd3 == 0x6e || cmd.cmd3 == 0x78) { // set basetime | |
| 1068 if (cmd.cmd4 == 1) { | |
| 1069 eprintf("set basetime\n"); | |
| 1070 base_time = old_time; | |
| 1071 cmd.clear(); | |
| 1072 } else if (cmd.cmd4 == 0) { // n-th base time | |
| 1073 int index = cmd.args[0].value; | |
| 1074 eprintf("set basetime (%d)\n",index); | |
| 1075 TimerAtom& atom = timer_var[index]; | |
| 1076 atom.from = 0; | |
| 1077 atom.to = 0; | |
| 1078 atom.total_time = 0; | |
| 1079 atom.start_time = old_time; | |
| 1080 cmd.clear(); | |
| 1081 } | |
| 1082 } else if (cmd.cmd3 == 0x72 || cmd.cmd3 == 0x7c) { // get time | |
| 1083 if (cmd.cmd4 == 1) { // get time | |
| 1084 eprintf("get time\n"); | |
| 1085 cmd.SetSysvar(old_time - base_time); | |
| 1086 } else if (cmd.cmd4 == 0) { // n-th get time | |
| 1087 int index = cmd.args[0].value; | |
| 1088 eprintf("get time %dth\n",index); | |
| 1089 if (timer_var.find(index) == timer_var.end()) cmd.SetSysvar(0); | |
| 1090 else cmd.SetSysvar(old_time - timer_var[index].start_time); | |
| 1091 } | |
| 1092 } else if (cmd.cmd3 == 0x26c || cmd.cmd3 == 0x270) { // set basetime(multi) | |
| 1093 int j = 0; | |
| 1094 eprintf("set basetime\n"); | |
| 1095 int i; for (i=0; i<cmd.argc; i++) { | |
| 1096 int cnt = cmd.args[j++].value; // 3なので無視 | |
| 1097 int num = cmd.args[j++].value; | |
| 1098 TimerAtom& atom = timer_var[num]; | |
| 1099 atom.from = cmd.args[j++].value; | |
| 1100 atom.to = cmd.args[j++].value; | |
| 1101 atom.total_time = cmd.args[j++].value; | |
| 1102 atom.start_time = old_time; | |
| 1103 } | |
| 1104 cmd.clear(); | |
| 1105 } else if (cmd.cmd3 == 0x276) { // get time (multi) | |
| 1106 int j = 0; | |
| 1107 eprintf("get timer value\n"); | |
| 1108 vector<VarInfo> args = cmd.args; | |
| 1109 vector<VarInfo>::iterator it = args.begin(); | |
| 1110 int argc = cmd.argc; | |
| 1111 int active_timers = 0; | |
| 1112 int i; for (i=0; i<argc; i++) { | |
| 1113 int cnt = (it++)->value; | |
| 1114 int num = (it++)->value; | |
| 1115 | |
| 1116 if (timer_var.find(num) == timer_var.end()) { | |
| 1117 cmd.SetFlagvar(*it++, 0); | |
| 1118 } else { | |
| 1119 TimerAtom& atom = timer_var[num]; | |
| 1120 if (atom.total_time <= 0) atom.total_time = 1; | |
| 1121 int cur_tm = old_time - atom.start_time; | |
| 1122 if (cur_tm < 0) cur_tm = atom.total_time; // エラーなら最終時間に合わせる | |
| 1123 if (cur_tm > atom.total_time) cur_tm = atom.total_time; | |
| 1124 // use 'long long'(64bit) or 'double'(80bit) type, since total_time, to and from is 32 bit. | |
| 1125 int v = atom.from + (long long)(atom.to-atom.from)*cur_tm/int(atom.total_time); | |
| 1126 cmd.SetFlagvar(*it++, v); | |
| 1127 if (atom.total_time != -1 && cur_tm < atom.total_time) active_timers++; | |
| 1128 } | |
| 1129 } | |
| 1130 if (active_timers) active_timers = 1; | |
| 1131 cmd.SetSysvar(active_timers); | |
| 1132 } else if (cmd.cmd3 == 0x1f4) { | |
| 1133 TimerAtom& atom = timer_var[cmd.args[0].value]; | |
| 1134 atom.from = cmd.args[1].value; | |
| 1135 atom.to = cmd.args[2].value; | |
| 1136 atom.total_time = cmd.args[3].value; | |
| 1137 atom.start_time = old_time; | |
| 1138 cmd.clear(); | |
| 1139 } else if (cmd.cmd3 == 0x3e8) { | |
| 1140 /* rand() */ | |
| 1141 int min = 0, max; | |
| 1142 if (cmd.args.size() == 2) { | |
| 1143 min = cmd.args[0].value; | |
| 1144 max = cmd.args[1].value; | |
| 1145 } else { | |
| 1146 max = cmd.args[1].value; | |
| 1147 } | |
| 1148 if (min > max) { | |
| 1149 int tmp = max; | |
| 1150 max = min; | |
| 1151 min = tmp; | |
| 1152 } | |
| 1153 int r = random(); | |
| 1154 if (min == max) r = min; | |
| 1155 else r = (r % (max-min)) + min; | |
| 1156 cmd.SetSysvar(r); | |
| 1157 } else if (cmd.cmd3 == 0x3ea) { | |
| 1158 int val = cmd.args[0].value; | |
| 1159 if (val < 0) val = -val; | |
| 1160 cmd.SetSysvar(val); | |
| 1161 } else if (cmd.cmd3 == 0x3ec) { | |
| 1162 /* min だよなあ・・・*/ | |
| 1163 int min = cmd.args[0].value; | |
| 1164 int max = cmd.args[1].value; | |
| 1165 if (max < min) min = max; | |
| 1166 cmd.SetSysvar(min); | |
| 1167 } else if (cmd.cmd3 == 0x3ef) { | |
| 1168 /* min */ | |
| 1169 int min = cmd.args[0].value; | |
| 1170 int max = cmd.args[1].value; | |
| 1171 if (max < min) min = max; | |
| 1172 cmd.SetSysvar(min); | |
| 1173 } else if (cmd.cmd3 == 0x320) { | |
| 1174 /* range conversion : 比率に丸める */ | |
| 1175 // アルゴリズムは間違えてるような気がする | |
| 1176 // | |
| 1177 if (cmd.args.size() >= 7) { | |
| 1178 int val = cmd.args[0].value; | |
| 1179 int offset = cmd.args[1].value; | |
| 1180 int r_min = cmd.args[2].value; | |
| 1181 int v_min = cmd.args[3].value; | |
| 1182 int v_max = cmd.args[4].value; | |
| 1183 int r_max = cmd.args[5].value; | |
| 1184 int mode = cmd.args[6].value; | |
| 1185 // rldev : mode == 1,3 : 'acceralating curve', 2,3: 'decelerating curve' | |
| 1186 // 複数の引数リスト(r_minからmodeまでのリスト)もつこともあり、その場合は | |
| 1187 // "cancel out in some way" らしい | |
| 1188 if (mode == 1 || mode == 3) val += offset; | |
| 1189 else if (mode == 2 || mode == 4) val -= offset; | |
| 1190 if (cmd.args.size() != 7) | |
| 1191 fprintf(stderr,"\n%d/%d: cmd 01-04:0320 : XXXX NOT SUPPORTED LIST : DOUBLE RANGE CONVERSION! XXXXXXXXXXX\n",cmd.scn,cmd.pos); | |
| 1192 if (val < v_min) val = v_min; | |
| 1193 if (val > v_max) val = v_max; | |
| 1194 val = (r_max-r_min)*(val-v_min)/(v_max-v_min) + r_min; | |
| 1195 cmd.SetSysvar(val); | |
| 1196 } | |
| 1197 } else if (cmd.cmd3 == 0x3f1) { | |
| 1198 /* range 内に丸める */ | |
| 1199 int min = cmd.args[0].value; | |
| 1200 int val = cmd.args[1].value; | |
| 1201 int max = cmd.args[2].value; | |
| 1202 if (min > max) { | |
| 1203 int tmp = max; | |
| 1204 max = min; | |
| 1205 min = tmp; | |
| 1206 } | |
| 1207 if (val < min) val = min; | |
| 1208 if (val > max) val = max; | |
| 1209 cmd.SetSysvar(val); | |
| 1210 } else if (cmd.cmd3 == 0x16c && cmd.cmd4 == 0) { | |
| 1211 /* なんかよくわからないけどカーソル形状変更にしとく */ | |
| 1212 SetCursor(cmd.args[0].value); | |
| 1213 cmd.clear(); | |
| 1214 } else if (cmd.cmd3 == 0x0bc1) { // メニューからのロード | |
| 1215 cmd.cmd_type = CMD_LOADREQ; | |
| 1216 } else if ( (cmd.cmd3 >= 0x8d4 && cmd.cmd3 <= 0x8d8) || cmd.cmd3 == 0x8db || cmd.cmd3 == 0x93f || cmd.cmd3 == 0xa39) { | |
| 1217 // テキストウィンドウの色設定 | |
| 1218 int r, g, b, a, flag; | |
| 1219 if (cmd.cmd3 == 0xa39) { // 元設定を取り出す | |
| 1220 config.GetOriginalParam("#WINDOW_ATTR", 5, &r, &g, &b, &a, &flag); | |
| 1221 } else { | |
| 1222 config.GetParam("#WINDOW_ATTR", 5, &r, &g, &b, &a, &flag); | |
| 1223 } | |
| 1224 if (cmd.cmd3 == 0xa39 || cmd.cmd3 == 0x93f) { // 設定を変数に取り出す | |
| 1225 if (cmd.args.size() != 5) { | |
| 1226 fprintf(stderr,"cmd 01-04:%4d : invalid arg size\n", cmd.cmd3); | |
| 1227 } else { | |
| 1228 vector<VarInfo> args(cmd.args); | |
| 1229 cmd.SetFlagvar(args[0], r); | |
| 1230 cmd.SetFlagvar(args[1], g); | |
| 1231 cmd.SetFlagvar(args[2], b); | |
| 1232 cmd.SetFlagvar(args[3], a); | |
| 1233 cmd.SetFlagvar(args[4], flag); | |
| 1234 } | |
| 1235 } else { | |
| 1236 switch(cmd.cmd3) { | |
| 1237 case 0x8d4: r = cmd.args[0].value; break; | |
| 1238 case 0x8d5: g = cmd.args[0].value; break; | |
| 1239 case 0x8d6: b = cmd.args[0].value; break; | |
| 1240 case 0x8d7: a = cmd.args[0].value; break; | |
| 1241 case 0x8d8: flag = cmd.args[0].value; break; | |
| 1242 case 0x8db: | |
| 1243 r = cmd.args[0].value; | |
| 1244 g = cmd.args[1].value; | |
| 1245 b = cmd.args[2].value; | |
| 1246 a = cmd.args[3].value; | |
| 1247 flag = cmd.args[4].value; | |
| 1248 break; | |
| 1249 } | |
| 1250 config.SetParam("#WINDOW_ATTR", 5, r, g, b, a, flag); | |
| 1251 SetWindowColor(r, g, b, a, flag); | |
| 1252 cmd.clear(); | |
| 1253 } | |
| 1254 } else if (cmd.cmd3 == 0xa28 || cmd.cmd3 == 0xa29 || cmd.cmd3 == 0xa2c || cmd.cmd3 == 0xa2d || cmd.cmd3 == 0xa2e) { | |
| 1255 int v = 0; | |
| 1256 switch(cmd.cmd3) { | |
| 1257 case 0xa28: case 0xa2d: config.GetOriginalParam("#INIT_MESSAGE_SPEED", 1, &v); break; | |
| 1258 case 0xa29: config.GetOriginalParam("#INIT_MESSAGE_SPEED_MOD", 1, &v); break; | |
| 1259 case 0xa2c: config.GetOriginalParam("#MESSAGE_KEY_WAIT_USE", 1, &v); break; | |
| 1260 case 0xa2e: config.GetOriginalParam("#MESSAGE_KEY_WAIT_TIME", 1, &v); break; | |
| 1261 } | |
| 1262 cmd.SetSysvar(v); | |
| 1263 } else if (cmd.cmd3 == 0x913 || cmd.cmd3 == 0x914 || cmd.cmd3 == 0x92f || cmd.cmd3 == 0x8af || cmd.cmd3 == 0x8b0 || cmd.cmd3 == 0x8cb) { | |
| 1264 // テキスト表示速度関連 | |
| 1265 int m, speed; | |
| 1266 config.GetParam("#INIT_MESSAGE_SPEED", 1, &speed); | |
| 1267 config.GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &m); | |
| 1268 if (cmd.cmd3 == 0x913 || cmd.cmd3 == 0x92f) fprintf(stderr,"TEXT speed %d\n",speed); | |
| 1269 else if (cmd.cmd3 == 0x914) fprintf(stderr,"TEXT mode %d\n",m); | |
| 1270 else if (cmd.cmd3 == 0x8af || cmd.cmd3 == 0x8cb) fprintf(stderr,"TEXT %d, %d <- speed %d\n",m,speed,cmd.args[0].value); | |
| 1271 else fprintf(stderr,"TEXT %d, %d <- mode %d\n",m,speed,cmd.args[0].value); | |
| 1272 if (cmd.cmd3 == 0x913 || cmd.cmd3 == 0x92f) cmd.SetSysvar(speed); | |
| 1273 else if (cmd.cmd3 == 0x914) cmd.SetSysvar(m); | |
| 1274 else { | |
| 1275 if (cmd.cmd3 == 0x8af || cmd.cmd3 == 0x8cb) speed = cmd.args[0].value; | |
| 1276 else m = cmd.args[0].value; | |
| 1277 if (speed < 10) speed = 10; | |
| 1278 else if (speed > 1000) speed = 1000; | |
| 1279 config.SetParam("#INIT_MESSAGE_SPEED", 1, speed); | |
| 1280 config.SetParam("#INIT_MESSAGE_SPEED_MOD", 1, m); | |
| 1281 if (m) speed = -1; | |
| 1282 SetTextSpeed(speed); | |
| 1283 cmd.clear(); | |
| 1284 } | |
| 1285 } else if (cmd.cmd3 == 0x92e || cmd.cmd3 == 0x930 || cmd.cmd3 == 0x8ca || cmd.cmd3 == 0x8cc) { | |
| 1286 // テキストオートモード関連 | |
| 1287 int m, wait; | |
| 1288 config.GetParam("#MESSAGE_KEY_WAIT_USE", 1, &m); | |
| 1289 config.GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait); | |
| 1290 if (cmd.cmd3 == 0x92e) fprintf(stderr,"AUTO mode %d\n",m); | |
| 1291 else if (cmd.cmd3 == 0x930) fprintf(stderr,"AUTO wait %d\n",wait); | |
| 1292 else if (cmd.cmd3 == 0x8ca) fprintf(stderr,"AUTO %d,%d <- mode %d\n",m,wait,cmd.args[0].value); | |
| 1293 else fprintf(stderr,"AUTO %d,%d <- wait %d\n",m,wait,cmd.args[0].value); | |
| 1294 | |
| 1295 if (cmd.cmd3 == 0x92e) cmd.SetSysvar(m); | |
| 1296 else if (cmd.cmd3 == 0x930) cmd.SetSysvar(wait); | |
| 1297 else { | |
| 1298 if (cmd.cmd3 == 0x8ca) m = cmd.args[0].value; | |
| 1299 else wait = cmd.args[1].value; | |
| 1300 if (wait < 0) wait = 0; | |
| 1301 else if (wait > 60000) wait = 60000; | |
| 1302 config.SetParam("#MESSAGE_KEY_WAIT_USE", 1, m); | |
| 1303 config.SetParam("#MESSAGE_KEY_WAIT_TIME", 1, wait); | |
| 1304 if (m) SetTextWait(wait); | |
| 1305 else SetTextWait(-1); | |
| 1306 cmd.clear(); | |
| 1307 } | |
| 1308 } else if (cmd.cmd3 == 0x51f && cmd.cmd4 == 0) { // replace_name2 の設定 | |
| 1309 int n = cmd.args[0].value; | |
| 1310 if (n>=0 && n<26) { | |
| 1311 replace_name2[n] = cmd.Str(cmd.args[1]); | |
| 1312 } | |
| 1313 cmd.clear(); | |
| 1314 } else if (cmd.cmd3 == 0x51e && cmd.cmd4 == 0) { // replace_name2 を得る | |
| 1315 int n = cmd.args[0].value; | |
| 1316 if (n >= 0 && n < 26) { | |
| 1317 cmd.SetStrvar(cmd.args[1], replace_name2[n]); | |
| 1318 } else { | |
| 1319 cmd.SetStrvar(cmd.args[1], ""); | |
| 1320 } | |
| 1321 } else if (cmd.cmd3 == 0x514 && cmd.cmd4 == 0) { // replace_name を得る | |
| 1322 int n = cmd.args[0].value; | |
| 1323 if (n >= 0 && n < 26) { | |
| 1324 cmd.SetStrvar(cmd.args[1], replace_name[n]); | |
| 1325 } else { | |
| 1326 cmd.SetStrvar(cmd.args[1], ""); | |
| 1327 } | |
| 1328 } | |
| 1329 } | |
| 1330 | |
| 1331 return; | |
| 1332 } | |
| 1333 extern int print_blit; | |
| 1334 bool TextImpl::Wait(unsigned int current_time, Cmd& cmd) { | |
| 1335 if (current_time != 0xffffffffUL) old_time = current_time; | |
| 1336 /* | |
| 1337 if (event.presscount(MOUSE_UP)) { | |
| 1338 if (text) text->Pic()->ReBlit(); | |
| 1339 } | |
| 1340 if (event.presscount(MOUSE_DOWN)) { | |
| 1341 print_blit^=1; | |
| 1342 } | |
| 1343 */ | |
| 1344 | |
| 1345 if (status == NORMAL && status_mask == NORMAL) return false; | |
| 1346 | |
| 1347 if (status_mask & WAIT_EXTRN_MASK) return true; | |
| 1348 if (status_mask & (BACKLOG_MASK|BACKLOG_MASK_FWD) ) { | |
| 1349 if (status_mask & BACKLOG_WAIT_MASK) ; | |
| 1350 else { | |
| 1351 if ( (status == WAIT_TEXT && text != 0) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) { | |
| 1352 if(text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) { | |
| 1353 text->wid->Flush(); // 表示を最後の状態にする | |
| 1354 } | |
| 1355 if (status == WAIT_TEXT && text != 0 && kcursor) kcursor->show(); | |
| 1356 } | |
| 1357 } | |
| 1358 if (status_mask & BACKLOG_MASK) { | |
| 1359 cmd.cmd_type = CMD_BACKLOGREQ; | |
| 1360 } else { | |
| 1361 cmd.cmd_type = CMD_BACKLOGREQ_FWD; | |
| 1362 } | |
| 1363 status_mask = Status(status_mask & ~(BACKLOG_MASK|BACKLOG_MASK_FWD)); | |
| 1364 return false; | |
| 1365 } | |
| 1366 if ( (status_mask & BACKLOG_WAIT_MASK) && (status_mask & BACKLOG_MASK_KOE)) { | |
| 1367 if (drawn_backlog_item.koe != -1) { | |
| 1368 cmd.cmd_type = CMD_OTHER; | |
| 1369 cmd.cmd1 = 1; | |
| 1370 cmd.cmd2 = 0x17; | |
| 1371 cmd.cmd3 = 0; | |
| 1372 cmd.cmd4 = 1; | |
| 1373 cmd.args.clear(); | |
| 1374 cmd.args.push_back(VarInfo(drawn_backlog_item.koe)); | |
| 1375 cmd.args.push_back(VarInfo(0)); | |
| 1376 } | |
| 1377 status_mask = Status(status_mask & ~BACKLOG_MASK_KOE); | |
| 1378 return false; | |
| 1379 } | |
| 1380 if (skip_mode & SKIP_IN_MENU) return false; | |
| 1381 if (status_mask & SAVEMASK) { | |
| 1382 cmd.cmd_type = CMD_SAVEREQ; | |
| 1383 status_mask = Status(status_mask & ~SAVEMASK); | |
| 1384 return false; | |
| 1385 } | |
| 1386 if (status_mask & LOADMASK) { | |
| 1387 cmd.cmd_type = CMD_LOADREQ; | |
| 1388 status_mask = Status(status_mask & ~LOADMASK); | |
| 1389 return false; | |
| 1390 } | |
| 1391 if (status_mask & SKIPEND_MASK) { | |
| 1392 if ( (skip_mode & SKIP_TEXT) && (skip_mode & SKIPEND_TEXT)) { | |
| 1393 if (skip_mode & SKIPEND_KEY) { // shift skip 中 | |
| 1394 SkipMode new_mode = SkipMode(skip_mode & (~SKIPEND_TEXT)); | |
| 1395 if (new_mode & (SKIP_GRP_NOEFFEC || SKIP_GRP_NODRAW)) | |
| 1396 new_mode = SkipMode(new_mode & (~SKIP_GRP_FAST)); | |
| 1397 cmd.SetSysvar(TYPE_SYS_SKIPMODE, new_mode); | |
| 1398 } else { | |
| 1399 cmd.SetSysvar(TYPE_SYS_SKIPMODE, SKIP_NO); | |
| 1400 } | |
| 1401 } | |
| 1402 status_mask = Status(status_mask & ~SKIPEND_MASK); | |
| 1403 } | |
| 1404 if (status_mask & SKIPMASK) { | |
| 1405 if (skip_mode != SKIP_NO) { | |
| 1406 cmd.SetSysvar(TYPE_SYS_SKIPMODE, skip_mode | SKIPEND_TEXT); | |
| 1407 } else { | |
| 1408 cmd.SetSysvar(TYPE_SYS_SKIPMODE, SKIP_TEXT | SKIP_GRP_FAST | SKIPEND_TEXT); | |
| 1409 } | |
| 1410 status_mask = Status(status_mask & ~SKIPMASK); | |
| 1411 return false; | |
| 1412 } | |
| 1413 if (event.presscount(MOUSE_RIGHT)) { | |
| 1414 if ( (status == WAIT_TEXT && text != 0) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) { | |
| 1415 if(text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) { | |
| 1416 text->wid->Flush(); // 表示を最後の状態にする | |
| 1417 } | |
| 1418 cmd.cmd_type = CMD_MENUREQ; | |
| 1419 if (!(status_mask & STATSAVE_MASK)) { | |
| 1420 status_saved = status; | |
| 1421 status_mask = Status(status_mask | STATSAVE_MASK); | |
| 1422 } | |
| 1423 return false; | |
| 1424 } else if (status == WAIT_CLICK_MOUSEPOS) { | |
| 1425 status = WAIT_CLICK_MOUSEPOSEND_R; | |
| 1426 } | |
| 1427 } | |
| 1428 if (event.presscount(MOUSE_UP)) { | |
| 1429 if ( (status == WAIT_TEXT && text != 0) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) { | |
| 1430 if(text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) { | |
| 1431 text->wid->Flush(); // 表示を最後の状態にする | |
| 1432 } | |
| 1433 cmd.cmd_type = CMD_BACKLOGREQ; | |
| 1434 if (!(status_mask & STATSAVE_MASK)) { | |
| 1435 status_saved = status; | |
| 1436 status_mask = Status(status_mask | STATSAVE_MASK); | |
| 1437 } | |
| 1438 return false; | |
| 1439 } | |
| 1440 } | |
| 1441 if (status_mask & CLEARSCR_MASK) { | |
| 1442 if ( (status == WAIT_TEXT && text != 0 ) || status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) { | |
| 1443 if (skip_mode) skip_mode = SKIP_NO; | |
| 1444 if (text && text->wid->status != WidText::PREPARE && text->wid->status != WidText::WAIT && text->wid->status != WidText::WAIT2) { | |
| 1445 text->wid->Flush(); // 表示を最後の状態にする | |
| 1446 return true; | |
| 1447 } | |
| 1448 status_mask = Status(status_mask & (~CLEARSCR_MASK) | CLEARSCR_WAIT_MASK); | |
| 1449 if (text) text->hide(); | |
| 1450 if (kcursor) kcursor->hide(); | |
| 1451 if (sel_widget) sel_widget->hide(); | |
| 1452 if (backlog_widget) backlog_widget->hide(); | |
| 1453 return true; | |
| 1454 } | |
| 1455 status_mask = Status(status_mask & (~CLEARSCR_MASK)); | |
| 1456 return false; | |
| 1457 } | |
| 1458 if (status_mask & CLEARSCR_WAIT_MASK) { | |
| 1459 return true; | |
| 1460 } | |
| 1461 if (status == WAIT_TEXT) { | |
| 1462 if (text == 0) { status = NORMAL; return false;} | |
| 1463 if (skip_mode & SKIP_TEXT) { | |
| 1464 } else if (text->wid->status != WidText::PREPARE) { | |
| 1465 return true; | |
| 1466 } | |
| 1467 if (kcursor) kcursor->hide(); | |
| 1468 text_stream.Clear(); | |
| 1469 status = NORMAL; | |
| 1470 cmd.cmd_type = CMD_TEXTEND; | |
| 1471 return false; | |
| 1472 } | |
| 1473 if (status == WAIT) { | |
| 1474 if (skip_mode & SKIP_TEXT) ; | |
| 1475 else if (wait_time > current_time) return true; | |
| 1476 status = NORMAL; | |
| 1477 } else if (status == WAIT_CLICK) { | |
| 1478 if (skip_mode & SKIP_TEXT) ; | |
| 1479 else if (wait_time > current_time) return true; | |
| 1480 status = NORMAL; | |
| 1481 cmd.SetSysvar(0); | |
| 1482 } else if (status == WAIT_ABORT) { | |
| 1483 cmd.SetSysvar(1); | |
| 1484 status = NORMAL; | |
| 1485 } else if (status == WAIT_CLICK_MOUSEPOS || status == WAIT_CLICK_MOUSEPOSEND_L || status == WAIT_CLICK_MOUSEPOSEND_R) { | |
| 1486 if (status == WAIT_CLICK_MOUSEPOS && (skip_mode & SKIP_TEXT) == 0) return true; // keep wait | |
| 1487 else { | |
| 1488 int x, y; | |
| 1489 event.MousePos(x,y); | |
| 1490 if (status == WAIT_CLICK_MOUSEPOS) x = y = 0; // skip mode | |
| 1491 cmd.clear(); | |
| 1492 cmd.SetFlagvar(wait_savedvar[0], x); | |
| 1493 cmd.SetFlagvar(wait_savedvar[1], y); | |
| 1494 if (status == WAIT_CLICK_MOUSEPOSEND_R) cmd.SetSysvar(-1); | |
| 1495 else cmd.SetSysvar(0); | |
| 1496 status = NORMAL; | |
| 1497 } | |
| 1498 } else if (status == WAIT_SELECT_INBOX || status == WAIT_SELECT_OUTBOX) { | |
| 1499 return true; | |
| 1500 } else if ( int(status) >= WAIT_SELECT_VALUE) { | |
| 1501 int sel_val = int(status) - WAIT_SELECT_VALUE; | |
| 1502 cmd.SetSysvar(sel_val); | |
| 1503 selects.clear(); | |
| 1504 delete sel_widget; | |
| 1505 sel_widget = 0; | |
| 1506 status = NORMAL; | |
| 1507 // CreateSelect() で作成された cur_backlog_item を backlog_item へ反映させる | |
| 1508 cur_backlog_item.text.InsertColor(sel_backlog_pos[sel_val], sel_backlog_pos[sel_val+1], 0xff, 0, 0); | |
| 1509 backlog_item = cur_backlog_item; | |
| 1510 cur_backlog_item.Clear(); | |
| 1511 } | |
| 1512 return false; | |
| 1513 } | |
| 1514 | |
| 1515 void clearbtn_press(void* pointer, WidButton* button) { | |
| 1516 if (pointer == 0) return; | |
| 1517 TextImpl* t = (TextImpl*)pointer; | |
| 1518 t->status_mask = TextImpl::Status(t->status_mask | TextImpl::CLEARSCR_MASK); | |
| 1519 return; | |
| 1520 } | |
| 1521 void TextImpl::PressFuncSkip(void* pointer, WidButton* from) { | |
| 1522 if (pointer == 0) return; | |
| 1523 TextImpl* t = (TextImpl*)pointer; | |
| 1524 t->status_mask = TextImpl::Status(t->status_mask | TextImpl::SKIPMASK); | |
| 1525 return; | |
| 1526 } | |
| 1527 void TextImpl::PressFuncLoad(void* pointer, WidButton* from) { | |
| 1528 if (pointer == 0) return; | |
| 1529 TextImpl* t = (TextImpl*)pointer; | |
| 1530 t->status_mask = TextImpl::Status(t->status_mask | TextImpl::LOADMASK); | |
| 1531 return; | |
| 1532 } | |
| 1533 void TextImpl::PressFuncSave(void* pointer, WidButton* from) { | |
| 1534 if (pointer == 0) return; | |
| 1535 TextImpl* t = (TextImpl*)pointer; | |
| 1536 t->status_mask = TextImpl::Status(t->status_mask | TextImpl::SAVEMASK); | |
| 1537 return; | |
| 1538 } | |
| 1539 void TextImpl::PressFuncBacklog(void* pointer, WidButton* from) { | |
| 1540 if (pointer == 0) return; | |
| 1541 TextImpl* t = (TextImpl*)pointer; | |
| 1542 t->status_mask = TextImpl::Status(t->status_mask | TextImpl::BACKLOG_MASK); | |
| 1543 return; | |
| 1544 } | |
| 1545 void TextImpl::PressFuncBacklogFwd(void* pointer, WidButton* from) { | |
| 1546 if (pointer == 0) return; | |
| 1547 TextImpl* t = (TextImpl*)pointer; | |
| 1548 t->status_mask = TextImpl::Status(t->status_mask | TextImpl::BACKLOG_MASK_FWD); | |
| 1549 return; | |
| 1550 } | |
| 1551 void movebtn_drag(int from_x, int from_y, int x, int y, void* pointer, WidButton* button) { | |
| 1552 if (pointer == 0) return; | |
| 1553 fprintf(stderr,"drag.\n"); | |
| 1554 } | |
| 1555 #define BTNCNT 10 | |
| 1556 static char* btnname[BTNCNT] = { | |
| 1557 "MOVE", | |
| 1558 "CLEAR", | |
| 1559 "READJUMP", | |
| 1560 "AUTOMODE", | |
| 1561 "MSGBK", | |
| 1562 "MSGBKLEFT", | |
| 1563 "MSGBKRIGHT", | |
| 1564 "EXBTN_000", | |
| 1565 "EXBTN_001", | |
| 1566 "EXBTN_002" | |
| 1567 }; | |
| 1568 static int btnpos[BTNCNT] = { // g00 ファイル内のボタン情報の位置 | |
| 1569 // 0, 1, 13, 12, 2, 3, 4, 5, 6, 7 // princess bride? | |
| 1570 0, 1, 13, 14, 2, 3, 4, 5, 6, 7 // tomoyo after? | |
| 1571 }; | |
| 1572 static WidButton::PressFunc btnpress[BTNCNT] = { | |
| 1573 0, clearbtn_press, &TextImpl::PressFuncSkip,0,&TextImpl::PressFuncBacklogFwd,&TextImpl::PressFuncBacklog,&TextImpl::PressFuncBacklogFwd,&TextImpl::PressFuncSave,&TextImpl::PressFuncLoad,0 | |
| 1574 }; | |
| 1575 static WidButton::DragFunc btndrag[BTNCNT] = { | |
| 1576 movebtn_drag, 0,0,0,0, 0,0,0,0, 0 | |
| 1577 }; | |
| 1578 | |
| 1579 void TextImpl::SetTextSpeed(int speed) { | |
| 1580 // 100 : 10char / sec | |
| 1581 // 10 : 100char / sec | |
| 1582 // text widget: | |
| 1583 if (speed <= 0) speed = -1; | |
| 1584 else if (speed > 1000) speed = 1; | |
| 1585 else speed = 1000 / speed; | |
| 1586 int i; | |
| 1587 for (i=0; i<32; i++) | |
| 1588 if (widgets[i]) widgets[i]->wid->SetSpeed(speed); | |
| 1589 } | |
| 1590 void TextImpl::SetTextWait(int wait) { | |
| 1591 int i; | |
| 1592 for (i=0; i<32; i++) | |
| 1593 if (widgets[i]) widgets[i]->wid->SetWait(wait); | |
| 1594 } | |
| 1595 | |
| 1596 void TextImpl::SetWindowColor(int r, int g, int b, int a, bool is_transparent) { | |
| 1597 char key[1024]; | |
| 1598 int w; | |
| 1599 | |
| 1600 for (w=0; w<32; w++) { | |
| 1601 if (widgets[w] == 0) continue; | |
| 1602 sprintf(key, "#WAKU.%03d.000.BACK", w); | |
| 1603 const char* back = config.GetParaStr(key); | |
| 1604 if (back == 0 || back[0] == 0) continue; | |
| 1605 sprintf(key, "%s.g00", back); | |
| 1606 Surface* back_s = parent.Root().NewSurface(key); | |
| 1607 if (back_s == 0) continue; | |
| 1608 Rect rect(*back_s); | |
| 1609 Surface* new_s = parent.Root().NewSurface(rect.width(), rect.height(), ALPHA_MASK); | |
| 1610 DSurfaceMove(back_s, rect, new_s, rect); | |
| 1611 DSurfaceFillA(new_s, rect, r, g, b, a); | |
| 1612 widgets[w]->wid->Pic()->SetSurface(new_s, 0, 0); | |
| 1613 widgets[w]->wid->Pic()->SetSurfaceFreeFlag(1); | |
| 1614 if (!is_transparent) | |
| 1615 widgets[w]->wid->Pic()->SetSurfaceAttribute(PicBase::BLIT_MULTIPLY); | |
| 1616 parent.Root().DeleteSurface(back_s); | |
| 1617 } | |
| 1618 return; | |
| 1619 } | |
| 1620 | |
| 1621 void TextImpl::SetCursor(int cursor_no) { | |
| 1622 char key[1024]; | |
| 1623 sprintf(key, "#CURSOR.%03d.NAME", cursor_no); | |
| 1624 string path = config.GetParaStr(key); | |
| 1625 if (path.length() == 0) return; // 名前なし | |
| 1626 path += ".pdt"; | |
| 1627 int w,h,cont,speed; | |
| 1628 sprintf(key, "#CURSOR.%03d.SIZE", cursor_no); | |
| 1629 config.GetParam(key, 2, &w, &h); | |
| 1630 sprintf(key, "#CURSOR.%03d.CONT", cursor_no); | |
| 1631 config.GetParam(key, 1, &cont); | |
| 1632 sprintf(key, "#CURSOR.%03d.SPEED", cursor_no); | |
| 1633 config.GetParam(key, 1, &speed); | |
| 1634 | |
| 1635 // speed で1周、cont 回変化 | |
| 1636 if (kcursor) delete kcursor; | |
| 1637 | |
| 1638 kcursor = new WidTimeCursor(event, speed/cont, &parent, path.c_str(), 0, 0, w, 0, cont, Rect(0,0,w,h)); | |
| 1639 int i; | |
| 1640 for (i=0; i<32; i++) { | |
| 1641 if (widgets[i]) widgets[i]->wid->SetCursor(kcursor); | |
| 1642 } | |
| 1643 } | |
| 1644 | |
| 1645 void kconv(const unsigned char* src, unsigned char* dest) { | |
| 1646 /* input : sjis output: euc */ | |
| 1647 while(*src) { | |
| 1648 unsigned int high = *src++; | |
| 1649 if (high < 0x80) { | |
| 1650 /* ASCII */ | |
| 1651 *dest++ = high; continue; | |
| 1652 } else if (high < 0xa0) { | |
| 1653 /* SJIS */ | |
| 1654 high -= 0x71; | |
| 1655 } else if (high < 0xe0) { | |
| 1656 /* hankaku KANA */ | |
| 1657 *dest++ = 0x8e; *dest++ = high; | |
| 1658 continue; | |
| 1659 } else { /* high >= 0xe0 : SJIS */ | |
| 1660 high -= 0xb1; | |
| 1661 } | |
| 1662 /* SJIS convert */ | |
| 1663 high = (high<<1) + 1; | |
| 1664 | |
| 1665 unsigned int low = *src++; | |
| 1666 if (low == 0) break; /* incorrect code */ | |
| 1667 if (low > 0x7f) low--; | |
| 1668 if (low >= 0x9e) { | |
| 1669 low -= 0x7d; | |
| 1670 high++; | |
| 1671 } else { | |
| 1672 low -= 0x1f; | |
| 1673 } | |
| 1674 *dest++ = high | 0x80; *dest++ = low | 0x80; | |
| 1675 } | |
| 1676 *dest = 0; | |
| 1677 } | |
| 1678 void kconv_rev(const unsigned char* src, unsigned char* dest) { | |
| 1679 /* input : euc output: sjis */ | |
| 1680 while(*src) { | |
| 1681 unsigned int high = *src++; | |
| 1682 if (high < 0x80) { | |
| 1683 /* ASCII */ | |
| 1684 *dest++ = high; continue; | |
| 1685 } else if (high == 0x8e) { /* hankaku KANA */ | |
| 1686 high = *src; | |
| 1687 if (high >= 0xa0 && high < 0xe0) | |
| 1688 *dest++ = *src++; | |
| 1689 continue; | |
| 1690 } else { | |
| 1691 unsigned int low = *src++; | |
| 1692 if (low == 0) break; /* incorrect code , EOS */ | |
| 1693 if (low < 0x80) continue; /* incorrect code */ | |
| 1694 /* convert */ | |
| 1695 low &= 0x7f; high &= 0x7f; | |
| 1696 low += (high & 1) ? 0x1f : 0x7d; | |
| 1697 high = (high-0x21)>>1; | |
| 1698 high += (high > 0x1e) ? 0xc1 : 0x81; | |
| 1699 *dest++ = high; | |
| 1700 if (low > 0x7f) low++; | |
| 1701 *dest++ = low; | |
| 1702 } | |
| 1703 } | |
| 1704 *dest = 0; | |
| 1705 } | |
| 1706 string kconv(const string& s) { | |
| 1707 char* out = new char[s.length()*2+100]; | |
| 1708 kconv((const unsigned char*)s.c_str(), (unsigned char*)out); | |
| 1709 string ret = out; | |
| 1710 delete[] out; | |
| 1711 return ret; | |
| 1712 } | |
| 1713 string kconv_rev(const string& s) { | |
| 1714 char* out = new char[s.length()*2+100]; | |
| 1715 kconv_rev((const unsigned char*)s.c_str(), (unsigned char*)out); | |
| 1716 string ret = out; | |
| 1717 delete[] out; | |
| 1718 return ret; | |
| 1719 } | |
| 1720 | |
| 1721 /**************************************************************:: | |
| 1722 ** | |
| 1723 ** Text | |
| 1724 */ | |
| 1725 Text::Text(Event::Container& _event, PicContainer& _parent, AyuSysConfig& config) { | |
| 1726 pimpl = new TextImpl(_event, _parent, config, backlog, backlog_item); | |
| 1727 } | |
| 1728 Text::~Text() { | |
| 1729 delete pimpl; | |
| 1730 } | |
| 1731 void Text::InitWindow(void) { | |
| 1732 pimpl->InitWindow(); | |
| 1733 } | |
| 1734 void Text::Exec(Cmd& cmd) { | |
| 1735 pimpl->Exec(cmd); | |
| 1736 } | |
| 1737 bool Text::Wait(unsigned int current_time, Cmd& cmd) { | |
| 1738 return pimpl->Wait(current_time, cmd); | |
| 1739 } | |
| 1740 void Text::SetSkipMode(SkipMode mode) { | |
| 1741 pimpl->SetSkipMode(mode); | |
| 1742 } | |
| 1743 void Text::Save(std::string& str, bool select_save) { | |
| 1744 pimpl->Save(str, select_save); | |
| 1745 } | |
| 1746 void Text::Load(const char* str) { | |
| 1747 pimpl->Load(str); | |
| 1748 } | |
| 1749 | |
| 1750 void Text::hide(void) { | |
| 1751 pimpl->hide(); | |
| 1752 } | |
| 1753 void Text::show(void) { | |
| 1754 pimpl->show(); | |
| 1755 } | |
| 1756 void Text::show(int num) { | |
| 1757 pimpl->show(num); | |
| 1758 } | |
| 1759 void Text::DrawBacklog(BacklogItem& item, Cmd& cmd) { | |
| 1760 pimpl->DrawBacklog(item, cmd); | |
| 1761 } | |
| 1762 /**************************************************************:: | |
| 1763 ** | |
| 1764 ** BacklogItem | |
| 1765 */ | |
| 1766 | |
| 1767 BacklogItem::BacklogItem(void) { | |
| 1768 scn = -1; | |
| 1769 pos = -1; | |
| 1770 koe = -1; | |
| 1771 face = ""; | |
| 1772 text.kanji_type = TextStream::sjis; | |
| 1773 } | |
| 1774 void BacklogItem::Clear(void) { | |
| 1775 scn = -1; | |
| 1776 pos = -1; | |
| 1777 koe = -1; | |
| 1778 text.Clear(); | |
| 1779 } | |
| 1780 void BacklogItem::AddTextPos(Cmd& cmd) { | |
| 1781 if (scn == -1 && pos == -1) { | |
| 1782 scn = cmd.scn; | |
| 1783 pos = cmd.pos; | |
| 1784 return; | |
| 1785 } | |
| 1786 DeleteTextPos(); | |
| 1787 } | |
| 1788 void BacklogItem::DeleteTextPos(void) { | |
| 1789 scn = 0; | |
| 1790 pos = -1; | |
| 1791 } | |
| 1792 BacklogItem& BacklogItem::operator =(const BacklogItem& p) { | |
| 1793 scn = p.scn; | |
| 1794 pos = p.pos; | |
| 1795 koe = p.koe; | |
| 1796 face = p.face; | |
| 1797 text = p.text; | |
| 1798 } | |
| 1799 void BacklogItem::SetSavepos(int p) { | |
| 1800 Clear(); | |
| 1801 scn = SaveSelect; | |
| 1802 pos = p; | |
| 1803 } | |
| 1804 | |
| 1805 Rect TextWindow::WakuSize(PicContainer& pic, int waku_no, const AyuSysConfig& config) { | |
| 1806 char key[1024]; | |
| 1807 sprintf(key, "#WAKU.%03d.000.NAME", waku_no); | |
| 1808 const char* name = config.GetParaStr(key); | |
| 1809 if (!name) return Rect(0,0,0,0); | |
| 1810 std::string str = name; str += ".g00"; | |
| 1811 Surface* s = pic.Root().NewSurface(str.c_str()); | |
| 1812 if (!s) return Rect(0,0,0,0); | |
| 1813 Rect r(*s); | |
| 1814 pic.Root().DeleteSurface(s); | |
| 1815 return r; | |
| 1816 } | |
| 1817 void TextWindow::MakeWaku(PicContainer& pic, Event::Container& event, int waku_no, int window_no, bool* use_btn, const AyuSysConfig& config, void* callback) { | |
| 1818 char key[1024]; | |
| 1819 std::string str; | |
| 1820 /* 枠を作成 */ | |
| 1821 sprintf(key, "#WAKU.%03d.000.NAME", waku_no); | |
| 1822 const char* name = config.GetParaStr(key); | |
| 1823 if (name && name[0] == 0) name = 0; | |
| 1824 sprintf(key, "#WAKU.%03d.000.BACK", waku_no); | |
| 1825 const char* back = config.GetParaStr(key); | |
| 1826 if (back && back[0] == 0) back = 0; | |
| 1827 sprintf(key, "#WAKU.%03d.000.BTN", waku_no); | |
| 1828 const char* btn = config.GetParaStr(key); | |
| 1829 if (btn && btn[0] == 0) btn = 0; | |
| 1830 | |
| 1831 if (name == 0 && back == 0 && btn == 0) return; | |
| 1832 | |
| 1833 /* まず、テキスト背景を設定 */ | |
| 1834 if (back) { | |
| 1835 str = back; str += ".g00"; | |
| 1836 int rc,gc,bc,ac, flag; | |
| 1837 char key[1024]; | |
| 1838 sprintf(key, "#WINDOW.%03d.ATTR", window_no); | |
| 1839 if (config.GetParam(key, 5, &rc, &gc, &bc, &ac, &flag) == -1) { | |
| 1840 config.GetParam("#WINDOW_ATTR", 5, &rc, &gc, &bc, &ac, &flag); | |
| 1841 } | |
| 1842 Surface* back_s = pic.Root().NewSurface(str.c_str()); | |
| 1843 if (back_s) { | |
| 1844 Rect rect(*back_s); | |
| 1845 Surface* s = pic.Root().NewSurface(rect.width(), rect.height(), ALPHA_MASK); | |
| 1846 DSurfaceMove(back_s, rect, s, rect); | |
| 1847 DSurfaceFillA(s, rect, rc, gc, bc, ac); // 透明度設定 | |
| 1848 pic.SetSurface(s, 0, 0); | |
| 1849 pic.SetSurfaceFreeFlag(1); | |
| 1850 if (flag == 0) wid->Pic()->SetSurfaceAttribute(PicBase::BLIT_MULTIPLY); | |
| 1851 pic.Root().DeleteSurface(back_s); | |
| 1852 } | |
| 1853 } | |
| 1854 /* その前に枠飾りを設定 */ | |
| 1855 if (name) { | |
| 1856 str = name; str += ".g00"; | |
| 1857 Surface* s = pic.Root().NewSurface(str.c_str()); | |
| 1858 if (s) { | |
| 1859 Rect rect(*s); | |
| 1860 pic.Root().DeleteSurface(s); | |
| 1861 PicBase* p = pic.create_leaf(Rect(0, 0, rect.width(), rect.height()),0); | |
| 1862 p->SetSurface(str.c_str(), 0, 0); | |
| 1863 p->ZMove(ZMOVE_BOTTOM); | |
| 1864 p->show(); | |
| 1865 } | |
| 1866 } | |
| 1867 if (btn == 0) return; | |
| 1868 if (use_btn == 0) return; | |
| 1869 // ボタンの作成 | |
| 1870 // 使用するボタンについては、必要に応じて show() すること | |
| 1871 | |
| 1872 /* ボタンの位置情報を求める */ | |
| 1873 str = btn; str += ".g00"; | |
| 1874 ARCINFO* info = file_searcher.Find(FILESEARCH::PDT, str.c_str(), "g00"); | |
| 1875 if (info == 0) return; // cannot find file | |
| 1876 const char* data = info->Read(); | |
| 1877 /* g00 ファイルのヘッダ部分に位置情報は入っている */ | |
| 1878 /* 存在しなければボタン画像ではない */ | |
| 1879 if (data == 0 || *data != 2) { | |
| 1880 delete info; | |
| 1881 return; | |
| 1882 } | |
| 1883 int index_count = read_little_endian_int(data+5); // 0x70 == 112 ( 8 個ずつグループなので、14個のボタン ) が標準 | |
| 1884 int i; | |
| 1885 for (i=0; i<BTNCNT; i++) { | |
| 1886 if (!use_btn[i]) continue; | |
| 1887 if (btnpos[i]*8 >= index_count) { | |
| 1888 continue; // ボタンが存在しない | |
| 1889 } | |
| 1890 int x, y, w, h; | |
| 1891 sprintf(key, "#WAKU.%03d.000.%s_BOX", waku_no, btnname[i]); | |
| 1892 if (config.GetParam(key, 5, 0, &x, &y, &w, &h) == -1) continue; | |
| 1893 int sx, sy, sdx, sdy, cnt; | |
| 1894 const char* d = data + 9 + btnpos[i]*24*8; | |
| 1895 sx = read_little_endian_int(d); | |
| 1896 sy = read_little_endian_int(d+4); | |
| 1897 sdx = read_little_endian_int(d+24) - sx; | |
| 1898 sdy = read_little_endian_int(d+24 + 4) - sy; | |
| 1899 cnt = 2; | |
| 1900 if (sx+sdx*2 == read_little_endian_int(d+2*24) && sy+sdy*2 == read_little_endian_int(d+2*24+4)) cnt = 3; | |
| 1901 WidButton* wid = new WidButton(event, &pic, str.c_str(), sx, sy, sdx, sdy, cnt, Rect(x, y, x+w, y+h), 1); | |
| 1902 if (btnpress[i]) { wid->press_func = btnpress[i]; wid->press_pointer = callback;} | |
| 1903 if (btndrag[i]) { wid->drag_func = btndrag[i]; wid->drag_pointer = callback;} | |
| 1904 } | |
| 1905 delete info; | |
| 1906 return; | |
| 1907 } | |
| 1908 | |
| 1909 TextWindow::TextWindow(PicContainer& parent, Event::Container& event, int win_no, const AyuSysConfig& config, void* callback) : | |
| 1910 wid(0), name_visible(true),name(0),name_container(0), face(0) { | |
| 1911 int i; for (i=0; i<8; i++) face_pics[i]=0; | |
| 1912 char key[1024]; | |
| 1913 bool use_btn[BTNCNT]; | |
| 1914 int size, rep1, rep2, cntw, cnth, mposx, mposy, posd, posx, posy, minx, miny, waku_no, ruby; | |
| 1915 sprintf(key, "#WINDOW.%03d.MOJI_SIZE", win_no); if (config.GetParam(key, 1, &size) == -1) return; | |
| 1916 sprintf(key, "#WINDOW.%03d.MOJI_REP", win_no); if (config.GetParam(key, 2, &rep1, &rep2) == -1) return; | |
| 1917 sprintf(key, "#WINDOW.%03d.MOJI_CNT", win_no); if (config.GetParam(key, 2, &cntw, &cnth) == -1) return; | |
| 1918 sprintf(key, "#WINDOW.%03d.POS", win_no); if (config.GetParam(key, 3, &posd, &posx, &posy) == -1) return; | |
| 1919 sprintf(key, "#WINDOW.%03d.MOJI_POS", win_no); if (config.GetParam(key, 4, &mposy, 0, &mposx, 0) == -1) return; | |
| 1920 sprintf(key, "#WINDOW.%03d.MOJI_MIN", win_no); if (config.GetParam(key, 2, &minx, &miny) == -1) return; | |
| 1921 sprintf(key, "#WINDOW.%03d.WAKU_SETNO", win_no);if (config.GetParam(key, 1, &waku_no) == -1) return; | |
| 1922 sprintf(key, "#WINDOW.%03d.LUBY_SIZE", win_no); if (config.GetParam(key, 1, &ruby) == -1) return; | |
| 1923 | |
| 1924 /* テキストウィジット:画面の右下一杯まで使用 */ | |
| 1925 /* posd == 2 なら画面下にひっつくように配置 */ | |
| 1926 Rect r(0,0); | |
| 1927 if (posd == 2) { | |
| 1928 r = WakuSize(parent, waku_no, config); | |
| 1929 r = Rect(0, parent.Height()-r.height(), r.width(), parent.Height()); | |
| 1930 posx = 0; | |
| 1931 posy = parent.Height()-r.height(); | |
| 1932 } else /* posd == 0 ? */ | |
| 1933 r = Rect(posx, posy, parent.Width(), parent.Height()); | |
| 1934 | |
| 1935 /* テキストウィンドウの作成 */ | |
| 1936 int w = size*cntw; int h = (size+ruby+2)*cnth; | |
| 1937 wid = new WidText(event, &parent, r, Rect(mposx, mposy, mposx+w, mposy+h), size); | |
| 1938 wid->stream.kanji_type = TextStream::sjis; | |
| 1939 /* 顔ウィンドウの作成 */ | |
| 1940 for (i=0; i<8; i++) { | |
| 1941 int x,y; | |
| 1942 sprintf(key, "#WINDOW.%03d.FACE.%03d", win_no, i); | |
| 1943 if (config.GetParam(key, 2, &x, &y) == -1) continue; | |
| 1944 /* 顔ウィンドウを作成する */ | |
| 1945 if (x >= 0 && y >= 0) { | |
| 1946 face_pics[i] = wid->PicNode()->create_leaf(Rect(x,y), PicBase::FIT_SURFACE); | |
| 1947 } else { | |
| 1948 face_pics[i] = parent.create_leaf(Rect(x+posx,y+posy), PicBase::FIT_SURFACE); | |
| 1949 } | |
| 1950 face_pics[i]->show(); | |
| 1951 } | |
| 1952 face = face_pics[0]; | |
| 1953 // ボタンの設定 | |
| 1954 for (i=0; i<BTNCNT; i++) { | |
| 1955 int num; | |
| 1956 sprintf(key, "#WINDOW.%03d.%s_USE", win_no, btnname[i]); | |
| 1957 config.GetParam(key, 1, &num); | |
| 1958 use_btn[i] = (num==0) ? false : true; | |
| 1959 } | |
| 1960 // make name window | |
| 1961 int shadow, name_mod, name_size, name_min, name_center, name_posx, name_posy, name_mposx, name_mposy; | |
| 1962 sprintf(key, "#WINDOW.%03d.MOJI_SHADOW", win_no); config.GetParam(key, 1, &shadow); | |
| 1963 sprintf(key, "#WINDOW.%03d.NAME_MOD", win_no); config.GetParam(key, 1, &name_mod); | |
| 1964 sprintf(key, "#WINDOW.%03d.NAME_MOJI_SIZE", win_no); config.GetParam(key, 1, &name_size); | |
| 1965 sprintf(key, "#WINDOW.%03d.NAME_MOJI_MIN", win_no); config.GetParam(key, 1, &name_min); | |
| 1966 sprintf(key, "#WINDOW.%03d.NAME_MOJI_POS", win_no); config.GetParam(key, 2, &name_mposx, &name_mposy); | |
| 1967 sprintf(key, "#WINDOW.%03d.NAME_CENTERING", win_no); config.GetParam(key, 1, &name_center); | |
| 1968 sprintf(key, "#WINDOW.%03d.NAME_POS", win_no); config.GetParam(key, 2, &name_posx, &name_posy); | |
| 1969 // if name_mode==0 name is in the text window | |
| 1970 // if name_mode == 1 open name window | |
| 1971 // if name_mode == 2 name is not used | |
| 1972 if (name_mod) { | |
| 1973 if (name_mod == 1) { | |
| 1974 int w = name_size*name_min; int h = name_size; | |
| 1975 int name_waku; | |
| 1976 sprintf(key, "#WINDOW.%03d.NAME_WAKU_SETNO", win_no); | |
| 1977 if (config.GetParam(key, 1, &name_waku) != -1 && name_waku != -1) { | |
| 1978 Rect waku_r = WakuSize(parent, name_waku, config); | |
| 1979 waku_r.rmove(r.lx, r.ty); // テキストウィンドウ位置に動かす | |
| 1980 waku_r.rmove(name_posx, name_posy-waku_r.height()); // NAME_POS へ位置補正 | |
| 1981 name_container = parent.create_node(waku_r, 0); | |
| 1982 MakeWaku(*name_container, event, name_waku, win_no, 0, config, callback); | |
| 1983 Rect name_r(0,0,w,h); | |
| 1984 name_r.rmove(name_mposx, name_mposy); | |
| 1985 name = new WidLabel(name_container, name_r, true, 0, name_size); | |
| 1986 name->show(); | |
| 1987 } else { // 名前専用枠なし | |
| 1988 Rect name_r(0, 0, w, h); | |
| 1989 name_r.rmove(r.lx, r.ty); | |
| 1990 name_r.rmove(name_posx, name_posy-name_size); | |
| 1991 name_container = parent.create_node(name_r, 0); | |
| 1992 name = new WidLabel(name_container, Rect(0,0,w,h), true, 0, name_size); | |
| 1993 name->show(); | |
| 1994 name_container->show(); | |
| 1995 } | |
| 1996 } else { // name_mod == 2 or 3 | |
| 1997 name_container = parent.create_node( Rect(0,0,1,1), 0); | |
| 1998 } | |
| 1999 } | |
| 2000 MakeWaku(*wid->PicNode(), event,waku_no, win_no, use_btn, config, callback); | |
| 2001 } | |
| 2002 void TextImpl::InitWindow(void) { | |
| 2003 int i,j,k; | |
| 2004 int w; | |
| 2005 std::string str; | |
| 2006 | |
| 2007 for (w=0; w<32; w++) { | |
| 2008 widgets[w] = new TextWindow(parent, event, w, config, (void*)this); | |
| 2009 if (widgets[w]->wid == 0) { | |
| 2010 delete widgets[w]; | |
| 2011 widgets[w] = 0; | |
| 2012 } | |
| 2013 } | |
| 2014 SetCursor(0); | |
| 2015 for (i=0; i<26; i++) { | |
| 2016 char buf[1024]; | |
| 2017 sprintf(buf, "#NAME.%c", i+'A'); | |
| 2018 const char* s = config.GetParaStr(buf); | |
| 2019 if (s) replace_name[i] = s; | |
| 2020 } | |
| 2021 // replace_name2 : 初期設定 | |
| 2022 // 渚、秋生、渚 (CLANNAD) | |
| 2023 char name_nagisa[3] = {0x8f,0x8d,0}; | |
| 2024 char name_akio[5] = {0x8f, 0x48, 0x90, 0xb6, 0}; | |
| 2025 replace_name2[0] = name_nagisa; | |
| 2026 replace_name2[1] = name_akio; | |
| 2027 replace_name2[2] = name_nagisa; | |
| 2028 text = 0; | |
| 2029 /* テキスト速度の設定 */ | |
| 2030 int speed, mod, wait, auto_mod; | |
| 2031 config.GetParam("#INIT_MESSAGE_SPEED", 1, &speed); | |
| 2032 config.GetParam("#INIT_MESSAGE_SPEED_MOD", 1, &mod); | |
| 2033 config.GetParam("#MESSAGE_KEY_WAIT_USE", 1, &auto_mod); | |
| 2034 config.GetParam("#MESSAGE_KEY_WAIT_TIME", 1, &wait); | |
| 2035 if (mod) speed = -1; | |
| 2036 if (!auto_mod) wait = -1; | |
| 2037 SetTextSpeed(speed); | |
| 2038 SetTextWait(wait); | |
| 2039 return; | |
| 2040 } |
