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