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