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