Mercurial > otakunoraifu
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 |