comparison scn2k/scn2k_impl.cc @ 0:223b71206888

Initial import
author thib
date Fri, 01 Aug 2008 16:32:45 +0000
parents
children 2c890434e30f
comparison
equal deleted inserted replaced
-1:000000000000 0:223b71206888
1 /*
2 * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <stdexcept>
29 #include"scn2k_impl.h"
30 #include"system/file.h"
31 #include"system/system_config.h"
32 #include"window/picture.h"
33 #include"window/system.h"
34
35 // #define DEBUG 1
36
37 using namespace std;
38
39 /**********************************************
40 ** Scn2k
41 */
42
43 void kconv(const unsigned char* src, unsigned char* dest);
44 void kconv_rev(const unsigned char* src, unsigned char* dest);
45 string kconv(const string& s);
46 string kconv_rev(const string& s);
47
48 Scn2k::Scn2k(Event::Container& _event, PicContainer& _parent, class MuSys& mu, AyuSysConfig& _config) :
49 Event::Time(_event),
50 event(_event),
51 parent(_parent),
52 config(_config),
53 text_exec(_event, _parent, config),
54 grp_exec(_event, _parent, flag, flag.cgm_data, mu, config)
55 {
56 system_version = 0;
57 skip_mode = SKIP_NO;
58
59 script_start = 0;
60 script = 0;
61 script_end = 0;
62
63 backlog_script_scn = -1;
64 backlog_script_start = 0;
65 backlog_script_end = 0;
66
67 save_scn = 0;
68 save_point = 0;
69 scn_number = 0;
70 scn_point = 0;
71 cmd_stack_str = cmd_stack_str_orig;
72
73 dialog = 0;
74 dialog_type = CMD_NOP;
75 menu = 0;
76 menu_mouseshown = false;
77
78 /* マウスカーソルを作成 */
79 mouse_type = 0;
80 mouse_surface = 0;
81 mouse_pressed = 0;
82 ShowCursor();
83
84 LoadSys();
85 text_exec.InitWindow();
86 grp_exec.InitSel(config);
87 }
88
89 Scn2k::~Scn2k() {
90 HideCursor();
91 SaveSys();
92 }
93
94 char* Scn2k::OpenScript(int new_scn_number, char*& end, int* call_vec, int& system_version) {
95 char fname[1024];
96 const char* data;
97 char* ret_data;
98 int offset = 0;
99 int scenario_magic;
100
101 sprintf(fname, "SEEN%04d.TXT", new_scn_number);
102 ARCINFO* info = file_searcher.Find(FILESEARCH::SCN, fname, "");
103 if (info == 0) goto err;
104 data = info->Read();
105
106 /* version 確認 */
107 scenario_magic = read_little_endian_int(data + 4);
108 if (scenario_magic != 0x2712 && scenario_magic != 0x1adb2) {
109 fprintf(stderr,"Invalid scenario header : scenario number %d\n",new_scn_number);
110 goto err;
111 }
112 if (read_little_endian_int(data) == 0x1cc) {
113 system_version = 0;
114 offset = 0x1cc + read_little_endian_int(data+0x20) + 4;
115 } else if (read_little_endian_int(data) == 0x1d0) {
116 system_version = 1;
117 offset = read_little_endian_int(data + 0x20);
118 } else {
119 fprintf(stderr,"Invalid scenario header : scenario number %d\n",new_scn_number);
120 goto err;
121 }
122 /* header から subroutine number とりだし */
123 if (call_vec) {
124 int i;
125 for (i=0; i<100; i++) {
126 call_vec[i] = read_little_endian_int(data + 0x34 + i * 4);
127 }
128 }
129 ret_data = new char[info->Size() - offset + 1024];
130 memcpy(ret_data, data+offset, info->Size()-offset);
131 memset(ret_data+info->Size()-offset, 0, 1024);
132 end = ret_data + info->Size() - offset;
133 delete info;
134 return ret_data;
135
136 err:
137 delete info;
138 fprintf(stderr,"Cannot open scenario number %d\n",new_scn_number);
139 throw std::invalid_argument("Scn2k::OpenScript");
140
141 return false;
142 }
143 bool Scn2k::ChangeScript(int new_scn_number, int call_no) {
144 int old_scn_number = scn_number;
145 int old_scn_pt = script - script_start;
146 int scn_pt = 0;
147
148 if (script_start) delete[] script_start;
149 script_start = 0;
150 script = 0;
151 script_end = 0;
152
153 int call_vec[100];
154
155 try {
156 script_start = OpenScript(new_scn_number, script_end, call_vec, system_version);
157 } catch(...) {
158 fprintf(stderr,"\tFrom script %d pt %d\n",old_scn_number, old_scn_pt);
159 throw;
160 }
161 if (call_no > 0 && call_no < 100) {
162 scn_pt = call_vec[call_no];
163 if (scn_pt == 0) {
164 fprintf(stderr,"Invalid subroutine number: scn %d sub %d\n",new_scn_number, call_no);
165 scn_pt = 0;
166 }
167 } else if (call_no < 0) {
168 scn_pt = -call_no; // デバッグ用
169 }
170
171 scn_number = new_scn_number;
172 scn_point = scn_pt;
173 script = script_start + scn_pt;
174 if (script < script_start || script >= script_end)
175 fprintf(stderr,"scn %d pt %d: Cannot jump to %d:%d; fall back to the top\n",old_scn_number, old_scn_pt, scn_number, scn_pt);
176 return true;
177 }
178 bool Scn2k::ReadCmdAt(Cmd& cmd, int scn, int pt) {
179 const char* d;
180 if (scn ==scn_number) {
181 d = script_start + pt;
182 if (d < script_start || d >= script_end) {
183 fprintf(stderr,"Cannot read script at current scn %d pt %d\n", scn, pt);
184 return false;
185 }
186 } else {
187 if (backlog_script_scn != scn) {
188 if (backlog_script_start) delete[] backlog_script_start;
189 backlog_script_start = OpenScript(scn, backlog_script_end, 0, system_version);
190 }
191 d = backlog_script_start + pt;
192 if (d < backlog_script_start || d >= backlog_script_end) {
193 fprintf(stderr,"Cannot read script at scn %d pt %d\n", scn, pt);
194 return false;
195 }
196 }
197
198 cmd.GetCmd(flag, d);
199 return true;
200 }
201
202 extern bool save_req, load_req; // キーボードからセーブ・ロードできるように
203 extern bool pressAreq;
204
205 void Scn2k::Elapsed(unsigned int current_time) {
206 SetWakeup(current_time + 10); // 10msに一回シナリオスクリプト解釈
207 if (script == 0) return;
208 //VarInfo info; info.type = 6; info.number = 0; // PB の「一回ゲームを開始したことがある」フラグ
209 //flag.Set(info,1);
210 //info.type = 0; info.number = 604; // Princess Bride: クリア対象設定フラグ (聖)
211 //flag.Set(info, 1);
212
213
214 Cmd cmd(flag, system_version);
215 int cnt1;
216 int cnt2 = 1000; // flag / jump / flag 系コマンドの最大実行回数
217
218 /* XXX */
219 if (save_req) {
220 save_req = false;
221 load_req = false;
222 cmd.cmd_type = CMD_SAVEREQ;
223 } else if (load_req) {
224 load_req = false;
225 save_req = false;
226 cmd.cmd_type = CMD_LOADREQ;
227 }
228 if (pressAreq) {
229 pressAreq = false;
230 LoadRollback(cmd);
231 return;
232 }
233
234 /* キー入力などに対応 */
235 // メニュー内以外で shift キーが押されたらスキップ開始
236 if ( (skip_mode&SKIP_IN_MENU) == 0) {
237 if (event.pressed(KEY_SHIFT)) {
238 if (skip_mode & SKIP_TEXT) {
239 ; // スキップ中ならなにもしない
240 } else {
241 SetSkipMode(SkipMode(SKIP_TEXT | SKIP_GRP_NOEFFEC | SKIPEND_KEY));
242 }
243 } else {
244 if ( skip_mode & SKIPEND_KEY) {
245 if ( (skip_mode & SKIPEND_TEXT) && (skip_mode & SKIP_TEXT)) {
246 SkipMode new_skip_mode = SkipMode(skip_mode & (~SKIPEND_KEY));
247 if ( (new_skip_mode & SKIP_GRP_FAST) || (new_skip_mode & SKIP_GRP_NODRAW)) {
248 new_skip_mode = SkipMode(skip_mode & (~SKIP_GRP_NOEFFEC));
249 }
250 SetSkipMode(new_skip_mode);
251 } else {
252 SetSkipMode(SKIP_NO);
253 }
254 }
255 }
256 }
257
258 for (cnt1=0; cnt1<20; cnt1++) { // 一回につき 20 個のコマンド実行
259 // 他のコマンド実行中なら終了
260 if ( (cmd.cmd_type == CMD_NOP && SysWait(cmd)) ||
261 // (cmd.cmd_type == CMD_NOP && text_exec.Wait(current_time, cmd)) ||
262 // (cmd.cmd_type == CMD_NOP && grp_exec.Wait(current_time, cmd))) {
263 (cmd.cmd_type == CMD_NOP && grp_exec.Wait(current_time, cmd)) ||
264 (cmd.cmd_type == CMD_NOP && text_exec.Wait(current_time, cmd))) {
265 break;
266 }
267 // コマンド読み込み
268 for (; cnt2 > 0; cnt2--) {
269 scn_point = script - script_start;
270 eprintf("%d / %d :", script - script_start, script_end-script_start);
271 // fprintf(stderr,"%d: %d / %d :",scn_number, script - script_start, script_end-script_start);
272 cmd.GetCmd(flag, script);
273 // if (cmd.cmd_type != CMD_NOP) {
274 if (0) {
275 fprintf(stderr,"%d / %d : 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",
276 scn_point, script_end-script_start,
277 cmd.cmd1,cmd.cmd2,cmd.cmd3,cmd.cmd4,cmd.argc);
278 int i; for (i=0; i<cmd.args.size(); i++) {
279 if (i == 0) fprintf(stderr,"\t");
280 VarInfo info = cmd.args[i];
281 if (info.type == TYPE_STR || info.type == TYPE_VARSTR)
282 fprintf(stderr,"\"%s\",", cmd.Str(info));
283 else
284 fprintf(stderr,"%d,",info.value);
285 }
286 fprintf(stderr,"\n");
287 }
288 cmd.scn = scn_number;
289 cmd.pos = scn_point;
290 if (cmd.IsError()) break;
291 if (cmd.cmd_type == CMD_NOP) continue;
292 if (cmd.cmd_type == CMD_JMP) {
293 // local jump
294 if (cmd.cmd1 == 0 && cmd.cmd2 == 1 && cmd.cmd3 == 16) {
295 int i;
296 for (i=0; i<cmd.args.size()-1; i++) {
297 VarInfo var;
298 var.type = 11;
299 var.number = i;
300 flag.Set(var, cmd.args[i].value);
301 }
302 cmd.args[0].value = cmd.args[i].value;
303 }
304 if ( cmd.cmd1 == 0 && cmd.cmd2 == 1 && (cmd.cmd3 == 5 || cmd.cmd3 == 8 || cmd.cmd3 == 16) ) { // local call / simple switch
305 int scn_pt = script - script_start;
306 // fprintf(stderr,"\nlocal call %d:%d from %d\n",scn_number,cmd.args[0].value,scn_pt);
307 stack.push_back(StackItem(-1, scn_pt));
308 }
309 if (cmd.cmd1 == 0 && cmd.cmd2 == 1 && cmd.cmd3 == 1) {
310 fprintf(stderr,"*** unsupported: cond 1\n");
311 }
312 script = script_start + cmd.args[0].value;
313 if (script < script_start || script >= script_end) {
314 fprintf(stderr,"scn %d pt %d: Cannot jump to %d; fall back to the top\n",scn_number, cmd.args[0].value);
315 script = script_start;
316 }
317 cmd.clear();
318 continue;
319 }
320 if (flag.Exec(cmd)) continue;
321 break;
322 }
323 if (cmd.IsError()) {
324 fprintf(stderr,"cmd error occured: scn %d pt %d / cur %d",scn_number,scn_point,script-script_start);
325 while(script < script_end) {
326 if (*script == 0x29 && script[1] == 0x0a) {script++;break;}
327 if (*script == 0 && script[1] == 0x0a) {script++;break;}
328 if (*script == 0 && script[1] == 0x23) {script++;break;}
329 script++;
330 fprintf(stderr," -> fall back to %d\n",script-script_start);
331 }
332 const char* dprev = script - 0x60;
333 if (dprev < script_start) dprev = script_start;
334 int ilen = (script-dprev+65)/16;
335 int i; for (i=0; i<ilen; i++) {
336 fprintf(stderr, "%6d: ",dprev-script_start);
337 int j; for (j=0; j<16; j++) {
338 if (dprev >= script_end) break;
339 fprintf(stderr, "%02x ",*(unsigned char*)(dprev));
340 dprev++;
341 }
342 fprintf(stderr, "\n");
343 }
344 break;
345 }
346 if (cmd.cmd_type == CMD_NOP) continue;
347
348 if (cmd.cmd_type == CMD_TEXT && cmd.pos != -1) {
349 set<int>& readflag = text_readflag[scn_number];
350 if (readflag.find(cmd.pos) == readflag.end()) { // 未読テキスト発見
351 readflag.insert(cmd.pos);
352 if (skip_mode & SKIPEND_TEXT) {
353 if (!(skip_mode & SKIPEND_KEY)) SetSkipMode(SKIP_NO);
354 }
355 }
356 }
357 text_exec.Exec(cmd);
358 grp_exec.Exec(cmd);
359 SysExec(cmd);
360 if (cmd.cmd_type == CMD_WAITFRAMEUPDATE) {
361 SetWakeup(Event::Time::FRAME_UPDATE);
362 break;
363 } else if (cmd.cmd_type != CMD_NOP) {
364 #if DEBUG
365 fprintf(stderr,"%d-%d / %d : unsupported command; 0x23 - cmd %02x-%02x:%04x:%02x[%2d] \n",
366 cmd.scn, script - script_start, script_end-script_start,
367 cmd.cmd1,cmd.cmd2,cmd.cmd3,cmd.cmd4,cmd.argc);
368 int i; for (i=0; i<cmd.args.size(); i++) {
369 if (i == 0) fprintf(stderr,"\t");
370 VarInfo info = cmd.args[i];
371 if (info.type == TYPE_STR || info.type == TYPE_VARSTR)
372 fprintf(stderr,"\"%s\",", cmd.Str(info));
373 else
374 fprintf(stderr,"%d,",info.value);
375 }
376 fprintf(stderr,"\n");
377 #endif
378 cmd.clear();
379 }
380 }
381 return;
382 }
383
384 void Scn2k::ShowCursor(void) {
385 HideCursor();
386 char key[1024];
387 sprintf(key, "#MOUSE_CURSOR.%03d.NAME",mouse_type);
388 const char* name = config.GetParaStr(key);
389 if (name == 0 || name[0] == 0) mouse_surface = DEFAULT_MOUSECURSOR;
390 else {
391 mouse_surface = parent.Root().NewSurface(name, COLOR_MASK);
392 }
393 if (mouse_surface == 0) mouse_surface = DEFAULT_MOUSECURSOR;
394 System::Main::SetCursor(mouse_surface, Rect(8, 8, 8+32, 8+32));
395 }
396
397 void Scn2k::HideCursor(void) {
398 if (mouse_surface) {
399 System::Main::SetCursor(0, Rect(0,0));
400 if (mouse_surface != DEFAULT_MOUSECURSOR)
401 parent.Root().DeleteSurface(mouse_surface);
402 mouse_surface = 0;
403 }
404 return;
405 }
406
407 bool Scn2k::SysWait(Cmd& cmd) {
408
409 if (menu) {
410 menu->Exec(cmd);
411 if (menu->status & Scn2kMenu::MENU_DELETE || menu->pimpl == 0) {
412 delete menu;
413 menu = 0;
414 if (! menu_mouseshown) HideCursor();
415 else ShowCursor();
416 SetSkipMode(SkipMode(skip_mode & (~SKIP_IN_MENU) ));
417 }
418 if (cmd.cmd_type == CMD_NOP) return true;
419 else return false; /* exec command */
420 }
421 return false;
422 }
423
424 void DllCall_LB(Cmd& cmd, Flags& flags);
425 void Scn2k::SysExec(Cmd& cmd) {
426 if (cmd.cmd_type == CMD_SYSVAR) {
427 int i;
428 for (i=0; i<cmd.args.size(); i++) {
429 if (cmd.args[i].type == TYPE_SYS) {
430 if (cmd.args[i].number == TYPE_SYS_SYS) {
431 flag.SetSys(cmd.args[i].value);
432 } else if (cmd.args[i].number == TYPE_SYS_SKIPMODE) {
433 SetSkipMode(SkipMode(cmd.args[i].value));
434 }
435 } else if (cmd.args[i].type == TYPE_VARSTR) {
436 flag.SetStr(cmd.args[i].number, cmd.Str(cmd.args[i]));
437 } else {
438 flag.Set(cmd.args[i], cmd.args[i].value);
439 }
440 }
441 cmd.clear();
442 }
443 if (cmd.cmd_type == CMD_SAVEPOINT || cmd.cmd_type == CMD_ROLLBACKPOINT) {
444 if (text_exec.backlog_item.scn != -1) {
445 text_exec.backlog.push_back(text_exec.backlog_item);
446 text_exec.backlog_item.Clear();
447 }
448 save_scn = scn_number;
449 save_point = scn_point;
450 if (!new_rollback_save.empty()) {
451 rollback_save.push_back(new_rollback_save);
452 new_rollback_save = "";
453 }
454 if (cmd.cmd_type == CMD_ROLLBACKPOINT) SaveRollback();
455 cmd.clear();
456 }
457 if (cmd.cmd_type == CMD_SAVEREQ || cmd.cmd_type == CMD_SAVE) {
458 Save(cmd);
459 return;
460 }
461 if (cmd.cmd_type == CMD_LOADREQ || cmd.cmd_type == CMD_LOAD) {
462 Load(cmd);
463 return;
464 }
465 if (cmd.cmd_type == CMD_BACKLOGREQ || cmd.cmd_type == CMD_BACKLOGREQ_FWD) {
466 if (menu) {
467 fprintf(stderr,"BACKLOG_REQ requested!!!\n");
468 return;
469 }
470 if (cmd.cmd_type == CMD_BACKLOGREQ_FWD) {
471 cmd.clear(); // backlog mode 以外で fwd を押されてもなにもしない
472 return;
473 }
474 SetSkipMode(SKIP_IN_MENU); // テキストスキップ等はここで中断
475 menu = new Scn2kMenu(Scn2kMenu::MENU_BACKLOG, *this, flag, text_exec, system_version);
476 menu->InitPanel(event, parent);
477 menu->InitTitle(Scn2kSaveTitle(*this));
478 if (mouse_surface) menu_mouseshown = true;
479 else menu_mouseshown = false;
480 ShowCursor();
481 return;
482 }
483 if (cmd.cmd_type == CMD_MENUREQ) {
484 int scn=0, pt=0;
485 config.GetParam("#CANCELCALL", 2, &scn, &pt);
486 if (scn) {
487 // 右クリックされたら global call を行う
488 cmd.cmd_type = CMD_OTHER;
489 cmd.cmd1 = 0;
490 cmd.cmd2 = 1;
491 cmd.cmd3 = 0x0c;
492 cmd.cmd4 = 1;
493 cmd.args.clear();
494 cmd.args.push_back(VarInfo(SCN_INFO_MENU));
495 cmd.args.push_back(0);
496 SetSkipMode(SKIP_IN_MENU); // テキストスキップ等はここで中断
497 }
498 }
499 if (cmd.cmd_type == CMD_SAVECMDGRP || cmd.cmd_type == CMD_SAVECMDGRP_START || cmd.cmd_type == CMD_SAVECMDGRP_ONCE || cmd.cmd_type == CMD_SAVECMD_ONCE) {
500 // 画像コマンド等はスタックに保存し、セーブ時に保存できるようにする
501 if (cmd.cmd_type == CMD_SAVECMDGRP_START) {
502 vector<CmdSimplified>::iterator it, cur;
503 cur = cmd_stack.begin();
504 cmd_stack_str = cmd_stack_str_orig;
505 /* 画像関連コマンド以外を別にする */
506 for (it=cmd_stack.begin(); it != cmd_stack.end(); it++) {
507 if (it->type != CMD_SAVECMDGRP && it->type != CMD_SAVECMDGRP_START && it->type != CMD_SAVECMDGRP_ONCE) {
508 cur->copy(*it, cmd_stack_str);
509 cur++;
510 }
511 }
512 cmd_stack.erase(cur, cmd_stack.end());
513 }
514 if (cmd.cmd_type == CMD_SAVECMD_ONCE || cmd.cmd_type == CMD_SAVECMDGRP_ONCE) { // 同じコマンドがあれば削除する
515 vector<CmdSimplified>::iterator it;
516 for (it = cmd_stack.end(); it != cmd_stack.begin(); ) {
517 --it;
518 if (it->cmd1 == cmd.cmd1 && it->cmd2 == cmd.cmd2 && it->cmd3 == cmd.cmd3 && it->cmd4 == cmd.cmd4) {
519 cmd_stack.erase(it);
520 break;
521 }
522 }
523 }
524 CmdSimplified cmd_item;
525 cmd.write(cmd_item, cmd_stack_str);
526 cmd_stack.push_back(cmd_item);
527 cmd.clear();
528 if (cmd_stack_str > cmd_stack_str_orig + 30000) { // char cmd_stack_str_orig[32768]
529 fprintf(stderr,"Error in Scn2k::SysExec: too long cmdstack (%d): stack string overflow\n",cmd_stack.size());
530 cmd_stack_str = cmd_stack_str_orig;
531 cmd_stack.clear();
532 }
533 }
534 if (cmd.cmd_type != CMD_OTHER) return;
535 if (cmd.cmd1 == 0 && cmd.cmd2 == 1) {
536 if (cmd.cmd3 == 0x0b) { // global jump
537 eprintf("global jump to %d\n",cmd.args[0].value);
538 if (! ChangeScript(cmd.args[0].value, 0)) return; // 読み込めない; abort.
539 cmd.clear();
540 } else if (cmd.cmd3 == 0x0c || cmd.cmd3 == 0x12) { // call (0x12 の方は微妙)
541 int new_scn = cmd.args[0].value;
542 int new_pt = 0;
543 if (cmd.args.size() >= 1) { // subroutine number が付く
544 // 引数が付くのもあるらしい
545 new_pt = cmd.args[1].value;
546 }
547 if (new_scn == SCN_INFO_MENU) { // menu call
548 config.GetParam("#CANCELCALL", 2, &new_scn, &new_pt);
549 stack.push_back(StackItem(SCN_INFO, SCN_INFO_MENU)); // menu call を示す特殊な記号
550 } else {
551 int i;
552 VarInfo var;
553 // ローカル変数を伴う subroutine call
554 var.type = 11;
555 var.number = 0;
556 int saved_vars = 0;
557 for (i=0; i<40; i++) {
558 int val = flag.Get(var.type, i);
559 if (val != 0) {
560 stack.push_back(StackItem(SCN_INFO_LOCALS + i, val));
561 saved_vars++;
562 }
563 }
564 var.type = TYPE_VARLOCSTR;
565 for (i=0; i<3; i++) {
566 string s = flag.Str(var.type, i);
567 if (s.size()) {
568 int sp = stack_strbuffer.size();
569 stack.push_back(StackItem(SCN_INFO_LOCALSTR+i, sp));
570 stack_strbuffer.push_back(s);
571 saved_vars++;
572 }
573 }
574 stack.push_back(StackItem(SCN_INFO, SCN_INFO_LOCALS + saved_vars));
575
576 var.type = 11;
577 var.number = 0;
578 // 特殊な subroutine call なので、余計な情報を引数に渡す
579 for (i=2; i<cmd.args.size(); i++) {
580 flag.Set(var, cmd.args[i].value);
581 // fprintf(stderr,"<%d:%d>=%d;",var.type,var.number,cmd.args[i].value);
582 var.number++;
583 }
584 // fprintf(stderr,"%d; ",stack.size());
585 }
586 int scn_pt = script - script_start;
587 stack.push_back(StackItem(scn_number, scn_pt));
588 // fprintf(stderr,"\nglobal call %d:%d from %d:%d\n",new_scn,new_pt,scn_number,scn_pt);
589 eprintf("global call to %d, %d\n",new_scn, new_pt);
590 if (! ChangeScript(new_scn, new_pt)) return; // 読み込めない; abort.
591 cmd.clear();
592 } else if (cmd.cmd3 == 0x65) { // 文字列の返り値をセットする
593 int arg1 = cmd.args[0].value;
594 string s = cmd.Str(cmd.args[1]);
595 int sp = stack_strbuffer.size();
596 stack.push_back(StackItem(SCN_INFO_RETSTR+arg1, sp));
597 stack_strbuffer.push_back(s);
598 cmd.clear();
599 } else if (cmd.cmd3 == 0x0d || cmd.cmd3 == 0x0a || cmd.cmd3 == 0x11 || cmd.cmd3 == 0x13) { // return (0a: local return) (0x13はよくわからない)
600 // fprintf(stderr,"global return : stack size %d\n",stack.size());
601 if (stack.empty()) {
602 cmd.clear();
603 return; // スタックがおかしい:abort
604 }
605 map<int, string> retstr;
606 while( (!stack.empty()) && stack.back().scn_number >= SCN_INFO_RETSTR) {
607 int ret_num = stack.back().scn_number - SCN_INFO_RETSTR;
608 // fprintf(stderr,"\nRetStr;");
609 string str = stack_strbuffer.back();
610 stack_strbuffer.pop_back();
611 retstr[ret_num] = str;
612 stack.pop_back();
613 }
614 if (stack.empty()) {
615 cmd.clear();
616 return; // スタックがおかしい:abort
617 }
618 StackItem s = stack.back();
619 stack.pop_back();
620 bool localvar_init = false;
621 while( (!stack.empty()) && stack.back().scn_number == SCN_INFO) {
622 int mode = stack.back().scn_pt;
623 stack.pop_back();
624 if (mode == SCN_INFO_MENU) {
625 // fprintf(stderr,"\nInfo Menu;");
626 // menu モード終了
627 SetSkipMode(SkipMode(skip_mode & (~SKIP_IN_MENU) ));
628 } else if (mode >= SCN_INFO_LOCALS && mode <= SCN_INFO_LOCALS+50) {
629 // fprintf(stderr,"\nInfo Local;");
630 int i;
631 // ローカル変数を元に戻す
632 VarInfo var;
633 var.type = 11;
634 var.number = 0;
635 for (i=0; i<40; i++) {
636 var.number = i;
637 flag.Set(var, 0);
638 }
639 var.type = TYPE_VARLOCSTR;
640 for (i=0; i<3; i++) {
641 var.number = i;
642 flag.SetStr(var, "");
643 }
644 int args = mode - SCN_INFO_LOCALS;
645 // fprintf(stderr," args = %d; ",args);
646 for (i=0; i<args; i++) {
647 if (stack.empty() || stack.back().scn_number < SCN_INFO) {
648 fprintf(stderr,"Fatal : Invalid stack found in preserved local variables!\n");
649 break;
650 }
651 var.number = stack.back().scn_number;
652 // fprintf(stderr,"%d:%d; ",stack.back().scn_number,stack.back().scn_pt);
653 if (var.number >= SCN_INFO_LOCALS && var.number < SCN_INFO_LOCALSTR) {
654 var.type = 11;
655 var.number -= SCN_INFO_LOCALS;
656 flag.Set(var, stack.back().scn_pt);
657 } else if (var.number >= SCN_INFO_LOCALSTR && var.number < SCN_INFO_RETSTR) {
658 var.type = TYPE_VARLOCSTR;
659 var.number -= SCN_INFO_LOCALSTR;
660 flag.SetStr(var, stack_strbuffer.back());
661 stack_strbuffer.pop_back();
662 }
663 stack.pop_back();
664 }
665 }
666 // fprintf(stderr,"stack size %d string size %d\n",stack.size(),stack_strbuffer.size());
667 }
668 if (cmd.cmd3 == 0x11 || cmd.cmd3 == 0x13) {
669 // fprintf(stderr,"\nSet RetLocal;");
670 // 返り値をセットする
671 map<int,string>::iterator it;
672 VarInfo var;
673 var.type = TYPE_VARLOCSTR;
674 for (it=retstr.begin(); it!=retstr.end(); it++) {
675 var.number = it->first;
676 flag.SetStr(var, it->second);
677 }
678 var.type = 11;
679 // fprintf(stderr,"return : cmd.cmd3 == 0x11; size %d\n",cmd.args.size());
680 if (cmd.args.size() == 1) {
681 // fprintf(stderr,"return value %d\n",cmd.args[0].value);
682 flag.SetSys(cmd.args[0].value);
683 } else {
684 int i;for (i=0; i<cmd.args.size(); i++) {
685 var.number = i;
686 flag.Set(var, cmd.args[i].value);
687 }
688 }
689 }
690 // fprintf(stderr,"global return : return to %d:%d\n",s.scn_number,s.scn_pt);
691 // fprintf(stderr,"\nglobal return %d:%d from %d:%d\n",s.scn_number,s.scn_pt,scn_number, script - script_start);
692 if (s.scn_number != -1) {
693 if (! ChangeScript(s.scn_number, 0)) return; // 読み込めない; abort.
694 }
695 script = script_start + s.scn_pt;
696 cmd.clear();
697 }
698 } else if (cmd.cmd1 == 2 && cmd.cmd2 == 1 && cmd.cmd3 == 12) { // DLL Call
699 const char* regname = config.GetParaStr("#REGNAME");
700 const char key_lb[] = "KEY\\LittleBusters";
701 if (strcmp(regname, key_lb) == 0) {
702 DllCall_LB(cmd, flag);
703 cmd.clear();
704 }
705 } else if (cmd.cmd1 == 0 && cmd.cmd2 == 0x04) { // メニューモード
706 if (cmd.cmd3 == 300 || cmd.cmd3 == 301 || cmd.cmd3 == 302) {
707 // メニューからのreturn
708 cmd.cmd2 = 1;
709 cmd.cmd3 = 0x0d;
710 SysExec(cmd);
711 }
712 } else if (cmd.cmd1 == 1 && cmd.cmd2 == 0x04) {
713 if (cmd.cmd3 == 0 && cmd.cmd4 == 0) { // タイトル名設定
714 const char* name = cmd.Str(cmd.args[0]);
715 if (name == 0) name = "";
716 window_title = name;
717 const char* config_name = config.GetParaStr("#CAPTION");
718 if (config_name == 0) config_name = "";
719 string setname = kconv(string(config_name) + " " + window_title);
720 parent.Root().SetWindowCaption(setname.c_str());
721 cmd.clear();
722 } else if (cmd.cmd3 == 0x82 && cmd.cmd4 == 0) {
723 /* cmd.cmd3 == 0x82 : マウスの press 状態クリアかも */
724 event.presscount(MOUSE_LEFT);
725 event.presscount(MOUSE_RIGHT);
726 cmd.clear();
727 } else if (cmd.cmd3 == 0x85 && cmd.cmd4 == 0) {
728 int x,y,left,right;
729 event.MousePos(x,y);
730 if (event.presscount(MOUSE_LEFT)) left = 2;
731 else if (event.pressed(MOUSE_LEFT)) left = 1;
732 else left = 0;
733
734 if (event.presscount(MOUSE_RIGHT)) right = 2;
735 else if (event.pressed(MOUSE_RIGHT)) right = 1;
736 else right = 0;
737
738 // eprintf("mouse pos\n");
739 flag.Set(cmd.args[0], x);
740 flag.Set(cmd.args[1], y);
741 flag.Set(cmd.args[2], left);
742 flag.Set(cmd.args[3], right);
743 cmd.clear();
744 } else if (cmd.cmd3 == 0x15e || cmd.cmd3 == 0x161 || cmd.cmd3 == 0x162 || cmd.cmd3 == 0x14c || cmd.cmd3 == 0x7d1) {
745 /* 15e, 161, 162, 14c, 7d1 : なんらかのシステム情報を返す(skip modeなど?) */
746 /* 7d1: == 1 || 14c: == 1 || (15e==1&&161==1&&162==0) || (press_val == 2) : スキップ中? タイトル画面のアニメーション終了 */
747 flag.SetSys(0);
748 cmd.clear();
749 } else if (cmd.cmd3 == 0x4b0) { // 終了
750 System::Main::Quit();
751 script = 0; script_start = 0; script_end = 0;
752 cmd.clear();
753 cmd.cmd_type = CMD_WAITFRAMEUPDATE;
754 } else if (cmd.cmd3 == 0x4b4 || cmd.cmd3 == 0x4b5) { // 選択肢巻き戻し
755 LoadRollback(cmd);
756 } else if (cmd.cmd3 == 0x58d) {
757 // 前にロード|セーブされた番号を返す。
758 flag.SetSys(-1);
759 } else if (cmd.cmd3 == 0x585) {
760 // 第一引数の記録された日付、タイトルなどが返される
761 // データがないなら sys に 0が、あるなら 1 が返る
762 int y,m,d,wd,h,min,s,ms;
763 string title;
764 fprintf(stderr,"StatSave %d:",cmd.args[0].value+1);
765 if (StatSaveFile(cmd.args[0].value+1,y,m,d,wd,h,min,s,ms,title) == true) {
766 flag.Set(cmd.args[1], y);
767 flag.Set(cmd.args[2], m);
768 flag.Set(cmd.args[3], d);
769 flag.Set(cmd.args[4], wd);
770 flag.Set(cmd.args[5], h);
771 flag.Set(cmd.args[6], min);
772 flag.Set(cmd.args[7], s);
773 flag.Set(cmd.args[8], ms);
774 if (cmd.args[9].type == TYPE_VARSTR) {
775 flag.SetStr(cmd.args[9].number, kconv_rev(title));
776 }
777 flag.SetSys(1);
778 } else {
779 flag.SetSys(0);
780 }
781 cmd.clear();
782 } else if (cmd.cmd3 == 0xc23) { // save
783 Save(cmd);
784 } else if (cmd.cmd3 == 0xc25) { // load
785 Load(cmd);
786 } else if (cmd.cmd3 == 0x4b1 || cmd.cmd3 == 0x4b3) { // menu へ戻る (4b3: バッドエンド)
787 int scn_start;
788 if (config.GetParam("#SEEN_MENU", 1, &scn_start) == 0) {
789 ChangeScript(scn_start, 0);
790 save_scn = 0;
791 save_point = 0;
792 window_title = "";
793 const char* window_title_config = config.GetParaStr("#CAPTION");
794 if (window_title_config) window_title = window_title_config;
795 parent.Root().SetWindowCaption(kconv(window_title).c_str());
796 stack.clear();
797 cmd_stack.clear();
798 cmd_stack_str = cmd_stack_str_orig;
799 flag.Load("");
800 text_exec.Load("");
801 grp_exec.Load("");
802 SetSkipMode(SKIP_NO);
803 }
804 } else if (cmd.cmd3 == 0xcc) {
805 eprintf("show mouse cursor\n");
806 ShowCursor();
807 cmd.clear();
808 } else if (cmd.cmd3 == 0xcd) {
809 eprintf("hide mouse cursor\n");
810 HideCursor();
811 cmd.clear();
812 } else if (cmd.cmd3 == 0xcf) {
813 mouse_type = cmd.args[0].value;
814 eprintf("change mouse cursor : %d\n", mouse_type);
815 if (mouse_surface) ShowCursor();
816 cmd.clear();
817 }
818 }
819
820 }
821
822 #include<sys/types.h>
823 #include<sys/stat.h>
824 #include<errno.h>
825 #include<unistd.h>
826
827 // セーブファイルの名前をつくる
828 string Scn2k::MakeSaveFile(void) const {
829 struct stat sstatus;
830 string dir = "~/.xkanon";
831
832 if (dir.c_str()[0] == '~' && dir.c_str()[1] == '/') {
833 char* home = getenv("HOME");
834 if (home != 0) {
835 string new_dir = string(home) + (dir.c_str()+1);
836 dir = new_dir;
837 }
838 }
839 // savepathにファイル名が入っていれば、それをセーブファイルとして使う
840 if (stat(dir.c_str(), &sstatus) == -1) {
841 if (errno != ENOENT) {
842 fprintf(stderr,"Cannot open save file; dir %s is not directory\n",dir.c_str());
843 return "";
844 }
845 if (mkdir(dir.c_str(), S_IRWXU) != 0 && errno != EEXIST) {
846 fprintf(stderr, "Cannot create directory %s ; Please create manually!!\n",dir.c_str());
847 }
848 } else {
849 if ( (sstatus.st_mode & S_IFMT) == S_IFREG) {
850 return dir;
851 }
852 }
853 // ファイル名を作る
854 const char* regname = config.GetParaStr("#REGNAME");
855
856 char* fname = new char[strlen(regname)+1];
857 /* レジストリ名をファイル名として有効なものにする */
858 int i; for (i=0; regname[i]!=0; i++) {
859 char c = regname[i];
860 if (c == '\\' || c == '/' || c == ':' || c <= 0x20) c = '_';
861 fname[i] = tolower(c);
862 }
863 fname[i] = 0;
864 dir += "/save.";
865 dir += fname;
866 return dir;
867 }
868 // セーブファイルの名前をつくる
869 string Scn2kSaveTitle::operator() (int number) const {
870 int y,m,d,wd,h,min,sec,msec;
871 string title;
872 if (! impl.StatSaveFile(number, y,m,d,wd,h,min,sec,msec,title)) {
873 return "";
874 } else {
875 char buf[1024];
876 sprintf(buf, "%2d/%2d %2d:%2d ",m,d,h,min);
877 return string(buf) + title;
878 }
879 };
880
881 void Scn2k::SaveSys(void) {
882 char buf[1024];
883 string save;
884 string path = MakeSaveFile();
885
886 sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME")); save += buf;
887 string save_config;
888 config.DiffOriginal(save_config);
889 save += "CONFIG=";
890 save += save_config;
891 save += "\n";
892 string save_flag; flag.SaveSys(save_flag);
893 save += save_flag;
894 string save_grp; grp_exec.SaveSys(save_grp);
895 save += save_grp;
896 map<int,set<int> >::iterator it;
897 save += "[TextRead]\n";
898 for (it=text_readflag.begin(); it != text_readflag.end(); it++) {
899 set<int>& read_flag = it->second;
900 set<int>::iterator jt;
901 char buf[1024];
902 sprintf(buf,"T<%05d>=",it->first);
903 string save_readflag = buf;
904 for (jt=read_flag.begin(); jt != read_flag.end(); jt++) {
905 sprintf(buf, "%d,", *jt);
906 save_readflag += buf;
907 }
908 save_readflag += "\n";
909 save += save_readflag;
910 }
911
912 path += ".0";
913 FILE* f = fopen(path.c_str(), "w");
914 if (f == 0) {
915 fprintf(stderr,"Cannot open save file %s\n",path.c_str());
916 return;
917 }
918 fwrite(save.c_str(), save.length(), 1, f);
919 fclose(f);
920 return;
921 }
922
923 void Scn2k::LoadSys(void) {
924 char buf[1024];
925 string path = MakeSaveFile();
926 path += ".0";
927 FILE* f = fopen(path.c_str(), "r");
928 if (f == 0) {
929 fprintf(stderr, "Cannot open save file %s\n",path.c_str());
930 } else {
931 fseek(f,0,2);
932 int sz = ftell(f);
933 fseek(f,0,0);
934 char* savedata = new char[sz+1];
935 fread(savedata, sz, 1, f);
936 savedata[sz] = 0;
937 fclose(f);
938
939 sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME"));
940 if (strncmp(savedata, buf, strlen(buf)) != 0) {
941 fprintf(stderr,"Invalid header in save file %s: it must be started with \"%s\"\n",buf);
942 } else {
943 char* config_str = strstr(savedata, "\nCONFIG=");
944 if (config_str) {
945 config_str += strlen("\nCONFIG=");
946 char* strend = strchr(config_str, '\n');
947 if (strend) {
948 int l = strend - config_str;
949 char* config_copy = new char[l+1];
950 strncpy(config_copy, config_str, l);
951 config_copy[l] = 0;
952 config.PatchOriginal(config_copy);
953 delete[] config_copy;
954 }
955 }
956 flag.LoadSys(savedata);
957 grp_exec.LoadSys(savedata);
958 char* save = strstr(savedata, "\n[TextRead]\n");
959 if (save) {
960 save += strlen("\n[TextRead]\n");
961 do {
962 if (save[0] == '[') break; // next section
963 char* next_save = strchr(save, '\n');
964 if (next_save) {
965 *next_save++ = 0;
966 }
967 // T<XXXXX>=YYY,YYY,YYY,...
968 if (strncmp(save,"T<",2) == 0) {
969 int scn_num = atoi(save+2);
970 set<int>& read_flag = text_readflag[scn_num];
971 save += strlen("T<XXXXX>=");
972 while(save && *save) {
973 if (save[0] >= '0' && save[0] <= '9') {
974 int num = atoi(save);
975 read_flag.insert(num);
976 }
977 save = strchr(save, ',');
978 if (save) save++;
979 }
980 }
981 save = next_save;
982 } while(save);
983 }
984
985 }
986 delete[] savedata;
987 }
988
989 /* 初期化 */
990 int scn_start; config.GetParam("#SEEN_START", 1, &scn_start);
991 ChangeScript(scn_start, 0);
992 save_scn = 0;
993 save_point = 0;
994 window_title = "";
995 const char* window_title_config = config.GetParaStr("#CAPTION");
996 if (window_title_config) window_title = window_title_config;
997 parent.Root().SetWindowCaption(kconv(window_title).c_str());
998 stack.clear();
999 cmd_stack.clear();
1000 cmd_stack_str = cmd_stack_str_orig;
1001
1002 return;
1003 }
1004
1005 bool Scn2k::StatSaveFile(int num, int& year, int& month, int& day, int& wday, int& hour,int& min, int& sec, int& msec, string& title) const {
1006 char buf[1024];
1007 string path = MakeSaveFile();
1008 if (num <= 0 || num > 99) return false;
1009 sprintf(buf,".%d",num);
1010 path += buf;
1011
1012 struct stat sb;
1013 if (stat(path.c_str(), &sb) == -1) return false;
1014 struct tm* t = localtime(&sb.st_mtime);
1015 month = t->tm_mon + 1;
1016 day = t->tm_mday;
1017 hour = t->tm_hour;
1018 min = t->tm_min;
1019 /* タイトルの取得 */
1020 FILE* savefile = fopen(path.c_str(), "rb");
1021 if (savefile == 0) return false;
1022 char regname[1024];
1023 sprintf(regname, "KEY=%s\n", config.GetParaStr("#REGNAME"));
1024 fgets(buf,1000,savefile);
1025 if (strncmp(regname, buf, strlen(regname)) != 0) {
1026 fprintf(stderr,"invalid save file %s (registory name is not %s)\n",path.c_str(),regname);
1027 fclose(savefile);
1028 return false;
1029 }
1030 title="none";
1031 while(!feof(savefile)) {
1032 fgets(buf,1000,savefile);
1033 if (strncmp(buf,"Title=",6) == 0) {
1034 if (buf[strlen(buf)-2] == 0x0a) buf[strlen(buf)-2] = 0;
1035 if (strlen(buf) > 20) buf[20] = 0, buf[21] = 0;
1036 title = kconv(buf+6);
1037 break;
1038 }
1039 }
1040 fclose(savefile);
1041 return true;
1042 }
1043
1044 void Scn2k::SaveRollback(void) {
1045 fprintf(stderr,"Save rollback\n");
1046 new_rollback_save = "";
1047 string save_sys; SaveImpl(save_sys);
1048 string save_flag; flag.Save(save_flag);
1049 string save_text; text_exec.Save(save_text, true);
1050 string save_grp; grp_exec.Save(save_grp);
1051 new_rollback_save += save_sys;
1052 new_rollback_save += save_flag;
1053 new_rollback_save += save_text;
1054 new_rollback_save += save_grp;
1055 }
1056
1057 void Scn2k::LoadRollback(Cmd& cmd) {
1058 if (rollback_save.empty()) return;
1059 new_rollback_save = "";
1060 string savedata = rollback_save.back();
1061 rollback_save.pop_back();
1062 LoadImpl(savedata.c_str());
1063 flag.Load(savedata.c_str());
1064 text_exec.Load(savedata.c_str());
1065 grp_exec.Load(savedata.c_str());
1066
1067 /* 画面の回復など */
1068 SetSkipMode(SKIP_NO);
1069 vector<CmdSimplified>::iterator it;
1070 cmd.clear();
1071 for (it = cmd_stack.begin(); it != cmd_stack.end(); it++) {
1072 cmd.read(*it);
1073 cmd.cmd_type = CMD_OTHER;
1074 flag.Exec(cmd);
1075 text_exec.Exec(cmd);
1076 grp_exec.Exec(cmd);
1077 }
1078 cmd.clear();
1079 return;
1080 }
1081
1082 void Scn2k::Save(Cmd& cmd) {
1083 if (cmd.cmd_type == CMD_SAVEREQ) {
1084 if (menu == 0) {
1085 SetSkipMode(SKIP_IN_MENU); // テキストスキップ等はここで中断
1086 menu = new Scn2kMenu(Scn2kMenu::MENU_SAVE, *this, flag, text_exec, system_version);
1087 menu->InitPanel(event, parent);
1088 menu->InitTitle(Scn2kSaveTitle(*this));
1089 if (mouse_surface) menu_mouseshown = true;
1090 else menu_mouseshown = false;
1091 ShowCursor();
1092 return;
1093 }
1094 }
1095 char buf[1024];
1096 string save;
1097 FILE* f = 0;
1098 if (save_scn == 0) {
1099 fprintf(stderr,"Cannot decide save point\n");
1100 return; // セーブ位置が保存されてない
1101 }
1102 string path = MakeSaveFile();
1103 int file_number = 1;
1104 if (cmd.args.size() == 1)
1105 file_number = cmd.args[0].value + 1;
1106 if (file_number <= 0) {
1107 fprintf(stderr, "Cannot open save file %s\n",path.c_str());
1108 return;
1109 }
1110 sprintf(buf, ".%d",file_number);
1111 path += buf;
1112
1113 /* セーブファイル確認 */
1114
1115 sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME")); save += buf;
1116 string save_sys; SaveImpl(save_sys);
1117 string save_flag; flag.Save(save_flag);
1118 string save_text; text_exec.Save(save_text, false);
1119 string save_grp; grp_exec.Save(save_grp);
1120 save += save_sys;
1121 save += save_flag;
1122 save += save_text;
1123 save += save_grp;
1124 vector<string>::iterator it;
1125 for (it=rollback_save.begin(); it != rollback_save.end(); it++) {
1126 save += "[Rollback Data]\n";
1127 save += *it;
1128 save += "[Rollback End]\n";
1129 }
1130
1131 f = fopen(path.c_str(), "w");
1132 if (f == 0) {
1133 fprintf(stderr,"Cannot open save file %s\n",path.c_str());
1134 return;
1135 }
1136 fwrite(save.c_str(), save.length(), 1, f);
1137 fclose(f);
1138 cmd.clear();
1139 return;
1140 }
1141
1142 void Scn2k::Load(Cmd& cmd) {
1143 if (cmd.cmd_type == CMD_LOADREQ) {
1144 if (menu == 0) {
1145 menu = new Scn2kMenu(Scn2kMenu::MENU_LOAD, *this, flag, text_exec, system_version);
1146 menu->InitPanel(event, parent);
1147 menu->InitTitle(Scn2kSaveTitle(*this));
1148 SetSkipMode(SKIP_IN_MENU); // テキストスキップ等はここで中断
1149 if (mouse_surface) menu_mouseshown = true;
1150 else menu_mouseshown = false;
1151 ShowCursor();
1152 return;
1153 }
1154 }
1155 char buf[1024];
1156 string path = MakeSaveFile();
1157 int file_number = 1;
1158 if (cmd.args.size() == 1)
1159 file_number = cmd.args[0].value + 1;
1160 sprintf(buf, ".%d",file_number);
1161 path += buf;
1162 FILE* f = 0;
1163 if (file_number > 0) f = fopen(path.c_str(), "r");
1164 if (f == 0) {
1165 fprintf(stderr, "Cannot open save file %s\n",path.c_str());
1166 return;
1167 }
1168
1169 fseek(f,0,2);
1170 int sz = ftell(f);
1171 fseek(f,0,0);
1172 char* savedata = new char[sz+1];
1173 fread(savedata, sz, 1, f);
1174 savedata[sz] = 0;
1175 fclose(f);
1176
1177 sprintf(buf, "KEY=%s\n", config.GetParaStr("#REGNAME"));
1178 if (strncmp(savedata, buf, strlen(buf)) != 0) {
1179 fprintf(stderr,"Invalid header in save file %s: it must be started with \"%s\"\n",buf);
1180 delete[] savedata;
1181 return;
1182 }
1183 LoadImpl(savedata);
1184 flag.Load(savedata);
1185 text_exec.Load(savedata);
1186 grp_exec.Load(savedata);
1187 rollback_save.clear();
1188 new_rollback_save = "";
1189 char* rollback_data = savedata;
1190 while( (rollback_data = strstr(rollback_data,"[Rollback Data]\n")) != 0) {
1191 rollback_data += strlen("[Rollback Data]\n");
1192 char* rollback_end = strstr(rollback_data, "[Rollback End]\n");
1193 if (rollback_end == 0) rollback_end = rollback_data + strlen(rollback_data);
1194 string s(rollback_data, rollback_end);
1195 rollback_save.push_back(s);
1196 rollback_data = rollback_end;
1197 }
1198
1199 /* 画面の回復など */
1200 SetSkipMode(SKIP_NO);
1201 vector<CmdSimplified>::iterator it;
1202 for (it = cmd_stack.begin(); it != cmd_stack.end(); it++) {
1203 cmd.read(*it);
1204 cmd.cmd_type = CMD_OTHER;
1205 flag.Exec(cmd);
1206 text_exec.Exec(cmd);
1207 grp_exec.Exec(cmd);
1208 }
1209 cmd.clear();
1210 return;
1211 }
1212
1213 void Scn2k::SaveImpl(string& save) {
1214 char buf[1024];
1215
1216 /* save point */
1217 sprintf(buf, "\n[SCENARIO]\nScn=%d\nPoint=%d\n",save_scn, save_point); save += buf;
1218 sprintf(buf, "Title=%s\nMouseType=%d\nMouseShown=1\n",window_title.c_str(), mouse_type); save += buf;
1219 vector<StackItem>::iterator sit;
1220 for (sit=stack.begin(); sit!=stack.end(); sit++) {
1221 if (sit->scn_number == SCN_INFO && sit->scn_pt == SCN_INFO_MENU) break; // メニューに入る直前までのスタックを保存
1222 sprintf(buf, "Stack=%d,%d\n",sit->scn_number,sit->scn_pt);
1223 save += buf;
1224 }
1225 vector<string>::reverse_iterator ssit;
1226 for (ssit=stack_strbuffer.rbegin(); ssit != stack_strbuffer.rend(); ssit++) {
1227 sprintf(buf, "StackStr=%s\n",ssit->c_str());
1228 save += buf;
1229 }
1230 vector<CmdSimplified>::iterator cit;
1231 for (cit=cmd_stack.begin(); cit != cmd_stack.end(); cit++) {
1232 if (cit->type == CMD_SAVECMDGRP || cit->type == CMD_SAVECMDGRP_ONCE || cit->type == CMD_SAVECMDGRP_START) {
1233 save += "CmdG=";
1234 } else {
1235 save += "Cmd=";
1236 }
1237 string s; cit->Save(s);
1238 save += s;
1239 save += "\n";
1240 }
1241 }
1242
1243 void Scn2k::LoadImpl(const char* save) {
1244 char buf[1024];
1245 save_scn = 0;
1246 save_point = 0;
1247 window_title = "";
1248 stack.clear();
1249 cmd_stack.clear();
1250 cmd_stack_str = cmd_stack_str_orig;
1251
1252 save = strstr(save, "\n[SCENARIO]\n");
1253 if (save == 0) return;
1254 save += strlen("\n[SCENARIO]\n");
1255 while(save[0] != 0 && save[0] != '[') { // while next section start
1256 if (strncmp(save, "Scn=", 4) == 0) {
1257 sscanf(save, "Scn=%d", &save_scn);
1258 } else if (strncmp(save, "Point=", 6) == 0) {
1259 sscanf(save, "Point=%d", &save_point);
1260 } else if (strncmp(save, "Title=", 6) == 0) {
1261 save += 6;
1262 char* s = strchr(save, '\n');
1263 if (s == 0) window_title = save;
1264 else window_title.assign(save, s-save);
1265 const char* config_name = config.GetParaStr("#CAPTION");
1266 if (config_name == 0) config_name = "";
1267 string setname = kconv(string(config_name)+" "+window_title);
1268 parent.Root().SetWindowCaption(setname.c_str());
1269 } else if (strncmp(save, "MouseType=", 10) == 0) {
1270 sscanf(save, "MouseType=%d", &mouse_type);
1271 } else if (strncmp(save, "MouseShown=", 11) == 0) {
1272 int v;
1273 sscanf(save, "MouseShown=%d", &v);
1274 if (v) ShowCursor();
1275 else HideCursor();
1276 } else if (strncmp(save, "Stack=", 6) == 0) {
1277 int scn, pt;
1278 sscanf(save, "Stack=%d,%d", &scn, &pt);
1279 stack.push_back( StackItem(scn, pt));
1280 } else if (strncmp(save, "StackStr=", 9) == 0) {
1281 save += 9;
1282 char* s = strchr(save, '\n');
1283 if (s == 0) stack_strbuffer.push_back("");
1284 else stack_strbuffer.push_back(string(save, s-save));
1285 } else if (strncmp(save, "Cmd=", 4) == 0) {
1286 CmdSimplified cmd;
1287 cmd.Load(save+4, cmd_stack_str);
1288 cmd_stack.push_back(cmd);
1289 } else if (strncmp(save, "CmdG=", 5) == 0) {
1290 CmdSimplified cmd;
1291 cmd.Load(save+5, cmd_stack_str);
1292 cmd.type = CMD_SAVECMDGRP;
1293 cmd_stack.push_back(cmd);
1294 }
1295 save = strchr(save, '\n');
1296 if (save != 0) save++;
1297 }
1298 ChangeScript(save_scn, 0);
1299 script = script_start + save_point;
1300 return;
1301 }
1302 void Scn2k::SetSkipMode(SkipMode mode) {
1303 if (skip_mode != mode) {
1304 skip_mode = mode;
1305 text_exec.SetSkipMode(mode);
1306 grp_exec.SetSkipMode(mode);
1307 }
1308 }
1309
1310 /***********************************************************
1311 **
1312 ** DLL Call Implementation
1313 **
1314 **/
1315 static double* lb_ef_param = 0;
1316 void DLLCall_LB_EF00_0(Cmd& cmd, Flags& flags) { // エフェクトの設定
1317 if (lb_ef_param == 0) {
1318 lb_ef_param = new double[sizeof(double) * 0x60 * 8];
1319 }
1320 int i,j;
1321 int param_top, param_size;
1322 if (cmd.args[2].value == 1) {
1323 param_top = 0;
1324 param_size = 0x20;
1325 } else {
1326 param_top = cmd.args[3].value;
1327 param_size = cmd.args[4].value;
1328 if (param_top < 0) param_top = 0;
1329 if (param_top > 0x20) param_top = 0x20;
1330 if (param_size+param_top > 0x20) param_size = 0x20 - param_top;
1331 }
1332 for (i=0; i<8; i++) {
1333 double* param = lb_ef_param + i*0x60 + param_top*3;
1334 for (j=0; j<param_size; j++) {
1335 *param++ = random() % 800 - 400;
1336 *param++ = random() % 600 - 300;
1337 *param++ = random() % 700 - 350;
1338 }
1339 }
1340 if (cmd.args[5].value != 1) return;
1341 static int random_dirtable[] = {
1342 0, 2, 1, 3, 0, 2, 1, 3,
1343 1, 3, 2, 0, 1, 3, 2, 0,
1344 0, 0, 0, 0, 3, 1, 2, 0,
1345 3, 1, 3, 1, 0, 2, 3, 1
1346 };
1347 int* dir = &random_dirtable[(random()&3) * 8];
1348 for (i=0; i<8; i++) {
1349 double* param = lb_ef_param + i*0x60;
1350 double x = random()%600 - 300;
1351 double y = random()%480-240;
1352 if (x < 0) x -= 80;
1353 else x += 80;
1354 if (y < 0) y -= 80;
1355 else y += 80;
1356 switch(*dir++) {
1357 case 0:
1358 if (x < 0) x = -x;
1359 if (y < 0) y = -y;
1360 break;
1361 case 1:
1362 if (x > 0) x = -x;
1363 if (y < 0) y = -y;
1364 break;
1365 case 2:
1366 if (x < 0) x = -x;
1367 if (y > 0) y = -y;
1368 break;
1369 case 4:
1370 if (x > 0) x = -x;
1371 if (y > 0) y = -y;
1372 break;
1373 }
1374 param[9] = x*1.2;
1375 param[10] = y*1.2;
1376 param[11] *= 1.2;
1377 param[12] *= -0.08;
1378 param[13] *= -0.08;
1379 param[14] *= -0.08;
1380 param[15] = -param[9];
1381 param[16] = -param[10];
1382 param[17] = -param[11];
1383 }
1384 return;
1385 }
1386 void DLLCall_LB_EF00_1(Cmd& cmd, Flags& flags) { // 計算を行う
1387 if (lb_ef_param == 0) {
1388 fprintf(stderr,"Warning : DLLCall_LB_EF00_1 : Script error : effect calculation was called before setting\n");
1389 return;
1390 }
1391 int index = cmd.args[2].value;
1392 int v5_1154 = flags.Get(5, 1154+index);
1393 int j = ((v5_1154) & 0x1f) + index * 0x20;
1394 int k = ((v5_1154+1) & 0x1f) + index * 0x20;
1395 int l = ((v5_1154+2) & 0x1f) + index * 0x20;
1396 int m = ((v5_1154+3) & 0x1f) + index * 0x20;
1397 j *= 3;
1398 k *= 3;
1399 l *= 3;
1400 m *= 3;
1401
1402 // 0 < x < 1
1403 // va - vd は 0-1 の範囲で対称性を持つ3次関数
1404 double x = double(flags.Get(5, 1162 + index)) * 0.001;
1405 double va = (x * x * x)/6;
1406 double vb = (-x*x*x + 3*x*x - 3*x + 1) / 6;
1407 double vc = (3*x*x*x - 6*x*x + 4) / 6;
1408 double vd = (-3*x*x*x+3*x*x+3*x+1) / 6;
1409
1410 double r1 = va * lb_ef_param[m+3] + vd * lb_ef_param[l+3] + vc * lb_ef_param[k+3] + vb * lb_ef_param[j+3];
1411 double r2 = va * lb_ef_param[m+2] + vd * lb_ef_param[l+2] + vc * lb_ef_param[k+2] + vb * lb_ef_param[j+2];
1412 double r3 = va * lb_ef_param[m+1] + vd * lb_ef_param[l+1] + vc * lb_ef_param[k+1] + vb * lb_ef_param[j+1];
1413 if (r1 != 400) {
1414 r2 = r2 * 800 / (400-r1);
1415 r3 = r3 * 700 / (400-r1);
1416 }
1417 VarInfo var;
1418 var.type = 5;
1419 var.number = 1151;
1420 flags.Set(var, int(r2));
1421 var.number = 1152;
1422 flags.Set(var, int(r3));
1423 var.number = 1153;
1424 flags.Set(var, int(r1));
1425 return;
1426 }
1427
1428
1429 void DllCall_LB(Cmd& cmd, Flags& flags) { // リトルバスターズ!の EF00.dll をエミュレート
1430 if (cmd.args[0].value == 1) {
1431 // "EF00.dll"
1432 if (cmd.args[1].value == 0) { // エフェクトの設定
1433 DLLCall_LB_EF00_0(cmd, flags);
1434 } else if (cmd.args[1].value == 1) { // 計算を行う
1435 DLLCall_LB_EF00_1(cmd, flags);
1436 }
1437 } else {
1438 fprintf(stderr,"Unsupported DLL call for DLL<%d>\n",cmd.args[0].value);
1439 }
1440 return;
1441 }
1442
1443 /**********************************************************
1444 **
1445 ** MenuImpl
1446 **
1447 */
1448
1449 #include"window/widget.h"
1450 #include"window/menuitem.h"
1451
1452 void DSurfaceFill(Surface* src, const Rect& rect, int r, int g, int b, int a = 0xff);
1453
1454 struct Scn2kMenuImpl {
1455 Scn2kMenu& interface;
1456 MenuItem* menu;
1457 Event::Container* pevent;
1458 PicContainer* pparent;
1459
1460 virtual void InitPanel(Event::Container& event, PicContainer& parent) = 0;
1461 virtual void InitTitle(const SaveTitle&) = 0;
1462 virtual void Cancel(void) = 0;
1463 virtual void Exec(Cmd& cmd) = 0;
1464 Scn2kMenuImpl(Scn2kMenu& _interface) : interface(_interface) {
1465 menu = 0;
1466 pevent = 0;
1467 pparent = 0;
1468 }
1469 virtual ~Scn2kMenuImpl() {
1470 if (menu) delete menu;
1471 menu = 0;
1472 }
1473 };
1474
1475 struct LoadMenu : Scn2kMenuImpl {
1476 vector<string> title;
1477 vector<int> title_valid;
1478 RadioButton* btn_local;
1479 RadioButton* btn_page;
1480 RadioButton* btn_set;
1481 Scale* btn_scale;
1482 Dialog* awk_dialog;
1483 int btn_page_val, btn_set_val, btn_local_val, select_page, select_value;
1484 LoadMenu(Scn2kMenu& _interface);
1485 ~LoadMenu();
1486 void InitPanel(Event::Container& event, PicContainer& parent);
1487 void InitTitle(const SaveTitle&);
1488 void Cancel(void);
1489 void Exec(Cmd& cmd);
1490 static void ChangeBtnPage(void* pointer, MenuItem* widget);
1491 static void ChangeBtnLocal(void* pointer, MenuItem* widget);
1492 static void ChangeBtnScale(void* pointer, Scale* widget);
1493 static void ChangeBtnSet(void* pointer, MenuItem* widget);
1494 static void ChangeDialog(void* pointer, Dialog* widget);
1495 bool in_setpage;
1496 void SetPage(int new_page);
1497 void SetValue(int new_value);
1498 void PressOk(void);
1499 };
1500 LoadMenu::LoadMenu(Scn2kMenu& _interface) : Scn2kMenuImpl(_interface) {
1501 btn_local = 0;
1502 btn_scale = 0;
1503 btn_set = 0;
1504 btn_page_val = 0;
1505 btn_set_val = -1;
1506 btn_local_val = -1;
1507 awk_dialog = 0;
1508 in_setpage = false;
1509 select_page = 0;
1510 select_value = -1;
1511 }
1512 LoadMenu::~LoadMenu() {
1513 if (awk_dialog) delete awk_dialog;
1514 }
1515 void LoadMenu::InitPanel(Event::Container& event, PicContainer& parent) {
1516 pevent = &event;
1517 pparent = &parent;
1518
1519 if (menu) delete menu;
1520 menu = 0;
1521 menu = new MenuItem(&parent, Rect(80,30,560, 450), 1, 3, 0);
1522 Surface* surface = parent.Root().NewSurface(menu->Pic()->Width(), menu->Pic()->Height(), ALPHA_MASK);
1523 if (interface.type == Scn2kMenu::MENU_LOAD) {
1524 menu->SetLabelTop(new Label(menu->PicNode(), Rect(0,0), true, "Load", 26), Rect(0,0,10,0), Rect(0,0,0,20));
1525 DSurfaceFill(surface, Rect(*surface), 0, 0, 0x80, 0x80);
1526 } else {
1527 menu->SetLabelTop(new Label(menu->PicNode(), Rect(0,0), true, "Save", 26), Rect(0,0,10,0), Rect(0,0,0,20));
1528 DSurfaceFill(surface, Rect(*surface), 0, 0x80, 0, 0x80);
1529 }
1530 menu->Pic()->SetSurface(surface, 0, 0);
1531 menu->Pic()->SetSurfaceFreeFlag();
1532
1533 btn_page = new RadioButton(event, menu->PicNode(), Rect(0, 0, 480, 40), 10, 1, &btn_page_val,
1534 Rect(0,0,0,0), 18, Color(0,0,0),Color(0xff,0,0),Color(0xff,0x80,0));
1535 btn_page->set_func = &ChangeBtnPage;
1536 btn_page->set_pointer = this;
1537 btn_page->SetLabelLeft(new Label(btn_page->PicNode(), Rect(0,0), true, "Page", 18), Rect(0, 0, 180, 0), Rect(0,0));
1538 btn_page->Add(" 1 ");
1539 btn_page->Add(" 2 ");
1540 btn_page->Add(" 3 ");
1541 btn_page->Add(" 4 ");
1542 btn_page->Add(" 5 ");
1543 btn_page->Add(" 6 ");
1544 btn_page->Add(" 7 ");
1545 btn_page->Add(" 8 ");
1546 btn_page->Add(" 9 ");
1547 btn_page->Add(" 10 ");
1548 btn_page->pack();
1549 /*
1550 surface = parent.Root().NewSurface(btn_page->Pic()->Width(), btn_page->Pic()->Height(), ALPHA_MASK);
1551 DSurfaceFill(surface, Rect(*surface), 0xff, 0, 0, 0x80);
1552 btn_page->Pic()->SetSurface(surface, 0, 0);
1553 btn_page->Pic()->SetSurfaceFreeFlag();
1554 */
1555 menu->item[0] = btn_page;
1556 btn_set = new RadioButton(event, menu->PicNode(), Rect(0, 0, 480, 40), 2, 1, &btn_set_val,
1557 Rect(0,0,0,0), 18, Color(0,0,0),Color(0xff,0,0),Color(0xff,0x80,0));
1558 btn_set->set_func = &ChangeBtnSet;
1559 btn_set->set_pointer = this;
1560 btn_set->SetLabelLeft(new Label(btn_set->PicNode(), Rect(0,0)), Rect(0,0,200,0), Rect(0,0));
1561 if (interface.type == Scn2kMenu::MENU_LOAD) {
1562 btn_set->Add(" Load ");
1563 } else {
1564 btn_set->Add(" Save ");
1565 }
1566 btn_set->Add(" Cancel ");
1567 btn_set->pack();
1568 /*
1569 surface = parent.Root().NewSurface(btn_set->Pic()->Width(), btn_set->Pic()->Height(), ALPHA_MASK);
1570 DSurfaceFill(surface, Rect(*surface), 0, 0, 0xff, 0x80);
1571 btn_set->Pic()->SetSurface(surface, 0, 0);
1572 btn_set->Pic()->SetSurfaceFreeFlag();
1573 */
1574 menu->item[2] = btn_set;
1575 // void btn_set_press(void* pointer, MenuItem* widget);
1576 // btn_set->set_func = btn_set_press;
1577 // btn_set->set_pointer = this;
1578 btn_local = new RadioButton(*pevent, menu->PicNode(), Rect(0, 0, 480, 300), 1, 100, &btn_local_val,
1579 Rect(0,0,300,30), 18, Color(0,0,0),Color(0xff,0,0),Color(0xff,0x80,0));
1580 btn_local->set_func = &ChangeBtnLocal;
1581 btn_local->set_pointer = this;
1582 /*
1583 surface = pparent->Root().NewSurface(btn_local->Pic()->Width(), btn_local->Pic()->Height(), ALPHA_MASK);
1584 DSurfaceFill(surface, Rect(*surface), 0, 0xff, 0, 0x80);
1585 btn_local->Pic()->SetSurface(surface, 0, 0);
1586 btn_local->Pic()->SetSurfaceFreeFlag();
1587 */
1588 menu->item[1] = btn_local;
1589 int i;
1590 for (i=0; i<12; i++)
1591 btn_local->Add("",false);
1592 btn_local->pack();
1593 btn_local->show_all();
1594 menu->pack();
1595
1596 PicBase* local_pic = btn_local->Pic();
1597 int local_x2 = local_pic->PosX() + local_pic->Width();
1598 int local_y2 = local_pic->PosY() + local_pic->Height();
1599 btn_scale = new Scale(*pevent, menu->PicNode(), Rect(local_x2-16, local_pic->PosY(), local_x2, local_y2), Color(0xff, 0x80, 0), true);
1600 btn_scale->SetRange(0, 900);
1601 btn_scale->InitCursor(1024/10);
1602 btn_scale->SetValue(0);
1603 btn_scale->change_func = &ChangeBtnScale;
1604 btn_scale->change_pointer = this;
1605
1606 menu->PicNode()->show_all();
1607 }
1608
1609 void LoadMenu::InitTitle(const SaveTitle& title_op) {
1610 title.clear();
1611 int i;
1612 for (i=1; i<=100; i++) {
1613 char buf[100];
1614 sprintf(buf,"%2d:",i);
1615 string t = title_op(i);
1616 string s = string(buf) + t;
1617 if (t.length() == 0) {
1618 string s = string(buf) + "--------";
1619 title_valid.push_back(0);
1620 } else {
1621 title_valid.push_back(1);
1622 }
1623 title.push_back(s);
1624 }
1625 if (btn_local==0) return;
1626 for (i=0; i<10; i++) {
1627 TextButton* button = dynamic_cast<TextButton*>(btn_local->item[i]);
1628 if (button) button->SetText(title[i].c_str());
1629 }
1630 }
1631
1632 void LoadMenu::SetPage(int new_page) {
1633 if (new_page < 0) new_page = 0;
1634 if (new_page > 900) new_page = 900;
1635 if (select_page == new_page) return;
1636 if (in_setpage) return;
1637 in_setpage = true;
1638
1639 int prev_page = select_page / 10;
1640 int cur_page = new_page / 10;
1641 int prev_point = select_page%10;
1642 int new_point = new_page%10;
1643 select_page = new_page;
1644 if (prev_page != cur_page) {
1645 int i;
1646 for (i=0; i<12; i++) {
1647 TextButton* button = dynamic_cast<TextButton*>(btn_local->item[i]);
1648 if (button) {
1649 if (cur_page+i < title.size()) button->SetText(title[cur_page+i].c_str());
1650 else button->SetText("----");
1651 }
1652 }
1653 // ボタンの内容を変更する
1654 if (select_value < cur_page || select_value > cur_page+12)
1655 btn_local->SetValue(-1);
1656 else
1657 btn_local->SetValue(select_value - cur_page);
1658 }
1659 if (prev_point != new_point) {
1660 int i;
1661 for (i=0; i<12; i++) {
1662 int old_x = btn_local->item[i]->Pic()->PosX();
1663 btn_local->item[i]->Pic()->Move(old_x, i*30-new_point*3);
1664 }
1665 }
1666 if (btn_page) {
1667 if (select_page%100 == 0) btn_page->SetValue(select_page/100);
1668 else btn_page->SetValue(-1);
1669 }
1670 if (btn_scale) {
1671 btn_scale->SetValue(select_page);
1672 }
1673 in_setpage = false;
1674 return;
1675 }
1676 void LoadMenu::SetValue(int new_value) {
1677 if (in_setpage) return;
1678 in_setpage = true;
1679
1680 if (new_value < 0 || new_value > title.size() ||
1681 (interface.type == Scn2kMenu::MENU_LOAD && title_valid[new_value] == 0) ) { // 無効な選択肢
1682 if (select_value < select_page/10 || select_value > select_page/10+12)
1683 btn_local->SetValue(-1);
1684 else
1685 btn_local->SetValue(select_value-select_page/10);
1686 } else { // 選択肢を変更する
1687 if (select_value == new_value) {
1688 PressOk(); // ダブルクリック
1689 } else {
1690 select_value = new_value;
1691 if (interface.type == Scn2kMenu::MENU_SAVE && title_valid[select_value] == 0) {
1692 PressOk(); // 新しいセーブデータなら無条件に選択
1693 }
1694 }
1695 }
1696
1697 in_setpage = false;
1698 return;
1699 }
1700 void LoadMenu::PressOk(void) {
1701 if (select_value == -1) {
1702 btn_set->SetValue(-1); // なにもしない
1703 return;
1704 }
1705 menu->deactivate();
1706 if (interface.type == Scn2kMenu::MENU_LOAD) {
1707 interface.cmd.cmd_type = CMD_LOAD;
1708 interface.cmd.args.push_back(VarInfo(select_value));
1709 awk_dialog = new Dialog(*pevent, pparent, "ファイルをロードしますか?", true);
1710 awk_dialog->set_pointer = this;
1711 awk_dialog->set_func = ChangeDialog;
1712 } else {// MENU_SAVE
1713 interface.cmd.cmd_type = CMD_SAVE;
1714 interface.cmd.args.push_back(VarInfo(select_value));
1715 if (title_valid[select_value] == 0) { // 新しいセーブデータ
1716 interface.status = Scn2kMenu::MenuStatus(Scn2kMenu::MENU_CMD | Scn2kMenu::MENU_DELETE);
1717 } else { // セーブデータを上書き:確認
1718 awk_dialog = new Dialog(*pevent, pparent, "データを上書きしますか?", true);
1719 awk_dialog->set_pointer = this;
1720 awk_dialog->set_func = ChangeDialog;
1721 }
1722 }
1723 }
1724 void LoadMenu::Cancel(void) {
1725 if (awk_dialog) { // ダイアログのキャンセル
1726 awk_dialog->status = Dialog::CANCEL;
1727 ChangeDialog(this, awk_dialog);
1728 } else { // 一般キャンセル
1729 btn_set->SetValue(1);
1730 }
1731 }
1732 void LoadMenu::Exec(Cmd& cmd) {
1733 }
1734 void LoadMenu::ChangeBtnPage(void* pointer, MenuItem* widget) {
1735 LoadMenu* instance = (LoadMenu*)pointer;
1736 if (instance->btn_page_val == -1) return;
1737 instance->SetPage(instance->btn_page_val*100);
1738 }
1739 void LoadMenu::ChangeBtnScale(void* pointer, Scale* from) {
1740 LoadMenu* instance = (LoadMenu*)pointer;
1741 int value = from->GetValue();
1742 instance->SetPage(value);
1743 }
1744 void LoadMenu::ChangeBtnSet(void* pointer, MenuItem* widget) {
1745 LoadMenu* instance = (LoadMenu*)pointer;
1746 if (instance->btn_set_val == 1) { // cancel
1747 instance->interface.status = Scn2kMenu::MENU_DELETE;
1748 return;
1749 } else if (instance->btn_set_val == 0) { // OK
1750 instance->PressOk();
1751 }
1752 }
1753 void LoadMenu::ChangeDialog(void* pointer, Dialog* widget) {
1754 LoadMenu* instance = (LoadMenu*)pointer;
1755 if (widget->status == Dialog::CANCEL) {
1756 // ダイアログ消去、OK ボタン復帰
1757 delete instance->awk_dialog;
1758 instance->awk_dialog = 0;
1759 instance->menu->activate();
1760 instance->btn_set->SetValue(-1);
1761 return;
1762 } else if (widget->status == Dialog::OK) {
1763 instance->interface.status = Scn2kMenu::MenuStatus(Scn2kMenu::MENU_CMD | Scn2kMenu::MENU_DELETE);
1764 return;
1765 }
1766 }
1767 void LoadMenu::ChangeBtnLocal(void* pointer, MenuItem* widget) {
1768 LoadMenu* instance = (LoadMenu*)pointer;
1769 if (instance->btn_local_val == -1) return;
1770 instance->SetValue( (instance->select_page/10) + instance->btn_local_val);
1771 }
1772
1773 struct BacklogMenu : Scn2kMenuImpl {
1774 Scn2k& scn_impl;
1775 Text& text_exec;
1776 bool backlog_update;
1777 int backlog_cnt;
1778 BacklogMenu(Scn2kMenu& _interface, Scn2k& scn_impl, Text& text_exec);
1779 ~BacklogMenu();
1780 void InitPanel(Event::Container& event, PicContainer& parent);
1781 void InitTitle(const SaveTitle&);
1782 void Cancel(void);
1783 void Exec(Cmd& cmd);
1784 };
1785 BacklogMenu::BacklogMenu(Scn2kMenu& _interface, Scn2k& _scn, Text& parent_text_exec) : Scn2kMenuImpl(_interface), scn_impl(_scn), text_exec(parent_text_exec) {
1786 backlog_cnt = -1;
1787 backlog_update = false;
1788 }
1789 BacklogMenu::~BacklogMenu() {
1790 }
1791 void BacklogMenu::InitPanel(Event::Container& event, PicContainer& parent) {
1792 pevent = &event;
1793 }
1794
1795 void BacklogMenu::InitTitle(const SaveTitle& title_op) {
1796 }
1797 void BacklogMenu::Cancel(void) {
1798 interface.status = Scn2kMenu::MenuStatus(Scn2kMenu::MENU_DELETE);
1799 }
1800 void BacklogMenu::Exec(Cmd& cmd) {
1801 int command_direction = 0; // forward
1802 if (cmd.cmd_type == CMD_NOP) text_exec.Wait(0xffffffffUL, cmd);
1803 if (cmd.cmd_type == CMD_BACKLOGREQ || pevent->presscount(MOUSE_UP)) {
1804 if (cmd.cmd_type == CMD_BACKLOGREQ) cmd.clear();
1805 backlog_cnt++;
1806 backlog_update = false;
1807 command_direction = 1;
1808 }
1809 if (cmd.cmd_type == CMD_BACKLOGREQ_FWD || pevent->presscount(MOUSE_DOWN)) {
1810 if (cmd.cmd_type == CMD_BACKLOGREQ_FWD) cmd.clear();
1811 backlog_cnt--;
1812 backlog_update = false;
1813 if (backlog_cnt == -2 || (
1814 (backlog_cnt == -1 && text_exec.backlog_item.scn == -1 && text_exec.backlog_item.pos == -1)) ){
1815 Cancel();
1816 return;
1817 }
1818 command_direction = -1;
1819 }
1820 if (cmd.cmd_type != CMD_NOP) return;
1821 if (backlog_update) return;
1822 // backlog を最新の状態に更新
1823 cmd.clear();
1824 BacklogItem item;
1825
1826 retry:
1827 if (backlog_cnt < -1) backlog_cnt = -1;
1828 if (backlog_cnt >= int(text_exec.backlog.size())) backlog_cnt = text_exec.backlog.size() - 1;
1829
1830 if (backlog_cnt == -1) {
1831 if (text_exec.backlog_item.scn == -1 && text_exec.backlog_item.pos == -1) {
1832 if (text_exec.backlog.size() == 0 || command_direction < 0) {
1833 Cancel();
1834 return;
1835 }
1836 item = text_exec.backlog.back();
1837 backlog_cnt = 0;
1838 } else {
1839 // item = text_exec.backlog.back();
1840 item = text_exec.backlog_item;
1841 }
1842 } else {
1843 item = text_exec.backlog[text_exec.backlog.size()-1-backlog_cnt];
1844 }
1845 if (item.scn == BacklogItem::SaveSelect) { // select marker ; skip this item
1846 if (command_direction == 0) command_direction = 1;
1847 backlog_cnt += command_direction;
1848 goto retry;
1849 }
1850 if (item.scn == 0 && item.pos == -1) ; // not read cmd
1851 else {
1852 scn_impl.ReadCmdAt(cmd, item.scn, item.pos);
1853 }
1854 text_exec.DrawBacklog(item, cmd);
1855 cmd.clear();
1856 backlog_update = true;
1857 }
1858
1859 /*******************************************************************************
1860 **
1861 **
1862 */
1863
1864 Scn2kMenu::Scn2kMenu(MenuType _type, Scn2k& scn_impl, const Flags& flags, Text& text_exec, int system_version) :
1865 cmd(flags, system_version), type(_type) {
1866 pimpl = 0;
1867 status = MENU_CONTINUE;
1868 switch(type) {
1869 case MENU_LOAD: pimpl = new LoadMenu(*this); break;
1870 case MENU_SAVE: pimpl = new LoadMenu(*this); break;
1871 case MENU_BACKLOG: pimpl = new BacklogMenu(*this, scn_impl, text_exec); break;
1872 }
1873 return;
1874 }
1875 Scn2kMenu::~Scn2kMenu() {
1876 if (pimpl) delete pimpl;
1877 pimpl = 0;
1878 }
1879 void Scn2kMenu::InitPanel(Event::Container& event, PicContainer& parent) {
1880 if (pimpl) pimpl->InitPanel(event, parent);
1881 }
1882 void Scn2kMenu::InitTitle(const SaveTitle& t) {
1883 if (pimpl) pimpl->InitTitle(t);
1884 }
1885 void Scn2kMenu::Cancel(void) {
1886 if (pimpl) pimpl->Cancel();
1887 }
1888 void Scn2kMenu::Exec(Cmd& ret_cmd) {
1889 if (pimpl == 0) return;
1890 pimpl->Exec(ret_cmd);
1891 if (pimpl->pevent->presscount(MOUSE_RIGHT)) {
1892 Cancel();
1893 }
1894 if (status & MENU_CMD && cmd.cmd_type != CMD_NOP) {
1895 status = Scn2kMenu::MenuStatus(status & (~Scn2kMenu::MENU_CMD) );
1896 CmdSimplified tmp_cmd;
1897 char cmd_str[32768];
1898 char* tmp_cmd_str = cmd_str;
1899 cmd.write(tmp_cmd, tmp_cmd_str);
1900 ret_cmd.read(tmp_cmd);
1901 }
1902 }
1903 void Scn2kMenu::activate(void) {
1904 if (pimpl && pimpl->menu) pimpl->menu->activate();
1905 }
1906 void Scn2kMenu::deactivate(void) {
1907 if (pimpl && pimpl->menu) pimpl->menu->deactivate();
1908 }
1909