• R/O
  • SSH
  • HTTPS

marathon: コミット


コミットメタ情報

リビジョン505 (tree)
日時2011-11-29 00:09:10
作者logue

ログメッセージ

r4647とマージ
・metaserver_dialogs.cppのダメ文字を修正。

変更サマリ

差分

--- marathon/trunk/Source_Files/shell.cpp (revision 504)
+++ marathon/trunk/Source_Files/shell.cpp (revision 505)
@@ -140,9 +140,18 @@
140140 char application_identifier[] = "org.bungie.source.AlephOne";
141141 #endif
142142
143+#if defined(HAVE_BUNDLE_NAME)
144+// legacy bundle path
145+static const char sBundlePlaceholder[] = "AlephOneSDL.app/Contents/Resources/DataFiles";
146+#endif
147+
143148 // Data directories
144149 vector <DirectorySpecifier> data_search_path; // List of directories in which data files are searched for
145150 DirectorySpecifier local_data_dir; // Local (per-user) data file directory
151+DirectorySpecifier default_data_dir; // Default scenario directory
152+#if defined(HAVE_BUNDLE_NAME)
153+DirectorySpecifier bundle_data_dir; // Data inside Mac OS X app bundle
154+#endif
146155 DirectorySpecifier preferences_dir; // Directory for preferences
147156 DirectorySpecifier saved_games_dir; // Directory for saved games
148157 DirectorySpecifier recordings_dir; // Directory for recordings (except film buffer, which is stored in local_data_dir)
@@ -191,31 +200,31 @@
191200
192201 static void usage(const char *prg_name)
193202 {
194-#ifdef __WIN32__
195- MessageBox(NULL, "コマンドラインスイッチ:\n\n"
196-#else
197- printf("\n使用方法:%s [オプション] [ディレクトリ] [ファイル]\n"
198-#endif
199- "\t[-h | --help] このヘルプメッセージを表\示します。\n"
200- "\t[-v | --version] ゲームのバージョンを表\示します。\n"
201- "\t[-d | --debug] コアダンプを出力するようにします。\n"
202- "\t (SDL parachuteを無効化します)\n"
203- "\t[-f | --fullscreen] ゲームをフルスクリーンで起動します。\n"
204- "\t[-w | --windowed] ゲームをウィンドウモードで起動します。\n"
205-#ifdef HAVE_OPENGL
206- "\t[-g | --nogl] OpenGLを使用せずに起動します。\n"
207-#endif
208- "\t[-s | --nosound] サウンドを無効化します。\n"
209- "\t[-m | --nogamma] ガンマエフェクトを無効化します。\n"
210- "\t (メニューのフェードなど)\n"
211- "\t[-j | --nojoystick] ジョイスティックの初期化を行いません。\n"
212- // Documenting this might be a bad idea?
213- // "\t[-i | --insecure_lua] Allow Lua netscripts to take over your computer\n"
214- "\tディレクトリ データーが含まれているディレクトリ\n"
215- "\tファイル 保存されたゲームやフィルムの再生\n"
216- "\nこの他にも、環境変数「ALEPHONE_DATA」の値を変更することで、\n"
217- "データディレクトリを指定することができます。\n"
218-#ifdef __WIN32__
203+#ifdef __WIN32__
204+ MessageBox(NULL, "コマンドラインスイッチ:\n\n"
205+#else
206+ printf("\n使用方法:%s [オプション] [ディレクトリ] [ファイル]\n"
207+#endif
208+ "\t[-h | --help] このヘルプメッセージを表\示します。\n"
209+ "\t[-v | --version] ゲームのバージョンを表\示します。\n"
210+ "\t[-d | --debug] コアダンプを出力するようにします。\n"
211+ "\t (SDL parachuteを無効化します)\n"
212+ "\t[-f | --fullscreen] ゲームをフルスクリーンで起動します。\n"
213+ "\t[-w | --windowed] ゲームをウィンドウモードで起動します。\n"
214+#ifdef HAVE_OPENGL
215+ "\t[-g | --nogl] OpenGLを使用せずに起動します。\n"
216+#endif
217+ "\t[-s | --nosound] サウンドを無効化します。\n"
218+ "\t[-m | --nogamma] ガンマエフェクトを無効化します。\n"
219+ "\t (メニューのフェードなど)\n"
220+ "\t[-j | --nojoystick] ジョイスティックの初期化を行いません。\n"
221+ // Documenting this might be a bad idea?
222+ // "\t[-i | --insecure_lua] Allow Lua netscripts to take over your computer\n"
223+ "\tディレクトリ データーが含まれているディレクトリ\n"
224+ "\tファイル 保存されたゲームやフィルムの再生\n"
225+ "\nこの他にも、環境変数「ALEPHONE_DATA」の値を変更することで、\n"
226+ "データディレクトリを指定することができます。\n"
227+#ifdef __WIN32__
219228 , "使用方法", MB_OK | MB_ICONINFORMATION
220229 #else
221230 , prg_name
@@ -270,28 +279,28 @@
270279 char app_name_version[256];
271280 expand_app_variables(app_name_version, "Aleph One JP $appLongVersion$");
272281 printf ("%s\n%s\n\n"
273- "オリジナルのコードは、Bungie Software <http://www.bungie.com/>によるものです。\n"
274- "この他にLoren Petrich, Chris Pruett, Rhys Hill氏らによって書かれています。\n"
275- "TCP/IP ネットワーク by Woody Zenfell\n"
276- "Expat XMLライブラリ by James Clark\n"
277- "SDLポート by Christian Bauer <Christian.Bauer@uni-mainz.de>\n"
278- "日本語化 by saiten <http://www.isidesystem.net/>, ookawa_mi, Logue <http://logue.be/>, marathon.\n"
279-#if defined(__MACH__) && defined(__APPLE__)
280- "Mac OS X/SDLバージョンは、Chris Lovell, Alexander Strange, and Woody Zenfell氏らによって作られました。\n"
281-#endif
282- "\nこのプログラムは有用であることを願って頒布されますが、*全くの無保証 *です。\n"
283- "商業可能\性の保証や特定目的への適合性は、言外に示されたものも 含め、全く存在しません。\n"
284- "詳しくはGNU 一般公衆利用許諾書をご覧ください。\n"
285-#if defined(__BEOS__) || defined(__WIN32__)
286- // BeOS and Windows are statically linked against SDL, so we have to include this:
287- "\nSimple DirectMedia Layer (SDL) ライブラリは、\n"
288- "GNU 一般公衆利用許諾書によってライセンスされています。\n"
289- "詳細については、COPYING.SDLを参考にしてください。\n"
290-#endif
291-#ifdef HAVE_SDL_NET
292- "\nこのビルドは、ネットワークプレイが有効です。\n"
293-#endif
294-#ifdef HAVE_LUA
282+ "オリジナルのコードは、Bungie Software <http://www.bungie.com/>によるものです。\n"
283+ "この他にLoren Petrich, Chris Pruett, Rhys Hill氏らによって書かれています。\n"
284+ "TCP/IP ネットワーク by Woody Zenfell\n"
285+ "Expat XMLライブラリ by James Clark\n"
286+ "SDLポート by Christian Bauer <Christian.Bauer@uni-mainz.de>\n"
287+ "日本語化 by saiten <http://www.isidesystem.net/>, ookawa_mi, Logue <http://logue.be/>, marathon.\n"
288+#if defined(__MACH__) && defined(__APPLE__)
289+ "Mac OS X/SDLバージョンは、Chris Lovell, Alexander Strange, and Woody Zenfell氏らによって作られました。\n"
290+#endif
291+ "\nこのプログラムは有用であることを願って頒布されますが、*全くの無保証 *です。\n"
292+ "商業可能\性の保証や特定目的への適合性は、言外に示されたものも 含め、全く存在しません。\n"
293+ "詳しくはGNU 一般公衆利用許諾書をご覧ください。\n"
294+#if defined(__BEOS__) || defined(__WIN32__)
295+ // BeOS and Windows are statically linked against SDL, so we have to include this:
296+ "\nSimple DirectMedia Layer (SDL) ライブラリは、\n"
297+ "GNU 一般公衆利用許諾書によってライセンスされています。\n"
298+ "詳細については、COPYING.SDLを参考にしてください。\n"
299+#endif
300+#ifdef HAVE_SDL_NET
301+ "\nこのビルドは、ネットワークプレイが有効です。\n"
302+#endif
303+#ifdef HAVE_LUA
295304 "\nこのビルドは、Luaスクリプトが有効です。\n"
296305 #endif
297306 , app_name_version, A1_HOMEPAGE_URL
@@ -362,15 +371,15 @@
362371 } catch (exception &e) {
363372 try
364373 {
365- logFatal("捕捉されなかった例外が発生しました:%s", e.what());
366- }
367- catch (...)
368- {
369- }
370- exit(1);
371- } catch (...) {
372- try
373- {
374+ logFatal("捕捉されなかった例外が発生しました:%s", e.what());
375+ }
376+ catch (...)
377+ {
378+ }
379+ exit(1);
380+ } catch (...) {
381+ try
382+ {
374383 logFatal("例外が発生しました。");
375384 }
376385 catch (...)
@@ -389,7 +398,6 @@
389398 #endif
390399
391400 // Find data directories, construct search path
392- DirectorySpecifier default_data_dir;
393401
394402 #if defined(unix) || defined(__NetBSD__) || defined(__OpenBSD__) || (defined(__APPLE__) && defined(__MACH__) && !defined(HAVE_BUNDLE_NAME))
395403
@@ -401,7 +409,7 @@
401409 log_dir = local_data_dir;
402410
403411 #elif defined(__APPLE__) && defined(__MACH__)
404- DirectorySpecifier bundle_data_dir = bundle_resource_path;
412+ bundle_data_dir = bundle_resource_path;
405413 bundle_data_dir += "DataFiles";
406414
407415 data_search_path.push_back(bundle_data_dir);
@@ -612,18 +620,18 @@
612620 #ifdef HAVE_SDL_NET
613621 // Initialize SDL_net
614622 if (SDLNet_Init () < 0) {
615- fprintf (stderr, "SDL_netの初期化に失敗しました。(%s)\n", SDLNet_GetError());
616- exit(1);
617- }
618-#endif
619-
620-#ifdef HAVE_SDL_TTF
621- if (TTF_Init() < 0) {
622- fprintf (stderr, "SDL_ttfの初期化に失敗しました。(%s)\n", TTF_GetError());
623+ fprintf (stderr, "SDL_netの初期化に失敗しました。(%s)\n", SDLNet_GetError());
623624 exit(1);
624625 }
625626 #endif
626627
628+#ifdef HAVE_SDL_TTF
629+ if (TTF_Init() < 0) {
630+ fprintf (stderr, "SDL_ttfの初期化に失敗しました。(%s)\n", TTF_GetError());
631+ exit(1);
632+ }
633+#endif
634+
627635 // Initialize everything
628636 mytm_initialize();
629637 // initialize_fonts();
@@ -691,13 +699,13 @@
691699 {
692700 dialog d;
693701 vertical_placer *placer = new vertical_placer;
694- placer->dual_add (new w_static_text("本当にゲームを中断しても"), d);
695- placer->dual_add (new w_static_text("よろしいですか?"), d);
696- placer->add (new w_spacer(), true);
697-
698- horizontal_placer *button_placer = new horizontal_placer;
699- w_button *default_button = new w_button("はい", dialog_ok, &d);
700- button_placer->dual_add (default_button, d);
702+ placer->dual_add (new w_static_text("本当にゲームを中断しても"), d);
703+ placer->dual_add (new w_static_text("よろしいですか?"), d);
704+ placer->add (new w_spacer(), true);
705+
706+ horizontal_placer *button_placer = new horizontal_placer;
707+ w_button *default_button = new w_button("はい", dialog_ok, &d);
708+ button_placer->dual_add (default_button, d);
701709 button_placer->dual_add (new w_button("いいえ", dialog_cancel, &d), d);
702710 d.activate_widget(default_button);
703711 placer->add(button_placer, true);
@@ -744,23 +752,23 @@
744752
745753 } else {
746754 // no stringset or no strings in stringset - use default message
747- placer->dual_add(new w_static_text("ここからは、ヴィドマスターの宣誓を誓わないといけないぜ。"), d);
748-
749- placer->add(new w_spacer(), true);
750- placer->dual_add(new w_static_text("『宣誓、"), d);
751- placer->dual_add(new w_static_text("全てのスイッチをこぶしで殴ってオンにし、"), d);
752- placer->dual_add(new w_static_text("グレネードを使える場所でも決して発射せず、"), d);
753- placer->dual_add(new w_static_text("最高難易度「虐殺」以外で遊ばず、"), d);
754- placer->dual_add(new w_static_text("Caps Loockを「走る」キーとしては決して使わず、"), d);
755- placer->dual_add(new w_static_text("そして、一人残らずボブ市民を皆殺しにしま〜す。』"), d);
756- }
757-
758- placer->add(new w_spacer(), true);
759- placer->dual_add(new w_static_text("開始レベル:"), d);
760-
761- w_levels *level_w = new w_levels(levels, &d);
762- placer->dual_add(level_w, d);
763- placer->add(new w_spacer(), true);
755+ placer->dual_add(new w_static_text("ここからは、ヴィドマスターの宣誓を誓わないといけないぜ。"), d);
756+
757+ placer->add(new w_spacer(), true);
758+ placer->dual_add(new w_static_text("『宣誓、"), d);
759+ placer->dual_add(new w_static_text("全てのスイッチをこぶしで殴ってオンにし、"), d);
760+ placer->dual_add(new w_static_text("グレネードを使える場所でも決して発射せず、"), d);
761+ placer->dual_add(new w_static_text("最高難易度「虐殺」以外で遊ばず、"), d);
762+ placer->dual_add(new w_static_text("Caps Loockを「走る」キーとしては決して使わず、"), d);
763+ placer->dual_add(new w_static_text("そして、一人残らずボブ市民を皆殺しにしま〜す。』"), d);
764+ }
765+
766+ placer->add(new w_spacer(), true);
767+ placer->dual_add(new w_static_text("開始レベル:"), d);
768+
769+ w_levels *level_w = new w_levels(levels, &d);
770+ placer->dual_add(level_w, d);
771+ placer->add(new w_spacer(), true);
764772 placer->dual_add(new w_button("キャンセル", dialog_cancel, &d), d);
765773
766774 d.activate_widget(level_w);
@@ -929,10 +937,10 @@
929937 do_menu_item_command(mGame, iQuitGame, false);
930938 }
931939 else {
932-#if defined(__APPLE__) && defined(__MACH__)
933- screen_printf("終了したい場合は、コマンドキーを押しながらQを押してください。");
934-#else
935- screen_printf("終了したい場合は、Altキーを押しながらQを押してください。");
940+#if defined(__APPLE__) && defined(__MACH__)
941+ screen_printf("終了したい場合は、コマンドキーを押しながらQを押してください。");
942+#else
943+ screen_printf("終了したい場合は、Altキーを押しながらQを押してください。");
936944 #endif
937945 }
938946 }
@@ -1500,7 +1508,66 @@
15001508 }
15011509 }
15021510 }
1503-
1511+
1512+bool expand_symbolic_paths_helper(char *dest, const char *src, int maxlen, const char *symbol, DirectorySpecifier& dir)
1513+{
1514+ int symlen = strlen(symbol);
1515+ if (!strncmp(src, symbol, symlen))
1516+ {
1517+ strncpy(dest, dir.GetPath(), maxlen);
1518+ dest[maxlen] = '\0';
1519+ strncat(dest, &src[symlen], maxlen-strlen(dest));
1520+ return true;
1521+ }
1522+ return false;
1523+}
1524+
1525+char *expand_symbolic_paths(char *dest, const char *src, int maxlen)
1526+{
1527+ bool expanded =
1528+#if defined(HAVE_BUNDLE_NAME)
1529+ expand_symbolic_paths_helper(dest, src, maxlen, "$bundle$", bundle_data_dir) ||
1530+ expand_symbolic_paths_helper(dest, src, maxlen, sBundlePlaceholder, bundle_data_dir) ||
1531+#endif
1532+ expand_symbolic_paths_helper(dest, src, maxlen, "$local$", local_data_dir) ||
1533+ expand_symbolic_paths_helper(dest, src, maxlen, "$default$", default_data_dir);
1534+ if (!expanded)
1535+ {
1536+ strncpy(dest, src, maxlen);
1537+ dest[maxlen] = '\0';
1538+ }
1539+ return dest;
1540+}
1541+
1542+bool contract_symbolic_paths_helper(char *dest, const char *src, int maxlen, const char *symbol, DirectorySpecifier &dir)
1543+{
1544+ const char *dpath = dir.GetPath();
1545+ int dirlen = strlen(dpath);
1546+ if (!strncmp(src, dpath, dirlen))
1547+ {
1548+ strncpy(dest, symbol, maxlen);
1549+ dest[maxlen] = '\0';
1550+ strncat(dest, &src[dirlen], maxlen-strlen(dest));
1551+ return true;
1552+ }
1553+ return false;
1554+}
1555+
1556+char *contract_symbolic_paths(char *dest, const char *src, int maxlen)
1557+{
1558+ bool contracted =
1559+#if defined(HAVE_BUNDLE_NAME)
1560+ contract_symbolic_paths_helper(dest, src, maxlen, "$bundle$", bundle_data_dir) ||
1561+#endif
1562+ contract_symbolic_paths_helper(dest, src, maxlen, "$local$", local_data_dir) ||
1563+ contract_symbolic_paths_helper(dest, src, maxlen, "$default$", default_data_dir);
1564+ if (!contracted)
1565+ {
1566+ strncpy(dest, src, maxlen);
1567+ dest[maxlen] = '\0';
1568+ }
1569+ return dest;
1570+}
15041571 const char *get_application_name(void)
15051572 {
15061573 return application_name;
--- marathon/trunk/Source_Files/Network/Metaserver/metaserver_dialogs.cpp (revision 504)
+++ marathon/trunk/Source_Files/Network/Metaserver/metaserver_dialogs.cpp (revision 505)
@@ -86,7 +86,7 @@
8686 dialog d;
8787 vertical_placer *placer = new vertical_placer;
8888
89- placer->dual_add(new w_title("アップデート可\能です"), d);
89+ placer->dual_add(new w_title("アップデート可能\です"), d);
9090 placer->add(new w_spacer(), true);
9191
9292 placer->dual_add(new w_static_text("新しいバージョンのAleph Oneがあります。"), d);
--- marathon/trunk/Source_Files/Misc/preferences.cpp (revision 504)
+++ marathon/trunk/Source_Files/Misc/preferences.cpp (revision 505)
@@ -124,11 +124,6 @@
124124
125125 static const size_t NUMBER_OF_NETWORK_GAME_PROTOCOL_NAMES = sizeof(sNetworkGameProtocolNames) / sizeof(sNetworkGameProtocolNames[0]);
126126
127-#if defined(HAVE_BUNDLE_NAME)
128-static const char sBundlePlaceholder[] = "AlephOneSDL.app";
129-#endif
130-
131-
132127 // MML-like Preferences Stuff; it makes obsolete
133128 // w_open_preferences_file(), w_get_data_from_preferences(), and w_write_preferences_file()
134129 // in wad_prefs.*
@@ -260,21 +255,21 @@
260255 // Create top-level dialog
261256 dialog d;
262257 vertical_placer *placer = new vertical_placer;
263- w_title *w_header = new w_title("初期設定");
264- d.add(w_header);
265- w_button *w_player = new w_button("プレイヤー", player_dialog, &d);
266- d.add(w_player);
267-
268- w_button *w_graphics = new w_button("グラフィック", graphics_dialog, &d);
269- d.add(w_graphics);
270- w_button *w_sound = new w_button("サウンド", sound_dialog, &d);
271- d.add(w_sound);
272- w_button *w_controls = new w_button("操作", controls_dialog, &d);
273- d.add(w_controls);
274- w_button *w_environment = new w_button("環境", environment_dialog, &d);
275- d.add(w_environment);
276-
277- w_button *w_return = new w_button("戻る", dialog_cancel, &d);
258+ w_title *w_header = new w_title("初期設定");
259+ d.add(w_header);
260+ w_button *w_player = new w_button("プレイヤー", player_dialog, &d);
261+ d.add(w_player);
262+
263+ w_button *w_graphics = new w_button("グラフィック", graphics_dialog, &d);
264+ d.add(w_graphics);
265+ w_button *w_sound = new w_button("サウンド", sound_dialog, &d);
266+ d.add(w_sound);
267+ w_button *w_controls = new w_button("操作", controls_dialog, &d);
268+ d.add(w_controls);
269+ w_button *w_environment = new w_button("環境", environment_dialog, &d);
270+ d.add(w_environment);
271+
272+ w_button *w_return = new w_button("戻る", dialog_cancel, &d);
278273 d.add(w_return);
279274
280275 placer->add(w_header);
@@ -404,68 +399,68 @@
404399 SliderSelectorWidget thicknessWidget(thickness_w);
405400 CrosshairPref thicknessPref(player_preferences->Crosshairs.Thickness);
406401 crosshair_binders->insert<int> (&thicknessWidget, &thicknessPref);
407- table->dual_add(thickness_w->label("太さ"), d);
408- table->dual_add(thickness_w, d);
409-
410- // From Center
411- w_slider *from_center_w = new w_slider(15, 0);
412- SliderSelectorWidget fromCenterWidget(from_center_w);
413- Int16Pref fromCenterPref(player_preferences->Crosshairs.FromCenter);
414- crosshair_binders->insert<int> (&fromCenterWidget, &fromCenterPref);
415- table->dual_add(from_center_w->label("ギャップ"), d);
416- table->dual_add(from_center_w, d);
417-
418- // Length
419- w_slider *length_w = new w_slider(15, 0);
420- SliderSelectorWidget lengthWidget(length_w);
421- CrosshairPref lengthPref(player_preferences->Crosshairs.Length);
422- crosshair_binders->insert<int> (&lengthWidget, &lengthPref);
423- table->dual_add(length_w->label("大きさ"), d);
424- table->dual_add(length_w, d);
425-
426- table->add_row(new w_spacer(), true);
427- table->dual_add_row(new w_static_text("色"), d);
428-
429- // Color
430- w_slider *red_w = new w_slider(16, 0);
431- SliderSelectorWidget redWidget(red_w);
432- ColorComponentPref redPref(player_preferences->Crosshairs.Color.red);
433- crosshair_binders->insert<int> (&redWidget, &redPref);
434- table->dual_add(red_w->label("赤"), d);
435- table->dual_add(red_w, d);
436-
437- w_slider *green_w = new w_slider(16, 0);
438- SliderSelectorWidget greenWidget(green_w);;
439- ColorComponentPref greenPref(player_preferences->Crosshairs.Color.green);
440- crosshair_binders->insert<int> (&greenWidget, &greenPref);
441- table->dual_add(green_w->label("緑"), d);
442- table->dual_add(green_w, d);
443-
444- w_slider *blue_w = new w_slider(16, 0);
445- SliderSelectorWidget blueWidget(blue_w);
446- ColorComponentPref bluePref(player_preferences->Crosshairs.Color.blue);
447- crosshair_binders->insert<int> (&blueWidget, &bluePref);
448- table->dual_add(blue_w->label("青"), d);
449- table->dual_add(blue_w, d);
450-
451- table->add_row(new w_spacer(), true);
452- table->dual_add_row(new w_static_text("OpenGLのみ(プレビューなし)"), d);
453-
454- w_slider *opacity_w = new w_slider(16, 0);
455- SliderSelectorWidget opacityWidget(opacity_w);
456- OpacityPref opacityPref(player_preferences->Crosshairs.Opacity);
457- crosshair_binders->insert<int> (&opacityWidget, &opacityPref);
458- table->dual_add(opacity_w->label("透過度"), d);
459- table->dual_add(opacity_w, d);
460-
461- placer->add(table, true);
462- placer->add(new w_spacer, true);
463-
464- horizontal_placer *button_placer = new horizontal_placer;
465- w_button *w_accept = new w_button("了承", dialog_ok, &d);
466- button_placer->dual_add(w_accept, d);
467- w_button *w_cancel = new w_button("キャンセル", dialog_cancel, &d);
468- button_placer->dual_add(w_cancel, d);
402+ table->dual_add(thickness_w->label("太さ"), d);
403+ table->dual_add(thickness_w, d);
404+
405+ // From Center
406+ w_slider *from_center_w = new w_slider(15, 0);
407+ SliderSelectorWidget fromCenterWidget(from_center_w);
408+ Int16Pref fromCenterPref(player_preferences->Crosshairs.FromCenter);
409+ crosshair_binders->insert<int> (&fromCenterWidget, &fromCenterPref);
410+ table->dual_add(from_center_w->label("ギャップ"), d);
411+ table->dual_add(from_center_w, d);
412+
413+ // Length
414+ w_slider *length_w = new w_slider(15, 0);
415+ SliderSelectorWidget lengthWidget(length_w);
416+ CrosshairPref lengthPref(player_preferences->Crosshairs.Length);
417+ crosshair_binders->insert<int> (&lengthWidget, &lengthPref);
418+ table->dual_add(length_w->label("大きさ"), d);
419+ table->dual_add(length_w, d);
420+
421+ table->add_row(new w_spacer(), true);
422+ table->dual_add_row(new w_static_text("色"), d);
423+
424+ // Color
425+ w_slider *red_w = new w_slider(16, 0);
426+ SliderSelectorWidget redWidget(red_w);
427+ ColorComponentPref redPref(player_preferences->Crosshairs.Color.red);
428+ crosshair_binders->insert<int> (&redWidget, &redPref);
429+ table->dual_add(red_w->label("赤"), d);
430+ table->dual_add(red_w, d);
431+
432+ w_slider *green_w = new w_slider(16, 0);
433+ SliderSelectorWidget greenWidget(green_w);;
434+ ColorComponentPref greenPref(player_preferences->Crosshairs.Color.green);
435+ crosshair_binders->insert<int> (&greenWidget, &greenPref);
436+ table->dual_add(green_w->label("緑"), d);
437+ table->dual_add(green_w, d);
438+
439+ w_slider *blue_w = new w_slider(16, 0);
440+ SliderSelectorWidget blueWidget(blue_w);
441+ ColorComponentPref bluePref(player_preferences->Crosshairs.Color.blue);
442+ crosshair_binders->insert<int> (&blueWidget, &bluePref);
443+ table->dual_add(blue_w->label("青"), d);
444+ table->dual_add(blue_w, d);
445+
446+ table->add_row(new w_spacer(), true);
447+ table->dual_add_row(new w_static_text("OpenGLのみ(プレビューなし)"), d);
448+
449+ w_slider *opacity_w = new w_slider(16, 0);
450+ SliderSelectorWidget opacityWidget(opacity_w);
451+ OpacityPref opacityPref(player_preferences->Crosshairs.Opacity);
452+ crosshair_binders->insert<int> (&opacityWidget, &opacityPref);
453+ table->dual_add(opacity_w->label("透過度"), d);
454+ table->dual_add(opacity_w, d);
455+
456+ placer->add(table, true);
457+ placer->add(new w_spacer, true);
458+
459+ horizontal_placer *button_placer = new horizontal_placer;
460+ w_button *w_accept = new w_button("了承", dialog_ok, &d);
461+ button_placer->dual_add(w_accept, d);
462+ w_button *w_cancel = new w_button("キャンセル", dialog_cancel, &d);
463+ button_placer->dual_add(w_cancel, d);
469464 placer->add(button_placer, true);
470465
471466 d.set_widget_placer(placer);
@@ -503,68 +498,68 @@
503498 // Create dialog
504499 dialog d;
505500 vertical_placer *placer = new vertical_placer;
506- placer->dual_add(new w_title("プレイヤー設定"), d);
507- placer->add(new w_spacer());
508-
509- table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
510- table->col_flags(0, placeable::kAlignRight);
511- table->col_flags(1, placeable::kAlignLeft);
512-
513- w_select *level_w = new w_select(player_preferences->difficulty_level, NULL /*level_labels*/);
514- level_w->set_labels_stringset(kDifficultyLevelsStringSetID);
515- table->dual_add(level_w->label("難易度"), d);
516- table->dual_add(level_w, d);
517-
518- table->add_row(new w_spacer(), true);
519-
520- table->dual_add_row(new w_static_text("外観"), d);
521-
522- w_text_entry *name_w = new w_text_entry(PREFERENCES_NAME_LENGTH, "");
523- name_w->set_identifier(NAME_W);
524- name_w->set_enter_pressed_callback(dialog_try_ok);
525- name_w->set_value_changed_callback(dialog_disable_ok_if_empty);
526- name_w->enable_mac_roman_input();
527- table->dual_add(name_w->label("名前"), d);
528- table->dual_add(name_w, d);
529-
530- w_player_color *pcolor_w = new w_player_color(player_preferences->color);
531- table->dual_add(pcolor_w->label("色"), d);
532- table->dual_add(pcolor_w, d);
533-
534- w_player_color *tcolor_w = new w_player_color(player_preferences->team);
535- table->dual_add(tcolor_w->label("チーム"), d);
536- table->dual_add(tcolor_w, d);
537-
538- table->add_row(new w_spacer(), true);
539- table->dual_add_row(new w_static_text("インターネットのゲームサーバーを探す"), d);
540-
541- w_enabling_toggle *login_as_guest_w = new w_enabling_toggle(strcmp(network_preferences->metaserver_login, "guest") == 0, false);
542- table->dual_add(login_as_guest_w->label("ゲスト"), d);
543- table->dual_add(login_as_guest_w, d);
544-
545- w_text_entry *login_w = new w_text_entry(network_preferences_data::kMetaserverLoginLength, network_preferences->metaserver_login);
546- table->dual_add(login_w->label("ログイン"), d);
547- table->dual_add(login_w, d);
548-
549- w_password_entry *password_w = new w_password_entry(network_preferences_data::kMetaserverLoginLength, network_preferences->metaserver_password);
550- table->dual_add(password_w->label("パスワード"), d);
551- table->dual_add(password_w, d);
552- w_toggle *mute_guests_w = new w_toggle(network_preferences->mute_metaserver_guests);
553- table->dual_add(mute_guests_w->label("すべてのゲストのチャットをミュートする"), d);
554- table->dual_add(mute_guests_w, d);
555-
556- table->add_row(new w_spacer(), true);
557- table->dual_add_row(new w_static_text("インターネットチャットの色"), d);
558- w_enabling_toggle *custom_colors_w = new w_enabling_toggle(network_preferences->use_custom_metaserver_colors);
559- table->dual_add(custom_colors_w->label("カスタムカラーを使用"), d);
560- table->dual_add(custom_colors_w, d);
561-
562- w_color_picker *primary_w = new w_color_picker(network_preferences->metaserver_colors[0]);
563- table->dual_add(primary_w->label("プライマリ"), d);
564- table->dual_add(primary_w, d);
565-
566- w_color_picker *secondary_w = new w_color_picker(network_preferences->metaserver_colors[1]);
567- table->dual_add(secondary_w->label("セカンダリ"), d);
501+ placer->dual_add(new w_title("プレイヤー設定"), d);
502+ placer->add(new w_spacer());
503+
504+ table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
505+ table->col_flags(0, placeable::kAlignRight);
506+ table->col_flags(1, placeable::kAlignLeft);
507+
508+ w_select *level_w = new w_select(player_preferences->difficulty_level, NULL /*level_labels*/);
509+ level_w->set_labels_stringset(kDifficultyLevelsStringSetID);
510+ table->dual_add(level_w->label("難易度"), d);
511+ table->dual_add(level_w, d);
512+
513+ table->add_row(new w_spacer(), true);
514+
515+ table->dual_add_row(new w_static_text("外観"), d);
516+
517+ w_text_entry *name_w = new w_text_entry(PREFERENCES_NAME_LENGTH, "");
518+ name_w->set_identifier(NAME_W);
519+ name_w->set_enter_pressed_callback(dialog_try_ok);
520+ name_w->set_value_changed_callback(dialog_disable_ok_if_empty);
521+ name_w->enable_mac_roman_input();
522+ table->dual_add(name_w->label("名前"), d);
523+ table->dual_add(name_w, d);
524+
525+ w_player_color *pcolor_w = new w_player_color(player_preferences->color);
526+ table->dual_add(pcolor_w->label("色"), d);
527+ table->dual_add(pcolor_w, d);
528+
529+ w_player_color *tcolor_w = new w_player_color(player_preferences->team);
530+ table->dual_add(tcolor_w->label("チーム"), d);
531+ table->dual_add(tcolor_w, d);
532+
533+ table->add_row(new w_spacer(), true);
534+ table->dual_add_row(new w_static_text("インターネットのゲームサーバーを探す"), d);
535+
536+ w_enabling_toggle *login_as_guest_w = new w_enabling_toggle(strcmp(network_preferences->metaserver_login, "guest") == 0, false);
537+ table->dual_add(login_as_guest_w->label("ゲスト"), d);
538+ table->dual_add(login_as_guest_w, d);
539+
540+ w_text_entry *login_w = new w_text_entry(network_preferences_data::kMetaserverLoginLength, network_preferences->metaserver_login);
541+ table->dual_add(login_w->label("ログイン"), d);
542+ table->dual_add(login_w, d);
543+
544+ w_password_entry *password_w = new w_password_entry(network_preferences_data::kMetaserverLoginLength, network_preferences->metaserver_password);
545+ table->dual_add(password_w->label("パスワード"), d);
546+ table->dual_add(password_w, d);
547+ w_toggle *mute_guests_w = new w_toggle(network_preferences->mute_metaserver_guests);
548+ table->dual_add(mute_guests_w->label("すべてのゲストのチャットをミュートする"), d);
549+ table->dual_add(mute_guests_w, d);
550+
551+ table->add_row(new w_spacer(), true);
552+ table->dual_add_row(new w_static_text("インターネットチャットの色"), d);
553+ w_enabling_toggle *custom_colors_w = new w_enabling_toggle(network_preferences->use_custom_metaserver_colors);
554+ table->dual_add(custom_colors_w->label("カスタムカラーを使用"), d);
555+ table->dual_add(custom_colors_w, d);
556+
557+ w_color_picker *primary_w = new w_color_picker(network_preferences->metaserver_colors[0]);
558+ table->dual_add(primary_w->label("プライマリ"), d);
559+ table->dual_add(primary_w, d);
560+
561+ w_color_picker *secondary_w = new w_color_picker(network_preferences->metaserver_colors[1]);
562+ table->dual_add(secondary_w->label("セカンダリ"), d);
568563 table->dual_add(secondary_w, d);
569564
570565 custom_colors_w->add_dependent_widget(primary_w);
@@ -578,16 +573,16 @@
578573
579574 placer->add(new w_spacer(), true);
580575
581- w_button *crosshair_button = new w_button("クロスヘアー", crosshair_dialog, &d);
582- placer->dual_add(crosshair_button, d);
583-
584- placer->add(new w_spacer(), true);
585-
586- horizontal_placer *button_placer = new horizontal_placer;
587-
588- w_button* ok_button = new w_button("了承", dialog_ok, &d);
589- ok_button->set_identifier(iOK);
590- button_placer->dual_add(ok_button, d);
576+ w_button *crosshair_button = new w_button("クロスヘアー", crosshair_dialog, &d);
577+ placer->dual_add(crosshair_button, d);
578+
579+ placer->add(new w_spacer(), true);
580+
581+ horizontal_placer *button_placer = new horizontal_placer;
582+
583+ w_button* ok_button = new w_button("了承", dialog_ok, &d);
584+ ok_button->set_identifier(iOK);
585+ button_placer->dual_add(ok_button, d);
591586 button_placer->dual_add(new w_button("キャンセル", dialog_cancel, &d), d);
592587
593588 placer->add(button_placer, true);
@@ -687,41 +682,41 @@
687682 * Handle graphics dialog
688683 */
689684
690-#ifdef TRUE_COLOR_ONLY
691-static const char* depth_labels[3] = {
692- "16ビット", "32ビット", NULL
693-};
694-#else
695-static const char *depth_labels[4] = {
696- "8ビット", "16ビット", "32ビット", NULL
697-};
698-#endif
699-
700-static const char *resolution_labels[3] = {
701- "低", "高", NULL
702-};
703-
704-static const char *sw_alpha_blending_labels[4] = {
705- "なし", "速度優先", "画質優先", NULL
706-};
707-
708-static const char *gamma_labels[9] = {
709- "とても暗い", "暗い", "やや暗い", "通常", "やや明るい", "明るい", "より明るい", "とても明るい", NULL
710-};
711-
712-static const char* renderer_labels[] = {
713- "ソ\フトウェア", "OpenGL(クラシック)", "OpenGL(シェーダー)", NULL
714-};
715-
716-static const char* hud_scale_labels[] = {
717- "通常", "2倍", "最大", NULL
718-};
719-
720-static const char* term_scale_labels[] = {
721- "通常", "2倍", "最大", NULL
685+#ifdef TRUE_COLOR_ONLY
686+static const char* depth_labels[3] = {
687+ "16ビット", "32ビット", NULL
722688 };
689+#else
690+static const char *depth_labels[4] = {
691+ "8ビット", "16ビット", "32ビット", NULL
692+};
693+#endif
723694
695+static const char *resolution_labels[3] = {
696+ "低", "高", NULL
697+};
724698
699+static const char *sw_alpha_blending_labels[4] = {
700+ "なし", "速度優先", "画質優先", NULL
701+};
702+
703+static const char *gamma_labels[9] = {
704+ "とても暗い", "暗い", "やや暗い", "通常", "やや明るい", "明るい", "より明るい", "とても明るい", NULL
705+};
706+
707+static const char* renderer_labels[] = {
708+ "ソ\フトウェア", "OpenGL(クラシック)", "OpenGL(シェーダー)", NULL
709+};
710+
711+static const char* hud_scale_labels[] = {
712+ "通常", "2倍", "最大", NULL
713+};
714+
715+static const char* term_scale_labels[] = {
716+ "通常", "2倍", "最大", NULL
717+};
718+
719+
725720 enum {
726721 iRENDERING_SYSTEM = 1000
727722 };
@@ -741,35 +736,35 @@
741736 // Create dialog
742737 dialog d;
743738 vertical_placer *placer = new vertical_placer;
744- placer->dual_add(new w_title("ソ\フトウェアレンダリング時のオプション"), d);
745- placer->add(new w_spacer(), true);
746-
747- table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
748- table->col_flags(0, placeable::kAlignRight);
749-
750-#ifdef TRUE_COLOR_ONLY
751- w_select *depth_w = new w_select(graphics_preferences->screen_mode.bit_depth == 16 ? 0 : 1, depth_labels);
752-#else
753- w_select *depth_w = new w_select(graphics_preferences->screen_mode.bit_depth == 8 ? 0 : graphics_preferences->screen_mode.bit_depth == 16 ? 1 : 2, depth_labels);
754-#endif
755- table->dual_add(depth_w->label("色深度"), d);
756- table->dual_add(depth_w, d);
757-
758- w_toggle *resolution_w = new w_toggle(graphics_preferences->screen_mode.high_resolution, resolution_labels);
759- table->dual_add(resolution_w->label("解像度"), d);
760- table->dual_add(resolution_w, d);
761-
762- table->add_row(new w_spacer(), true);
763-
764- w_select *sw_alpha_blending_w = new w_select(graphics_preferences->software_alpha_blending, sw_alpha_blending_labels);
765- table->dual_add(sw_alpha_blending_w->label("液体を半透明化"), d);
766- table->dual_add(sw_alpha_blending_w, d);
767-
768- placer->add(table, true);
769-
770- placer->add(new w_spacer(), true);
771- horizontal_placer *button_placer = new horizontal_placer;
772- button_placer->dual_add(new w_button("了承", dialog_ok, &d), d);
739+ placer->dual_add(new w_title("ソ\フトウェアレンダリング時のオプション"), d);
740+ placer->add(new w_spacer(), true);
741+
742+ table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
743+ table->col_flags(0, placeable::kAlignRight);
744+
745+#ifdef TRUE_COLOR_ONLY
746+ w_select *depth_w = new w_select(graphics_preferences->screen_mode.bit_depth == 16 ? 0 : 1, depth_labels);
747+#else
748+ w_select *depth_w = new w_select(graphics_preferences->screen_mode.bit_depth == 8 ? 0 : graphics_preferences->screen_mode.bit_depth == 16 ? 1 : 2, depth_labels);
749+#endif
750+ table->dual_add(depth_w->label("色深度"), d);
751+ table->dual_add(depth_w, d);
752+
753+ w_toggle *resolution_w = new w_toggle(graphics_preferences->screen_mode.high_resolution, resolution_labels);
754+ table->dual_add(resolution_w->label("解像度"), d);
755+ table->dual_add(resolution_w, d);
756+
757+ table->add_row(new w_spacer(), true);
758+
759+ w_select *sw_alpha_blending_w = new w_select(graphics_preferences->software_alpha_blending, sw_alpha_blending_labels);
760+ table->dual_add(sw_alpha_blending_w->label("液体を半透明化"), d);
761+ table->dual_add(sw_alpha_blending_w, d);
762+
763+ placer->add(table, true);
764+
765+ placer->add(new w_spacer(), true);
766+ horizontal_placer *button_placer = new horizontal_placer;
767+ button_placer->dual_add(new w_button("了承", dialog_ok, &d), d);
773768 button_placer->dual_add(new w_button("キャンセル", dialog_cancel, &d), d);
774769 placer->add(button_placer, true);
775770
@@ -857,7 +852,7 @@
857852 dialog d;
858853
859854 vertical_placer *placer = new vertical_placer;
860- placer->dual_add(new w_title("グラフィック設定"), d);
855+ placer->dual_add(new w_title("グラフィック設定"), d);
861856 placer->add(new w_spacer(), true);
862857
863858 table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
@@ -886,54 +881,54 @@
886881 if (SDL_VERSIONNUM(version->major, version->minor, version->patch) >= SDL_VERSIONNUM(1, 2, 10))
887882 {
888883 fill_screen_w = new w_toggle(graphics_preferences->screen_mode.fill_the_screen);
889- table->dual_add(fill_screen_w->label("画面に合わせる"), d);
890- table->dual_add(fill_screen_w, d);
891- }
892-
893- w_toggle *fixh_w = new w_toggle(!graphics_preferences->screen_mode.fix_h_not_v);
894- table->dual_add(fixh_w->label("垂直表\示を制限"), d);
895- table->dual_add(fixh_w, d);
896-
897- w_select_popup *gamma_w = new w_select_popup();
898- gamma_w->set_labels(build_stringvector_from_cstring_array(gamma_labels));
899- gamma_w->set_selection(graphics_preferences->screen_mode.gamma_level);
900- table->dual_add(gamma_w->label("明るさ"), d);
901- table->dual_add(gamma_w, d);
902-
903- table->add_row(new w_spacer(), true);
904-
905- w_toggle *fullscreen_w = new w_toggle(!graphics_preferences->screen_mode.fullscreen);
906- table->dual_add(fullscreen_w->label("ウィンドウモード"), d);
907- table->dual_add(fullscreen_w, d);
908-
909- table->add_row(new w_spacer(), true);
910- table->dual_add_row(new w_static_text("ヘッドアップディスプレイ(HUD)"), d);
911- w_enabling_toggle *hud_w = new w_enabling_toggle(graphics_preferences->screen_mode.hud);
912- table->dual_add(hud_w->label("HUDを表\示"), d);
913- table->dual_add(hud_w, d);
914-
915- w_select_popup *hud_scale_w = new w_select_popup();
916- hud_scale_w->set_labels(build_stringvector_from_cstring_array(hud_scale_labels));
917- hud_scale_w->set_selection(graphics_preferences->screen_mode.hud_scale_level);
918- table->dual_add(hud_scale_w->label("HUDのサイズ"), d);
919- table->dual_add(hud_scale_w, d);
920- hud_w->add_dependent_widget(hud_scale_w);
921-
922- w_select_popup *term_scale_w = new w_select_popup();
923- term_scale_w->set_labels(build_stringvector_from_cstring_array(term_scale_labels));
924- term_scale_w->set_selection(graphics_preferences->screen_mode.term_scale_level);
925- table->dual_add(term_scale_w->label("ターミナルのサイズ"), d);
926- table->dual_add(term_scale_w, d);
927-
928- w_toggle *map_w = new w_toggle(graphics_preferences->screen_mode.translucent_map);
929- table->dual_add(map_w->label("オーバーレイマップ"), d);
930- table->dual_add(map_w, d);
931-
932- placer->add(table, true);
933-
934- placer->add(new w_spacer(), true);
935- placer->dual_add(new w_button("レンダリングオプション", rendering_options_dialog_demux, &d), d);
884+ table->dual_add(fill_screen_w->label("画面に合わせる"), d);
885+ table->dual_add(fill_screen_w, d);
886+ }
887+
888+ w_toggle *fixh_w = new w_toggle(!graphics_preferences->screen_mode.fix_h_not_v);
889+ table->dual_add(fixh_w->label("垂直表\示を制限"), d);
890+ table->dual_add(fixh_w, d);
891+
892+ w_select_popup *gamma_w = new w_select_popup();
893+ gamma_w->set_labels(build_stringvector_from_cstring_array(gamma_labels));
894+ gamma_w->set_selection(graphics_preferences->screen_mode.gamma_level);
895+ table->dual_add(gamma_w->label("明るさ"), d);
896+ table->dual_add(gamma_w, d);
897+
898+ table->add_row(new w_spacer(), true);
899+
900+ w_toggle *fullscreen_w = new w_toggle(!graphics_preferences->screen_mode.fullscreen);
901+ table->dual_add(fullscreen_w->label("ウィンドウモード"), d);
902+ table->dual_add(fullscreen_w, d);
903+
904+ table->add_row(new w_spacer(), true);
905+ table->dual_add_row(new w_static_text("ヘッドアップディスプレイ(HUD)"), d);
906+ w_enabling_toggle *hud_w = new w_enabling_toggle(graphics_preferences->screen_mode.hud);
907+ table->dual_add(hud_w->label("HUDを表\示"), d);
908+ table->dual_add(hud_w, d);
909+
910+ w_select_popup *hud_scale_w = new w_select_popup();
911+ hud_scale_w->set_labels(build_stringvector_from_cstring_array(hud_scale_labels));
912+ hud_scale_w->set_selection(graphics_preferences->screen_mode.hud_scale_level);
913+ table->dual_add(hud_scale_w->label("HUDのサイズ"), d);
914+ table->dual_add(hud_scale_w, d);
915+ hud_w->add_dependent_widget(hud_scale_w);
916+
917+ w_select_popup *term_scale_w = new w_select_popup();
918+ term_scale_w->set_labels(build_stringvector_from_cstring_array(term_scale_labels));
919+ term_scale_w->set_selection(graphics_preferences->screen_mode.term_scale_level);
920+ table->dual_add(term_scale_w->label("ターミナルのサイズ"), d);
921+ table->dual_add(term_scale_w, d);
922+
923+ w_toggle *map_w = new w_toggle(graphics_preferences->screen_mode.translucent_map);
924+ table->dual_add(map_w->label("オーバーレイマップ"), d);
925+ table->dual_add(map_w, d);
926+
927+ placer->add(table, true);
928+
936929 placer->add(new w_spacer(), true);
930+ placer->dual_add(new w_button("レンダリングオプション", rendering_options_dialog_demux, &d), d);
931+ placer->add(new w_spacer(), true);
937932
938933 #ifndef HAVE_OPENGL
939934
@@ -942,8 +937,8 @@
942937 placer->add(new w_spacer(), true);
943938
944939 horizontal_placer *button_placer = new horizontal_placer;
945- button_placer->dual_add(new w_button("了承", dialog_ok, &d), d);
946- button_placer->dual_add(new w_button("キャンセル", dialog_cancel, &d), d);
940+ button_placer->dual_add(new w_button("了承", dialog_ok, &d), d);
941+ button_placer->dual_add(new w_button("キャンセル", dialog_cancel, &d), d);
947942
948943 placer->add(button_placer, true);
949944
@@ -1095,71 +1090,71 @@
10951090 // Create dialog
10961091 dialog d;
10971092 vertical_placer *placer = new vertical_placer;
1098- placer->dual_add(new w_title("サウンド設定"), d);
1099- placer->add(new w_spacer(), true);
1100-
1101- table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1102- table->col_flags(0, placeable::kAlignRight);
1103-
1104- static const char *quality_labels[3] = {"8ビット", "16ビット", NULL};
1105- w_toggle *quality_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _16bit_sound_flag), quality_labels);
1106- table->dual_add(quality_w->label("音質"), d);
1107- table->dual_add(quality_w, d);
1108-
1109- stereo_w = new w_stereo_toggle(sound_preferences->flags & _stereo_flag);
1110- table->dual_add(quality_w->label("ステレオ"), d);
1111- table->dual_add(stereo_w, d);
1112-
1113- dynamic_w = new w_dynamic_toggle(TEST_FLAG(sound_preferences->flags, _dynamic_tracking_flag));
1114- table->dual_add(dynamic_w->label("音の定位を変化させる"), d);
1115- table->dual_add(dynamic_w, d);
1116-
1117- w_toggle *ambient_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _ambient_sound_flag));
1118- table->dual_add(ambient_w->label("周辺サウンド"), d);
1119- table->dual_add(ambient_w, d);
1120-
1121- w_toggle *more_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _more_sounds_flag));
1122- table->dual_add(more_w->label("追加のサウンド"), d);
1123- table->dual_add(more_w, d);
1124-
1125- w_toggle *button_sounds_w = new w_toggle(TEST_FLAG(input_preferences->modifiers, _inputmod_use_button_sounds));
1126- table->dual_add(button_sounds_w->label("インターフェースボタンのサウンド"), d);
1127- table->dual_add(button_sounds_w, d);
1128-
1129- w_select *channels_w = new w_select(static_cast<int>(std::floor(std::log(static_cast<float>(sound_preferences->channel_count)) / std::log(2.0) + 0.5)), channel_labels);
1130- table->dual_add(channels_w->label("チャンネル数"), d);
1131- table->dual_add(channels_w, d);
1132-
1133- w_volume_slider *volume_w = new w_volume_slider(sound_preferences->volume);
1134- table->dual_add(volume_w->label("音量"), d);
1135- table->dual_add(volume_w, d);
1136-
1137- w_slider *music_volume_w = new w_slider(NUMBER_OF_SOUND_VOLUME_LEVELS, sound_preferences->music);
1138- table->dual_add(music_volume_w->label("音楽の音量"), d);
1139- table->dual_add(music_volume_w, d);
1140-
1141-
1142- table->add_row(new w_spacer(), true);
1143- table->dual_add_row(new w_static_text("ネットワークマイク"), d);
1144-
1145- w_toggle* mute_while_transmitting_w = new w_toggle(!sound_preferences->mute_while_transmitting);
1146- table->dual_add(mute_while_transmitting_w->label("Headset Mic Mode"), d);
1147- table->dual_add(mute_while_transmitting_w, d);
1148-
1149- table->add_row(new w_spacer(), true);
1150- table->dual_add_row(new w_static_text("実験中のサウンドオプション"), d);
1151- w_toggle *zrd_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _zero_restart_delay));
1152- table->dual_add(zrd_w->label("リスタートディレイをゼロに"), d);
1153- table->dual_add(zrd_w, d);
1154-
1155- placer->add(table, true);
1156-
1157- placer->add(new w_spacer(), true);
1158-
1159- horizontal_placer *button_placer = new horizontal_placer;
1160- button_placer->dual_add(new w_button("了承", dialog_ok, &d), d);
1161- button_placer->dual_add(new w_button("キャンセル", dialog_cancel, &d), d);
1162-
1093+ placer->dual_add(new w_title("サウンド設定"), d);
1094+ placer->add(new w_spacer(), true);
1095+
1096+ table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1097+ table->col_flags(0, placeable::kAlignRight);
1098+
1099+ static const char *quality_labels[3] = {"8ビット", "16ビット", NULL};
1100+ w_toggle *quality_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _16bit_sound_flag), quality_labels);
1101+ table->dual_add(quality_w->label("音質"), d);
1102+ table->dual_add(quality_w, d);
1103+
1104+ stereo_w = new w_stereo_toggle(sound_preferences->flags & _stereo_flag);
1105+ table->dual_add(quality_w->label("ステレオ"), d);
1106+ table->dual_add(stereo_w, d);
1107+
1108+ dynamic_w = new w_dynamic_toggle(TEST_FLAG(sound_preferences->flags, _dynamic_tracking_flag));
1109+ table->dual_add(dynamic_w->label("音の定位を変化させる"), d);
1110+ table->dual_add(dynamic_w, d);
1111+
1112+ w_toggle *ambient_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _ambient_sound_flag));
1113+ table->dual_add(ambient_w->label("周辺サウンド"), d);
1114+ table->dual_add(ambient_w, d);
1115+
1116+ w_toggle *more_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _more_sounds_flag));
1117+ table->dual_add(more_w->label("追加のサウンド"), d);
1118+ table->dual_add(more_w, d);
1119+
1120+ w_toggle *button_sounds_w = new w_toggle(TEST_FLAG(input_preferences->modifiers, _inputmod_use_button_sounds));
1121+ table->dual_add(button_sounds_w->label("インターフェースボタンのサウンド"), d);
1122+ table->dual_add(button_sounds_w, d);
1123+
1124+ w_select *channels_w = new w_select(static_cast<int>(std::floor(std::log(static_cast<float>(sound_preferences->channel_count)) / std::log(2.0) + 0.5)), channel_labels);
1125+ table->dual_add(channels_w->label("チャンネル数"), d);
1126+ table->dual_add(channels_w, d);
1127+
1128+ w_volume_slider *volume_w = new w_volume_slider(sound_preferences->volume);
1129+ table->dual_add(volume_w->label("音量"), d);
1130+ table->dual_add(volume_w, d);
1131+
1132+ w_slider *music_volume_w = new w_slider(NUMBER_OF_SOUND_VOLUME_LEVELS, sound_preferences->music);
1133+ table->dual_add(music_volume_w->label("音楽の音量"), d);
1134+ table->dual_add(music_volume_w, d);
1135+
1136+
1137+ table->add_row(new w_spacer(), true);
1138+ table->dual_add_row(new w_static_text("ネットワークマイク"), d);
1139+
1140+ w_toggle* mute_while_transmitting_w = new w_toggle(!sound_preferences->mute_while_transmitting);
1141+ table->dual_add(mute_while_transmitting_w->label("Headset Mic Mode"), d);
1142+ table->dual_add(mute_while_transmitting_w, d);
1143+
1144+ table->add_row(new w_spacer(), true);
1145+ table->dual_add_row(new w_static_text("実験中のサウンドオプション"), d);
1146+ w_toggle *zrd_w = new w_toggle(TEST_FLAG(sound_preferences->flags, _zero_restart_delay));
1147+ table->dual_add(zrd_w->label("リスタートディレイをゼロに"), d);
1148+ table->dual_add(zrd_w, d);
1149+
1150+ placer->add(table, true);
1151+
1152+ placer->add(new w_spacer(), true);
1153+
1154+ horizontal_placer *button_placer = new horizontal_placer;
1155+ button_placer->dual_add(new w_button("了承", dialog_ok, &d), d);
1156+ button_placer->dual_add(new w_button("キャンセル", dialog_cancel, &d), d);
1157+
11631158 placer->add(button_placer, true);
11641159
11651160 d.set_widget_placer(placer);
@@ -1258,183 +1253,183 @@
12581253 // Create dialog
12591254 dialog d;
12601255 vertical_placer *placer = new vertical_placer;
1261- placer->dual_add(new w_title("操作"), d);
1262- placer->add(new w_spacer(), true);
1263-
1264- tab_placer* tabs = new tab_placer();
1265-
1266- std::vector<std::string> labels;
1267- labels.push_back("一般");
1268- labels.push_back("マウス");
1269- labels.push_back("ジョイスティック");
1270- w_tab *tab_w = new w_tab(labels, tabs);
1271-
1272- placer->dual_add(tab_w, d);
1273- placer->add(new w_spacer(), true);
1274-
1275- vertical_placer *general = new vertical_placer();
1276- table_placer* mouse = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1277- table_placer* joystick = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1278- mouse->col_flags(0, placeable::kAlignRight);
1279- joystick->col_flags(0, placeable::kAlignRight);
1280-
1281- mouse_w = new w_enabling_toggle(input_preferences->input_device == 1, true);
1282- mouse_w->set_selection_changed_callback(input_selected);
1283- mouse->dual_add(mouse_w->label("マウスを使用"), d);
1284- mouse->dual_add(mouse_w, d);
1285-
1286- mouse->add_row(new w_spacer(), true);
1287-
1288- w_toggle *mouse_acceleration_w = new w_toggle(input_preferences->mouse_acceleration);
1289- mouse->dual_add(mouse_acceleration_w->label("マウスの動きを加速させる"), d);
1290- mouse->dual_add(mouse_acceleration_w, d);
1291-
1292- mouse_w->add_dependent_widget(mouse_acceleration_w);
1293-
1294- w_toggle *invert_mouse_w = new w_toggle(TEST_FLAG(input_preferences->modifiers, _inputmod_invert_mouse));
1295- mouse->dual_add(invert_mouse_w->label("マウスを反転"), d);
1296- mouse->dual_add(invert_mouse_w, d);
1297-
1298- mouse_w->add_dependent_widget(invert_mouse_w);
1299-
1300- const float kMinSensitivityLog = -3.0f;
1301- const float kMaxSensitivityLog = 3.0f;
1302- const float kSensitivityLogRange = kMaxSensitivityLog - kMinSensitivityLog;
1303-
1304- // LP: split this into horizontal and vertical sensitivities
1305- float theSensitivity, theSensitivityLog;
1306-
1307- theSensitivity = ((float) input_preferences->sens_vertical) / FIXED_ONE;
1308- if (theSensitivity <= 0.0f) theSensitivity = 1.0f;
1309- theSensitivityLog = std::log(theSensitivity);
1310- int theVerticalSliderPosition =
1311- (int) ((theSensitivityLog - kMinSensitivityLog) * (1000.0f / kSensitivityLogRange));
1312-
1313- w_slider* sens_vertical_w = new w_slider(1000, theVerticalSliderPosition);
1314- mouse->dual_add(sens_vertical_w->label("マウスの垂直感度"), d);
1315- mouse->dual_add(sens_vertical_w, d);
1316-
1317- mouse_w->add_dependent_widget(sens_vertical_w);
1318-
1319- theSensitivity = ((float) input_preferences->sens_horizontal) / FIXED_ONE;
1320- if (theSensitivity <= 0.0f) theSensitivity = 1.0f;
1321- theSensitivityLog = std::log(theSensitivity);
1322- int theHorizontalSliderPosition =
1323- (int) ((theSensitivityLog - kMinSensitivityLog) * (1000.0f / kSensitivityLogRange));
1324-
1325- w_slider* sens_horizontal_w = new w_slider(1000, theHorizontalSliderPosition);
1326- mouse->dual_add(sens_vertical_w->label("マウスの垂平感度"), d);
1327- mouse->dual_add(sens_horizontal_w, d);
1328-
1329- mouse_w->add_dependent_widget(sens_horizontal_w);
1330-
1331- joystick_w = new w_enabling_toggle(input_preferences->input_device == 0 && SDL_NumJoysticks() > 0 && input_preferences->joystick_id >= 0, true);
1332- joystick_w->set_selection_changed_callback(input_selected);
1333- joystick->dual_add(joystick_w->label("ジョイスティク/ゲームパッドを使用"), d);
1334- joystick->dual_add(joystick_w, d);
1335-
1336- joystick->add_row(new w_spacer(), true);
1337-
1338- std::vector<std::string> joystick_labels;
1339- if (SDL_NumJoysticks())
1340- {
1341- for (int i = 0; i < SDL_NumJoysticks(); ++i)
1342- {
1343- joystick_labels.push_back(SDL_JoystickName(i));
1344- }
1345- }
1346- else
1347- {
1348- joystick_labels.push_back("ジョイスティック無し");
1349- }
1350- w_select_popup* which_joystick_w = new w_select_popup();
1351- which_joystick_w->set_labels(joystick_labels);
1352- which_joystick_w->set_selection(std::max(0, std::min(SDL_NumJoysticks(), static_cast<int>(input_preferences->joystick_id))));
1353- joystick->dual_add(which_joystick_w->label("ジョイスティク/ゲームパッド"), d);
1354- joystick->dual_add(which_joystick_w, d);
1355- joystick_w->add_dependent_widget(which_joystick_w);
1356-
1357- joystick->add_row(new w_spacer(), true);
1358- joystick->dual_add_row(new w_static_text("スティックのマッピング"), d);
1359-
1360- std::vector<std::string> axis_labels;
1361- axis_labels.push_back("無し");
1362- for (int i = 1; i <= 8; ++i)
1363- {
1364- stringstream s;
1365- s << "軸 " << i;
1366- axis_labels.push_back(s.str());
1367- }
1368- for (int i = 0; i < NUMBER_OF_JOYSTICK_MAPPINGS; ++i)
1369- {
1370- joystick_axis_w[i] = new w_select_popup();
1371- joystick_axis_w[i]->set_labels(axis_labels);
1372- joystick_axis_w[i]->set_selection(input_preferences->joystick_axis_mappings[i] + 1);
1373- joystick_axis_w[i]->set_popup_callback(axis_mapped, joystick_axis_w[i]);
1374- }
1375-
1376- joystick->dual_add(joystick_axis_w[_joystick_strafe]->label("左右にサイドステップ"), d);
1377- joystick->dual_add(joystick_axis_w[_joystick_strafe], d);
1378-
1379- joystick->dual_add(joystick_axis_w[_joystick_velocity]->label("前後移動"), d);
1380- joystick->dual_add(joystick_axis_w[_joystick_velocity], d);
1381-
1382- joystick->dual_add(joystick_axis_w[_joystick_yaw]->label("左右を向く"), d);
1383- joystick->dual_add(joystick_axis_w[_joystick_yaw], d);
1384-
1385- joystick->dual_add(joystick_axis_w[_joystick_pitch]->label("上下に視野を移動"), d);
1386- joystick->dual_add(joystick_axis_w[_joystick_pitch], d);
1387-
1388- for (int i = 0; i < NUMBER_OF_JOYSTICK_MAPPINGS; ++i)
1389- {
1390- joystick_w->add_dependent_widget(joystick_axis_w[i]);
1391- }
1392-
1393- joystick->add_row(new w_spacer(), true);
1394-
1395- table_placer* general_table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1396- general_table->col_flags(0, placeable::kAlignRight);
1397-
1398- w_toggle *always_run_w = new w_toggle(input_preferences->modifiers & _inputmod_interchange_run_walk);
1399- general_table->dual_add(always_run_w->label("常時走行"), d);
1400- general_table->dual_add(always_run_w, d);
1401-
1402- w_toggle *always_swim_w = new w_toggle(TEST_FLAG(input_preferences->modifiers, _inputmod_interchange_swim_sink));
1403- general_table->dual_add(always_swim_w->label("常時泳ぐ"), d);
1404- general_table->dual_add(always_swim_w, d);
1405-
1406- general_table->add_row(new w_spacer(), true);
1407-
1408- w_toggle *weapon_w = new w_toggle(!(input_preferences->modifiers & _inputmod_dont_switch_to_new_weapon));
1409- general_table->dual_add(weapon_w->label("武器の自動切換え"), d);
1410- general_table->dual_add(weapon_w, d);
1411-
1412- w_toggle* auto_recenter_w = new w_toggle(!(input_preferences->modifiers & _inputmod_dont_auto_recenter));
1413- general_table->dual_add(auto_recenter_w->label("視点の自動リセンター"), d);
1256+ placer->dual_add(new w_title("操作"), d);
1257+ placer->add(new w_spacer(), true);
1258+
1259+ tab_placer* tabs = new tab_placer();
1260+
1261+ std::vector<std::string> labels;
1262+ labels.push_back("一般");
1263+ labels.push_back("マウス");
1264+ labels.push_back("ジョイスティック");
1265+ w_tab *tab_w = new w_tab(labels, tabs);
1266+
1267+ placer->dual_add(tab_w, d);
1268+ placer->add(new w_spacer(), true);
1269+
1270+ vertical_placer *general = new vertical_placer();
1271+ table_placer* mouse = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1272+ table_placer* joystick = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1273+ mouse->col_flags(0, placeable::kAlignRight);
1274+ joystick->col_flags(0, placeable::kAlignRight);
1275+
1276+ mouse_w = new w_enabling_toggle(input_preferences->input_device == 1, true);
1277+ mouse_w->set_selection_changed_callback(input_selected);
1278+ mouse->dual_add(mouse_w->label("マウスを使用"), d);
1279+ mouse->dual_add(mouse_w, d);
1280+
1281+ mouse->add_row(new w_spacer(), true);
1282+
1283+ w_toggle *mouse_acceleration_w = new w_toggle(input_preferences->mouse_acceleration);
1284+ mouse->dual_add(mouse_acceleration_w->label("マウスの動きを加速させる"), d);
1285+ mouse->dual_add(mouse_acceleration_w, d);
1286+
1287+ mouse_w->add_dependent_widget(mouse_acceleration_w);
1288+
1289+ w_toggle *invert_mouse_w = new w_toggle(TEST_FLAG(input_preferences->modifiers, _inputmod_invert_mouse));
1290+ mouse->dual_add(invert_mouse_w->label("マウスを反転"), d);
1291+ mouse->dual_add(invert_mouse_w, d);
1292+
1293+ mouse_w->add_dependent_widget(invert_mouse_w);
1294+
1295+ const float kMinSensitivityLog = -3.0f;
1296+ const float kMaxSensitivityLog = 3.0f;
1297+ const float kSensitivityLogRange = kMaxSensitivityLog - kMinSensitivityLog;
1298+
1299+ // LP: split this into horizontal and vertical sensitivities
1300+ float theSensitivity, theSensitivityLog;
1301+
1302+ theSensitivity = ((float) input_preferences->sens_vertical) / FIXED_ONE;
1303+ if (theSensitivity <= 0.0f) theSensitivity = 1.0f;
1304+ theSensitivityLog = std::log(theSensitivity);
1305+ int theVerticalSliderPosition =
1306+ (int) ((theSensitivityLog - kMinSensitivityLog) * (1000.0f / kSensitivityLogRange));
1307+
1308+ w_slider* sens_vertical_w = new w_slider(1000, theVerticalSliderPosition);
1309+ mouse->dual_add(sens_vertical_w->label("マウスの垂直感度"), d);
1310+ mouse->dual_add(sens_vertical_w, d);
1311+
1312+ mouse_w->add_dependent_widget(sens_vertical_w);
1313+
1314+ theSensitivity = ((float) input_preferences->sens_horizontal) / FIXED_ONE;
1315+ if (theSensitivity <= 0.0f) theSensitivity = 1.0f;
1316+ theSensitivityLog = std::log(theSensitivity);
1317+ int theHorizontalSliderPosition =
1318+ (int) ((theSensitivityLog - kMinSensitivityLog) * (1000.0f / kSensitivityLogRange));
1319+
1320+ w_slider* sens_horizontal_w = new w_slider(1000, theHorizontalSliderPosition);
1321+ mouse->dual_add(sens_vertical_w->label("マウスの垂平感度"), d);
1322+ mouse->dual_add(sens_horizontal_w, d);
1323+
1324+ mouse_w->add_dependent_widget(sens_horizontal_w);
1325+
1326+ joystick_w = new w_enabling_toggle(input_preferences->input_device == 0 && SDL_NumJoysticks() > 0 && input_preferences->joystick_id >= 0, true);
1327+ joystick_w->set_selection_changed_callback(input_selected);
1328+ joystick->dual_add(joystick_w->label("ジョイスティク/ゲームパッドを使用"), d);
1329+ joystick->dual_add(joystick_w, d);
1330+
1331+ joystick->add_row(new w_spacer(), true);
1332+
1333+ std::vector<std::string> joystick_labels;
1334+ if (SDL_NumJoysticks())
1335+ {
1336+ for (int i = 0; i < SDL_NumJoysticks(); ++i)
1337+ {
1338+ joystick_labels.push_back(SDL_JoystickName(i));
1339+ }
1340+ }
1341+ else
1342+ {
1343+ joystick_labels.push_back("ジョイスティック無し");
1344+ }
1345+ w_select_popup* which_joystick_w = new w_select_popup();
1346+ which_joystick_w->set_labels(joystick_labels);
1347+ which_joystick_w->set_selection(std::max(0, std::min(SDL_NumJoysticks(), static_cast<int>(input_preferences->joystick_id))));
1348+ joystick->dual_add(which_joystick_w->label("ジョイスティク/ゲームパッド"), d);
1349+ joystick->dual_add(which_joystick_w, d);
1350+ joystick_w->add_dependent_widget(which_joystick_w);
1351+
1352+ joystick->add_row(new w_spacer(), true);
1353+ joystick->dual_add_row(new w_static_text("スティックのマッピング"), d);
1354+
1355+ std::vector<std::string> axis_labels;
1356+ axis_labels.push_back("無し");
1357+ for (int i = 1; i <= 8; ++i)
1358+ {
1359+ stringstream s;
1360+ s << "軸 " << i;
1361+ axis_labels.push_back(s.str());
1362+ }
1363+ for (int i = 0; i < NUMBER_OF_JOYSTICK_MAPPINGS; ++i)
1364+ {
1365+ joystick_axis_w[i] = new w_select_popup();
1366+ joystick_axis_w[i]->set_labels(axis_labels);
1367+ joystick_axis_w[i]->set_selection(input_preferences->joystick_axis_mappings[i] + 1);
1368+ joystick_axis_w[i]->set_popup_callback(axis_mapped, joystick_axis_w[i]);
1369+ }
1370+
1371+ joystick->dual_add(joystick_axis_w[_joystick_strafe]->label("左右にサイドステップ"), d);
1372+ joystick->dual_add(joystick_axis_w[_joystick_strafe], d);
1373+
1374+ joystick->dual_add(joystick_axis_w[_joystick_velocity]->label("前後移動"), d);
1375+ joystick->dual_add(joystick_axis_w[_joystick_velocity], d);
1376+
1377+ joystick->dual_add(joystick_axis_w[_joystick_yaw]->label("左右を向く"), d);
1378+ joystick->dual_add(joystick_axis_w[_joystick_yaw], d);
1379+
1380+ joystick->dual_add(joystick_axis_w[_joystick_pitch]->label("上下に視野を移動"), d);
1381+ joystick->dual_add(joystick_axis_w[_joystick_pitch], d);
1382+
1383+ for (int i = 0; i < NUMBER_OF_JOYSTICK_MAPPINGS; ++i)
1384+ {
1385+ joystick_w->add_dependent_widget(joystick_axis_w[i]);
1386+ }
1387+
1388+ joystick->add_row(new w_spacer(), true);
1389+
1390+ table_placer* general_table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1391+ general_table->col_flags(0, placeable::kAlignRight);
1392+
1393+ w_toggle *always_run_w = new w_toggle(input_preferences->modifiers & _inputmod_interchange_run_walk);
1394+ general_table->dual_add(always_run_w->label("常時走行"), d);
1395+ general_table->dual_add(always_run_w, d);
1396+
1397+ w_toggle *always_swim_w = new w_toggle(TEST_FLAG(input_preferences->modifiers, _inputmod_interchange_swim_sink));
1398+ general_table->dual_add(always_swim_w->label("常時泳ぐ"), d);
1399+ general_table->dual_add(always_swim_w, d);
1400+
1401+ general_table->add_row(new w_spacer(), true);
1402+
1403+ w_toggle *weapon_w = new w_toggle(!(input_preferences->modifiers & _inputmod_dont_switch_to_new_weapon));
1404+ general_table->dual_add(weapon_w->label("武器の自動切換え"), d);
1405+ general_table->dual_add(weapon_w, d);
1406+
1407+ w_toggle* auto_recenter_w = new w_toggle(!(input_preferences->modifiers & _inputmod_dont_auto_recenter));
1408+ general_table->dual_add(auto_recenter_w->label("視点の自動リセンター"), d);
14141409 general_table->dual_add(auto_recenter_w, d);
14151410
14161411 general->add(general_table, true);
14171412
1418- general->add(new w_spacer(), true);
1419- general->dual_add(new w_static_text("注意:武器の自動切換えと、視点の自動リセンターは、ネットワークプレイで"), d);
1420- general->dual_add(new w_static_text("自動的にオンになります。シングルプレイヤーモードでも、映画を録画する際"), d);
1421- general->dual_add(new w_static_text("どちらかをオフにしても、自動的に無効化されます。"), d);
1422-
1423- tabs->add(general, true);
1424- tabs->add(mouse, true);
1425- tabs->add(joystick, true);
1426-
1427- placer->add(tabs, true);
1428-
1429- placer->add(new w_spacer(), true);
1430- placer->add(new w_spacer(), true);
1431- placer->dual_add(new w_button("キー設定/ボタン", keyboard_dialog, &d), d);
1432-
1433- placer->add(new w_spacer(), true);
1434-
1435- horizontal_placer *button_placer = new horizontal_placer;
1436- button_placer->dual_add(new w_button("了承", dialog_ok, &d), d);
1437- button_placer->dual_add(new w_button("キャンセル", dialog_cancel, &d), d);
1413+ general->add(new w_spacer(), true);
1414+ general->dual_add(new w_static_text("注意:武器の自動切換えと、視点の自動リセンターは、ネットワークプレイで"), d);
1415+ general->dual_add(new w_static_text("自動的にオンになります。シングルプレイヤーモードでも、映画を録画する際"), d);
1416+ general->dual_add(new w_static_text("どちらかをオフにしても、自動的に無効化されます。"), d);
1417+
1418+ tabs->add(general, true);
1419+ tabs->add(mouse, true);
1420+ tabs->add(joystick, true);
1421+
1422+ placer->add(tabs, true);
1423+
1424+ placer->add(new w_spacer(), true);
1425+ placer->add(new w_spacer(), true);
1426+ placer->dual_add(new w_button("キー設定/ボタン", keyboard_dialog, &d), d);
1427+
1428+ placer->add(new w_spacer(), true);
1429+
1430+ horizontal_placer *button_placer = new horizontal_placer;
1431+ button_placer->dual_add(new w_button("了承", dialog_ok, &d), d);
1432+ button_placer->dual_add(new w_button("キャンセル", dialog_cancel, &d), d);
14381433 placer->add(button_placer, true);
14391434
14401435 d.set_widget_placer(placer);
@@ -1530,18 +1525,18 @@
15301525
15311526 const int NUM_KEYS = 21;
15321527
1533-static const char *action_name[NUM_KEYS] = {
1534- "前進", "後退", "左に向く", "右に向く", "左にサイドステップ", "右にサイドステップ",
1535- "左を一瞥", "右を一瞥", "上を見る", "下を見る", "Look Ahead",
1536- "前の武器", "次の武器", "主砲", "副砲",
1537- "サイドステップ", "走る/泳ぐ", "見る",
1538- "アクション", "地図", "マイク"
1539-};
1540-
1541-static const char *shell_action_name[NUMBER_OF_SHELL_KEYS] = {
1542- "道具左", "道具右", "プレイヤービューを切り替え", "ボリュームを上げる", "ボリュームを下げる", "マップを拡大", "マップを縮小", "FPSを表\示", "チャット/コンソ\ール", "ネットワーク状況"
1528+static const char *action_name[NUM_KEYS] = {
1529+ "前進", "後退", "左に向く", "右に向く", "左にサイドステップ", "右にサイドステップ",
1530+ "左を一瞥", "右を一瞥", "上を見る", "下を見る", "Look Ahead",
1531+ "前の武器", "次の武器", "主砲", "副砲",
1532+ "サイドステップ", "走る/泳ぐ", "見る",
1533+ "アクション", "地図", "マイク"
15431534 };
15441535
1536+static const char *shell_action_name[NUMBER_OF_SHELL_KEYS] = {
1537+ "道具左", "道具右", "プレイヤービューを切り替え", "ボリュームを上げる", "ボリュームを下げる", "マップを拡大", "マップを縮小", "FPSを表\示", "チャット/コンソ\ール", "ネットワーク状況"
1538+};
1539+
15451540 static SDLKey default_keys[NUM_KEYS] = {
15461541 SDLK_KP8, SDLK_KP5, SDLK_KP4, SDLK_KP6, // moving/turning
15471542 SDLK_z, SDLK_x, // sidestepping
@@ -1699,13 +1694,13 @@
16991694
17001695 placer->add(table, true);
17011696
1702- placer->add(new w_spacer(), true);
1703- placer->dual_add(new w_button("デフォルト", load_default_keys, &d), d);
1704- placer->add(new w_spacer(), true);
1705-
1706- horizontal_placer *button_placer = new horizontal_placer;
1707- button_placer->dual_add(new w_button("了承", dialog_ok, &d), d);
1708- button_placer->dual_add(new w_button("キャンセル", dialog_cancel, &d), d);
1697+ placer->add(new w_spacer(), true);
1698+ placer->dual_add(new w_button("デフォルト", load_default_keys, &d), d);
1699+ placer->add(new w_spacer(), true);
1700+
1701+ horizontal_placer *button_placer = new horizontal_placer;
1702+ button_placer->dual_add(new w_button("了承", dialog_ok, &d), d);
1703+ button_placer->dual_add(new w_button("キャンセル", dialog_cancel, &d), d);
17091704 placer->add(button_placer, true);
17101705
17111706 d.set_widget_placer(placer);
@@ -1760,8 +1755,8 @@
17601755 placer->add(new w_spacer, true);
17611756
17621757 horizontal_placer* button_placer = new horizontal_placer;
1763- w_button* accept_w = new w_button("了承", dialog_ok, &d);
1764- button_placer->dual_add(accept_w, d);
1758+ w_button* accept_w = new w_button("了承", dialog_ok, &d);
1759+ button_placer->dual_add(accept_w, d);
17651760 w_button* cancel_w = new w_button("キャンセル", dialog_cancel, &d);
17661761 button_placer->dual_add(cancel_w, d);
17671762
@@ -1806,87 +1801,87 @@
18061801 // Create dialog
18071802 dialog d;
18081803 vertical_placer *placer = new vertical_placer;
1809- w_title *w_header = new w_title("環境設定");
1810- placer->dual_add(w_header, d);
1811- placer->add(new w_spacer, true);
1812-
1813- table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1814- table->col_flags(0, placeable::kAlignRight);
1815-
1816- w_env_select *map_w = new w_env_select(environment_preferences->map_file, "使用可能\なマップ", _typecode_scenario, &d);
1817- table->dual_add(map_w->label("マップ"), d);
1818- table->dual_add(map_w, d);
1819-
1820- w_env_select *physics_w = new w_env_select(environment_preferences->physics_file, "使用可能\な物理モデル", _typecode_physics, &d);
1821- table->dual_add(physics_w->label("物理"), d);
1822- table->dual_add(physics_w, d);
1823-
1824- w_env_select *shapes_w = new w_env_select(environment_preferences->shapes_file, "使用可能\な形態", _typecode_shapes, &d);
1825- table->dual_add(shapes_w->label("形態"), d);
1826- table->dual_add(shapes_w, d);
1827-
1828- w_env_select *sounds_w = new w_env_select(environment_preferences->sounds_file, "使用可能\なサウンド", _typecode_sounds, &d);
1829- table->dual_add(sounds_w->label("サウンド"), d);
1830- table->dual_add(sounds_w, d);
1831-
1832- table->add_row(new w_spacer, true);
1833- table->dual_add_row(new w_button("プラグイン", plugins_dialog, &d), d);
1834-
1835- table->add_row(new w_spacer, true);
1836- table->dual_add_row(new w_static_text("ソ\ロスクリプト"), d);
1837- w_enabling_toggle* use_solo_lua_w = new w_enabling_toggle(environment_preferences->use_solo_lua);
1838- table->dual_add(use_solo_lua_w->label("ソ\ロスクリプトを使用"), d);
1839- table->dual_add(use_solo_lua_w, d);
1840-
1841- w_file_chooser *solo_lua_w = new w_file_chooser("スクリプトを選ぶ", _typecode_netscript);
1842- solo_lua_w->set_file(environment_preferences->solo_lua_file);
1843- table->dual_add(solo_lua_w->label("スクリプトファイル"), d);
1844- table->dual_add(solo_lua_w, d);
1845- use_solo_lua_w->add_dependent_widget(solo_lua_w);
1846-
1847- table->add_row(new w_spacer, true);
1848- table->dual_add_row(new w_static_text("HUDスクリプト"), d);
1849- w_enabling_toggle* use_hud_lua_w = new w_enabling_toggle(environment_preferences->use_hud_lua);
1850- table->dual_add(use_hud_lua_w->label("HUDスクリプトを使用"), d);
1851- table->dual_add(use_hud_lua_w, d);
1852-
1853- w_file_chooser *hud_lua_w = new w_file_chooser("スクリプトを選ぶ", _typecode_netscript);
1854- hud_lua_w->set_file(environment_preferences->hud_lua_file);
1855- table->dual_add(hud_lua_w->label("Script File"), d);
1856- table->dual_add(hud_lua_w, d);
1857- use_hud_lua_w->add_dependent_widget(hud_lua_w);
1858-
1859- table->add_row(new w_spacer, true);
1860- table->dual_add_row(new w_static_text("テーマ"), d);
1861-
1862- w_env_select *theme_w = new w_env_select(environment_preferences->theme_dir, "使用可能\なテーマ", _typecode_theme, &d);
1863- table->dual_add(theme_w->label("テーマ"), d);
1864- table->dual_add(theme_w, d);
1865-
1866- w_toggle *smooth_text_w = new w_toggle(environment_preferences->smooth_text);
1867- table->dual_add(smooth_text_w->label("文字を滑らかに"), d);
1868- table->dual_add(smooth_text_w, d);
1869-
1870- table->add_row(new w_spacer, true);
1871- table->dual_add_row(new w_static_text("オプション"), d);
1872-
1873- w_toggle *hide_extensions_w = new w_toggle(environment_preferences->hide_extensions);
1874- table->dual_add(hide_extensions_w->label("拡張子を隠す"), d);
1875- table->dual_add(hide_extensions_w, d);
1876-
1877- w_select* film_profile_w = new w_select(environment_preferences->film_profile, film_profile_labels);
1878- table->dual_add(film_profile_w->label("フィルムのプレイバック"), d);
1879- table->dual_add(film_profile_w, d);
1880-
1881- placer->add(table, true);
1882-
1883- placer->add(new w_spacer, true);
1884-
1885- horizontal_placer *button_placer = new horizontal_placer;
1886- w_button *w_accept = new w_button("了承", dialog_ok, &d);
1887- button_placer->dual_add(w_accept, d);
1888- w_button *w_cancel = new w_button("キャンセル", dialog_cancel, &d);
1889- button_placer->dual_add(w_cancel, d);
1804+ w_title *w_header = new w_title("環境設定");
1805+ placer->dual_add(w_header, d);
1806+ placer->add(new w_spacer, true);
1807+
1808+ table_placer *table = new table_placer(2, get_theme_space(ITEM_WIDGET), true);
1809+ table->col_flags(0, placeable::kAlignRight);
1810+
1811+ w_env_select *map_w = new w_env_select(environment_preferences->map_file, "使用可能\なマップ", _typecode_scenario, &d);
1812+ table->dual_add(map_w->label("マップ"), d);
1813+ table->dual_add(map_w, d);
1814+
1815+ w_env_select *physics_w = new w_env_select(environment_preferences->physics_file, "使用可能\な物理モデル", _typecode_physics, &d);
1816+ table->dual_add(physics_w->label("物理"), d);
1817+ table->dual_add(physics_w, d);
1818+
1819+ w_env_select *shapes_w = new w_env_select(environment_preferences->shapes_file, "使用可能\な形態", _typecode_shapes, &d);
1820+ table->dual_add(shapes_w->label("形態"), d);
1821+ table->dual_add(shapes_w, d);
1822+
1823+ w_env_select *sounds_w = new w_env_select(environment_preferences->sounds_file, "使用可能\なサウンド", _typecode_sounds, &d);
1824+ table->dual_add(sounds_w->label("サウンド"), d);
1825+ table->dual_add(sounds_w, d);
1826+
1827+ table->add_row(new w_spacer, true);
1828+ table->dual_add_row(new w_button("プラグイン", plugins_dialog, &d), d);
1829+
1830+ table->add_row(new w_spacer, true);
1831+ table->dual_add_row(new w_static_text("ソ\ロスクリプト"), d);
1832+ w_enabling_toggle* use_solo_lua_w = new w_enabling_toggle(environment_preferences->use_solo_lua);
1833+ table->dual_add(use_solo_lua_w->label("ソ\ロスクリプトを使用"), d);
1834+ table->dual_add(use_solo_lua_w, d);
1835+
1836+ w_file_chooser *solo_lua_w = new w_file_chooser("スクリプトを選ぶ", _typecode_netscript);
1837+ solo_lua_w->set_file(environment_preferences->solo_lua_file);
1838+ table->dual_add(solo_lua_w->label("スクリプトファイル"), d);
1839+ table->dual_add(solo_lua_w, d);
1840+ use_solo_lua_w->add_dependent_widget(solo_lua_w);
1841+
1842+ table->add_row(new w_spacer, true);
1843+ table->dual_add_row(new w_static_text("HUDスクリプト"), d);
1844+ w_enabling_toggle* use_hud_lua_w = new w_enabling_toggle(environment_preferences->use_hud_lua);
1845+ table->dual_add(use_hud_lua_w->label("HUDスクリプトを使用"), d);
1846+ table->dual_add(use_hud_lua_w, d);
1847+
1848+ w_file_chooser *hud_lua_w = new w_file_chooser("スクリプトを選ぶ", _typecode_netscript);
1849+ hud_lua_w->set_file(environment_preferences->hud_lua_file);
1850+ table->dual_add(hud_lua_w->label("Script File"), d);
1851+ table->dual_add(hud_lua_w, d);
1852+ use_hud_lua_w->add_dependent_widget(hud_lua_w);
1853+
1854+ table->add_row(new w_spacer, true);
1855+ table->dual_add_row(new w_static_text("テーマ"), d);
1856+
1857+ w_env_select *theme_w = new w_env_select(environment_preferences->theme_dir, "使用可能\なテーマ", _typecode_theme, &d);
1858+ table->dual_add(theme_w->label("テーマ"), d);
1859+ table->dual_add(theme_w, d);
1860+
1861+ w_toggle *smooth_text_w = new w_toggle(environment_preferences->smooth_text);
1862+ table->dual_add(smooth_text_w->label("文字を滑らかに"), d);
1863+ table->dual_add(smooth_text_w, d);
1864+
1865+ table->add_row(new w_spacer, true);
1866+ table->dual_add_row(new w_static_text("オプション"), d);
1867+
1868+ w_toggle *hide_extensions_w = new w_toggle(environment_preferences->hide_extensions);
1869+ table->dual_add(hide_extensions_w->label("拡張子を隠す"), d);
1870+ table->dual_add(hide_extensions_w, d);
1871+
1872+ w_select* film_profile_w = new w_select(environment_preferences->film_profile, film_profile_labels);
1873+ table->dual_add(film_profile_w->label("フィルムのプレイバック"), d);
1874+ table->dual_add(film_profile_w, d);
1875+
1876+ placer->add(table, true);
1877+
1878+ placer->add(new w_spacer, true);
1879+
1880+ horizontal_placer *button_placer = new horizontal_placer;
1881+ w_button *w_accept = new w_button("了承", dialog_ok, &d);
1882+ button_placer->dual_add(w_accept, d);
1883+ w_button *w_cancel = new w_button("キャンセル", dialog_cancel, &d);
1884+ button_placer->dual_add(w_cancel, d);
18901885 placer->add(button_placer, true);
18911886
18921887 d.set_widget_placer(placer);
@@ -2045,6 +2040,7 @@
20452040 // converting XML's reserved characters into appropriate strings.
20462041 void WriteXML_PasString(FILE *F, const char *Prefix, const unsigned char *String, const char *Suffix);
20472042 void WriteXML_CString(FILE *F, const char *Prefix, const char *String, int MaxLen, const char *Suffix);
2043+void WriteXML_Pathname(FILE *F, const char *Prefix, const char *String, const char *Suffix);
20482044 void WriteXML_Char(FILE *F, unsigned char c);
20492045
20502046 extern void hub_set_minimum_send_period(int32);
@@ -2340,7 +2336,7 @@
23402336 fprintf(F," game_protocol=\"%s\"\n",sNetworkGameProtocolNames[network_preferences->game_protocol]);
23412337 fprintf(F," use_speex_netmic_encoder=\"%s\"\n", BoolString(network_preferences->use_speex_encoder));
23422338 fprintf(F," use_netscript=\"%s\"\n", BoolString(network_preferences->use_netscript));
2343- WriteXML_CString(F," netscript_file=\"", network_preferences->netscript_file, sizeof(network_preferences->netscript_file), "\"\n");
2339+ WriteXML_Pathname(F," netscript_file=\"", network_preferences->netscript_file, "\"\n");
23442340 fprintf(F," cheat_flags=\"%hu\"\n",network_preferences->cheat_flags);
23452341 fprintf(F," advertise_on_metaserver=\"%s\"\n",BoolString(network_preferences->advertise_on_metaserver));
23462342 fprintf(F," attempt_upnp=\"%s\"\n", BoolString(network_preferences->attempt_upnp));
@@ -2369,20 +2365,11 @@
23692365 #endif // !defined(DISABLE_NETWORKING)
23702366
23712367 fprintf(F,"<environment\n");
2372- WriteXML_CString(F," map_file=\"",environment_preferences->map_file,256,"\"\n");
2373- WriteXML_CString(F," physics_file=\"",environment_preferences->physics_file,256,"\"\n");
2374- WriteXML_CString(F," shapes_file=\"",environment_preferences->shapes_file,256,"\"\n");
2375- WriteXML_CString(F," sounds_file=\"",environment_preferences->sounds_file,256,"\"\n");
2376-#if defined(HAVE_BUNDLE_NAME)
2377- extern char *bundle_name; // SDLMain.m
2378- // replace our leading bundle name with generic "AlephOneSDL.app" (we do reverse when loading)
2379- if (!strncmp(environment_preferences->theme_dir, bundle_name, strlen(bundle_name))) {
2380- strlcpy(temporary, sBundlePlaceholder, sizeof(temporary));
2381- strlcat(temporary, environment_preferences->theme_dir + strlen(bundle_name), sizeof(temporary));
2382- WriteXML_CString(F," theme_dir=\"",temporary,256,"\"\n");
2383- } else
2384-#endif
2385- WriteXML_CString(F," theme_dir=\"",environment_preferences->theme_dir,256,"\"\n");
2368+ WriteXML_Pathname(F," map_file=\"",environment_preferences->map_file,"\"\n");
2369+ WriteXML_Pathname(F," physics_file=\"",environment_preferences->physics_file,"\"\n");
2370+ WriteXML_Pathname(F," shapes_file=\"",environment_preferences->shapes_file,"\"\n");
2371+ WriteXML_Pathname(F," sounds_file=\"",environment_preferences->sounds_file,"\"\n");
2372+ WriteXML_Pathname(F," theme_dir=\"",environment_preferences->theme_dir,"\"\n");
23862373 fprintf(F," map_checksum=\"%u\"\n",environment_preferences->map_checksum);
23872374 fprintf(F," physics_checksum=\"%u\"\n",environment_preferences->physics_checksum);
23882375 fprintf(F," shapes_mod_date=\"%u\"\n",uint32(environment_preferences->shapes_mod_date));
@@ -2390,9 +2377,9 @@
23902377 fprintf(F," group_by_directory=\"%s\"\n",BoolString(environment_preferences->group_by_directory));
23912378 fprintf(F," reduce_singletons=\"%s\"\n",BoolString(environment_preferences->reduce_singletons));
23922379 fprintf(F," smooth_text=\"%s\"\n", BoolString(environment_preferences->smooth_text));
2393- WriteXML_CString(F," solo_lua_file=\"", environment_preferences->solo_lua_file, 256, "\"\n");
2380+ WriteXML_Pathname(F," solo_lua_file=\"", environment_preferences->solo_lua_file, "\"\n");
23942381 fprintf(F," use_solo_lua=\"%s\"\n", BoolString(environment_preferences->use_solo_lua));
2395- WriteXML_CString(F," hud_lua_file=\"", environment_preferences->hud_lua_file, 256, "\"\n");
2382+ WriteXML_Pathname(F," hud_lua_file=\"", environment_preferences->hud_lua_file, "\"\n");
23962383 fprintf(F," use_hud_lua=\"%s\"\n", BoolString(environment_preferences->use_hud_lua));
23972384 fprintf(F," hide_alephone_extensions=\"%s\"\n", BoolString(environment_preferences->hide_extensions));
23982385 fprintf(F," film_profile=\"%u\"\n", static_cast<uint32>(environment_preferences->film_profile));
@@ -2399,7 +2386,7 @@
23992386 fprintf(F,">\n");
24002387 for (Plugins::iterator it = Plugins::instance()->begin(); it != Plugins::instance()->end(); ++it) {
24012388 if (it->compatible() && !it->enabled) {
2402- fprintf(F," <disable_plugin path=\"%s\"/>\n", it->directory.GetPath());
2389+ WriteXML_Pathname(F," <disable_plugin path=\"", it->directory.GetPath(), "\"/>\n");
24032390 }
24042391 }
24052392 fprintf(F,"</environment>\n\n");
@@ -2876,6 +2863,17 @@
28762863 fprintf(F,"%s",Suffix);
28772864 }
28782865
2866+void WriteXML_Pathname(FILE *F, const char *Prefix, const char *String, const char *Suffix)
2867+{
2868+ char tempstr[256];
2869+ contract_symbolic_paths(tempstr, String, 255);
2870+ fprintf(F,"%s",Prefix);
2871+ size_t Len = strlen(tempstr);
2872+ for (size_t k=0; k<Len; k++)
2873+ WriteXML_Char(F,tempstr[k]);
2874+ fprintf(F,"%s",Suffix);
2875+}
2876+
28792877 void WriteXML_Char(FILE *F, unsigned char c)
28802878 {
28812879 // Make XML-friendly
@@ -3892,7 +3890,9 @@
38923890 }
38933891 else if (StringsEqual(Tag,"netscript_file"))
38943892 {
3895- DeUTF8_C(Value,strlen(Value),network_preferences->netscript_file,sizeof(network_preferences->netscript_file));
3893+ char tempstr[256];
3894+ expand_symbolic_paths(tempstr, Value, 255);
3895+ DeUTF8_C(tempstr,strlen(tempstr),network_preferences->netscript_file,sizeof(network_preferences->netscript_file));
38963896 }
38973897 else if (StringsEqual(Tag,"cheat_flags"))
38983898 {
@@ -3958,7 +3958,8 @@
39583958
39593959 bool XML_DisablePluginsParser::HandleAttribute(const char* Tag, const char* Value) {
39603960 if (StringsEqual(Tag, "path")) {
3961- Plugins::instance()->disable(Value);
3961+ char tempstr[256];
3962+ Plugins::instance()->disable(expand_symbolic_paths(tempstr, Value, 255));
39623963 return true;
39633964 }
39643965
@@ -3975,164 +3976,155 @@
39753976 XML_EnvironmentPrefsParser(): XML_ElementParser("environment") {}
39763977 };
39773978
3978-bool XML_EnvironmentPrefsParser::HandleAttribute(const char *Tag, const char *Value)
3979-{
3980- if (StringsEqual(Tag,"map_file"))
3981- {
3982- strncpy(environment_preferences->map_file, Value, 255);
3983- return true;
3984- }
3985- else if (StringsEqual(Tag,"physics_file"))
3986- {
3987- strncpy(environment_preferences->physics_file, Value, 255);
3988- return true;
3989- }
3990- else if (StringsEqual(Tag,"shapes_file"))
3991- {
3992- strncpy(environment_preferences->shapes_file, Value, 255);
3993- return true;
3994- }
3995- else if (StringsEqual(Tag,"sounds_file"))
3996- {
3997- strncpy(environment_preferences->sounds_file, Value, 255);
3998- return true;
3999- }
4000- else if (StringsEqual(Tag,"theme_dir"))
4001- {
4002- strncpy(environment_preferences->theme_dir, Value, 255);
4003-#if defined(HAVE_BUNDLE_NAME)
4004- extern char *bundle_name; // SDLMain.m
4005- // replace leading "AlephOneSDL.app" with our actual bundle name (we do reverse when saving)
4006- if (!strncmp(environment_preferences->theme_dir, sBundlePlaceholder, strlen(sBundlePlaceholder))) {
4007- strlcpy(temporary, bundle_name, sizeof(temporary));
4008- strlcat(temporary, environment_preferences->theme_dir + strlen(sBundlePlaceholder), sizeof(temporary));
4009- strlcpy(environment_preferences->theme_dir, temporary, 255);
4010- }
4011-#endif
4012- return true;
4013- }
4014- else if (StringsEqual(Tag,"map_checksum"))
4015- {
4016- return ReadUInt32Value(Value,environment_preferences->map_checksum);
4017- }
4018- else if (StringsEqual(Tag,"physics_checksum"))
4019- {
4020- return ReadUInt32Value(Value,environment_preferences->physics_checksum);
4021- }
4022- else if (StringsEqual(Tag,"shapes_mod_date"))
4023- {
4024- uint32 ModDate;
4025- if (ReadUInt32Value(Value,ModDate))
4026- {
4027- environment_preferences->shapes_mod_date = TimeType(ModDate);
4028- return true;
4029- }
4030- else
4031- return false;
4032- }
4033- else if (StringsEqual(Tag,"sounds_mod_date"))
4034- {
4035- uint32 ModDate;
4036- if (ReadUInt32Value(Value,ModDate))
4037- {
4038- environment_preferences->sounds_mod_date = TimeType(ModDate);
4039- return true;
4040- }
4041- else
4042- return false;
4043- }
4044- else if (StringsEqual(Tag,"group_by_directory"))
4045- {
4046- return ReadBooleanValue(Value,environment_preferences->group_by_directory);
4047- }
4048- else if (StringsEqual(Tag,"reduce_singletons"))
4049- {
4050- return ReadBooleanValue(Value,environment_preferences->reduce_singletons);
4051- }
4052- else if (StringsEqual(Tag,"non_bungie_warning"))
4053- {
4054- // obsolete
4055- return true;
4056- }
4057- else if (StringsEqual(Tag,"smooth_text"))
4058- {
4059- return ReadBooleanValue(Value, environment_preferences->smooth_text);
4060- }
4061- else if (StringsEqual(Tag,"solo_lua_file"))
4062- {
4063- strncpy(environment_preferences->solo_lua_file, Value, 255);
4064- return true;
4065- }
4066- else if (StringsEqual(Tag,"use_solo_lua"))
4067- {
4068- return ReadBooleanValue(Value, environment_preferences->use_solo_lua);
4069- }
4070- else if (StringsEqual(Tag,"hud_lua_file"))
4071- {
4072- strncpy(environment_preferences->hud_lua_file, Value, 255);
4073- return true;
4074- }
4075- else if (StringsEqual(Tag,"use_hud_lua"))
4076- {
4077- return ReadBooleanValue(Value, environment_preferences->use_hud_lua);
4078- }
4079- else if (StringsEqual(Tag, "hide_alephone_extensions"))
4080- {
4081- return ReadBooleanValue(Value, environment_preferences->hide_extensions);
4082- }
4083- else if (StringsEqual(Tag, "film_profile"))
4084- {
4085- uint32 profile;
4086- if (ReadUInt32Value(Value, profile))
4087- {
4088- environment_preferences->film_profile = static_cast<FilmProfileType>(profile);
4089- return true;
4090- }
4091- return false;
4092- }
4093- return true;
4094-}
4095-
4096-static XML_EnvironmentPrefsParser EnvironmentPrefsParser;
4097-
4098-
4099-
4100-void SetupPrefsParseTree()
4101-{
4102- // Add the root object here
4103- PrefsRootParser.AddChild(&MarathonPrefsParser);
4104-
4105- // Add all the others
4106-
4107- VoidPrefsParser.AddChild(Color_GetParser());
4108- GraphicsPrefsParser.AddChild(&VoidPrefsParser);
4109- LandscapePrefsParser.AddChild(Color_GetParser());
4110- GraphicsPrefsParser.AddChild(&LandscapePrefsParser);
4111- GraphicsPrefsParser.AddChild(&TexturePrefsParser);
4112- MarathonPrefsParser.AddChild(&GraphicsPrefsParser);
4113-
4114- PlayerPrefsParser.AddChild(&ChaseCamPrefsParser);
4115- CrosshairsPrefsParser.AddChild(Color_GetParser());
4116- PlayerPrefsParser.AddChild(&CrosshairsPrefsParser);
4117- MarathonPrefsParser.AddChild(&PlayerPrefsParser);
4118-
4119- InputPrefsParser.AddChild(&MouseButtonPrefsParser);
4120- InputPrefsParser.AddChild(&AxisMappingPrefsParser);
4121- InputPrefsParser.AddChild(&MacKeyPrefsParser);
4122- InputPrefsParser.AddChild(&SDLKeyPrefsParser);
4123- MarathonPrefsParser.AddChild(&InputPrefsParser);
4124-
4125- MarathonPrefsParser.AddChild(&SoundPrefsParser);
4126-
4127-#if !defined(DISABLE_NETWORKING)
4128- NetworkPrefsParser.AddChild(Color_GetParser());
4129- NetworkPrefsParser.AddChild(StarGameProtocol::GetParser());
4130- NetworkPrefsParser.AddChild(RingGameProtocol::GetParser());
4131-#endif // !defined(DISABLE_NETWORKING)
4132- NetworkPrefsParser.AddChild(&MacFSSpecPrefsParser);
4133- MarathonPrefsParser.AddChild(&NetworkPrefsParser);
4134-
4135- EnvironmentPrefsParser.AddChild(&MacFSSpecPrefsParser);
4136- EnvironmentPrefsParser.AddChild(&DisablePluginsParser);
4137- MarathonPrefsParser.AddChild(&EnvironmentPrefsParser);
4138-}
3979+bool XML_EnvironmentPrefsParser::HandleAttribute(const char *Tag, const char *Value)
3980+{
3981+ if (StringsEqual(Tag,"map_file"))
3982+ {
3983+ expand_symbolic_paths(environment_preferences->map_file, Value, 255);
3984+ return true;
3985+ }
3986+ else if (StringsEqual(Tag,"physics_file"))
3987+ {
3988+ expand_symbolic_paths(environment_preferences->physics_file, Value, 255);
3989+ return true;
3990+ }
3991+ else if (StringsEqual(Tag,"shapes_file"))
3992+ {
3993+ expand_symbolic_paths(environment_preferences->shapes_file, Value, 255);
3994+ return true;
3995+ }
3996+ else if (StringsEqual(Tag,"sounds_file"))
3997+ {
3998+ expand_symbolic_paths(environment_preferences->sounds_file, Value, 255);
3999+ return true;
4000+ }
4001+ else if (StringsEqual(Tag,"theme_dir"))
4002+ {
4003+ expand_symbolic_paths(environment_preferences->theme_dir, Value, 255);
4004+ return true;
4005+ }
4006+ else if (StringsEqual(Tag,"map_checksum"))
4007+ {
4008+ return ReadUInt32Value(Value,environment_preferences->map_checksum);
4009+ }
4010+ else if (StringsEqual(Tag,"physics_checksum"))
4011+ {
4012+ return ReadUInt32Value(Value,environment_preferences->physics_checksum);
4013+ }
4014+ else if (StringsEqual(Tag,"shapes_mod_date"))
4015+ {
4016+ uint32 ModDate;
4017+ if (ReadUInt32Value(Value,ModDate))
4018+ {
4019+ environment_preferences->shapes_mod_date = TimeType(ModDate);
4020+ return true;
4021+ }
4022+ else
4023+ return false;
4024+ }
4025+ else if (StringsEqual(Tag,"sounds_mod_date"))
4026+ {
4027+ uint32 ModDate;
4028+ if (ReadUInt32Value(Value,ModDate))
4029+ {
4030+ environment_preferences->sounds_mod_date = TimeType(ModDate);
4031+ return true;
4032+ }
4033+ else
4034+ return false;
4035+ }
4036+ else if (StringsEqual(Tag,"group_by_directory"))
4037+ {
4038+ return ReadBooleanValue(Value,environment_preferences->group_by_directory);
4039+ }
4040+ else if (StringsEqual(Tag,"reduce_singletons"))
4041+ {
4042+ return ReadBooleanValue(Value,environment_preferences->reduce_singletons);
4043+ }
4044+ else if (StringsEqual(Tag,"non_bungie_warning"))
4045+ {
4046+ // obsolete
4047+ return true;
4048+ }
4049+ else if (StringsEqual(Tag,"smooth_text"))
4050+ {
4051+ return ReadBooleanValue(Value, environment_preferences->smooth_text);
4052+ }
4053+ else if (StringsEqual(Tag,"solo_lua_file"))
4054+ {
4055+ expand_symbolic_paths(environment_preferences->solo_lua_file, Value, 255);
4056+ return true;
4057+ }
4058+ else if (StringsEqual(Tag,"use_solo_lua"))
4059+ {
4060+ return ReadBooleanValue(Value, environment_preferences->use_solo_lua);
4061+ }
4062+ else if (StringsEqual(Tag,"hud_lua_file"))
4063+ {
4064+ expand_symbolic_paths(environment_preferences->hud_lua_file, Value, 255);
4065+ return true;
4066+ }
4067+ else if (StringsEqual(Tag,"use_hud_lua"))
4068+ {
4069+ return ReadBooleanValue(Value, environment_preferences->use_hud_lua);
4070+ }
4071+ else if (StringsEqual(Tag, "hide_alephone_extensions"))
4072+ {
4073+ return ReadBooleanValue(Value, environment_preferences->hide_extensions);
4074+ }
4075+ else if (StringsEqual(Tag, "film_profile"))
4076+ {
4077+ uint32 profile;
4078+ if (ReadUInt32Value(Value, profile))
4079+ {
4080+ environment_preferences->film_profile = static_cast<FilmProfileType>(profile);
4081+ return true;
4082+ }
4083+ return false;
4084+ }
4085+ return true;
4086+}
4087+
4088+static XML_EnvironmentPrefsParser EnvironmentPrefsParser;
4089+
4090+
4091+
4092+void SetupPrefsParseTree()
4093+{
4094+ // Add the root object here
4095+ PrefsRootParser.AddChild(&MarathonPrefsParser);
4096+
4097+ // Add all the others
4098+
4099+ VoidPrefsParser.AddChild(Color_GetParser());
4100+ GraphicsPrefsParser.AddChild(&VoidPrefsParser);
4101+ LandscapePrefsParser.AddChild(Color_GetParser());
4102+ GraphicsPrefsParser.AddChild(&LandscapePrefsParser);
4103+ GraphicsPrefsParser.AddChild(&TexturePrefsParser);
4104+ MarathonPrefsParser.AddChild(&GraphicsPrefsParser);
4105+
4106+ PlayerPrefsParser.AddChild(&ChaseCamPrefsParser);
4107+ CrosshairsPrefsParser.AddChild(Color_GetParser());
4108+ PlayerPrefsParser.AddChild(&CrosshairsPrefsParser);
4109+ MarathonPrefsParser.AddChild(&PlayerPrefsParser);
4110+
4111+ InputPrefsParser.AddChild(&MouseButtonPrefsParser);
4112+ InputPrefsParser.AddChild(&AxisMappingPrefsParser);
4113+ InputPrefsParser.AddChild(&MacKeyPrefsParser);
4114+ InputPrefsParser.AddChild(&SDLKeyPrefsParser);
4115+ MarathonPrefsParser.AddChild(&InputPrefsParser);
4116+
4117+ MarathonPrefsParser.AddChild(&SoundPrefsParser);
4118+
4119+#if !defined(DISABLE_NETWORKING)
4120+ NetworkPrefsParser.AddChild(Color_GetParser());
4121+ NetworkPrefsParser.AddChild(StarGameProtocol::GetParser());
4122+ NetworkPrefsParser.AddChild(RingGameProtocol::GetParser());
4123+#endif // !defined(DISABLE_NETWORKING)
4124+ NetworkPrefsParser.AddChild(&MacFSSpecPrefsParser);
4125+ MarathonPrefsParser.AddChild(&NetworkPrefsParser);
4126+
4127+ EnvironmentPrefsParser.AddChild(&MacFSSpecPrefsParser);
4128+ EnvironmentPrefsParser.AddChild(&DisablePluginsParser);
4129+ MarathonPrefsParser.AddChild(&EnvironmentPrefsParser);
4130+}
--- marathon/trunk/Source_Files/shell.h (revision 504)
+++ marathon/trunk/Source_Files/shell.h (revision 505)
@@ -103,8 +103,10 @@
103103 // Load the base MML scripts:
104104 void LoadBaseMMLScripts();
105105
106-// Application info:
106+// Application and directory info:
107107 const char *get_application_name(void);
108+char *expand_symbolic_paths(char *dest, const char *src, int maxlen);
109+char *contract_symbolic_paths(char *dest, const char *src, int maxlen);
108110
109111 /* ---------- prototypes/SHAPES.C */
110112
--- marathon/trunk/Source_Files/Files/FileHandler.cpp (revision 504)
+++ marathon/trunk/Source_Files/Files/FileHandler.cpp (revision 505)
@@ -1,1477 +1,1480 @@
1-/*
2-
3- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4- and the "Aleph One" developers.
5-
6- This program is free software; you can redistribute it and/or modify
7- it under the terms of the GNU General Public License as published by
8- the Free Software Foundation; either version 3 of the License, or
9- (at your option) any later version.
10-
11- This program is distributed in the hope that it will be useful,
12- but WITHOUT ANY WARRANTY; without even the implied warranty of
13- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14- GNU General Public License for more details.
15-
16- This license is contained in the file "COPYING",
17- which is included with this source code; it is available online at
18- http://www.gnu.org/licenses/gpl.html
19-
20-*/
21-
22-/*
23- * FileHandler_SDL.cpp - Platform-independant file handling, SDL implementation
24- *
25- * Written in 2000 by Christian Bauer
26- */
27-#ifndef SDL_RFORK_HACK
28-#include "cseries.h"
29-#include "FileHandler.h"
30-#include "resource_manager.h"
31-
32-#include "shell.h"
33-#include "interface.h"
34-#include "game_errors.h"
35-#include "tags.h"
36-
37-#include <stdio.h>
38-#include <stdlib.h>
39-#include <errno.h>
40-#include <limits.h>
41-#include <string>
42-#include <vector>
43-
44-#include <SDL_endian.h>
45-
46-#ifdef HAVE_UNISTD_H
47-#include <sys/stat.h>
48-#include <fcntl.h>
49-#include <dirent.h>
50-#include <unistd.h>
51-#endif
52-
53-#ifdef HAVE_ZZIP
54-#include <zzip/lib.h>
55-#include "SDL_rwops_zzip.h"
56-#endif
57-
58-#ifdef __MACOS__
59-#include "mac_rwops.h"
60-#endif
61-
62-#if defined(__WIN32__)
63-#define PATH_SEP '\\'
64-#elif !defined(__MACOS__)
65-#define PATH_SEP '/'
66-#else
67-#define PATH_SEP ':'
68-#endif
69-
70-#ifdef __MVCPP__
71-
72-#include <direct.h> // for mkdir()
73-#include <io.h> // for access()
74-#define R_OK 4 // for access(), this checks for read access. 6 should be used for read and write access both.
75-#include <sys/types.h> // for stat()
76-#include <sys/stat.h> // for stat()
77-
78-#endif
79-
80-#include "sdl_dialogs.h"
81-#include "sdl_widgets.h"
82-#include "SoundManager.h" // !
83-
84-#include "preferences.h"
85-
86-#include <boost/bind.hpp>
87-#include <boost/function.hpp>
88-#include <boost/algorithm/string/predicate.hpp>
89-
90-// From shell_sdl.cpp
91-extern vector<DirectorySpecifier> data_search_path;
92-extern DirectorySpecifier local_data_dir, preferences_dir, saved_games_dir, recordings_dir;
93-
94-extern bool is_applesingle(SDL_RWops *f, bool rsrc_fork, int32 &offset, int32 &length);
95-extern bool is_macbinary(SDL_RWops *f, int32 &data_length, int32 &rsrc_length);
96-
97-/*
98- * Opened file
99- */
100-
101-OpenedFile::OpenedFile() : f(NULL), err(0), is_forked(false), fork_offset(0), fork_length(0) {}
102-
103-bool OpenedFile::IsOpen()
104-{
105- return f != NULL;
106-}
107-
108-bool OpenedFile::Close()
109-{
110- if (f) {
111- SDL_RWclose(f);
112- f = NULL;
113- err = 0;
114- }
115- is_forked = false;
116- fork_offset = 0;
117- fork_length = 0;
118- return true;
119-}
120-
121-bool OpenedFile::GetPosition(int32 &Position)
122-{
123- if (f == NULL)
124- return false;
125-
126- err = 0;
127- Position = SDL_RWtell(f) - fork_offset;
128- return true;
129-}
130-
131-bool OpenedFile::SetPosition(int32 Position)
132-{
133- if (f == NULL)
134- return false;
135-
136- err = 0;
137- if (SDL_RWseek(f, Position + fork_offset, SEEK_SET) < 0)
138- err = errno;
139- return err == 0;
140-}
141-
142-bool OpenedFile::GetLength(int32 &Length)
143-{
144- if (f == NULL)
145- return false;
146-
147- if (is_forked)
148- Length = fork_length;
149- else {
150- int32 pos = SDL_RWtell(f);
151- SDL_RWseek(f, 0, SEEK_END);
152- Length = SDL_RWtell(f);
153- SDL_RWseek(f, pos, SEEK_SET);
154- }
155- err = 0;
156- return true;
157-}
158-
159-bool OpenedFile::Read(int32 Count, void *Buffer)
160-{
161- if (f == NULL)
162- return false;
163-
164- err = 0;
165- return (SDL_RWread(f, Buffer, 1, Count) == Count);
166-}
167-
168-bool OpenedFile::Write(int32 Count, void *Buffer)
169-{
170- if (f == NULL)
171- return false;
172-
173- err = 0;
174- return (SDL_RWwrite(f, Buffer, 1, Count) == Count);
175-}
176-
177-
178-SDL_RWops *OpenedFile::TakeRWops ()
179-{
180- SDL_RWops *taken = f;
181- f = NULL;
182- Close ();
183- return taken;
184-}
185-
186-/*
187- * Loaded resource
188- */
189-
190-LoadedResource::LoadedResource() : p(NULL), size(0) {}
191-
192-bool LoadedResource::IsLoaded()
193-{
194- return p != NULL;
195-}
196-
197-void LoadedResource::Unload()
198-{
199- if (p) {
200- free(p);
201- p = NULL;
202- size = 0;
203- }
204-}
205-
206-size_t LoadedResource::GetLength()
207-{
208- return size;
209-}
210-
211-void *LoadedResource::GetPointer(bool DoDetach)
212-{
213- void *ret = p;
214- if (DoDetach)
215- Detach();
216- return ret;
217-}
218-
219-void LoadedResource::SetData(void *data, size_t length)
220-{
221- Unload();
222- p = data;
223- size = length;
224-}
225-
226-void LoadedResource::Detach()
227-{
228- p = NULL;
229- size = 0;
230-}
231-
232-
233-/*
234- * Opened resource file
235- */
236-
237-OpenedResourceFile::OpenedResourceFile() : f(NULL), saved_f(NULL), err(0) {}
238-
239-bool OpenedResourceFile::Push()
240-{
241- saved_f = cur_res_file();
242- if (saved_f != f)
243- use_res_file(f);
244- err = 0;
245- return true;
246-}
247-
248-bool OpenedResourceFile::Pop()
249-{
250- if (f != saved_f)
251- use_res_file(saved_f);
252- err = 0;
253- return true;
254-}
255-
256-bool OpenedResourceFile::Check(uint32 Type, int16 ID)
257-{
258- Push();
259- bool result = has_1_resource(Type, ID);
260- err = result ? 0 : errno;
261- Pop();
262- return result;
263-}
264-
265-bool OpenedResourceFile::Get(uint32 Type, int16 ID, LoadedResource &Rsrc)
266-{
267- Push();
268- bool success = get_1_resource(Type, ID, Rsrc);
269- err = success ? 0 : errno;
270- Pop();
271- return success;
272-}
273-
274-bool OpenedResourceFile::IsOpen()
275-{
276- return f != NULL;
277-}
278-
279-bool OpenedResourceFile::Close()
280-{
281- if (f) {
282- close_res_file(f);
283- f = NULL;
284- err = 0;
285- }
286- return true;
287-}
288-
289-
290-/*
291- * File specification
292- */
293-//AS: Constructor moved here to fix linking errors
294-FileSpecifier::FileSpecifier(): err(0) {}
295-const FileSpecifier &FileSpecifier::operator=(const FileSpecifier &other)
296-{
297- if (this != &other) {
298- name = other.name;
299- err = other.err;
300- }
301- return *this;
302-}
303-
304-// Create file
305-bool FileSpecifier::Create(Typecode Type)
306-{
307- Delete();
308- // files are automatically created when opened for writing
309- err = 0;
310- return true;
311-}
312-
313-// Create directory
314-bool FileSpecifier::CreateDirectory()
315-{
316- err = 0;
317-#if defined(__WIN32__)
318- if (mkdir(GetPath()) < 0)
319-#else
320- if (mkdir(GetPath(), 0777) < 0)
321-#endif
322- err = errno;
323- return err == 0;
324-}
325-
326-static std::string unix_path_separators(const std::string& input)
327-{
328- if (PATH_SEP == '/') return input;
329-
330- std::string output;
331- for (std::string::const_iterator it = input.begin(); it != input.end(); ++it) {
332- if (*it == PATH_SEP)
333- output.push_back('/');
334- else
335- output.push_back(*it);
336- }
337-
338- return output;
339-}
340-
341-// Open data file
342-bool FileSpecifier::Open(OpenedFile &OFile, bool Writable)
343-{
344- OFile.Close();
345-
346- SDL_RWops *f;
347-#ifdef __MACOS__
348- if (!Writable)
349- f = OFile.f = open_fork_from_existing_path(GetPath(), false);
350- else
351-#endif
352- {
353-#ifdef HAVE_ZZIP
354- if (!Writable)
355- {
356- f = OFile.f = SDL_RWFromZZIP(unix_path_separators(GetPath()).c_str(), "rb");
357- }
358- else
359-#endif
360- f = OFile.f = SDL_RWFromFile(GetPath(), Writable ? "wb+" : "rb");
361- }
362-
363- err = f ? 0 : errno;
364- if (f == NULL) {
365- set_game_error(systemError, err);
366- return false;
367- }
368- if (Writable)
369- return true;
370-
371- // Transparently handle AppleSingle and MacBinary files on reading
372- int32 offset, data_length, rsrc_length;
373- if (is_applesingle(f, false, offset, data_length)) {
374- OFile.is_forked = true;
375- OFile.fork_offset = offset;
376- OFile.fork_length = data_length;
377- SDL_RWseek(f, offset, SEEK_SET);
378- return true;
379- } else if (is_macbinary(f, data_length, rsrc_length)) {
380- OFile.is_forked = true;
381- OFile.fork_offset = 128;
382- OFile.fork_length = data_length;
383- SDL_RWseek(f, 128, SEEK_SET);
384- return true;
385- }
386- SDL_RWseek(f, 0, SEEK_SET);
387- return true;
388-}
389-
390-// Open resource file
391-bool FileSpecifier::Open(OpenedResourceFile &OFile, bool Writable)
392-{
393- OFile.Close();
394-
395- OFile.f = open_res_file(*this);
396- err = OFile.f ? 0 : errno;
397- if (OFile.f == NULL) {
398- set_game_error(systemError, err);
399- return false;
400- } else
401- return true;
402-}
403-
404-// Check for existence of file
405-bool FileSpecifier::Exists()
406-{
407- // Check whether the file is readable
408- err = 0;
409- if (access(GetPath(), R_OK) < 0)
410- err = errno;
411-
412-#ifdef HAVE_ZZIP
413- if (err)
414- {
415- // Check whether zzip can open the file (slow!)
416- ZZIP_FILE* file = zzip_open(unix_path_separators(GetPath()).c_str(), R_OK);
417- if (file)
418- {
419- zzip_close(file);
420- return true;
421- }
422- else
423- {
424- return false;
425- }
426- }
427-#endif
428- return (err == 0);
429-}
430-
431-bool FileSpecifier::IsDir()
432-{
433- struct stat st;
434- err = 0;
435- if (stat(GetPath(), &st) < 0)
436- return false;
437- return (S_ISDIR(st.st_mode));
438-}
439-
440-// Get modification date
441-TimeType FileSpecifier::GetDate()
442-{
443- struct stat st;
444- err = 0;
445- if (stat(GetPath(), &st) < 0) {
446- err = errno;
447- return 0;
448- }
449- return st.st_mtime;
450-}
451-
452-static const char * alephone_extensions[] = {
453- ".sceA",
454- ".sgaA",
455- ".filA",
456- ".phyA",
457- ".shpA",
458- ".sndA",
459- 0
460-};
461-
462-std::string FileSpecifier::HideExtension(const std::string& filename)
463-{
464- if (environment_preferences->hide_extensions)
465- {
466- const char **extension = alephone_extensions;
467- while (*extension)
468- {
469- if (boost::algorithm::ends_with(filename, *extension))
470- {
471- return filename.substr(0, filename.length() - strlen(*extension));
472- }
473-
474- ++extension;
475- }
476- }
477-
478- return filename;
479-}
480-
481-struct extension_mapping
482-{
483- const char *extension;
484- Typecode typecode;
485-};
486-
487-static extension_mapping extensions[] =
488-{
489- // some common extensions, to speed up building map lists
490- { "dds", _typecode_unknown },
491- { "jpg", _typecode_unknown },
492- { "png", _typecode_unknown },
493- { "bmp", _typecode_unknown },
494- { "txt", _typecode_unknown },
495- { "ttf", _typecode_unknown },
496-
497- { "lua", _typecode_netscript }, // netscript, or unknown?
498- { "mml", _typecode_unknown }, // no type code for this yet
499-
500- { "sceA", _typecode_scenario },
501- { "sgaA", _typecode_savegame },
502- { "filA", _typecode_film },
503- { "phyA", _typecode_physics },
504- { "shpA", _typecode_shapes },
505- { "sndA", _typecode_sounds },
506-
507- { "scen", _typecode_scenario },
508- { "shps", _typecode_shapes },
509-
510- {0, _typecode_unknown}
511-};
512-
513-// Determine file type
514-Typecode FileSpecifier::GetType()
515-{
516-
517- // if there's an extension, assume it's correct
518- const char *extension = strrchr(GetPath(), '.');
519- if (extension) {
520- extension_mapping *mapping = extensions;
521- while (mapping->extension)
522- {
523- if (strcasecmp(extension + 1, mapping->extension) == 0)
524- {
525- return mapping->typecode;
526- }
527- ++mapping;
528- }
529- }
530-
531- // Open file
532- OpenedFile f;
533- if (!Open(f))
534- return _typecode_unknown;
535- SDL_RWops *p = f.GetRWops();
536- int32 file_length = 0;
537- f.GetLength(file_length);
538-
539- // Check for Sounds file
540- {
541- f.SetPosition(0);
542- uint32 version = SDL_ReadBE32(p);
543- uint32 tag = SDL_ReadBE32(p);
544- if ((version == 0 || version == 1) && tag == FOUR_CHARS_TO_INT('s', 'n', 'd', '2'))
545- return _typecode_sounds;
546- }
547-
548- // Check for Map/Physics file
549- {
550- f.SetPosition(0);
551- int version = SDL_ReadBE16(p);
552- int data_version = SDL_ReadBE16(p);
553- if ((version == 0 || version == 1 || version == 2 || version == 4) && (data_version == 0 || data_version == 1 || data_version == 2)) {
554- SDL_RWseek(p, 68, SEEK_CUR);
555- int32 directory_offset = SDL_ReadBE32(p);
556- if (directory_offset >= file_length)
557- goto not_map;
558- f.SetPosition(128);
559- uint32 tag = SDL_ReadBE32(p);
560- // ghs: I do not believe this list is comprehensive
561- // I think it's just what we've seen so far?
562- switch (tag) {
563- case LINE_TAG:
564- case POINT_TAG:
565- case SIDE_TAG:
566- return _typecode_scenario;
567- break;
568- case MONSTER_PHYSICS_TAG:
569- return _typecode_physics;
570- break;
571- }
572-
573- }
574-not_map: ;
575- }
576-
577- // Check for Shapes file
578- {
579- f.SetPosition(0);
580- for (int i=0; i<32; i++) {
581- uint32 status_flags = SDL_ReadBE32(p);
582- int32 offset = SDL_ReadBE32(p);
583- int32 length = SDL_ReadBE32(p);
584- int32 offset16 = SDL_ReadBE32(p);
585- int32 length16 = SDL_ReadBE32(p);
586- if (status_flags != 0
587- || (offset != NONE && (offset >= file_length || offset + length > file_length))
588- || (offset16 != NONE && (offset16 >= file_length || offset16 + length16 > file_length)))
589- goto not_shapes;
590- SDL_RWseek(p, 12, SEEK_CUR);
591- }
592- return _typecode_shapes;
593-not_shapes: ;
594- }
595-
596- // Not identified
597- return _typecode_unknown;
598-}
599-
600-// Get free space on disk
601-bool FileSpecifier::GetFreeSpace(uint32 &FreeSpace)
602-{
603- // This is impossible to do in a platform-independant way, so we
604- // just return 16MB which should be enough for everything
605- FreeSpace = 16 * 1024 * 1024;
606- err = 0;
607- return true;
608-}
609-
610-// Exchange two files
611-bool FileSpecifier::Exchange(FileSpecifier &other)
612-{
613- // Create temporary name (this is cheap, we should make sure that the
614- // name is not already in use...)
615- FileSpecifier tmp;
616- ToDirectory(tmp);
617- tmp.AddPart("exchange_tmp_file");
618-
619- err = 0;
620- if (rename(GetPath(), tmp.GetPath()) < 0)
621- err = errno;
622- else
623- rename(other.GetPath(), GetPath());
624- if (rename(tmp.GetPath(), other.GetPath()) < 0)
625- err = errno;
626- return err == 0;
627-}
628-
629-// Delete file
630-bool FileSpecifier::Delete()
631-{
632- err = 0;
633- if (remove(GetPath()) < 0)
634- err = errno;
635- return err == 0;
636-}
637-
638-bool FileSpecifier::Rename(const FileSpecifier& Destination)
639-{
640- return rename(GetPath(), Destination.GetPath()) == 0;
641-}
642-
643-// Set to local (per-user) data directory
644-void FileSpecifier::SetToLocalDataDir()
645-{
646- name = local_data_dir.name;
647-}
648-
649-// Set to preferences directory
650-void FileSpecifier::SetToPreferencesDir()
651-{
652- name = preferences_dir.name;
653-}
654-
655-// Set to saved games directory
656-void FileSpecifier::SetToSavedGamesDir()
657-{
658- name = saved_games_dir.name;
659-}
660-
661-// Set to recordings directory
662-void FileSpecifier::SetToRecordingsDir()
663-{
664- name = recordings_dir.name;
665-}
666-
667-static string local_path_separators(const char *path)
668-{
669- string local_path = path;
670- if (PATH_SEP == '/') return local_path;
671-
672- for (size_t k = 0; k < local_path.size(); ++k) {
673- if (local_path[k] == '/')
674- local_path[k] = PATH_SEP;
675- }
676-
677- return local_path;
678-}
679-
680-// Traverse search path, look for file given relative path name
681-bool FileSpecifier::SetNameWithPath(const char *NameWithPath)
682-{
683- FileSpecifier full_path;
684- string rel_path = local_path_separators(NameWithPath);
685-
686- vector<DirectorySpecifier>::const_iterator i = data_search_path.begin(), end = data_search_path.end();
687- while (i != end) {
688- full_path = *i + rel_path;
689- if (full_path.Exists()) {
690- name = full_path.name;
691- err = 0;
692- return true;
693- }
694- i++;
695- }
696- err = ENOENT;
697- return false;
698-}
699-
700-bool FileSpecifier::SetNameWithPath(const char* NameWithPath, const DirectorySpecifier& Directory)
701-{
702- FileSpecifier full_path;
703- string rel_path = local_path_separators(NameWithPath);
704-
705- full_path = Directory + rel_path;
706- if (full_path.Exists()) {
707- name = full_path.name;
708- err = 0;
709- return true;
710- }
711-
712- err = ENOENT;
713- return false;
714-}
715-
716-// Get last element of path
717-void FileSpecifier::GetName(char *part) const
718-{
719- string::size_type pos = name.rfind(PATH_SEP);
720- if (pos == string::npos)
721- strcpy(part, name.c_str());
722- else
723- strcpy(part, name.substr(pos + 1).c_str());
724-}
725-
726-// Add part to path name
727-void FileSpecifier::AddPart(const string &part)
728-{
729- if (name.length() && name[name.length() - 1] == PATH_SEP)
730- name += local_path_separators(part.c_str());
731- else
732- name = name + PATH_SEP + local_path_separators(part.c_str());
733-
734- canonicalize_path();
735-}
736-
737-// Split path to base and last part
738-void FileSpecifier::SplitPath(string &base, string &part) const
739-{
740- string::size_type pos = name.rfind(PATH_SEP);
741- if (pos == string::npos) {
742- base = name;
743- part.erase();
744- } else if (pos == 0) {
745- base = PATH_SEP;
746- part = name.substr(1);
747- } else {
748- base = name.substr(0, pos);
749- part = name.substr(pos + 1);
750- }
751-}
752-
753-// Fill file specifier with base name
754-void FileSpecifier::ToDirectory(DirectorySpecifier &dir)
755-{
756- string part;
757- SplitPath(dir, part);
758-}
759-
760-// Set file specifier from directory specifier
761-void FileSpecifier::FromDirectory(DirectorySpecifier &Dir)
762-{
763- name = Dir.name;
764-}
765-
766-// Canonicalize path
767-void FileSpecifier::canonicalize_path(void)
768-{
769-#if !defined(__WIN32__)
770-
771- // Replace multiple consecutive '/'s by a single '/'
772- while (true) {
773- string::size_type pos = name.find("//");
774- if (pos == string::npos)
775- break;
776- name.erase(pos, 1);
777- }
778-
779-#endif
780-
781- // Remove trailing '/'
782- // ZZZ: only if we're not naming the root directory /
783- if (!name.empty() && name[name.size()-1] == PATH_SEP && name.size() != 1)
784- name.erase(name.size()-1, 1);
785-}
786-
787-// Read directory contents
788-bool FileSpecifier::ReadDirectory(vector<dir_entry> &vec)
789-{
790- vec.clear();
791-
792-#if defined(__MVCPP__)
793-
794- WIN32_FIND_DATA findData;
795-
796- // We need to add a wildcard to the search name
797- string search_name;
798- search_name = name;
799- search_name += "\\*.*";
800-
801- HANDLE hFind = ::FindFirstFile(search_name.c_str(), &findData);
802-
803- if (hFind == INVALID_HANDLE_VALUE) {
804- err = ::GetLastError();
805- return false;
806- }
807-
808- do {
809- // Exclude current and parent directories
810- if (findData.cFileName[0] != '.' ||
811- (findData.cFileName[1] && findData.cFileName[1] != '.')) {
812- // Return found files to dir_entry
813- int32 fileSize = (findData.nFileSizeHigh * MAXDWORD) + findData.nFileSizeLow;
814- vec.push_back(dir_entry(findData.cFileName, fileSize,
815- (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0, false));
816- }
817- } while(::FindNextFile(hFind, &findData));
818-
819- if (!::FindClose(hFind))
820- err = ::GetLastError(); // not sure if we should return this or not
821- else
822- err = 0;
823- return true;
824-
825-#else
826-
827- DIR *d = opendir(GetPath());
828-
829- if (d == NULL) {
830- err = errno;
831- return false;
832- }
833- struct dirent *de = readdir(d);
834- while (de) {
835- FileSpecifier full_path = name;
836- full_path += de->d_name;
837- struct stat st;
838- if (stat(full_path.GetPath(), &st) == 0) {
839- // Ignore files starting with '.' and the directories '.' and '..'
840- if (de->d_name[0] != '.' || (S_ISDIR(st.st_mode) && !(de->d_name[1] == '\0' || de->d_name[1] == '.')))
841- vec.push_back(dir_entry(de->d_name, st.st_size, S_ISDIR(st.st_mode), false, st.st_mtime));
842- }
843- de = readdir(d);
844- }
845- closedir(d);
846- err = 0;
847- return true;
848-
849-#endif
850-}
851-
852-// Copy file contents
853-bool FileSpecifier::CopyContents(FileSpecifier &source_name)
854-{
855- err = 0;
856- OpenedFile src, dst;
857- if (source_name.Open(src)) {
858- Delete();
859- if (Open(dst, true)) {
860- const int BUFFER_SIZE = 1024;
861- uint8 buffer[BUFFER_SIZE];
862-
863- int32 length = 0;
864- src.GetLength(length);
865-
866- while (length && err == 0) {
867- int32 count = length > BUFFER_SIZE ? BUFFER_SIZE : length;
868- if (src.Read(count, buffer)) {
869- if (!dst.Write(count, buffer))
870- err = dst.GetError();
871- } else
872- err = src.GetError();
873- length -= count;
874- }
875- }
876- } else
877- err = source_name.GetError();
878- if (err)
879- Delete();
880- return err == 0;
881-}
882-
883-// ZZZ: Filesystem browsing list that lets user actually navigate directories...
884-class w_directory_browsing_list : public w_list<dir_entry>
885-{
886-public:
887- w_directory_browsing_list(const FileSpecifier& inStartingDirectory, dialog* inParentDialog)
888- : w_list<dir_entry>(entries, 400, 15, 0), parent_dialog(inParentDialog), current_directory(inStartingDirectory), sort_order(sort_by_name)
889- {
890- refresh_entries();
891- }
892-
893-
894- w_directory_browsing_list(const FileSpecifier& inStartingDirectory, dialog* inParentDialog, const string& inStartingFile)
895- : w_list<dir_entry>(entries, 400, 15, 0), parent_dialog(inParentDialog), current_directory(inStartingDirectory)
896- {
897- refresh_entries();
898- if(entries.size() != 0)
899- select_entry(inStartingFile, false);
900- }
901-
902-
903- void set_directory_changed_callback(action_proc inCallback, void* inArg = NULL)
904- {
905- directory_changed_proc = inCallback;
906- directory_changed_proc_arg = inArg;
907- }
908-
909-
910- void draw_item(vector<dir_entry>::const_iterator i, SDL_Surface *s, int16 x, int16 y, uint16 width, bool selected) const
911- {
912- y += font->get_ascent();
913- set_drawing_clip_rectangle(0, x, s->h, x + width);
914-
915- if(i->is_directory)
916- {
917- string theName = i->name + "/";
918- draw_text(s, theName.c_str (), x, y, selected ? get_theme_color (ITEM_WIDGET, ACTIVE_STATE) : get_theme_color (ITEM_WIDGET, DEFAULT_STATE), font, style, true);
919- }
920- else
921- {
922- char date[256];
923- tm *time_info = localtime(&i->date);
924-
925- if (time_info)
926- {
927- strftime(date, 256, "%x %R", time_info);
928- int date_width = text_width(date, font, style);
929- draw_text(s, date, x + width - date_width, y, selected ? get_theme_color(ITEM_WIDGET, ACTIVE_STATE) : get_theme_color(ITEM_WIDGET, DEFAULT_STATE), font, style);
930- set_drawing_clip_rectangle(0, x, s->h, x + width - date_width - 4);
931- }
932- draw_text(s, FileSpecifier::HideExtension(i->name).c_str (), x, y, selected ? get_theme_color (ITEM_WIDGET, ACTIVE_STATE) : get_theme_color (ITEM_WIDGET, DEFAULT_STATE), font, style, true);
933- }
934-
935- set_drawing_clip_rectangle(SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
936- }
937-
938-
939- bool can_move_up_a_level()
940- {
941- string base;
942- string part;
943- current_directory.SplitPath(base, part);
944- return (part != string());
945- }
946-
947-
948- void move_up_a_level()
949- {
950- string base;
951- string part;
952- current_directory.SplitPath(base, part);
953- if(part != string())
954- {
955- FileSpecifier parent_directory(base);
956- if(parent_directory.Exists())
957- {
958- current_directory = parent_directory;
959- refresh_entries();
960- select_entry(part, true);
961- announce_directory_changed();
962- }
963- }
964- }
965-
966-
967- void item_selected(void)
968- {
969- current_directory.AddPart(entries[selection].name);
970-
971- if(entries[selection].is_directory)
972- {
973- refresh_entries();
974- announce_directory_changed();
975- }
976- else if (file_selected)
977- {
978- file_selected(entries[selection].name);
979- }
980- }
981-
982- enum SortOrder {
983- sort_by_name,
984- sort_by_date,
985- };
986-
987- void sort_by(SortOrder order)
988- {
989- sort_order = order;
990- refresh_entries();
991- }
992-
993-
994- const FileSpecifier& get_file() { return current_directory; }
995-
996- boost::function<void(const std::string&)> file_selected;
997-
998-private:
999- vector<dir_entry> entries;
1000- dialog* parent_dialog;
1001- FileSpecifier current_directory;
1002- action_proc directory_changed_proc;
1003- void* directory_changed_proc_arg;
1004- SortOrder sort_order;
1005-
1006- struct most_recent
1007- {
1008- bool operator()(const dir_entry& a, const dir_entry& b)
1009- {
1010- return a.date > b.date;
1011- }
1012- };
1013-
1014- void refresh_entries()
1015- {
1016- if(current_directory.ReadDirectory(entries))
1017- {
1018- if (sort_order == sort_by_name)
1019- {
1020- sort(entries.begin(), entries.end());
1021- }
1022- else
1023- {
1024- sort(entries.begin(), entries.end(), most_recent());
1025- }
1026- }
1027- num_items = entries.size();
1028- new_items();
1029- }
1030-
1031- void select_entry(const string& inName, bool inIsDirectory)
1032- {
1033- dir_entry theEntryToFind(inName, NONE /* length - ignored for our purpose */, inIsDirectory);
1034- vector<dir_entry>::iterator theEntry = find(entries.begin(), entries.end(), theEntryToFind);
1035- if(theEntry != entries.end())
1036- set_selection(theEntry - entries.begin());
1037- }
1038-
1039- void announce_directory_changed()
1040- {
1041- if(directory_changed_proc != NULL)
1042- directory_changed_proc(directory_changed_proc_arg);
1043- }
1044-};
1045-
1046-const char* sort_by_labels[] = {
1047- "name",
1048- "date",
1049- 0
1050-};
1051-
1052-// common functionality for read and write dialogs
1053-class FileDialog {
1054-public:
1055- FileDialog() {
1056- }
1057-
1058- bool Run() {
1059- Layout();
1060-
1061- bool result = false;
1062- if (m_dialog.run() == 0)
1063- {
1064- result = true;
1065- }
1066-
1067- if (get_game_state() == _game_in_progress) update_game_window();
1068- return result;
1069- }
1070-
1071-protected:
1072- void Init(const FileSpecifier& dir, w_directory_browsing_list::SortOrder default_order, std::string filename) {
1073- m_sort_by_w = new w_select(static_cast<size_t>(default_order), sort_by_labels);
1074- m_sort_by_w->set_selection_changed_callback(boost::bind(&FileDialog::on_change_sort_order, this));
1075- m_up_button_w = new w_button("UP", boost::bind(&FileDialog::on_up, this));
1076- if (filename.empty())
1077- {
1078- m_list_w = new w_directory_browsing_list(dir, &m_dialog);
1079- }
1080- else
1081- {
1082- m_list_w = new w_directory_browsing_list(dir, &m_dialog, filename);
1083- }
1084- m_list_w->sort_by(default_order);
1085- m_list_w->set_directory_changed_callback(boost::bind(&FileDialog::on_directory_changed, this));
1086-
1087- dir.GetName(temporary);
1088- m_directory_name_w = new w_static_text(temporary);
1089- }
1090-
1091- dialog m_dialog;
1092- w_select* m_sort_by_w;
1093- w_button* m_up_button_w;
1094- w_static_text* m_directory_name_w;
1095- w_directory_browsing_list* m_list_w;
1096-
1097-private:
1098- virtual void Layout() = 0;
1099-
1100-
1101- void on_directory_changed() {
1102- m_list_w->get_file().GetName(temporary);
1103- m_directory_name_w->set_text(temporary);
1104-
1105- m_up_button_w->set_enabled(m_list_w->can_move_up_a_level());
1106-
1107- m_dialog.draw();
1108- }
1109-
1110- void on_change_sort_order() {
1111- m_list_w->sort_by(static_cast<w_directory_browsing_list::SortOrder>(m_sort_by_w->get_selection()));
1112- }
1113-
1114- void on_up() {
1115- m_list_w->move_up_a_level();
1116- }
1117-
1118-};
1119-
1120-class ReadFileDialog : public FileDialog
1121-{
1122-public:
1123- ReadFileDialog(FileSpecifier dir, Typecode type, const char* prompt) : FileDialog(), m_prompt(prompt) {
1124- w_directory_browsing_list::SortOrder default_order = w_directory_browsing_list::sort_by_name;
1125-
1126- if (!m_prompt)
1127- {
1128- switch(type)
1129- {
1130- case _typecode_savegame:
1131- m_prompt = "CONTINUE SAVED GAME";
1132- break;
1133- case _typecode_film:
1134- m_prompt = "REPLAY SAVED FILM";
1135- break;
1136- default:
1137- m_prompt = "OPEN FILE";
1138- break;
1139- }
1140- }
1141-
1142- std::string filename;
1143- switch (type)
1144- {
1145- case _typecode_savegame:
1146- dir.SetToSavedGamesDir();
1147- default_order = w_directory_browsing_list::sort_by_date;
1148- break;
1149- case _typecode_film:
1150- dir.SetToRecordingsDir();
1151- break;
1152- case _typecode_scenario:
1153- case _typecode_netscript:
1154- {
1155- // Go to most recently-used directory
1156- DirectorySpecifier theDirectory;
1157- dir.SplitPath(theDirectory, filename);
1158- dir.FromDirectory(theDirectory);
1159- if (!dir.Exists())
1160- dir.SetToLocalDataDir();
1161- }
1162- break;
1163- default:
1164- dir.SetToLocalDataDir();
1165- break;
1166- }
1167-
1168- Init(dir, default_order, filename);
1169-
1170- m_list_w->file_selected = boost::bind(&ReadFileDialog::on_file_selected, this);
1171- }
1172-
1173- void Layout() {
1174- vertical_placer* placer = new vertical_placer;
1175- placer->dual_add(new w_title(m_prompt), m_dialog);
1176- placer->add(new w_spacer, true);
1177-
1178- placer->dual_add(m_directory_name_w, m_dialog);
1179-
1180- placer->add(new w_spacer(), true);
1181-
1182- horizontal_placer* top_row_placer = new horizontal_placer;
1183-
1184- top_row_placer->dual_add(m_sort_by_w->label("Sorted by: "), m_dialog);
1185- top_row_placer->dual_add(m_sort_by_w, m_dialog);
1186- top_row_placer->add_flags(placeable::kFill);
1187- top_row_placer->add(new w_spacer, true);
1188- top_row_placer->add_flags();
1189- top_row_placer->dual_add(m_up_button_w, m_dialog);
1190-
1191- placer->add_flags(placeable::kFill);
1192- placer->add(top_row_placer, true);
1193- placer->add_flags();
1194-
1195- placer->dual_add(m_list_w, m_dialog);
1196- placer->add(new w_spacer, true);
1197-
1198- horizontal_placer* button_placer = new horizontal_placer;
1199- button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &m_dialog), m_dialog);
1200-
1201- placer->add(button_placer, true);
1202-
1203- m_dialog.activate_widget(m_list_w);
1204- m_dialog.set_widget_placer(placer);
1205- }
1206-
1207- FileSpecifier GetFile() {
1208- return m_list_w->get_file();
1209- }
1210-
1211-private:
1212- void on_file_selected() {
1213- m_dialog.quit(0);
1214- }
1215-
1216- const char* m_prompt;
1217- std::string m_filename;
1218-};
1219-
1220-bool FileSpecifier::ReadDialog(Typecode type, const char *prompt)
1221-{
1222- ReadFileDialog d(*this, type, prompt);
1223- if (d.Run())
1224- {
1225- *this = d.GetFile();
1226- return true;
1227- }
1228- else
1229- {
1230- return false;
1231- }
1232-}
1233-
1234-class w_file_name : public w_text_entry {
1235-public:
1236- w_file_name(dialog *d, const char *initial_name = NULL) : w_text_entry(31, initial_name), parent(d) {}
1237- ~w_file_name() {}
1238-
1239- void event(SDL_Event & e)
1240- {
1241- // Return = close dialog
1242- if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_RETURN)
1243- parent->quit(0);
1244- w_text_entry::event(e);
1245- }
1246-
1247-private:
1248- dialog *parent;
1249-};
1250-
1251-class WriteFileDialog : public FileDialog
1252-{
1253-public:
1254- WriteFileDialog(FileSpecifier dir, Typecode type, const char* prompt, const char* default_name) : FileDialog(), m_prompt(prompt), m_default_name(default_name), m_extension(0) {
1255- if (!m_prompt)
1256- {
1257- switch (type)
1258- {
1259- case _typecode_savegame:
1260- prompt = "SAVE GAME";
1261- break;
1262- case _typecode_film:
1263- prompt = "SAVE FILM";
1264- break;
1265- default:
1266- prompt = "SAVE FILE";
1267- break;
1268- }
1269- }
1270-
1271- switch (type)
1272- {
1273- case _typecode_savegame:
1274- m_extension = ".sgaA";
1275- break;
1276- case _typecode_film:
1277- m_extension = ".filA";
1278- break;
1279- default:
1280- break;
1281- }
1282-
1283- if (m_extension && boost::algorithm::ends_with(m_default_name, m_extension))
1284- {
1285- m_default_name.resize(m_default_name.size() - strlen(m_extension));
1286- }
1287-
1288- w_directory_browsing_list::SortOrder default_order = w_directory_browsing_list::sort_by_name;
1289- switch (type) {
1290- case _typecode_savegame:
1291- {
1292- string base;
1293- string part;
1294- dir.SplitPath(base, part);
1295- if (part != string())
1296- {
1297- dir = base;
1298- }
1299- default_order = w_directory_browsing_list::sort_by_date;
1300- }
1301- break;
1302- case _typecode_film:
1303- dir.SetToRecordingsDir();
1304- break;
1305- default:
1306- dir.SetToLocalDataDir();
1307- break;
1308- }
1309-
1310- Init(dir, default_order, m_default_name);
1311-
1312- m_list_w->file_selected = boost::bind(&WriteFileDialog::on_file_selected, this, _1);
1313- }
1314-
1315- void Layout() {
1316- vertical_placer* placer = new vertical_placer;
1317- placer->dual_add(new w_title(m_prompt), m_dialog);
1318- placer->add(new w_spacer, true);
1319-
1320- placer->dual_add(m_directory_name_w, m_dialog);
1321-
1322- placer->add(new w_spacer(), true);
1323-
1324- horizontal_placer* top_row_placer = new horizontal_placer;
1325-
1326- top_row_placer->dual_add(m_sort_by_w->label("Sorted by: "), m_dialog);
1327- top_row_placer->dual_add(m_sort_by_w, m_dialog);
1328- top_row_placer->add_flags(placeable::kFill);
1329- top_row_placer->add(new w_spacer, true);
1330- top_row_placer->add_flags();
1331- top_row_placer->dual_add(m_up_button_w, m_dialog);
1332-
1333- placer->add_flags(placeable::kFill);
1334- placer->add(top_row_placer, true);
1335- placer->add_flags();
1336-
1337- placer->dual_add(m_list_w, m_dialog);
1338- placer->add(new w_spacer, true);
1339-
1340- placer->add_flags(placeable::kFill);
1341-
1342- horizontal_placer* file_name_placer = new horizontal_placer;
1343- m_name_w = new w_file_name(&m_dialog, m_default_name.c_str());
1344- file_name_placer->dual_add(m_name_w->label("File Name:"), m_dialog);
1345- file_name_placer->add_flags(placeable::kFill);
1346- file_name_placer->dual_add(m_name_w, m_dialog);
1347-
1348- placer->add_flags(placeable::kFill);
1349- placer->add(file_name_placer, true);
1350- placer->add_flags();
1351- placer->add(new w_spacer, true);
1352-
1353- horizontal_placer* button_placer = new horizontal_placer;
1354- button_placer->dual_add(new w_button("OK", dialog_ok, &m_dialog), m_dialog);
1355- button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &m_dialog), m_dialog);
1356-
1357- placer->add(button_placer, true);
1358-
1359- m_dialog.activate_widget(m_name_w);
1360- m_dialog.set_widget_placer(placer);
1361- }
1362-
1363- FileSpecifier GetPath() {
1364- FileSpecifier dir = m_list_w->get_file();
1365- std::string base;
1366- std::string part;
1367- dir.SplitPath(base, part);
1368-
1369- std::string filename = GetFilename();
1370- if (part == filename)
1371- {
1372- dir = base;
1373- }
1374-
1375- if (m_extension && !boost::algorithm::ends_with(filename, m_extension))
1376- {
1377- filename += m_extension;
1378- }
1379- dir.AddPart(filename);
1380- return dir;
1381- }
1382-
1383- std::string GetFilename() {
1384- return m_name_w->get_text();
1385- }
1386-
1387-private:
1388- void on_file_selected(const std::string& filename) {
1389- m_name_w->set_text(filename.c_str());
1390- m_dialog.quit(0);
1391- }
1392-
1393- const char* m_prompt;
1394- std::string m_default_name;
1395- const char* m_extension;
1396- w_file_name* m_name_w;
1397-};
1398-
1399-static bool confirm_save_choice(FileSpecifier & file);
1400-
1401-bool FileSpecifier::WriteDialog(Typecode type, const char *prompt, const char *default_name)
1402-{
1403-again:
1404- WriteFileDialog d(*this, type, prompt, default_name);
1405- bool result = false;
1406- if (d.Run())
1407- {
1408- if (d.GetFilename().empty())
1409- {
1410- play_dialog_sound(DIALOG_ERROR_SOUND);
1411- goto again;
1412- }
1413-
1414- *this = d.GetPath();
1415-
1416- if (!confirm_save_choice(*this))
1417- {
1418- goto again;
1419- }
1420-
1421- result = true;
1422- }
1423-
1424- return result;
1425-
1426-}
1427-
1428-bool FileSpecifier::WriteDialogAsync(Typecode type, char *prompt, char *default_name)
1429-{
1430- return FileSpecifier::WriteDialog(type, prompt, default_name);
1431-}
1432-
1433-static bool confirm_save_choice(FileSpecifier & file)
1434-{
1435- // If the file doesn't exist, everything is alright
1436- if (!file.Exists())
1437- return true;
1438-
1439- // Construct message
1440- char name[256];
1441- file.GetName(name);
1442- char message[512];
1443- sprintf(message, "'%s' already exists.", name);
1444-
1445- // Create dialog
1446- dialog d;
1447- vertical_placer *placer = new vertical_placer;
1448- placer->dual_add(new w_static_text(message), d);
1449- placer->dual_add(new w_static_text("Ok to overwrite?"), d);
1450- placer->add(new w_spacer(), true);
1451-
1452- horizontal_placer *button_placer = new horizontal_placer;
1453- w_button *default_button = new w_button("YES", dialog_ok, &d);
1454- button_placer->dual_add(default_button, d);
1455- button_placer->dual_add(new w_button("NO", dialog_cancel, &d), d);
1456-
1457- placer->add(button_placer, true);
1458-
1459- d.activate_widget(default_button);
1460-
1461- d.set_widget_placer(placer);
1462-
1463- // Run dialog
1464- return d.run() == 0;
1465-}
1466-
1467-ScopedSearchPath::ScopedSearchPath(const DirectorySpecifier& dir)
1468-{
1469- data_search_path.insert(data_search_path.begin(), dir);
1470-}
1471-
1472-ScopedSearchPath::~ScopedSearchPath()
1473-{
1474- data_search_path.erase(data_search_path.begin());
1475-}
1476-
1477-#endif
1+/*
2+
3+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4+ and the "Aleph One" developers.
5+
6+ This program is free software; you can redistribute it and/or modify
7+ it under the terms of the GNU General Public License as published by
8+ the Free Software Foundation; either version 3 of the License, or
9+ (at your option) any later version.
10+
11+ This program is distributed in the hope that it will be useful,
12+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ GNU General Public License for more details.
15+
16+ This license is contained in the file "COPYING",
17+ which is included with this source code; it is available online at
18+ http://www.gnu.org/licenses/gpl.html
19+
20+*/
21+
22+/*
23+ * FileHandler_SDL.cpp - Platform-independant file handling, SDL implementation
24+ *
25+ * Written in 2000 by Christian Bauer
26+ */
27+#ifndef SDL_RFORK_HACK
28+#include "cseries.h"
29+#include "FileHandler.h"
30+#include "resource_manager.h"
31+
32+#include "shell.h"
33+#include "interface.h"
34+#include "game_errors.h"
35+#include "tags.h"
36+
37+#include <stdio.h>
38+#include <stdlib.h>
39+#include <errno.h>
40+#include <limits.h>
41+#include <string>
42+#include <vector>
43+
44+#include <SDL_endian.h>
45+
46+#ifdef HAVE_UNISTD_H
47+#include <sys/stat.h>
48+#include <fcntl.h>
49+#include <dirent.h>
50+#include <unistd.h>
51+#endif
52+
53+#ifdef HAVE_ZZIP
54+#include <zzip/lib.h>
55+#include "SDL_rwops_zzip.h"
56+#endif
57+
58+#ifdef __MACOS__
59+#include "mac_rwops.h"
60+#endif
61+
62+#if defined(__WIN32__)
63+#define PATH_SEP '\\'
64+#elif !defined(__MACOS__)
65+#define PATH_SEP '/'
66+#else
67+#define PATH_SEP ':'
68+#endif
69+
70+#ifdef __MVCPP__
71+
72+#include <direct.h> // for mkdir()
73+#include <io.h> // for access()
74+#define R_OK 4 // for access(), this checks for read access. 6 should be used for read and write access both.
75+#include <sys/types.h> // for stat()
76+#include <sys/stat.h> // for stat()
77+
78+#endif
79+
80+#include "sdl_dialogs.h"
81+#include "sdl_widgets.h"
82+#include "SoundManager.h" // !
83+
84+#include "preferences.h"
85+
86+#include <boost/bind.hpp>
87+#include <boost/function.hpp>
88+#include <boost/algorithm/string/predicate.hpp>
89+
90+// From shell_sdl.cpp
91+extern vector<DirectorySpecifier> data_search_path;
92+extern DirectorySpecifier local_data_dir, preferences_dir, saved_games_dir, recordings_dir;
93+
94+extern bool is_applesingle(SDL_RWops *f, bool rsrc_fork, int32 &offset, int32 &length);
95+extern bool is_macbinary(SDL_RWops *f, int32 &data_length, int32 &rsrc_length);
96+
97+/*
98+ * Opened file
99+ */
100+
101+OpenedFile::OpenedFile() : f(NULL), err(0), is_forked(false), fork_offset(0), fork_length(0) {}
102+
103+bool OpenedFile::IsOpen()
104+{
105+ return f != NULL;
106+}
107+
108+bool OpenedFile::Close()
109+{
110+ if (f) {
111+ SDL_RWclose(f);
112+ f = NULL;
113+ err = 0;
114+ }
115+ is_forked = false;
116+ fork_offset = 0;
117+ fork_length = 0;
118+ return true;
119+}
120+
121+bool OpenedFile::GetPosition(int32 &Position)
122+{
123+ if (f == NULL)
124+ return false;
125+
126+ err = 0;
127+ Position = SDL_RWtell(f) - fork_offset;
128+ return true;
129+}
130+
131+bool OpenedFile::SetPosition(int32 Position)
132+{
133+ if (f == NULL)
134+ return false;
135+
136+ err = 0;
137+ if (SDL_RWseek(f, Position + fork_offset, SEEK_SET) < 0)
138+ err = errno;
139+ return err == 0;
140+}
141+
142+bool OpenedFile::GetLength(int32 &Length)
143+{
144+ if (f == NULL)
145+ return false;
146+
147+ if (is_forked)
148+ Length = fork_length;
149+ else {
150+ int32 pos = SDL_RWtell(f);
151+ SDL_RWseek(f, 0, SEEK_END);
152+ Length = SDL_RWtell(f);
153+ SDL_RWseek(f, pos, SEEK_SET);
154+ }
155+ err = 0;
156+ return true;
157+}
158+
159+bool OpenedFile::Read(int32 Count, void *Buffer)
160+{
161+ if (f == NULL)
162+ return false;
163+
164+ err = 0;
165+ return (SDL_RWread(f, Buffer, 1, Count) == Count);
166+}
167+
168+bool OpenedFile::Write(int32 Count, void *Buffer)
169+{
170+ if (f == NULL)
171+ return false;
172+
173+ err = 0;
174+ return (SDL_RWwrite(f, Buffer, 1, Count) == Count);
175+}
176+
177+
178+SDL_RWops *OpenedFile::TakeRWops ()
179+{
180+ SDL_RWops *taken = f;
181+ f = NULL;
182+ Close ();
183+ return taken;
184+}
185+
186+/*
187+ * Loaded resource
188+ */
189+
190+LoadedResource::LoadedResource() : p(NULL), size(0) {}
191+
192+bool LoadedResource::IsLoaded()
193+{
194+ return p != NULL;
195+}
196+
197+void LoadedResource::Unload()
198+{
199+ if (p) {
200+ free(p);
201+ p = NULL;
202+ size = 0;
203+ }
204+}
205+
206+size_t LoadedResource::GetLength()
207+{
208+ return size;
209+}
210+
211+void *LoadedResource::GetPointer(bool DoDetach)
212+{
213+ void *ret = p;
214+ if (DoDetach)
215+ Detach();
216+ return ret;
217+}
218+
219+void LoadedResource::SetData(void *data, size_t length)
220+{
221+ Unload();
222+ p = data;
223+ size = length;
224+}
225+
226+void LoadedResource::Detach()
227+{
228+ p = NULL;
229+ size = 0;
230+}
231+
232+
233+/*
234+ * Opened resource file
235+ */
236+
237+OpenedResourceFile::OpenedResourceFile() : f(NULL), saved_f(NULL), err(0) {}
238+
239+bool OpenedResourceFile::Push()
240+{
241+ saved_f = cur_res_file();
242+ if (saved_f != f)
243+ use_res_file(f);
244+ err = 0;
245+ return true;
246+}
247+
248+bool OpenedResourceFile::Pop()
249+{
250+ if (f != saved_f)
251+ use_res_file(saved_f);
252+ err = 0;
253+ return true;
254+}
255+
256+bool OpenedResourceFile::Check(uint32 Type, int16 ID)
257+{
258+ Push();
259+ bool result = has_1_resource(Type, ID);
260+ err = result ? 0 : errno;
261+ Pop();
262+ return result;
263+}
264+
265+bool OpenedResourceFile::Get(uint32 Type, int16 ID, LoadedResource &Rsrc)
266+{
267+ Push();
268+ bool success = get_1_resource(Type, ID, Rsrc);
269+ err = success ? 0 : errno;
270+ Pop();
271+ return success;
272+}
273+
274+bool OpenedResourceFile::IsOpen()
275+{
276+ return f != NULL;
277+}
278+
279+bool OpenedResourceFile::Close()
280+{
281+ if (f) {
282+ close_res_file(f);
283+ f = NULL;
284+ err = 0;
285+ }
286+ return true;
287+}
288+
289+
290+/*
291+ * File specification
292+ */
293+//AS: Constructor moved here to fix linking errors
294+FileSpecifier::FileSpecifier(): err(0) {}
295+const FileSpecifier &FileSpecifier::operator=(const FileSpecifier &other)
296+{
297+ if (this != &other) {
298+ name = other.name;
299+ err = other.err;
300+ }
301+ return *this;
302+}
303+
304+// Create file
305+bool FileSpecifier::Create(Typecode Type)
306+{
307+ Delete();
308+ // files are automatically created when opened for writing
309+ err = 0;
310+ return true;
311+}
312+
313+// Create directory
314+bool FileSpecifier::CreateDirectory()
315+{
316+ err = 0;
317+#if defined(__WIN32__)
318+ if (mkdir(GetPath()) < 0)
319+#else
320+ if (mkdir(GetPath(), 0777) < 0)
321+#endif
322+ err = errno;
323+ return err == 0;
324+}
325+
326+static std::string unix_path_separators(const std::string& input)
327+{
328+ if (PATH_SEP == '/') return input;
329+
330+ std::string output;
331+ for (std::string::const_iterator it = input.begin(); it != input.end(); ++it) {
332+ if (*it == PATH_SEP)
333+ output.push_back('/');
334+ else
335+ output.push_back(*it);
336+ }
337+
338+ return output;
339+}
340+
341+// Open data file
342+bool FileSpecifier::Open(OpenedFile &OFile, bool Writable)
343+{
344+ OFile.Close();
345+
346+ SDL_RWops *f;
347+#ifdef __MACOS__
348+ if (!Writable)
349+ f = OFile.f = open_fork_from_existing_path(GetPath(), false);
350+ else
351+#endif
352+ {
353+#ifdef HAVE_ZZIP
354+ if (!Writable)
355+ {
356+ f = OFile.f = SDL_RWFromZZIP(unix_path_separators(GetPath()).c_str(), "rb");
357+ }
358+ else
359+#endif
360+ f = OFile.f = SDL_RWFromFile(GetPath(), Writable ? "wb+" : "rb");
361+ }
362+
363+ err = f ? 0 : errno;
364+ if (f == NULL) {
365+ set_game_error(systemError, err);
366+ return false;
367+ }
368+ if (Writable)
369+ return true;
370+
371+ // Transparently handle AppleSingle and MacBinary files on reading
372+ int32 offset, data_length, rsrc_length;
373+ if (is_applesingle(f, false, offset, data_length)) {
374+ OFile.is_forked = true;
375+ OFile.fork_offset = offset;
376+ OFile.fork_length = data_length;
377+ SDL_RWseek(f, offset, SEEK_SET);
378+ return true;
379+ } else if (is_macbinary(f, data_length, rsrc_length)) {
380+ OFile.is_forked = true;
381+ OFile.fork_offset = 128;
382+ OFile.fork_length = data_length;
383+ SDL_RWseek(f, 128, SEEK_SET);
384+ return true;
385+ }
386+ SDL_RWseek(f, 0, SEEK_SET);
387+ return true;
388+}
389+
390+// Open resource file
391+bool FileSpecifier::Open(OpenedResourceFile &OFile, bool Writable)
392+{
393+ OFile.Close();
394+
395+ OFile.f = open_res_file(*this);
396+ err = OFile.f ? 0 : errno;
397+ if (OFile.f == NULL) {
398+ set_game_error(systemError, err);
399+ return false;
400+ } else
401+ return true;
402+}
403+
404+// Check for existence of file
405+bool FileSpecifier::Exists()
406+{
407+ // Check whether the file is readable
408+ err = 0;
409+ if (access(GetPath(), R_OK) < 0)
410+ err = errno;
411+
412+#ifdef HAVE_ZZIP
413+ if (err)
414+ {
415+ // Check whether zzip can open the file (slow!)
416+ ZZIP_FILE* file = zzip_open(unix_path_separators(GetPath()).c_str(), R_OK);
417+ if (file)
418+ {
419+ zzip_close(file);
420+ return true;
421+ }
422+ else
423+ {
424+ return false;
425+ }
426+ }
427+#endif
428+ return (err == 0);
429+}
430+
431+bool FileSpecifier::IsDir()
432+{
433+ struct stat st;
434+ err = 0;
435+ if (stat(GetPath(), &st) < 0)
436+ return false;
437+ return (S_ISDIR(st.st_mode));
438+}
439+
440+// Get modification date
441+TimeType FileSpecifier::GetDate()
442+{
443+ struct stat st;
444+ err = 0;
445+ if (stat(GetPath(), &st) < 0) {
446+ err = errno;
447+ return 0;
448+ }
449+ return st.st_mtime;
450+}
451+
452+static const char * alephone_extensions[] = {
453+ ".sceA",
454+ ".sgaA",
455+ ".filA",
456+ ".phyA",
457+ ".shpA",
458+ ".sndA",
459+ 0
460+};
461+
462+std::string FileSpecifier::HideExtension(const std::string& filename)
463+{
464+ if (environment_preferences->hide_extensions)
465+ {
466+ const char **extension = alephone_extensions;
467+ while (*extension)
468+ {
469+ if (boost::algorithm::ends_with(filename, *extension))
470+ {
471+ return filename.substr(0, filename.length() - strlen(*extension));
472+ }
473+
474+ ++extension;
475+ }
476+ }
477+
478+ return filename;
479+}
480+
481+struct extension_mapping
482+{
483+ const char *extension;
484+ bool case_sensitive;
485+ Typecode typecode;
486+};
487+
488+static extension_mapping extensions[] =
489+{
490+ // some common extensions, to speed up building map lists
491+ { "dds", false, _typecode_unknown },
492+ { "jpg", false, _typecode_unknown },
493+ { "png", false, _typecode_unknown },
494+ { "bmp", false, _typecode_unknown },
495+ { "txt", false, _typecode_unknown },
496+ { "ttf", false, _typecode_unknown },
497+
498+ { "lua", false, _typecode_netscript }, // netscript, or unknown?
499+ { "mml", false, _typecode_unknown }, // no type code for this yet
500+
501+ { "sceA", false, _typecode_scenario },
502+ { "sgaA", false, _typecode_savegame },
503+ { "filA", false, _typecode_film },
504+ { "phyA", false, _typecode_physics },
505+ { "ShPa", true, _typecode_shapespatch }, // must come before shpA
506+ { "shpA", false, _typecode_shapes },
507+ { "sndA", false, _typecode_sounds },
508+
509+ { "scen", false, _typecode_scenario },
510+ { "shps", false, _typecode_shapes },
511+
512+ {0, false, _typecode_unknown}
513+};
514+
515+// Determine file type
516+Typecode FileSpecifier::GetType()
517+{
518+
519+ // if there's an extension, assume it's correct
520+ const char *extension = strrchr(GetPath(), '.');
521+ if (extension) {
522+ extension_mapping *mapping = extensions;
523+ while (mapping->extension)
524+ {
525+ if (( mapping->case_sensitive && (strcmp(extension + 1, mapping->extension) == 0)) ||
526+ (!mapping->case_sensitive && (strcasecmp(extension + 1, mapping->extension) == 0)))
527+ {
528+ return mapping->typecode;
529+ }
530+ ++mapping;
531+ }
532+ }
533+
534+ // Open file
535+ OpenedFile f;
536+ if (!Open(f))
537+ return _typecode_unknown;
538+ SDL_RWops *p = f.GetRWops();
539+ int32 file_length = 0;
540+ f.GetLength(file_length);
541+
542+ // Check for Sounds file
543+ {
544+ f.SetPosition(0);
545+ uint32 version = SDL_ReadBE32(p);
546+ uint32 tag = SDL_ReadBE32(p);
547+ if ((version == 0 || version == 1) && tag == FOUR_CHARS_TO_INT('s', 'n', 'd', '2'))
548+ return _typecode_sounds;
549+ }
550+
551+ // Check for Map/Physics file
552+ {
553+ f.SetPosition(0);
554+ int version = SDL_ReadBE16(p);
555+ int data_version = SDL_ReadBE16(p);
556+ if ((version == 0 || version == 1 || version == 2 || version == 4) && (data_version == 0 || data_version == 1 || data_version == 2)) {
557+ SDL_RWseek(p, 68, SEEK_CUR);
558+ int32 directory_offset = SDL_ReadBE32(p);
559+ if (directory_offset >= file_length)
560+ goto not_map;
561+ f.SetPosition(128);
562+ uint32 tag = SDL_ReadBE32(p);
563+ // ghs: I do not believe this list is comprehensive
564+ // I think it's just what we've seen so far?
565+ switch (tag) {
566+ case LINE_TAG:
567+ case POINT_TAG:
568+ case SIDE_TAG:
569+ return _typecode_scenario;
570+ break;
571+ case MONSTER_PHYSICS_TAG:
572+ return _typecode_physics;
573+ break;
574+ }
575+
576+ }
577+not_map: ;
578+ }
579+
580+ // Check for Shapes file
581+ {
582+ f.SetPosition(0);
583+ for (int i=0; i<32; i++) {
584+ uint32 status_flags = SDL_ReadBE32(p);
585+ int32 offset = SDL_ReadBE32(p);
586+ int32 length = SDL_ReadBE32(p);
587+ int32 offset16 = SDL_ReadBE32(p);
588+ int32 length16 = SDL_ReadBE32(p);
589+ if (status_flags != 0
590+ || (offset != NONE && (offset >= file_length || offset + length > file_length))
591+ || (offset16 != NONE && (offset16 >= file_length || offset16 + length16 > file_length)))
592+ goto not_shapes;
593+ SDL_RWseek(p, 12, SEEK_CUR);
594+ }
595+ return _typecode_shapes;
596+not_shapes: ;
597+ }
598+
599+ // Not identified
600+ return _typecode_unknown;
601+}
602+
603+// Get free space on disk
604+bool FileSpecifier::GetFreeSpace(uint32 &FreeSpace)
605+{
606+ // This is impossible to do in a platform-independant way, so we
607+ // just return 16MB which should be enough for everything
608+ FreeSpace = 16 * 1024 * 1024;
609+ err = 0;
610+ return true;
611+}
612+
613+// Exchange two files
614+bool FileSpecifier::Exchange(FileSpecifier &other)
615+{
616+ // Create temporary name (this is cheap, we should make sure that the
617+ // name is not already in use...)
618+ FileSpecifier tmp;
619+ ToDirectory(tmp);
620+ tmp.AddPart("exchange_tmp_file");
621+
622+ err = 0;
623+ if (rename(GetPath(), tmp.GetPath()) < 0)
624+ err = errno;
625+ else
626+ rename(other.GetPath(), GetPath());
627+ if (rename(tmp.GetPath(), other.GetPath()) < 0)
628+ err = errno;
629+ return err == 0;
630+}
631+
632+// Delete file
633+bool FileSpecifier::Delete()
634+{
635+ err = 0;
636+ if (remove(GetPath()) < 0)
637+ err = errno;
638+ return err == 0;
639+}
640+
641+bool FileSpecifier::Rename(const FileSpecifier& Destination)
642+{
643+ return rename(GetPath(), Destination.GetPath()) == 0;
644+}
645+
646+// Set to local (per-user) data directory
647+void FileSpecifier::SetToLocalDataDir()
648+{
649+ name = local_data_dir.name;
650+}
651+
652+// Set to preferences directory
653+void FileSpecifier::SetToPreferencesDir()
654+{
655+ name = preferences_dir.name;
656+}
657+
658+// Set to saved games directory
659+void FileSpecifier::SetToSavedGamesDir()
660+{
661+ name = saved_games_dir.name;
662+}
663+
664+// Set to recordings directory
665+void FileSpecifier::SetToRecordingsDir()
666+{
667+ name = recordings_dir.name;
668+}
669+
670+static string local_path_separators(const char *path)
671+{
672+ string local_path = path;
673+ if (PATH_SEP == '/') return local_path;
674+
675+ for (size_t k = 0; k < local_path.size(); ++k) {
676+ if (local_path[k] == '/')
677+ local_path[k] = PATH_SEP;
678+ }
679+
680+ return local_path;
681+}
682+
683+// Traverse search path, look for file given relative path name
684+bool FileSpecifier::SetNameWithPath(const char *NameWithPath)
685+{
686+ FileSpecifier full_path;
687+ string rel_path = local_path_separators(NameWithPath);
688+
689+ vector<DirectorySpecifier>::const_iterator i = data_search_path.begin(), end = data_search_path.end();
690+ while (i != end) {
691+ full_path = *i + rel_path;
692+ if (full_path.Exists()) {
693+ name = full_path.name;
694+ err = 0;
695+ return true;
696+ }
697+ i++;
698+ }
699+ err = ENOENT;
700+ return false;
701+}
702+
703+bool FileSpecifier::SetNameWithPath(const char* NameWithPath, const DirectorySpecifier& Directory)
704+{
705+ FileSpecifier full_path;
706+ string rel_path = local_path_separators(NameWithPath);
707+
708+ full_path = Directory + rel_path;
709+ if (full_path.Exists()) {
710+ name = full_path.name;
711+ err = 0;
712+ return true;
713+ }
714+
715+ err = ENOENT;
716+ return false;
717+}
718+
719+// Get last element of path
720+void FileSpecifier::GetName(char *part) const
721+{
722+ string::size_type pos = name.rfind(PATH_SEP);
723+ if (pos == string::npos)
724+ strcpy(part, name.c_str());
725+ else
726+ strcpy(part, name.substr(pos + 1).c_str());
727+}
728+
729+// Add part to path name
730+void FileSpecifier::AddPart(const string &part)
731+{
732+ if (name.length() && name[name.length() - 1] == PATH_SEP)
733+ name += local_path_separators(part.c_str());
734+ else
735+ name = name + PATH_SEP + local_path_separators(part.c_str());
736+
737+ canonicalize_path();
738+}
739+
740+// Split path to base and last part
741+void FileSpecifier::SplitPath(string &base, string &part) const
742+{
743+ string::size_type pos = name.rfind(PATH_SEP);
744+ if (pos == string::npos) {
745+ base = name;
746+ part.erase();
747+ } else if (pos == 0) {
748+ base = PATH_SEP;
749+ part = name.substr(1);
750+ } else {
751+ base = name.substr(0, pos);
752+ part = name.substr(pos + 1);
753+ }
754+}
755+
756+// Fill file specifier with base name
757+void FileSpecifier::ToDirectory(DirectorySpecifier &dir)
758+{
759+ string part;
760+ SplitPath(dir, part);
761+}
762+
763+// Set file specifier from directory specifier
764+void FileSpecifier::FromDirectory(DirectorySpecifier &Dir)
765+{
766+ name = Dir.name;
767+}
768+
769+// Canonicalize path
770+void FileSpecifier::canonicalize_path(void)
771+{
772+#if !defined(__WIN32__)
773+
774+ // Replace multiple consecutive '/'s by a single '/'
775+ while (true) {
776+ string::size_type pos = name.find("//");
777+ if (pos == string::npos)
778+ break;
779+ name.erase(pos, 1);
780+ }
781+
782+#endif
783+
784+ // Remove trailing '/'
785+ // ZZZ: only if we're not naming the root directory /
786+ if (!name.empty() && name[name.size()-1] == PATH_SEP && name.size() != 1)
787+ name.erase(name.size()-1, 1);
788+}
789+
790+// Read directory contents
791+bool FileSpecifier::ReadDirectory(vector<dir_entry> &vec)
792+{
793+ vec.clear();
794+
795+#if defined(__MVCPP__)
796+
797+ WIN32_FIND_DATA findData;
798+
799+ // We need to add a wildcard to the search name
800+ string search_name;
801+ search_name = name;
802+ search_name += "\\*.*";
803+
804+ HANDLE hFind = ::FindFirstFile(search_name.c_str(), &findData);
805+
806+ if (hFind == INVALID_HANDLE_VALUE) {
807+ err = ::GetLastError();
808+ return false;
809+ }
810+
811+ do {
812+ // Exclude current and parent directories
813+ if (findData.cFileName[0] != '.' ||
814+ (findData.cFileName[1] && findData.cFileName[1] != '.')) {
815+ // Return found files to dir_entry
816+ int32 fileSize = (findData.nFileSizeHigh * MAXDWORD) + findData.nFileSizeLow;
817+ vec.push_back(dir_entry(findData.cFileName, fileSize,
818+ (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0, false));
819+ }
820+ } while(::FindNextFile(hFind, &findData));
821+
822+ if (!::FindClose(hFind))
823+ err = ::GetLastError(); // not sure if we should return this or not
824+ else
825+ err = 0;
826+ return true;
827+
828+#else
829+
830+ DIR *d = opendir(GetPath());
831+
832+ if (d == NULL) {
833+ err = errno;
834+ return false;
835+ }
836+ struct dirent *de = readdir(d);
837+ while (de) {
838+ FileSpecifier full_path = name;
839+ full_path += de->d_name;
840+ struct stat st;
841+ if (stat(full_path.GetPath(), &st) == 0) {
842+ // Ignore files starting with '.' and the directories '.' and '..'
843+ if (de->d_name[0] != '.' || (S_ISDIR(st.st_mode) && !(de->d_name[1] == '\0' || de->d_name[1] == '.')))
844+ vec.push_back(dir_entry(de->d_name, st.st_size, S_ISDIR(st.st_mode), false, st.st_mtime));
845+ }
846+ de = readdir(d);
847+ }
848+ closedir(d);
849+ err = 0;
850+ return true;
851+
852+#endif
853+}
854+
855+// Copy file contents
856+bool FileSpecifier::CopyContents(FileSpecifier &source_name)
857+{
858+ err = 0;
859+ OpenedFile src, dst;
860+ if (source_name.Open(src)) {
861+ Delete();
862+ if (Open(dst, true)) {
863+ const int BUFFER_SIZE = 1024;
864+ uint8 buffer[BUFFER_SIZE];
865+
866+ int32 length = 0;
867+ src.GetLength(length);
868+
869+ while (length && err == 0) {
870+ int32 count = length > BUFFER_SIZE ? BUFFER_SIZE : length;
871+ if (src.Read(count, buffer)) {
872+ if (!dst.Write(count, buffer))
873+ err = dst.GetError();
874+ } else
875+ err = src.GetError();
876+ length -= count;
877+ }
878+ }
879+ } else
880+ err = source_name.GetError();
881+ if (err)
882+ Delete();
883+ return err == 0;
884+}
885+
886+// ZZZ: Filesystem browsing list that lets user actually navigate directories...
887+class w_directory_browsing_list : public w_list<dir_entry>
888+{
889+public:
890+ w_directory_browsing_list(const FileSpecifier& inStartingDirectory, dialog* inParentDialog)
891+ : w_list<dir_entry>(entries, 400, 15, 0), parent_dialog(inParentDialog), current_directory(inStartingDirectory), sort_order(sort_by_name)
892+ {
893+ refresh_entries();
894+ }
895+
896+
897+ w_directory_browsing_list(const FileSpecifier& inStartingDirectory, dialog* inParentDialog, const string& inStartingFile)
898+ : w_list<dir_entry>(entries, 400, 15, 0), parent_dialog(inParentDialog), current_directory(inStartingDirectory)
899+ {
900+ refresh_entries();
901+ if(entries.size() != 0)
902+ select_entry(inStartingFile, false);
903+ }
904+
905+
906+ void set_directory_changed_callback(action_proc inCallback, void* inArg = NULL)
907+ {
908+ directory_changed_proc = inCallback;
909+ directory_changed_proc_arg = inArg;
910+ }
911+
912+
913+ void draw_item(vector<dir_entry>::const_iterator i, SDL_Surface *s, int16 x, int16 y, uint16 width, bool selected) const
914+ {
915+ y += font->get_ascent();
916+ set_drawing_clip_rectangle(0, x, s->h, x + width);
917+
918+ if(i->is_directory)
919+ {
920+ string theName = i->name + "/";
921+ draw_text(s, theName.c_str (), x, y, selected ? get_theme_color (ITEM_WIDGET, ACTIVE_STATE) : get_theme_color (ITEM_WIDGET, DEFAULT_STATE), font, style, true);
922+ }
923+ else
924+ {
925+ char date[256];
926+ tm *time_info = localtime(&i->date);
927+
928+ if (time_info)
929+ {
930+ strftime(date, 256, "%x %R", time_info);
931+ int date_width = text_width(date, font, style);
932+ draw_text(s, date, x + width - date_width, y, selected ? get_theme_color(ITEM_WIDGET, ACTIVE_STATE) : get_theme_color(ITEM_WIDGET, DEFAULT_STATE), font, style);
933+ set_drawing_clip_rectangle(0, x, s->h, x + width - date_width - 4);
934+ }
935+ draw_text(s, FileSpecifier::HideExtension(i->name).c_str (), x, y, selected ? get_theme_color (ITEM_WIDGET, ACTIVE_STATE) : get_theme_color (ITEM_WIDGET, DEFAULT_STATE), font, style, true);
936+ }
937+
938+ set_drawing_clip_rectangle(SHRT_MIN, SHRT_MIN, SHRT_MAX, SHRT_MAX);
939+ }
940+
941+
942+ bool can_move_up_a_level()
943+ {
944+ string base;
945+ string part;
946+ current_directory.SplitPath(base, part);
947+ return (part != string());
948+ }
949+
950+
951+ void move_up_a_level()
952+ {
953+ string base;
954+ string part;
955+ current_directory.SplitPath(base, part);
956+ if(part != string())
957+ {
958+ FileSpecifier parent_directory(base);
959+ if(parent_directory.Exists())
960+ {
961+ current_directory = parent_directory;
962+ refresh_entries();
963+ select_entry(part, true);
964+ announce_directory_changed();
965+ }
966+ }
967+ }
968+
969+
970+ void item_selected(void)
971+ {
972+ current_directory.AddPart(entries[selection].name);
973+
974+ if(entries[selection].is_directory)
975+ {
976+ refresh_entries();
977+ announce_directory_changed();
978+ }
979+ else if (file_selected)
980+ {
981+ file_selected(entries[selection].name);
982+ }
983+ }
984+
985+ enum SortOrder {
986+ sort_by_name,
987+ sort_by_date,
988+ };
989+
990+ void sort_by(SortOrder order)
991+ {
992+ sort_order = order;
993+ refresh_entries();
994+ }
995+
996+
997+ const FileSpecifier& get_file() { return current_directory; }
998+
999+ boost::function<void(const std::string&)> file_selected;
1000+
1001+private:
1002+ vector<dir_entry> entries;
1003+ dialog* parent_dialog;
1004+ FileSpecifier current_directory;
1005+ action_proc directory_changed_proc;
1006+ void* directory_changed_proc_arg;
1007+ SortOrder sort_order;
1008+
1009+ struct most_recent
1010+ {
1011+ bool operator()(const dir_entry& a, const dir_entry& b)
1012+ {
1013+ return a.date > b.date;
1014+ }
1015+ };
1016+
1017+ void refresh_entries()
1018+ {
1019+ if(current_directory.ReadDirectory(entries))
1020+ {
1021+ if (sort_order == sort_by_name)
1022+ {
1023+ sort(entries.begin(), entries.end());
1024+ }
1025+ else
1026+ {
1027+ sort(entries.begin(), entries.end(), most_recent());
1028+ }
1029+ }
1030+ num_items = entries.size();
1031+ new_items();
1032+ }
1033+
1034+ void select_entry(const string& inName, bool inIsDirectory)
1035+ {
1036+ dir_entry theEntryToFind(inName, NONE /* length - ignored for our purpose */, inIsDirectory);
1037+ vector<dir_entry>::iterator theEntry = find(entries.begin(), entries.end(), theEntryToFind);
1038+ if(theEntry != entries.end())
1039+ set_selection(theEntry - entries.begin());
1040+ }
1041+
1042+ void announce_directory_changed()
1043+ {
1044+ if(directory_changed_proc != NULL)
1045+ directory_changed_proc(directory_changed_proc_arg);
1046+ }
1047+};
1048+
1049+const char* sort_by_labels[] = {
1050+ "name",
1051+ "date",
1052+ 0
1053+};
1054+
1055+// common functionality for read and write dialogs
1056+class FileDialog {
1057+public:
1058+ FileDialog() {
1059+ }
1060+
1061+ bool Run() {
1062+ Layout();
1063+
1064+ bool result = false;
1065+ if (m_dialog.run() == 0)
1066+ {
1067+ result = true;
1068+ }
1069+
1070+ if (get_game_state() == _game_in_progress) update_game_window();
1071+ return result;
1072+ }
1073+
1074+protected:
1075+ void Init(const FileSpecifier& dir, w_directory_browsing_list::SortOrder default_order, std::string filename) {
1076+ m_sort_by_w = new w_select(static_cast<size_t>(default_order), sort_by_labels);
1077+ m_sort_by_w->set_selection_changed_callback(boost::bind(&FileDialog::on_change_sort_order, this));
1078+ m_up_button_w = new w_button("UP", boost::bind(&FileDialog::on_up, this));
1079+ if (filename.empty())
1080+ {
1081+ m_list_w = new w_directory_browsing_list(dir, &m_dialog);
1082+ }
1083+ else
1084+ {
1085+ m_list_w = new w_directory_browsing_list(dir, &m_dialog, filename);
1086+ }
1087+ m_list_w->sort_by(default_order);
1088+ m_list_w->set_directory_changed_callback(boost::bind(&FileDialog::on_directory_changed, this));
1089+
1090+ dir.GetName(temporary);
1091+ m_directory_name_w = new w_static_text(temporary);
1092+ }
1093+
1094+ dialog m_dialog;
1095+ w_select* m_sort_by_w;
1096+ w_button* m_up_button_w;
1097+ w_static_text* m_directory_name_w;
1098+ w_directory_browsing_list* m_list_w;
1099+
1100+private:
1101+ virtual void Layout() = 0;
1102+
1103+
1104+ void on_directory_changed() {
1105+ m_list_w->get_file().GetName(temporary);
1106+ m_directory_name_w->set_text(temporary);
1107+
1108+ m_up_button_w->set_enabled(m_list_w->can_move_up_a_level());
1109+
1110+ m_dialog.draw();
1111+ }
1112+
1113+ void on_change_sort_order() {
1114+ m_list_w->sort_by(static_cast<w_directory_browsing_list::SortOrder>(m_sort_by_w->get_selection()));
1115+ }
1116+
1117+ void on_up() {
1118+ m_list_w->move_up_a_level();
1119+ }
1120+
1121+};
1122+
1123+class ReadFileDialog : public FileDialog
1124+{
1125+public:
1126+ ReadFileDialog(FileSpecifier dir, Typecode type, const char* prompt) : FileDialog(), m_prompt(prompt) {
1127+ w_directory_browsing_list::SortOrder default_order = w_directory_browsing_list::sort_by_name;
1128+
1129+ if (!m_prompt)
1130+ {
1131+ switch(type)
1132+ {
1133+ case _typecode_savegame:
1134+ m_prompt = "CONTINUE SAVED GAME";
1135+ break;
1136+ case _typecode_film:
1137+ m_prompt = "REPLAY SAVED FILM";
1138+ break;
1139+ default:
1140+ m_prompt = "OPEN FILE";
1141+ break;
1142+ }
1143+ }
1144+
1145+ std::string filename;
1146+ switch (type)
1147+ {
1148+ case _typecode_savegame:
1149+ dir.SetToSavedGamesDir();
1150+ default_order = w_directory_browsing_list::sort_by_date;
1151+ break;
1152+ case _typecode_film:
1153+ dir.SetToRecordingsDir();
1154+ break;
1155+ case _typecode_scenario:
1156+ case _typecode_netscript:
1157+ {
1158+ // Go to most recently-used directory
1159+ DirectorySpecifier theDirectory;
1160+ dir.SplitPath(theDirectory, filename);
1161+ dir.FromDirectory(theDirectory);
1162+ if (!dir.Exists())
1163+ dir.SetToLocalDataDir();
1164+ }
1165+ break;
1166+ default:
1167+ dir.SetToLocalDataDir();
1168+ break;
1169+ }
1170+
1171+ Init(dir, default_order, filename);
1172+
1173+ m_list_w->file_selected = boost::bind(&ReadFileDialog::on_file_selected, this);
1174+ }
1175+
1176+ void Layout() {
1177+ vertical_placer* placer = new vertical_placer;
1178+ placer->dual_add(new w_title(m_prompt), m_dialog);
1179+ placer->add(new w_spacer, true);
1180+
1181+ placer->dual_add(m_directory_name_w, m_dialog);
1182+
1183+ placer->add(new w_spacer(), true);
1184+
1185+ horizontal_placer* top_row_placer = new horizontal_placer;
1186+
1187+ top_row_placer->dual_add(m_sort_by_w->label("Sorted by: "), m_dialog);
1188+ top_row_placer->dual_add(m_sort_by_w, m_dialog);
1189+ top_row_placer->add_flags(placeable::kFill);
1190+ top_row_placer->add(new w_spacer, true);
1191+ top_row_placer->add_flags();
1192+ top_row_placer->dual_add(m_up_button_w, m_dialog);
1193+
1194+ placer->add_flags(placeable::kFill);
1195+ placer->add(top_row_placer, true);
1196+ placer->add_flags();
1197+
1198+ placer->dual_add(m_list_w, m_dialog);
1199+ placer->add(new w_spacer, true);
1200+
1201+ horizontal_placer* button_placer = new horizontal_placer;
1202+ button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &m_dialog), m_dialog);
1203+
1204+ placer->add(button_placer, true);
1205+
1206+ m_dialog.activate_widget(m_list_w);
1207+ m_dialog.set_widget_placer(placer);
1208+ }
1209+
1210+ FileSpecifier GetFile() {
1211+ return m_list_w->get_file();
1212+ }
1213+
1214+private:
1215+ void on_file_selected() {
1216+ m_dialog.quit(0);
1217+ }
1218+
1219+ const char* m_prompt;
1220+ std::string m_filename;
1221+};
1222+
1223+bool FileSpecifier::ReadDialog(Typecode type, const char *prompt)
1224+{
1225+ ReadFileDialog d(*this, type, prompt);
1226+ if (d.Run())
1227+ {
1228+ *this = d.GetFile();
1229+ return true;
1230+ }
1231+ else
1232+ {
1233+ return false;
1234+ }
1235+}
1236+
1237+class w_file_name : public w_text_entry {
1238+public:
1239+ w_file_name(dialog *d, const char *initial_name = NULL) : w_text_entry(31, initial_name), parent(d) {}
1240+ ~w_file_name() {}
1241+
1242+ void event(SDL_Event & e)
1243+ {
1244+ // Return = close dialog
1245+ if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_RETURN)
1246+ parent->quit(0);
1247+ w_text_entry::event(e);
1248+ }
1249+
1250+private:
1251+ dialog *parent;
1252+};
1253+
1254+class WriteFileDialog : public FileDialog
1255+{
1256+public:
1257+ WriteFileDialog(FileSpecifier dir, Typecode type, const char* prompt, const char* default_name) : FileDialog(), m_prompt(prompt), m_default_name(default_name), m_extension(0) {
1258+ if (!m_prompt)
1259+ {
1260+ switch (type)
1261+ {
1262+ case _typecode_savegame:
1263+ prompt = "SAVE GAME";
1264+ break;
1265+ case _typecode_film:
1266+ prompt = "SAVE FILM";
1267+ break;
1268+ default:
1269+ prompt = "SAVE FILE";
1270+ break;
1271+ }
1272+ }
1273+
1274+ switch (type)
1275+ {
1276+ case _typecode_savegame:
1277+ m_extension = ".sgaA";
1278+ break;
1279+ case _typecode_film:
1280+ m_extension = ".filA";
1281+ break;
1282+ default:
1283+ break;
1284+ }
1285+
1286+ if (m_extension && boost::algorithm::ends_with(m_default_name, m_extension))
1287+ {
1288+ m_default_name.resize(m_default_name.size() - strlen(m_extension));
1289+ }
1290+
1291+ w_directory_browsing_list::SortOrder default_order = w_directory_browsing_list::sort_by_name;
1292+ switch (type) {
1293+ case _typecode_savegame:
1294+ {
1295+ string base;
1296+ string part;
1297+ dir.SplitPath(base, part);
1298+ if (part != string())
1299+ {
1300+ dir = base;
1301+ }
1302+ default_order = w_directory_browsing_list::sort_by_date;
1303+ }
1304+ break;
1305+ case _typecode_film:
1306+ dir.SetToRecordingsDir();
1307+ break;
1308+ default:
1309+ dir.SetToLocalDataDir();
1310+ break;
1311+ }
1312+
1313+ Init(dir, default_order, m_default_name);
1314+
1315+ m_list_w->file_selected = boost::bind(&WriteFileDialog::on_file_selected, this, _1);
1316+ }
1317+
1318+ void Layout() {
1319+ vertical_placer* placer = new vertical_placer;
1320+ placer->dual_add(new w_title(m_prompt), m_dialog);
1321+ placer->add(new w_spacer, true);
1322+
1323+ placer->dual_add(m_directory_name_w, m_dialog);
1324+
1325+ placer->add(new w_spacer(), true);
1326+
1327+ horizontal_placer* top_row_placer = new horizontal_placer;
1328+
1329+ top_row_placer->dual_add(m_sort_by_w->label("Sorted by: "), m_dialog);
1330+ top_row_placer->dual_add(m_sort_by_w, m_dialog);
1331+ top_row_placer->add_flags(placeable::kFill);
1332+ top_row_placer->add(new w_spacer, true);
1333+ top_row_placer->add_flags();
1334+ top_row_placer->dual_add(m_up_button_w, m_dialog);
1335+
1336+ placer->add_flags(placeable::kFill);
1337+ placer->add(top_row_placer, true);
1338+ placer->add_flags();
1339+
1340+ placer->dual_add(m_list_w, m_dialog);
1341+ placer->add(new w_spacer, true);
1342+
1343+ placer->add_flags(placeable::kFill);
1344+
1345+ horizontal_placer* file_name_placer = new horizontal_placer;
1346+ m_name_w = new w_file_name(&m_dialog, m_default_name.c_str());
1347+ file_name_placer->dual_add(m_name_w->label("File Name:"), m_dialog);
1348+ file_name_placer->add_flags(placeable::kFill);
1349+ file_name_placer->dual_add(m_name_w, m_dialog);
1350+
1351+ placer->add_flags(placeable::kFill);
1352+ placer->add(file_name_placer, true);
1353+ placer->add_flags();
1354+ placer->add(new w_spacer, true);
1355+
1356+ horizontal_placer* button_placer = new horizontal_placer;
1357+ button_placer->dual_add(new w_button("OK", dialog_ok, &m_dialog), m_dialog);
1358+ button_placer->dual_add(new w_button("CANCEL", dialog_cancel, &m_dialog), m_dialog);
1359+
1360+ placer->add(button_placer, true);
1361+
1362+ m_dialog.activate_widget(m_name_w);
1363+ m_dialog.set_widget_placer(placer);
1364+ }
1365+
1366+ FileSpecifier GetPath() {
1367+ FileSpecifier dir = m_list_w->get_file();
1368+ std::string base;
1369+ std::string part;
1370+ dir.SplitPath(base, part);
1371+
1372+ std::string filename = GetFilename();
1373+ if (part == filename)
1374+ {
1375+ dir = base;
1376+ }
1377+
1378+ if (m_extension && !boost::algorithm::ends_with(filename, m_extension))
1379+ {
1380+ filename += m_extension;
1381+ }
1382+ dir.AddPart(filename);
1383+ return dir;
1384+ }
1385+
1386+ std::string GetFilename() {
1387+ return m_name_w->get_text();
1388+ }
1389+
1390+private:
1391+ void on_file_selected(const std::string& filename) {
1392+ m_name_w->set_text(filename.c_str());
1393+ m_dialog.quit(0);
1394+ }
1395+
1396+ const char* m_prompt;
1397+ std::string m_default_name;
1398+ const char* m_extension;
1399+ w_file_name* m_name_w;
1400+};
1401+
1402+static bool confirm_save_choice(FileSpecifier & file);
1403+
1404+bool FileSpecifier::WriteDialog(Typecode type, const char *prompt, const char *default_name)
1405+{
1406+again:
1407+ WriteFileDialog d(*this, type, prompt, default_name);
1408+ bool result = false;
1409+ if (d.Run())
1410+ {
1411+ if (d.GetFilename().empty())
1412+ {
1413+ play_dialog_sound(DIALOG_ERROR_SOUND);
1414+ goto again;
1415+ }
1416+
1417+ *this = d.GetPath();
1418+
1419+ if (!confirm_save_choice(*this))
1420+ {
1421+ goto again;
1422+ }
1423+
1424+ result = true;
1425+ }
1426+
1427+ return result;
1428+
1429+}
1430+
1431+bool FileSpecifier::WriteDialogAsync(Typecode type, char *prompt, char *default_name)
1432+{
1433+ return FileSpecifier::WriteDialog(type, prompt, default_name);
1434+}
1435+
1436+static bool confirm_save_choice(FileSpecifier & file)
1437+{
1438+ // If the file doesn't exist, everything is alright
1439+ if (!file.Exists())
1440+ return true;
1441+
1442+ // Construct message
1443+ char name[256];
1444+ file.GetName(name);
1445+ char message[512];
1446+ sprintf(message, "'%s' already exists.", name);
1447+
1448+ // Create dialog
1449+ dialog d;
1450+ vertical_placer *placer = new vertical_placer;
1451+ placer->dual_add(new w_static_text(message), d);
1452+ placer->dual_add(new w_static_text("Ok to overwrite?"), d);
1453+ placer->add(new w_spacer(), true);
1454+
1455+ horizontal_placer *button_placer = new horizontal_placer;
1456+ w_button *default_button = new w_button("YES", dialog_ok, &d);
1457+ button_placer->dual_add(default_button, d);
1458+ button_placer->dual_add(new w_button("NO", dialog_cancel, &d), d);
1459+
1460+ placer->add(button_placer, true);
1461+
1462+ d.activate_widget(default_button);
1463+
1464+ d.set_widget_placer(placer);
1465+
1466+ // Run dialog
1467+ return d.run() == 0;
1468+}
1469+
1470+ScopedSearchPath::ScopedSearchPath(const DirectorySpecifier& dir)
1471+{
1472+ data_search_path.insert(data_search_path.begin(), dir);
1473+}
1474+
1475+ScopedSearchPath::~ScopedSearchPath()
1476+{
1477+ data_search_path.erase(data_search_path.begin());
1478+}
1479+
1480+#endif
--- marathon/trunk/Source_Files/Makefile.am (revision 504)
+++ marathon/trunk/Source_Files/Makefile.am (revision 505)
@@ -1,61 +1,77 @@
1-## Process this file with automake to produce Makefile.in
2-
3-SUBDIRS = CSeries Expat Files GameWorld Input LibNAT Lua Misc ModelView Network \
4- RenderMain RenderOther Sound TCPMess XML
5-
6-if MAKE_WINDOWS
7-bin_PROGRAMS = AlephOne
8-else
9-bin_PROGRAMS = alephone
10-endif
11-
12-alephone_SOURCES = shell.h \
13- \
14- shell.cpp shell_misc.cpp Misc/DefaultStringSets.cpp
15-
16-alephone_LDADD = \
17- CSeries/libcseries.a Expat/libexpat.a Files/libfiles.a \
18- GameWorld/libgameworld.a Input/libinput.a Lua/liba1lua.a Misc/libmisc.a \
19- ModelView/libmodelview.a Network/libnetwork.a Network/Metaserver/libmetaserver.a \
20- RenderMain/librendermain.a RenderOther/librenderother.a Sound/libsound.a \
21- XML/libxml.a \
22- \
23- CSeries/libcseries.a Expat/libexpat.a Files/libfiles.a \
24- GameWorld/libgameworld.a LibNAT/libnat.a Input/libinput.a Lua/liba1lua.a Misc/libmisc.a \
25- ModelView/libmodelview.a Network/libnetwork.a Network/Metaserver/libmetaserver.a \
26- RenderMain/librendermain.a RenderOther/librenderother.a Sound/libsound.a \
27- TCPMess/libtcpmess.a XML/libxml.a
28-
29-INCLUDES = -I$(top_srcdir)/Source_Files/CSeries -I$(top_srcdir)/Source_Files/Files \
30- -I$(top_srcdir)/Source_Files/GameWorld -I$(top_srcdir)/Source_Files/Input \
31- -I$(top_srcdir)/Source_Files/Lua -I$(top_srcdir)/Source_Files/Misc \
32- -I$(top_srcdir)/Source_Files/ModelView -I$(top_srcdir)/Source_Files/Network \
33- -I$(top_srcdir)/Source_Files/Network/Metaserver \
34- -I$(top_srcdir)/Source_Files/Pfhortran -I$(top_srcdir)/Source_Files/RenderMain \
35- -I$(top_srcdir)/Source_Files/RenderOther -I$(top_srcdir)/Source_Files/Sound \
36- -I$(top_srcdir)/Source_Files/XML -I$(top_srcdir)/Source_Files/Expat \
37- -I$(top_srcdir)/Source_Files/TCPMess
38-
39-AlephOne_LDADD = $(alephone_LDADD) alephone-resources.o
40-AlephOne_SOURCES = $(alephone_SOURCES)
41-
42-# Data directories
43-confpaths.h: Makefile
44- echo "#define PKGDATADIR \"$(pkgdatadir)\"" > $@
45-
46-DISTCLEANFILES = confpaths.h
47-
48-if MAKE_WINDOWS
49-BUILD_YEAR = `echo $(VERSION) | cut -c 1-4`
50-BUILD_MONTH = `echo $(VERSION) | cut -c 5-6 | sed -e s/^0//`
51-BUILD_DAY = `echo $(VERSION) | cut -c 7-8 | sed -e s/^0//`
52-WIN_VERSION_STRING= 0, $(BUILD_YEAR), $(BUILD_MONTH), $(BUILD_DAY)
53-A1_DISPLAY_VERSION= `grep '^\#define A1_DISPLAY_VERSION' $(srcdir)/Misc/alephversion.h | sed -e 's/\(.*\"\)\(.*\)\(\"\)/\2/g' | tr -d '\n'`
54-endif
55-
56-alephone-resources.o: FORCE
57- sed -e s/BUILDDATE/`date +%Y-%m-%d`/g -e "s/WIN_VERSION_STRING/$(WIN_VERSION_STRING)/g" -e "s/A1_DISPLAY_VERSION/$(A1_DISPLAY_VERSION)/g" $(top_srcdir)/Resources/Windows/alephone.rc | @WINDRES@ -I$(top_srcdir)/Resources/Windows -o alephone-resources.o
58-
59-FORCE:
60-
61-shell.o: confpaths.h
1+## Process this file with automake to produce Makefile.in
2+
3+SUBDIRS = CSeries Expat Files GameWorld Input LibNAT Lua Misc ModelView Network \
4+ RenderMain RenderOther Sound TCPMess XML
5+
6+if MAKE_WINDOWS
7+bin_PROGRAMS = AlephOne Marathon Marathon2 MarathonInfinity
8+else
9+bin_PROGRAMS = alephone
10+endif
11+
12+alephone_SOURCES = shell.h \
13+ \
14+ shell.cpp shell_misc.cpp Misc/DefaultStringSets.cpp
15+
16+alephone_LDADD = \
17+ CSeries/libcseries.a Expat/libexpat.a Files/libfiles.a \
18+ GameWorld/libgameworld.a Input/libinput.a Lua/liba1lua.a Misc/libmisc.a \
19+ ModelView/libmodelview.a Network/libnetwork.a Network/Metaserver/libmetaserver.a \
20+ RenderMain/librendermain.a RenderOther/librenderother.a Sound/libsound.a \
21+ XML/libxml.a \
22+ \
23+ CSeries/libcseries.a Expat/libexpat.a Files/libfiles.a \
24+ GameWorld/libgameworld.a LibNAT/libnat.a Input/libinput.a Lua/liba1lua.a Misc/libmisc.a \
25+ ModelView/libmodelview.a Network/libnetwork.a Network/Metaserver/libmetaserver.a \
26+ RenderMain/librendermain.a RenderOther/librenderother.a Sound/libsound.a \
27+ TCPMess/libtcpmess.a XML/libxml.a
28+
29+INCLUDES = -I$(top_srcdir)/Source_Files/CSeries -I$(top_srcdir)/Source_Files/Files \
30+ -I$(top_srcdir)/Source_Files/GameWorld -I$(top_srcdir)/Source_Files/Input \
31+ -I$(top_srcdir)/Source_Files/Lua -I$(top_srcdir)/Source_Files/Misc \
32+ -I$(top_srcdir)/Source_Files/ModelView -I$(top_srcdir)/Source_Files/Network \
33+ -I$(top_srcdir)/Source_Files/Network/Metaserver \
34+ -I$(top_srcdir)/Source_Files/Pfhortran -I$(top_srcdir)/Source_Files/RenderMain \
35+ -I$(top_srcdir)/Source_Files/RenderOther -I$(top_srcdir)/Source_Files/Sound \
36+ -I$(top_srcdir)/Source_Files/XML -I$(top_srcdir)/Source_Files/Expat \
37+ -I$(top_srcdir)/Source_Files/TCPMess
38+
39+AlephOne_LDADD = $(alephone_LDADD) alephone-resources.o
40+AlephOne_SOURCES = $(alephone_SOURCES)
41+
42+Marathon_LDADD = $(alephone_LDADD) marathon-resources.o
43+Marathon_SOURCES = $(alephone_SOURCES)
44+
45+Marathon2_LDADD = $(alephone_LDADD) marathon2-resources.o
46+Marathon2_SOURCES = $(alephone_SOURCES)
47+
48+MarathonInfinity_LDADD = $(alephone_LDADD) marathon-infinity-resources.o
49+MarathonInfinity_SOURCES = $(alephone_SOURCES)
50+
51+# Data directories
52+confpaths.h: Makefile
53+ echo "#define PKGDATADIR \"$(pkgdatadir)\"" > $@
54+
55+DISTCLEANFILES = confpaths.h
56+
57+if MAKE_WINDOWS
58+BUILD_YEAR = `echo $(VERSION) | cut -c 1-4`
59+BUILD_MONTH = `echo $(VERSION) | cut -c 5-6 | sed -e s/^0//`
60+BUILD_DAY = `echo $(VERSION) | cut -c 7-8 | sed -e s/^0//`
61+WIN_VERSION_STRING= 0, $(BUILD_YEAR), $(BUILD_MONTH), $(BUILD_DAY)
62+A1_DISPLAY_VERSION= `grep '^\#define A1_DISPLAY_VERSION' $(srcdir)/Misc/alephversion.h | sed -e 's/\(.*\"\)\(.*\)\(\"\)/\2/g' | tr -d '\n'`
63+endif
64+
65+alephone-resources.o: $(top_srcdir)/Resources/Windows/alephone.rc Misc/alephversion.h
66+ sed -e "s/WIN_VERSION_STRING/$(WIN_VERSION_STRING)/g" -e "s/A1_DISPLAY_VERSION/$(A1_DISPLAY_VERSION)/g" $(top_srcdir)/Resources/Windows/alephone.rc | @WINDRES@ -I$(top_srcdir)/Resources/Windows -o alephone-resources.o
67+
68+marathon-resources.o: $(top_srcdir)/Resources/Windows/marathon.rc Misc/alephversion.h $(top_srcdir)/Resources/Windows/marathon.ico
69+ sed -e "s/WIN_VERSION_STRING/$(WIN_VERSION_STRING)/g" -e "s/A1_DISPLAY_VERSION/$(A1_DISPLAY_VERSION)/g" $(top_srcdir)/Resources/Windows/marathon.rc | @WINDRES@ -I$(top_srcdir)/Resources/Windows -o marathon-resources.o
70+
71+marathon2-resources.o: $(top_srcdir)/Resources/Windows/marathon2.rc Misc/alephversion.h $(top_srcdir)/Resources/Windows/marathon2.ico
72+ sed -e "s/WIN_VERSION_STRING/$(WIN_VERSION_STRING)/g" -e "s/A1_DISPLAY_VERSION/$(A1_DISPLAY_VERSION)/g" $(top_srcdir)/Resources/Windows/marathon2.rc | @WINDRES@ -I$(top_srcdir)/Resources/Windows -o marathon2-resources.o
73+
74+marathon-infinity-resources.o: $(top_srcdir)/Resources/Windows/marathon-infinity.rc Misc/alephversion.h $(top_srcdir)/Resources/Windows/marathon-infinity.ico
75+ sed -e "s/WIN_VERSION_STRING/$(WIN_VERSION_STRING)/g" -e "s/A1_DISPLAY_VERSION/$(A1_DISPLAY_VERSION)/g" $(top_srcdir)/Resources/Windows/marathon-infinity.rc | @WINDRES@ -I$(top_srcdir)/Resources/Windows -o marathon-infinity-resources.o
76+
77+shell.o: confpaths.h
--- marathon/trunk/Makefile.am (revision 504)
+++ marathon/trunk/Makefile.am (revision 505)
@@ -3,17 +3,21 @@
33 SUBDIRS = Source_Files tools data
44
55 # Requires automake 1.5
6-AUTOMAKE_OPTIONS = 1.5 foreign
6+AUTOMAKE_OPTIONS = 1.5 foreign dist-bzip2 no-dist-gzip
77
88 EXTRA_DIST = COPYING.SDL INSTALL.BeOS INSTALL.Unix INSTALL.Windows \
99 Makefile.BeOS docs/MML.html docs/Lua.html docs/Lua_HUD.html \
1010 data/Fonts Resources/Windows/alephone.ico \
1111 Resources/Windows/alephone.rc \
12+ Resources/Windows/marathon.rc Resources/Windows/marathon.ico \
13+ Resources/Windows/marathon2.rc Resources/Windows/marathon2.ico \
14+ Resources/Windows/marathon-infinity.rc \
15+ Resources/Windows/marathon-infinity.ico \
1216 PBProjects/AlephOne.xcodeproj/project.pbxproj \
1317 PBProjects/English.lproj/InfoPlist.strings PBProjects/FilmIcon.icns \
1418 PBProjects/ImagesIcon.icns PBProjects/MapIcon.icns \
1519 PBProjects/MMLIcon.icns PBProjects/MusakIcon.icns \
16- PBProjects/PhysIcon.icns \
20+ PBProjects/PhysIcon.icns \
1721 PBProjects/SaveIcon.icns PBProjects/ShapesIcon.icns \
1822 PBProjects/SoundsIcon.icns PBProjects/Info-AlephOne_SDL.plist \
1923 PBProjects/precompiled_headers.h PBProjects/SDLMain.h \
@@ -31,8 +35,6 @@
3135
3236 man_MANS = docs/alephone.6
3337
34-WINDISTDIR=$(PACKAGE)-$(VERSION)
35-
3638 dist-hook: AlephOne.spec
3739 cp AlephOne.spec $(distdir)
3840 cp "$(srcdir)/Aleph One Classic SDL.mcp" $(distdir)
@@ -47,15 +49,12 @@
4749 cp "$(srcdir)/PBProjects/AppStore/Marathon Infinity/English.lproj/InfoPlist.strings" "$(distdir)/PBProjects/AppStore/Marathon Infinity/English.lproj/"
4850
4951
50-$(PACKAGE)-$(VERSION)-MacWinSrc.7z: distdir
51- cp -r ${srcdir}/Libraries ${distdir}/
52- tar cf - $(distdir) --exclude-vcs | xz > $(PACKAGE)-$(VERSION)-MacWinSrc.xz
53- $(am__remove_distdir)
52+$(PACKAGE)-$(VERSION)-MacWinLibs-Src.tar.bz2: Libraries
53+ tar cjf $(PACKAGE)-$(VERSION)-MacWinLibs-Src.tar.bz2 -C $(srcdir) --exclude '.svn' Libraries
5454
55-libsrc: $(PACKAGE)-$(VERSION)-MacWinSrc.7z
55+libsrc: $(PACKAGE)-$(VERSION)-MacWinLibs-Src.tar.bz2
5656
57-# Rule to build tar-gzipped distribution package
58-$(PACKAGE)-$(VERSION).tar.gz: dist
57+release: dist windist libsrc
5958
6059 # Rule to build RPM distribution package
6160 rpm: $(PACKAGE)-$(VERSION).tar.gz
@@ -64,138 +63,124 @@
6463 ChangeLog:
6564 svn2cl --break-before-msg
6665
66+# Rules to build Windows zipfiles
67+WINZIP=$(PACKAGE)-$(VERSION)-Win.zip
68+M1_WINZIP=Marathon-$(VERSION)-Win.zip
69+M2_WINZIP=Marathon2-$(VERSION)-Win.zip
70+MINF_WINZIP=MarathonInfinity-$(VERSION)-Win.zip
71+
72+M1_WINUP=Marathon-$(VERSION)-Exe-Win.zip
73+M2_WINUP=Marathon2-$(VERSION)-Exe-Win.zip
74+MINF_WINUP=MarathonInfinity-$(VERSION)-Exe-Win.zip
75+
76+winzip: $(WINZIP)
77+m1-winzip: $(M1_WINZIP)
78+m2-winzip: $(M2_WINZIP)
79+inf-winzip: $(MINF_WINZIP)
80+
81+m1-winup: $(M1_WINUP)
82+m2-winup: $(M2_WINUP)
83+inf-winup: $(MINF_WINUP)
84+
85+windist: winzip m1-winzip m2-winzip inf-winzip m1-winup m2-winup inf-winup
86+
87+# Windows directories
88+
89+
90+define cp_no_svn
91+mkdir -p "$(2)"
92+tar -c --exclude='.svn' -C "$(1)" . | tar -x -C "$(2)"
93+endef
94+
95+define windist_common
96+unix2dos -n $(srcdir)/THANKS "$(1)/THANKS.txt"
97+unix2dos -n $(srcdir)/COPYING "$(1)/COPYING.txt"
98+unix2dos -n $(srcdir)/README "$(1)/README.txt"
99+mkdir "$(1)/docs"
100+cp $(srcdir)/docs/Lua.html "$(1)/docs/Lua.html"
101+cp $(srcdir)/docs/Lua_HUD.html "$(1)/docs/Lua_HUD.html"
102+cp $(srcdir)/docs/MML.html "$(1)/docs/MML.html"
103+$(call cp_no_svn,$(srcdir)/data/default_theme,$(1)/Themes/Default)
104+mkdir "$(1)/Extras"
105+cp $(srcdir)/data/Software_Transparent_Liquids.mml "$(1)/Extras"
106+cp $(srcdir)/data/Transparent_Liquids.mml "$(1)/Extras"
107+cp $(srcdir)/data/Carnage_Messages.mml "$(1)/Extras"
108+unix2dos -n $(srcdir)/examples/lua/Cheats.lua "$(1)/Extras/Cheats.lua"
109+cp $(srcdir)/data/Fonts "$(1)/Fonts.fntA"
110+$(call cp_no_svn,$(srcdir)/Resources/Library Licenses,$(1)/docs/Library Licenses)
111+endef
112+
67113 # Windows version
68-$(PACKAGE)-$(VERSION).zip: Source_Files/AlephOne.exe
69- mkdir $(WINDISTDIR)
114+
115+WINDISTDIR=$(PACKAGE)-$(VERSION)
116+$(WINZIP): Source_Files/AlephOne.exe
117+ mkdir "$(WINDISTDIR)"
118+ $(call windist_common,$(WINDISTDIR))
70119 cp Source_Files/AlephOne.exe $(WINDISTDIR)/
71- unix2dos -n $(srcdir)/AUTHORS $(WINDISTDIR)/AUTHORS.txt
72- unix2dos -n $(srcdir)/THANKS $(WINDISTDIR)/THANKS.txt
73- unix2dos -n $(srcdir)/COPYING $(WINDISTDIR)/COPYING.txt
74- unix2dos -n $(srcdir)/INSTALL.Windows $(WINDISTDIR)/INSTALL.Windows.txt
75- unix2dos -n $(srcdir)/README $(WINDISTDIR)/README.txt
76- mkdir $(WINDISTDIR)/docs
77- cp $(srcdir)/docs/Lua.html $(WINDISTDIR)/docs/Lua.html
78- cp $(srcdir)/docs/Lua_HUD.html $(WINDISTDIR)/docs/Lua_HUD.html
79- cp $(srcdir)/docs/MML.html $(WINDISTDIR)/docs/MML.html
80- unix2dos -n $(srcdir)/docs/Troubleshooting.txt $(WINDISTDIR)/docs/Troubleshooting.txt
81- mkdir $(WINDISTDIR)/Themes
82- cp -r $(srcdir)/data/default_theme $(WINDISTDIR)/Themes/Default
83- rm -rf "$(WINDISTDIR)/Themes/Default/.svn"
84- mkdir $(WINDISTDIR)/Extras
85- cp $(srcdir)/data/Software_Transparent_Liquids.mml $(WINDISTDIR)/Extras
86- cp $(srcdir)/data/Transparent_Liquids.mml $(WINDISTDIR)/Extras
120+ unix2dos -n $(srcdir)/INSTALL.Windows "$(WINDISTDIR)/docs/INSTALL.Windows.txt"
87121 cp $(srcdir)/data/Transparent_Sprites.mml $(WINDISTDIR)/Extras
88- cp $(srcdir)/data/Carnage_Messages.mml $(WINDISTDIR)/Extras
89- unix2dos -n $(srcdir)/examples/lua/Cheats.lua $(WINDISTDIR)/Extras/Cheats.lua
90- cp $(srcdir)/data/Fonts $(WINDISTDIR)/
91- cp -r "$(srcdir)/Resources/Library Licenses" $(WINDISTDIR)/
92- rm -rf "$(WINDISTDIR)/Library Licenses/.svn"
93- zip -r $(PACKAGE)-$(VERSION).zip $(WINDISTDIR)
122+ rm -f $(WINZIP)
123+ zip -r $(WINZIP) $(WINDISTDIR)
94124 rm -rf "$(WINDISTDIR)"
95125
96-winzip: $(PACKAGE)-$(VERSION).zip
126+WINUPDIR_M1=Marathon-$(VERSION)
127+$(M1_WINUP): Source_Files/Marathon.exe
128+ mkdir "$(WINUPDIR_M1)"
129+ $(call windist_common,$(WINUPDIR_M1))
130+ cp Source_Files/Marathon.exe "$(WINUPDIR_M1)/Marathon.exe"
131+ rm -f $(M1_WINUP)
132+ zip -r $(M1_WINUP) "$(WINUPDIR_M1)"
133+ rm -rf "$(WINUPDIR_M1)"
97134
98-$(PACKAGE)-$(VERSION)-M1A1.zip: Source_Files/AlephOne.exe
99- cp -r "$(srcdir)/data/Scenarios/M1A1" $(WINDISTDIR)-M1A1
100- rm -rf "$(WINDISTDIR)-M1A1/.svn"
101- rm -rf "$(WINDISTDIR)-M1A1/Physics Models/.svn"
102- rm -rf "$(WINDISTDIR)-M1A1/Plugins/.svn"
103- rm -rf $(WINDISTDIR)-M1A1/Plugins/*/.svn
104- rm -rf $(WINDISTDIR)-M1A1/Plugins/*/*/.svn
105- rm -rf $(WINDISTDIR)-M1A1/Plugins/*/*/*/.svn
106- rm -rf "$(WINDISTDIR)-M1A1/Scripts/.svn"
107- rm -rf "$(WINDISTDIR)-M1A1/Tracks/.svn"
108- cp Source_Files/AlephOne.exe $(WINDISTDIR)-M1A1/
109- unix2dos -n $(srcdir)/AUTHORS $(WINDISTDIR)-M1A1/AUTHORS.txt
110- unix2dos -n $(srcdir)/COPYING $(WINDISTDIR)-M1A1/COPYING.txt
111- unix2dos -n $(srcdir)/INSTALL.Windows $(WINDISTDIR)-M1A1/INSTALL.Windows.txt
112- unix2dos -n $(srcdir)/README $(WINDISTDIR)-M1A1/README.txt
113- mkdir $(WINDISTDIR)-M1A1/docs
114- cp $(srcdir)/docs/Lua.html $(WINDISTDIR)-M1A1/docs/Lua.html
115- cp $(srcdir)/docs/Lua_HUD.html $(WINDISTDIR)-M1A1/docs/Lua_HUD.html
116- cp $(srcdir)/docs/MML.html $(WINDISTDIR)-M1A1/docs/MML.html
117- unix2dos -n $(srcdir)/docs/Troubleshooting.txt $(WINDISTDIR)-M1A1/docs/Troubleshooting.txt
118- mkdir $(WINDISTDIR)-M1A1/Themes
119- cp -r $(srcdir)/data/default_theme $(WINDISTDIR)-M1A1/Themes/Default
120- rm -rf "$(WINDISTDIR)-M1A1/Themes/Default/.svn"
121- mkdir $(WINDISTDIR)-M1A1/Extras
122- unix2dos -n $(srcdir)/examples/lua/Cheats.lua $(WINDISTDIR)-M1A1/Extras/Cheats.lua
123- cp $(srcdir)/data/Fonts $(WINDISTDIR)-M1A1/Fonts.fntA
124- cp -r "$(srcdir)/Resources/Library Licenses" $(WINDISTDIR)-M1A1/
125- rm -rf "$(WINDISTDIR)-M1A1/Library Licenses/.svn"
126- zip -r $(PACKAGE)-$(VERSION)-M1A1.zip $(WINDISTDIR)-M1A1
127- rm -rf "$(WINDISTDIR)-M1A1"
135+WINDISTDIR_M1=Marathon (A1)
136+$(M1_WINZIP): Source_Files/Marathon.exe
137+ mkdir "$(WINDISTDIR_M1)"
138+ $(call windist_common,$(WINDISTDIR_M1))
139+ $(call cp_no_svn,$(srcdir)/data/Scenarios/M1A1,$(WINDISTDIR_M1))
140+ cp Source_Files/Marathon.exe "$(WINDISTDIR_M1)/Marathon.exe"
141+ rm -f $(M1_WINZIP)
142+ zip -r $(M1_WINZIP) "$(WINDISTDIR_M1)"
143+ rm -rf "$(WINDISTDIR_M1)"
128144
129-win1zip: $(PACKAGE)-$(VERSION)-M1A1.zip
145+WINUPDIR_M2=Marathon2-$(VERSION)
146+$(M2_WINUP): Source_Files/Marathon2.exe
147+ mkdir "$(WINUPDIR_M2)"
148+ $(call windist_common,$(WINUPDIR_M2))
149+ cp Source_Files/Marathon2.exe "$(WINUPDIR_M2)/Marathon 2.exe"
150+ rm -f $(M2_WINUP)
151+ zip -r $(M2_WINUP) "$(WINUPDIR_M2)"
152+ rm -rf "$(WINUPDIR_M2)"
130153
131-$(PACKAGE)-$(VERSION)-Durandal.zip: Source_Files/AlephOne.exe
132- cp -r "$(srcdir)/data/Scenarios/Marathon 2" $(WINDISTDIR)-Durandal
133- cp -r $(srcdir)/data/XBLA_HUD $(WINDISTDIR)-Durandal/Plugins/XBLA_HUD
134- rm -rf "$(WINDISTDIR)-Durandal/.svn"
135- rm -rf "$(WINDISTDIR)-Durandal/Physics Models/.svn"
136- rm -rf "$(WINDISTDIR)-Durandal/Plugins/.svn"
137- rm -rf $(WINDISTDIR)-Durandal/Plugins/*/.svn
138- rm -rf $(WINDISTDIR)-Durandal/Plugins/*/*/.svn
139- rm -rf $(WINDISTDIR)-Durandal/Plugins/*/*/*/.svn
140- rm -rf $(WINDISTDIR)-Durandal/Plugins/*/*/*/*/.svn
141- rm -rf "$(WINDISTDIR)-Durandal/Scripts/.svn"
142- cp Source_Files/AlephOne.exe $(WINDISTDIR)-Durandal/
143- unix2dos -n $(srcdir)/AUTHORS $(WINDISTDIR)-Durandal/AUTHORS.txt
144- unix2dos -n $(srcdir)/COPYING $(WINDISTDIR)-Durandal/COPYING.txt
145- unix2dos -n $(srcdir)/INSTALL.Windows $(WINDISTDIR)-Durandal/INSTALL.Windows.txt
146- unix2dos -n $(srcdir)/README $(WINDISTDIR)-Durandal/README.txt
147- mkdir $(WINDISTDIR)-Durandal/docs
148- cp $(srcdir)/docs/Lua.html $(WINDISTDIR)-Durandal/docs/Lua.html
149- cp $(srcdir)/docs/Lua_HUD.html $(WINDISTDIR)-Durandal/docs/Lua_HUD.html
150- cp $(srcdir)/docs/MML.html $(WINDISTDIR)-Durandal/docs/MML.html
151- unix2dos -n $(srcdir)/docs/Troubleshooting.txt $(WINDISTDIR)-Durandal/docs/Troubleshooting.txt
152- mkdir $(WINDISTDIR)-Durandal/Themes
153- cp -r $(srcdir)/data/default_theme $(WINDISTDIR)-Durandal/Themes/Default
154- rm -rf "$(WINDISTDIR)-Durandal/Themes/Default/.svn"
155- mkdir $(WINDISTDIR)-Durandal/Extras
156- cp $(srcdir)/data/Software_Transparent_Liquids.mml $(WINDISTDIR)-Durandal/Extras
157- cp $(srcdir)/data/Transparent_Sprites.mml $(WINDISTDIR)-Durandal/Extras
158- cp $(srcdir)/data/Carnage_Messages.mml $(WINDISTDIR)-Durandal/Extras
159- unix2dos -n $(srcdir)/examples/lua/Cheats.lua $(WINDISTDIR)-Durandal/Extras/Cheats.lua
160- cp -r "$(srcdir)/Resources/Library Licenses" $(WINDISTDIR)-Durandal/
161- rm -rf "$(WINDISTDIR)-Durandal/Library Licenses/.svn"
162- zip -r $(PACKAGE)-$(VERSION)-Durandal.zip $(WINDISTDIR)-Durandal
163- rm -rf "$(WINDISTDIR)-Durandal"
154+WINDISTDIR_M2=Marathon 2
155+$(M2_WINZIP): Source_Files/Marathon2.exe
156+ mkdir "$(WINDISTDIR_M2)"
157+ $(call windist_common,$(WINDISTDIR_M2))
158+ $(call cp_no_svn,$(srcdir)/data/Scenarios/Marathon 2,$(WINDISTDIR_M2))
159+ $(call cp_no_svn,$(srcdir)/data/XBLA_HUD,$(WINDISTDIR_M2)/Plugins/XBLA_HUD)
160+ cp Source_Files/Marathon2.exe "$(WINDISTDIR_M2)/Marathon 2.exe"
161+ rm -f $(M2_WINZIP)
162+ zip -r $(M2_WINZIP) "$(WINDISTDIR_M2)"
163+ rm -rf "$(WINDISTDIR_M2)"
164164
165-win2zip: $(PACKAGE)-$(VERSION)-Durandal.zip
166165
167-$(PACKAGE)-$(VERSION)-Infinity.zip: Source_Files/AlephOne.exe
168- cp -r "$(srcdir)/data/Scenarios/Marathon Infinity" $(WINDISTDIR)-Infinity
169- mkdir $(WINDISTDIR)-Infinity/Plugins
170- cp -r $(srcdir)/data/XBLA_HUD $(WINDISTDIR)-Infinity/Plugins/XBLA_HUD
171- rm -rf "$(WINDISTDIR)-Infinity/.svn"
172- rm -rf "$(WINDISTDIR)-Infinity/Physics Models/.svn"
173- rm -rf $(WINDISTDIR)-Infinity/Plugins/*/.svn
174- rm -rf $(WINDISTDIR)-Infinity/Plugins/*/*/.svn
175- rm -rf "$(WINDISTDIR)-Infinity/Scripts/.svn"
176- cp Source_Files/AlephOne.exe $(WINDISTDIR)-Infinity/
177- unix2dos -n $(srcdir)/AUTHORS $(WINDISTDIR)-Infinity/AUTHORS.txt
178- unix2dos -n $(srcdir)/COPYING $(WINDISTDIR)-Infinity/COPYING.txt
179- unix2dos -n $(srcdir)/INSTALL.Windows $(WINDISTDIR)-Infinity/INSTALL.Windows.txt
180- unix2dos -n $(srcdir)/README $(WINDISTDIR)-Infinity/README.txt
181- mkdir $(WINDISTDIR)-Infinity/docs
182- cp $(srcdir)/docs/Lua.html $(WINDISTDIR)-Infinity/docs/Lua.html
183- cp $(srcdir)/docs/Lua_HUD.html $(WINDISTDIR)-Infinity/docs/Lua_HUD.html
184- cp $(srcdir)/docs/MML.html $(WINDISTDIR)-Infinity/docs/MML.html
185- unix2dos -n $(srcdir)/docs/Troubleshooting.txt $(WINDISTDIR)-Infinity/docs/Troubleshooting.txt
186- mkdir $(WINDISTDIR)-Infinity/Themes
187- cp -r $(srcdir)/data/default_theme $(WINDISTDIR)-Infinity/Themes/Default
188- rm -rf "$(WINDISTDIR)-Infinity/Themes/Default/.svn"
189- mkdir $(WINDISTDIR)-Infinity/Extras
190- cp $(srcdir)/data/Software_Transparent_Liquids.mml $(WINDISTDIR)-Infinity/Extras
191- cp $(srcdir)/data/Transparent_Sprites.mml $(WINDISTDIR)-Infinity/Extras
192- cp $(srcdir)/data/Carnage_Messages.mml $(WINDISTDIR)-Infinity/Extras
193- unix2dos -n $(srcdir)/examples/lua/Cheats.lua $(WINDISTDIR)-Infinity/Extras/Cheats.lua
194- cp -r "$(srcdir)/Resources/Library Licenses" $(WINDISTDIR)-Infinity/
195- rm -rf "$(WINDISTDIR)-Infinity/Library Licenses/.svn"
196- zip -r $(PACKAGE)-$(VERSION)-Infinity.zip $(WINDISTDIR)-Infinity
197- rm -rf "$(WINDISTDIR)-Infinity"
166+WINUPDIR_MINF=MarathonInfinity-$(VERSION)
167+$(MINF_WINUP): Source_Files/MarathonInfinity.exe
168+ mkdir "$(WINUPDIR_MINF)"
169+ $(call windist_common,$(WINUPDIR_MINF))
170+ cp Source_Files/MarathonInfinity.exe "$(WINUPDIR_MINF)/Marathon Infinity.exe"
171+ rm -f $(MINF_WINUP)
172+ zip -r $(MINF_WINUP) "$(WINUPDIR_MINF)"
173+ rm -rf "$(WINUPDIR_MINF)"
198174
199-win3zip: $(PACKAGE)-$(VERSION)-Infinity.zip
175+WINDISTDIR_MINF=Marathon Infinity
176+$(MINF_WINZIP): Source_Files/Marathon2.exe
177+ mkdir "$(WINDISTDIR_MINF)"
178+ $(call windist_common,$(WINDISTDIR_MINF))
179+ $(call cp_no_svn,$(srcdir)/data/Scenarios/Marathon Infinity,$(WINDISTDIR_MINF))
180+ $(call cp_no_svn,$(srcdir)/data/XBLA_HUD,$(WINDISTDIR_MINF)/Plugins/XBLA_HUD)
181+ cp Source_Files/MarathonInfinity.exe "$(WINDISTDIR_MINF)/Marathon Infinity.exe"
182+ rm -f $(MINF_WINZIP)
183+ zip -r $(MINF_WINZIP) "$(WINDISTDIR_MINF)"
184+ rm -rf "$(WINDISTDIR_MINF)"
200185
201186 FORCE:
旧リポジトリブラウザで表示