From ad86bc2a303927981ae748526c45587785c318ac Mon Sep 17 00:00:00 2001 From: Chris Cromer Date: Wed, 1 May 2019 17:46:38 -0400 Subject: [PATCH] initial 1.3.0 --- COPYING | 341 +++++ README | 99 ++ agistudio.1 | 34 + help/about_agi.html | 19 + help/about_agi_studio.html | 47 + help/about_help.html | 11 + help/accept_input.html | 16 + help/add_to_pic.html | 20 + help/add_to_pic_v.html | 20 + help/adding_resources.html | 11 + help/addn.html | 20 + help/addv.html | 19 + help/agi-pic-template.pdf | Bin 0 -> 5273 bytes help/agi-pic-template.sxd | Bin 0 -> 9509 bytes help/allow_menu.html | 17 + help/animate_obj.html | 17 + help/assignn.html | 18 + help/assignv.html | 18 + help/block.html | 22 + help/call.html | 17 + help/call_v.html | 17 + help/cancel_line.html | 15 + help/center_posn.html | 19 + help/clear_lines.html | 16 + help/clear_text_rect.html | 18 + help/close_dialogue.html | 18 + help/close_window.html | 19 + help/commands_by_category.html | 20 + help/commands_by_name.html | 213 +++ help/compare_strings.html | 16 + help/configure_screen.html | 23 + help/control_commands.html | 15 + help/controller.html | 17 + help/controlling_obstacles.html | 63 + help/creating_new_games.html | 23 + help/current_cel.html | 19 + help/current_loop.html | 19 + help/current_view.html | 17 + help/cycle_time.html | 19 + help/cycling_objects.html | 59 + help/data_used.html | 16 + help/debug_commands.html | 13 + help/decrement.html | 18 + help/deleting_resources.html | 10 + help/disable_item.html | 19 + help/discard_pic.html | 17 + help/discard_sound.html | 16 + help/discard_view.html | 18 + help/discard_view_v.html | 18 + help/display.html | 17 + help/display_commands.html | 26 + help/display_v.html | 17 + help/displaying_text.html | 13 + help/distance.html | 18 + help/div_n.html | 18 + help/div_v.html | 18 + help/draw.html | 16 + help/draw_pic.html | 20 + help/drawing_pictures.html | 35 + help/drop.html | 15 + help/echo_line.html | 17 + help/enable_item.html | 17 + help/end_of_loop.html | 17 + help/equaln.html | 15 + help/equalv.html | 17 + help/erase.html | 16 + help/extra_commands.html | 22 + help/extracting_resources.html | 11 + help/fence_mouse.html | 20 + help/files_used.html | 20 + help/fix_loop.html | 17 + help/flag_commands.html | 15 + help/follow_ego.html | 19 + help/force_update.html | 18 + help/get.html | 16 + help/get_dir.html | 18 + help/get_num.html | 16 + help/get_posn.html | 16 + help/get_priority.html | 16 + help/get_room_v.html | 15 + help/get_string.html | 16 + help/get_v.html | 16 + help/getting_started.html | 17 + help/gpl.txt | 343 +++++ help/graphics.html | 16 + help/greatern.html | 18 + help/greaterv.html | 18 + help/has.html | 17 + help/have_key.html | 16 + help/hide_mouse.html | 19 + help/hold_key.html | 16 + help/ignore_blocks.html | 18 + help/ignore_horizon.html | 18 + help/ignore_objs.html | 18 + help/increment.html | 18 + help/index.html | 35 + help/indexabc.html | 274 ++++ help/init_disk.html | 15 + help/init_joy.html | 15 + help/initializing_objects.html | 28 + help/inventory_commands.html | 18 + help/isset.html | 18 + help/issetv.html | 17 + help/kq3.png | Bin 0 -> 8037 bytes help/last_cel.html | 19 + help/lessn.html | 18 + help/lessv.html | 18 + help/lindirectn.html | 18 + help/lindirectv.html | 18 + help/load_logics.html | 17 + help/load_logics_v.html | 17 + help/load_pic.html | 19 + help/load_sound.html | 16 + help/load_view.html | 20 + help/load_view_v.html | 20 + help/log.html | 16 + help/logic-editor.png | Bin 0 -> 9613 bytes help/logic_contents.html | 18 + help/logic_descr.html | 15 + help/logic_diag-directions.png | Bin 0 -> 2443 bytes help/logic_editor_main.html | 36 + help/logic_syntax.html | 189 +++ help/logo.bmp | Bin 0 -> 142134 bytes help/logo.png | Bin 0 -> 4335 bytes help/math_commands.html | 30 + help/menu_commands.html | 16 + help/menu_input.html | 20 + help/mouse_posn.html | 19 + help/move_obj.html | 26 + help/move_obj_v.html | 25 + help/moving_objects.html | 35 + help/mul_n.html | 19 + help/mul_v.html | 18 + help/new_room.html | 36 + help/new_room_v.html | 36 + help/normal_cycle.html | 19 + help/normal_motion.html | 19 + help/notes | 6 + help/number_of_loops.html | 19 + help/obj_in_box.html | 19 + help/obj_in_room.html | 17 + help/obj_status_v.html | 16 + help/object-editor.png | Bin 0 -> 9356 bytes help/object_commands.html | 80 ++ help/object_descr.html | 19 + help/object_editor_main.html | 25 + help/object_on_anything.html | 18 + help/object_on_land.html | 18 + help/object_on_water.html | 18 + help/objects.html | 19 + help/observe_blocks.html | 18 + help/observe_horizon.html | 18 + help/observe_objs.html | 17 + help/open_dialogue.html | 18 + help/opening_games.html | 13 + help/overlay_pic.html | 23 + help/parse.html | 15 + help/pause.html | 18 + help/picture-editor.png | Bin 0 -> 10003 bytes help/picture-viewing.png | Bin 0 -> 5824 bytes help/picture_commands.html | 11 + help/picture_descr.html | 24 + help/picture_editor_main.html | 236 ++++ help/player_control.html | 16 + help/pop_script.html | 16 + help/position.html | 22 + help/position_v.html | 22 + help/positioning_objects.html | 17 + help/posn.html | 19 + help/prevent_input.html | 16 + help/pridemo-1.pmg | Bin 0 -> 25106 bytes help/pridemo-1.png | Bin 0 -> 2277 bytes help/pridemo-2.png | Bin 0 -> 1356 bytes help/print.html | 21 + help/print_at.html | 21 + help/print_at_v.html | 21 + help/print_v.html | 21 + help/priorities.html | 47 + help/program_control.html | 19 + help/project_status.html | 13 + help/push_script.html | 16 + help/put.html | 16 + help/put_v.html | 16 + help/quit.html | 15 + help/random.html | 15 + help/rebuilding_vol_files.html | 16 + help/release_key.html | 16 + help/release_loop.html | 17 + help/release_priority.html | 18 + help/renumbering_resources.html | 8 + help/reposition.html | 27 + help/reposition_to.html | 22 + help/reposition_to_v.html | 22 + help/reset.html | 16 + help/reset_scan_start.html | 16 + help/reset_v.html | 16 + help/restart_game.html | 15 + help/restore_game.html | 18 + help/return.html | 16 + help/reverse_cycle.html | 19 + help/reverse_loop.html | 17 + help/right_posn.html | 19 + help/rindirect.html | 18 + help/said.html | 36 + help/save_game.html | 18 + help/script_buffer.html | 21 + help/script_size.html | 15 + help/set.html | 16 + help/set_cel.html | 23 + help/set_cel_v.html | 23 + help/set_cursor_char.html | 15 + help/set_dir.html | 21 + help/set_game_id.html | 20 + help/set_horizon.html | 20 + help/set_key.html | 66 + help/set_loop.html | 23 + help/set_loop_v.html | 23 + help/set_menu.html | 17 + help/set_menu_item.html | 19 + help/set_pri_base.html | 15 + help/set_priority.html | 22 + help/set_priority_v.html | 22 + help/set_scan_start.html | 16 + help/set_simple.html | 32 + help/set_string.html | 15 + help/set_text_attribute.html | 19 + help/set_upper_left.html | 15 + help/set_v.html | 16 + help/set_view.html | 19 + help/set_view_v.html | 19 + help/setting_up_menus_and_keys.html | 37 + help/settings.html | 49 + help/shake_screen.html | 15 + help/show_mem.html | 20 + help/show_mouse.html | 19 + help/show_obj.html | 22 + help/show_obj_v.html | 22 + help/show_pic.html | 16 + help/show_pri_screen.html | 16 + help/sound.html | 18 + help/sound_commands.html | 9 + help/sound_descr.html | 12 + help/special_flags.html | 67 + help/special_variables.html | 93 ++ help/start_cycling.html | 21 + help/start_motion.html | 22 + help/start_update.html | 17 + help/status.html | 17 + help/status_line_off.html | 19 + help/status_line_on.html | 19 + help/step_size.html | 20 + help/step_time.html | 20 + help/stop_cycling.html | 19 + help/stop_motion.html | 18 + help/stop_sound.html | 16 + help/stop_update.html | 17 + help/string_commands.html | 12 + help/submit_menu.html | 20 + help/subn.html | 18 + help/subv.html | 18 + help/system_commands.html | 22 + help/test.html | 19 + help/test_commands.html | 24 + help/text_editor_main.html | 13 + help/text_screen.html | 19 + help/todo.html | 60 + help/toggle.html | 16 + help/toggle_monitor.html | 21 + help/toggle_v.html | 16 + help/trace_info.html | 18 + help/trace_mode.html | 17 + help/trace_on.html | 18 + help/types.html | 74 + help/unanimate_all.html | 16 + help/unblock.html | 17 + help/version.html | 15 + help/view-description.png | Bin 0 -> 3883 bytes help/view-editor.png | Bin 0 -> 9161 bytes help/view-viewing.png | Bin 0 -> 1910 bytes help/view_descr.html | 23 + help/view_editor_main.html | 66 + help/viewing_resources.html | 19 + help/wander.html | 16 + help/word_to_string.html | 15 + help/wordstok-editor.png | Bin 0 -> 10873 bytes help/wordstok_descr.html | 21 + help/wordstok_editor_main.html | 49 + packaging/README.Packaging | 6 + packaging/agistudio.desktop | 7 + packaging/debian/agistudio.doc-base | 10 + packaging/debian/agistudio.install | 4 + packaging/debian/agistudio.xpm | 37 + packaging/debian/changelog | 141 ++ packaging/debian/control | 15 + packaging/debian/copyright | 35 + packaging/debian/dirs | 3 + packaging/debian/docs | 2 + packaging/debian/menu | 4 + packaging/debian/rules | 95 ++ packaging/qtagistudio.xpm | 40 + packaging/rpm/agistudio.spec | 39 + relnotes | 44 + src/agicommands.cpp | 266 ++++ src/agicommands.h | 53 + src/agiplay.cpp | 291 ++++ src/agistudio.aps | Bin 0 -> 18054 bytes src/agistudio.dsp | 670 +++++++++ src/agistudio.dsw | 29 + src/agistudio.kdevelop | 114 ++ src/agistudio.pro | 63 + src/agistudio.rc | 72 + src/app_icon.xpm | 40 + src/back.xpm | 27 + src/bmp2agipic.cpp | 413 ++++++ src/bmp2agipic.h | 33 + src/bpicture.cpp | 545 ++++++++ src/dir.cpp | 98 ++ src/dir.h | 28 + src/downarrow_x.xpm | 24 + src/forward.xpm | 27 + src/game.cpp | 1591 +++++++++++++++++++++ src/game.h | 127 ++ src/global.h | 28 + src/helpwindow.cpp | 371 +++++ src/helpwindow.h | 70 + src/home.xpm | 26 + src/icon1.ico | Bin 0 -> 9710 bytes src/left.xpm | 24 + src/left1.xpm | 24 + src/left1_x.xpm | 24 + src/left2.xpm | 24 + src/left2_x.xpm | 24 + src/left_x.xpm | 24 + src/leftarrow_x.xpm | 24 + src/linklist.cpp | 282 ++++ src/linklist.h | 37 + src/logcompile.cpp | 1508 ++++++++++++++++++++ src/logdecode.cpp | 685 +++++++++ src/logedit.cpp | 1436 +++++++++++++++++++ src/logedit.h | 147 ++ src/logic.cpp | 37 + src/logic.h | 91 ++ src/logo.xpm | 168 +++ src/main.cpp | 80 ++ src/menu.cpp | 1173 ++++++++++++++++ src/menu.h | 170 +++ src/midi.cpp | 306 +++++ src/midi.h | 27 + src/object.cpp | 194 +++ src/object.h | 44 + src/objedit.cpp | 363 +++++ src/objedit.h | 81 ++ src/options.cpp | 297 ++++ src/options.h | 83 ++ src/picedit.cpp | 1490 ++++++++++++++++++++ src/picedit.h | 192 +++ src/picture.cpp | 1562 +++++++++++++++++++++ src/picture.h | 218 +++ src/preview.cpp | 650 +++++++++ src/preview.h | 131 ++ src/resource.h | 16 + src/resources.cpp | 779 +++++++++++ src/resources.h | 110 ++ src/right.xpm | 24 + src/right1.xpm | 24 + src/right1_x.xpm | 24 + src/right2.xpm | 24 + src/right2_x.xpm | 24 + src/right_x.xpm | 24 + src/rightarrow_x.xpm | 24 + src/roomgen.cpp | 916 +++++++++++++ src/roomgen.h | 148 ++ src/toolbar_close.xpm | 201 +++ src/toolbar_logedit.xpm | 124 ++ src/toolbar_objedit.xpm | 206 +++ src/toolbar_open.xpm | 210 +++ src/toolbar_picedit.xpm | 202 +++ src/toolbar_run.xpm | 130 ++ src/toolbar_textedit.xpm | 116 ++ src/toolbar_viewedit.xpm | 64 + src/toolbar_wordsedit.xpm | 208 +++ src/uparrow_x.xpm | 24 + src/util.cpp | 242 ++++ src/util.h | 64 + src/view.cpp | 942 +++++++++++++ src/view.h | 106 ++ src/viewedit.cpp | 1983 +++++++++++++++++++++++++++ src/viewedit.h | 251 ++++ src/words.cpp | 527 +++++++ src/words.h | 65 + src/wordsedit.cpp | 904 ++++++++++++ src/wordsedit.h | 141 ++ src/wutil.cpp | 185 +++ src/wutil.h | 73 + src/zoom_minus.xpm | 38 + src/zoom_minus_x.xpm | 38 + src/zoom_plus.xpm | 38 + src/zoom_plus_x.xpm | 38 + template/logdir | Bin 0 -> 300 bytes template/object | Bin 0 -> 23 bytes template/picdir | Bin 0 -> 9 bytes template/snddir | 0 template/src/defines.txt | 162 +++ template/src/logic0.txt | 334 +++++ template/src/logic1.txt | 30 + template/src/logic2.txt | 92 ++ template/src/logic90.txt | 74 + template/src/logic91.txt | 65 + template/src/logic92.txt | 38 + template/src/logic93.txt | 47 + template/src/logic94.txt | 73 + template/src/logic95.txt | 190 +++ template/src/logic98.txt | 36 + template/src/logic99.txt | 135 ++ template/src/newroom.txt | 35 + template/viewdir | Bin 0 -> 666 bytes template/vol.0 | Bin 0 -> 16799 bytes template/words.tok | Bin 0 -> 541 bytes 418 files changed, 34837 insertions(+) create mode 100644 COPYING create mode 100644 README create mode 100644 agistudio.1 create mode 100644 help/about_agi.html create mode 100644 help/about_agi_studio.html create mode 100644 help/about_help.html create mode 100644 help/accept_input.html create mode 100644 help/add_to_pic.html create mode 100644 help/add_to_pic_v.html create mode 100644 help/adding_resources.html create mode 100644 help/addn.html create mode 100644 help/addv.html create mode 100644 help/agi-pic-template.pdf create mode 100644 help/agi-pic-template.sxd create mode 100644 help/allow_menu.html create mode 100644 help/animate_obj.html create mode 100644 help/assignn.html create mode 100644 help/assignv.html create mode 100644 help/block.html create mode 100644 help/call.html create mode 100644 help/call_v.html create mode 100644 help/cancel_line.html create mode 100644 help/center_posn.html create mode 100644 help/clear_lines.html create mode 100644 help/clear_text_rect.html create mode 100644 help/close_dialogue.html create mode 100644 help/close_window.html create mode 100644 help/commands_by_category.html create mode 100644 help/commands_by_name.html create mode 100644 help/compare_strings.html create mode 100644 help/configure_screen.html create mode 100644 help/control_commands.html create mode 100644 help/controller.html create mode 100644 help/controlling_obstacles.html create mode 100644 help/creating_new_games.html create mode 100644 help/current_cel.html create mode 100644 help/current_loop.html create mode 100644 help/current_view.html create mode 100644 help/cycle_time.html create mode 100644 help/cycling_objects.html create mode 100644 help/data_used.html create mode 100644 help/debug_commands.html create mode 100644 help/decrement.html create mode 100644 help/deleting_resources.html create mode 100644 help/disable_item.html create mode 100644 help/discard_pic.html create mode 100644 help/discard_sound.html create mode 100644 help/discard_view.html create mode 100644 help/discard_view_v.html create mode 100644 help/display.html create mode 100644 help/display_commands.html create mode 100644 help/display_v.html create mode 100644 help/displaying_text.html create mode 100644 help/distance.html create mode 100644 help/div_n.html create mode 100644 help/div_v.html create mode 100644 help/draw.html create mode 100644 help/draw_pic.html create mode 100644 help/drawing_pictures.html create mode 100644 help/drop.html create mode 100644 help/echo_line.html create mode 100644 help/enable_item.html create mode 100644 help/end_of_loop.html create mode 100644 help/equaln.html create mode 100644 help/equalv.html create mode 100644 help/erase.html create mode 100644 help/extra_commands.html create mode 100644 help/extracting_resources.html create mode 100644 help/fence_mouse.html create mode 100644 help/files_used.html create mode 100644 help/fix_loop.html create mode 100644 help/flag_commands.html create mode 100644 help/follow_ego.html create mode 100644 help/force_update.html create mode 100644 help/get.html create mode 100644 help/get_dir.html create mode 100644 help/get_num.html create mode 100644 help/get_posn.html create mode 100644 help/get_priority.html create mode 100644 help/get_room_v.html create mode 100644 help/get_string.html create mode 100644 help/get_v.html create mode 100644 help/getting_started.html create mode 100644 help/gpl.txt create mode 100644 help/graphics.html create mode 100644 help/greatern.html create mode 100644 help/greaterv.html create mode 100644 help/has.html create mode 100644 help/have_key.html create mode 100644 help/hide_mouse.html create mode 100644 help/hold_key.html create mode 100644 help/ignore_blocks.html create mode 100644 help/ignore_horizon.html create mode 100644 help/ignore_objs.html create mode 100644 help/increment.html create mode 100644 help/index.html create mode 100644 help/indexabc.html create mode 100644 help/init_disk.html create mode 100644 help/init_joy.html create mode 100644 help/initializing_objects.html create mode 100644 help/inventory_commands.html create mode 100644 help/isset.html create mode 100644 help/issetv.html create mode 100644 help/kq3.png create mode 100644 help/last_cel.html create mode 100644 help/lessn.html create mode 100644 help/lessv.html create mode 100644 help/lindirectn.html create mode 100644 help/lindirectv.html create mode 100644 help/load_logics.html create mode 100644 help/load_logics_v.html create mode 100644 help/load_pic.html create mode 100644 help/load_sound.html create mode 100644 help/load_view.html create mode 100644 help/load_view_v.html create mode 100644 help/log.html create mode 100644 help/logic-editor.png create mode 100644 help/logic_contents.html create mode 100644 help/logic_descr.html create mode 100644 help/logic_diag-directions.png create mode 100644 help/logic_editor_main.html create mode 100644 help/logic_syntax.html create mode 100644 help/logo.bmp create mode 100644 help/logo.png create mode 100644 help/math_commands.html create mode 100644 help/menu_commands.html create mode 100644 help/menu_input.html create mode 100644 help/mouse_posn.html create mode 100644 help/move_obj.html create mode 100644 help/move_obj_v.html create mode 100644 help/moving_objects.html create mode 100644 help/mul_n.html create mode 100644 help/mul_v.html create mode 100644 help/new_room.html create mode 100644 help/new_room_v.html create mode 100644 help/normal_cycle.html create mode 100644 help/normal_motion.html create mode 100644 help/notes create mode 100644 help/number_of_loops.html create mode 100644 help/obj_in_box.html create mode 100644 help/obj_in_room.html create mode 100644 help/obj_status_v.html create mode 100644 help/object-editor.png create mode 100644 help/object_commands.html create mode 100644 help/object_descr.html create mode 100644 help/object_editor_main.html create mode 100644 help/object_on_anything.html create mode 100644 help/object_on_land.html create mode 100644 help/object_on_water.html create mode 100644 help/objects.html create mode 100644 help/observe_blocks.html create mode 100644 help/observe_horizon.html create mode 100644 help/observe_objs.html create mode 100644 help/open_dialogue.html create mode 100644 help/opening_games.html create mode 100644 help/overlay_pic.html create mode 100644 help/parse.html create mode 100644 help/pause.html create mode 100644 help/picture-editor.png create mode 100644 help/picture-viewing.png create mode 100644 help/picture_commands.html create mode 100644 help/picture_descr.html create mode 100644 help/picture_editor_main.html create mode 100644 help/player_control.html create mode 100644 help/pop_script.html create mode 100644 help/position.html create mode 100644 help/position_v.html create mode 100644 help/positioning_objects.html create mode 100644 help/posn.html create mode 100644 help/prevent_input.html create mode 100644 help/pridemo-1.pmg create mode 100644 help/pridemo-1.png create mode 100644 help/pridemo-2.png create mode 100644 help/print.html create mode 100644 help/print_at.html create mode 100644 help/print_at_v.html create mode 100644 help/print_v.html create mode 100644 help/priorities.html create mode 100644 help/program_control.html create mode 100644 help/project_status.html create mode 100644 help/push_script.html create mode 100644 help/put.html create mode 100644 help/put_v.html create mode 100644 help/quit.html create mode 100644 help/random.html create mode 100644 help/rebuilding_vol_files.html create mode 100644 help/release_key.html create mode 100644 help/release_loop.html create mode 100644 help/release_priority.html create mode 100644 help/renumbering_resources.html create mode 100644 help/reposition.html create mode 100644 help/reposition_to.html create mode 100644 help/reposition_to_v.html create mode 100644 help/reset.html create mode 100644 help/reset_scan_start.html create mode 100644 help/reset_v.html create mode 100644 help/restart_game.html create mode 100644 help/restore_game.html create mode 100644 help/return.html create mode 100644 help/reverse_cycle.html create mode 100644 help/reverse_loop.html create mode 100644 help/right_posn.html create mode 100644 help/rindirect.html create mode 100644 help/said.html create mode 100644 help/save_game.html create mode 100644 help/script_buffer.html create mode 100644 help/script_size.html create mode 100644 help/set.html create mode 100644 help/set_cel.html create mode 100644 help/set_cel_v.html create mode 100644 help/set_cursor_char.html create mode 100644 help/set_dir.html create mode 100644 help/set_game_id.html create mode 100644 help/set_horizon.html create mode 100644 help/set_key.html create mode 100644 help/set_loop.html create mode 100644 help/set_loop_v.html create mode 100644 help/set_menu.html create mode 100644 help/set_menu_item.html create mode 100644 help/set_pri_base.html create mode 100644 help/set_priority.html create mode 100644 help/set_priority_v.html create mode 100644 help/set_scan_start.html create mode 100644 help/set_simple.html create mode 100644 help/set_string.html create mode 100644 help/set_text_attribute.html create mode 100644 help/set_upper_left.html create mode 100644 help/set_v.html create mode 100644 help/set_view.html create mode 100644 help/set_view_v.html create mode 100644 help/setting_up_menus_and_keys.html create mode 100644 help/settings.html create mode 100644 help/shake_screen.html create mode 100644 help/show_mem.html create mode 100644 help/show_mouse.html create mode 100644 help/show_obj.html create mode 100644 help/show_obj_v.html create mode 100644 help/show_pic.html create mode 100644 help/show_pri_screen.html create mode 100644 help/sound.html create mode 100644 help/sound_commands.html create mode 100644 help/sound_descr.html create mode 100644 help/special_flags.html create mode 100644 help/special_variables.html create mode 100644 help/start_cycling.html create mode 100644 help/start_motion.html create mode 100644 help/start_update.html create mode 100644 help/status.html create mode 100644 help/status_line_off.html create mode 100644 help/status_line_on.html create mode 100644 help/step_size.html create mode 100644 help/step_time.html create mode 100644 help/stop_cycling.html create mode 100644 help/stop_motion.html create mode 100644 help/stop_sound.html create mode 100644 help/stop_update.html create mode 100644 help/string_commands.html create mode 100644 help/submit_menu.html create mode 100644 help/subn.html create mode 100644 help/subv.html create mode 100644 help/system_commands.html create mode 100644 help/test.html create mode 100644 help/test_commands.html create mode 100644 help/text_editor_main.html create mode 100644 help/text_screen.html create mode 100644 help/todo.html create mode 100644 help/toggle.html create mode 100644 help/toggle_monitor.html create mode 100644 help/toggle_v.html create mode 100644 help/trace_info.html create mode 100644 help/trace_mode.html create mode 100644 help/trace_on.html create mode 100644 help/types.html create mode 100644 help/unanimate_all.html create mode 100644 help/unblock.html create mode 100644 help/version.html create mode 100644 help/view-description.png create mode 100644 help/view-editor.png create mode 100644 help/view-viewing.png create mode 100644 help/view_descr.html create mode 100644 help/view_editor_main.html create mode 100644 help/viewing_resources.html create mode 100644 help/wander.html create mode 100644 help/word_to_string.html create mode 100644 help/wordstok-editor.png create mode 100644 help/wordstok_descr.html create mode 100644 help/wordstok_editor_main.html create mode 100644 packaging/README.Packaging create mode 100644 packaging/agistudio.desktop create mode 100644 packaging/debian/agistudio.doc-base create mode 100644 packaging/debian/agistudio.install create mode 100644 packaging/debian/agistudio.xpm create mode 100644 packaging/debian/changelog create mode 100644 packaging/debian/control create mode 100644 packaging/debian/copyright create mode 100644 packaging/debian/dirs create mode 100644 packaging/debian/docs create mode 100644 packaging/debian/menu create mode 100755 packaging/debian/rules create mode 100644 packaging/qtagistudio.xpm create mode 100644 packaging/rpm/agistudio.spec create mode 100644 relnotes create mode 100644 src/agicommands.cpp create mode 100644 src/agicommands.h create mode 100644 src/agiplay.cpp create mode 100644 src/agistudio.aps create mode 100644 src/agistudio.dsp create mode 100644 src/agistudio.dsw create mode 100644 src/agistudio.kdevelop create mode 100644 src/agistudio.pro create mode 100644 src/agistudio.rc create mode 100644 src/app_icon.xpm create mode 100644 src/back.xpm create mode 100644 src/bmp2agipic.cpp create mode 100644 src/bmp2agipic.h create mode 100644 src/bpicture.cpp create mode 100644 src/dir.cpp create mode 100644 src/dir.h create mode 100644 src/downarrow_x.xpm create mode 100644 src/forward.xpm create mode 100644 src/game.cpp create mode 100644 src/game.h create mode 100644 src/global.h create mode 100644 src/helpwindow.cpp create mode 100644 src/helpwindow.h create mode 100644 src/home.xpm create mode 100644 src/icon1.ico create mode 100644 src/left.xpm create mode 100644 src/left1.xpm create mode 100644 src/left1_x.xpm create mode 100644 src/left2.xpm create mode 100644 src/left2_x.xpm create mode 100644 src/left_x.xpm create mode 100644 src/leftarrow_x.xpm create mode 100644 src/linklist.cpp create mode 100644 src/linklist.h create mode 100644 src/logcompile.cpp create mode 100644 src/logdecode.cpp create mode 100644 src/logedit.cpp create mode 100644 src/logedit.h create mode 100644 src/logic.cpp create mode 100644 src/logic.h create mode 100644 src/logo.xpm create mode 100644 src/main.cpp create mode 100644 src/menu.cpp create mode 100644 src/menu.h create mode 100644 src/midi.cpp create mode 100644 src/midi.h create mode 100644 src/object.cpp create mode 100644 src/object.h create mode 100644 src/objedit.cpp create mode 100644 src/objedit.h create mode 100644 src/options.cpp create mode 100644 src/options.h create mode 100644 src/picedit.cpp create mode 100644 src/picedit.h create mode 100644 src/picture.cpp create mode 100644 src/picture.h create mode 100644 src/preview.cpp create mode 100644 src/preview.h create mode 100644 src/resource.h create mode 100644 src/resources.cpp create mode 100644 src/resources.h create mode 100644 src/right.xpm create mode 100644 src/right1.xpm create mode 100644 src/right1_x.xpm create mode 100644 src/right2.xpm create mode 100644 src/right2_x.xpm create mode 100644 src/right_x.xpm create mode 100644 src/rightarrow_x.xpm create mode 100644 src/roomgen.cpp create mode 100644 src/roomgen.h create mode 100644 src/toolbar_close.xpm create mode 100644 src/toolbar_logedit.xpm create mode 100644 src/toolbar_objedit.xpm create mode 100644 src/toolbar_open.xpm create mode 100644 src/toolbar_picedit.xpm create mode 100644 src/toolbar_run.xpm create mode 100644 src/toolbar_textedit.xpm create mode 100644 src/toolbar_viewedit.xpm create mode 100644 src/toolbar_wordsedit.xpm create mode 100644 src/uparrow_x.xpm create mode 100644 src/util.cpp create mode 100644 src/util.h create mode 100644 src/view.cpp create mode 100644 src/view.h create mode 100644 src/viewedit.cpp create mode 100644 src/viewedit.h create mode 100644 src/words.cpp create mode 100644 src/words.h create mode 100644 src/wordsedit.cpp create mode 100644 src/wordsedit.h create mode 100644 src/wutil.cpp create mode 100644 src/wutil.h create mode 100644 src/zoom_minus.xpm create mode 100644 src/zoom_minus_x.xpm create mode 100644 src/zoom_plus.xpm create mode 100644 src/zoom_plus_x.xpm create mode 100644 template/logdir create mode 100644 template/object create mode 100644 template/picdir create mode 100644 template/snddir create mode 100644 template/src/defines.txt create mode 100644 template/src/logic0.txt create mode 100644 template/src/logic1.txt create mode 100644 template/src/logic2.txt create mode 100644 template/src/logic90.txt create mode 100644 template/src/logic91.txt create mode 100644 template/src/logic92.txt create mode 100644 template/src/logic93.txt create mode 100644 template/src/logic94.txt create mode 100644 template/src/logic95.txt create mode 100644 template/src/logic98.txt create mode 100644 template/src/logic99.txt create mode 100644 template/src/newroom.txt create mode 100644 template/viewdir create mode 100644 template/vol.0 create mode 100644 template/words.tok diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..056e8c6 --- /dev/null +++ b/COPYING @@ -0,0 +1,341 @@ + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/README b/README new file mode 100644 index 0000000..78f0ae6 --- /dev/null +++ b/README @@ -0,0 +1,99 @@ +QT AGI Studio, release 1.3.0 + +About +===== + +AGI (Adventure Game Interpreter) is the adventure game engine used by +Sierra On-Line(tm) to create some of their early games. QT AGI Studio +(formerly known as Linux AGI Studio) is a program which allows you to +view, create and edit AGI games. Basically, it is an enhanced port of +the Windows AGI Studio developed by Peter Kelly. + +The program contains very little platform specific code so brave ones +are encouraged to try it on other operating systems that have QT +library support. + + +Availability +============ + +QT AGI Studio is available at http://agistudio.sourceforge.net/ +The project is licensed under the GPL, GNU General Public License. +See COPYING for details. + + +System requirements +=================== + +Linux: GNU make, g++, X Window System, QT library + +The program is now being developed with QT version 4 + +NAGI, Sarien or ScummVM AGI interpreter is recommended to run games. +Sarien is available at http://sarien.sourceforge.net/ +and NAGI at http://www.agidev.com/nagi.html +Sarien is more focused on portability and NAGI on compatibility +with Sierra's original AGI interpreter. Both are free. +ScummVM is actively developed, but does not integrate well +with QT AGI studio. + +WINDOWS NOTE: the code hasn't been tested on Windows lately. +If you are interested, please go ahead, make a working +Visual Studio project and send a patch! + + +Building +======== + +Run "make" in the src subdirectory. If the supplied Makefile doesn't work, +you can either fix it or use tmake to generate a makefile for your platform: + + qmake agistudio.pro -o Makefile + +If you don't have tmake, you can download it at http://www.trolltech.com + +Make assumes that QT4 is installed and working (in particular, the QTDIR +environment variable is properly set) + + +Installation and setup +====================== + +The binary is called agistudio and will be built in the src subdirectory; you +can copy it to any path convenient to use (e.g. /usr/local/bin). In order to +use the help and an example game template, copy them to any convenient place +and specify the appropriate paths in the "Settings" menu when you'll run +agistudio. + +AGI studio has its own help viewer, but you can also view the help with +any HTML browser. + +If agistudio complains that it can't load qt shared library, then set the +LD_LIBRARY_PATH environment variable to the path which contains libqt.so.*. + +Using +===== + +Please read the online help. Note that if you want to use existing games' +files, all the filenames must be in lower case. + + +Credits +======= + + * Helen Zommer - primary development + * Jarno Elonen - bitmap import, current maintainer + + * Nat Budin - Win32 port + * Claudio Matsuoka - sound support + * Peter Kelly - the original Windows version + * Lance Ewing - the original (DOS) Picedit + + +Feedback +======== + +Please visit project website at http://agistudio.sourceforge.net/ to +submit bug reports, comments, suggestions, etc. + +Hope you'll have as much fun using it as we've had developing it :-) diff --git a/agistudio.1 b/agistudio.1 new file mode 100644 index 0000000..7b68e4a --- /dev/null +++ b/agistudio.1 @@ -0,0 +1,34 @@ +.\" Hey, EMACS: -*- nroff -*- +.TH AGISTUDIO 1 "August 25, 2012" "agistudio" "QT AGI Studio 1.3.0" +.SH NAME +QT AGI Studio \- an AGI adventure game development environment +.SH SYNOPSIS +.B agistudio +.RI [ options ] +.br +.SH DESCRIPTION +AGI (Adventure Game Interpreter) is the adventure game engine used by +Sierra On-Line(tm) to create some of their early games. \fBQT AGI Studio\fP +is a program that allows you to view, create and edit AGI games with +a friendly GUI. +.PP +.nf +The user interface is documented in HTML format, see +.fi +.nh +.IR /usr/share/agistudio/help +.hy +.SH OPTIONS +.TP +.B \-help +.br +Show of options. +.TP +.B \-dir GAMEDIR +.br +Open an existing game in GAMEDIR. +.SH SEE ALSO +.BR nagi(6),sarien(6),scummvm(6) +.IR +.SH AUTHOR +(C) 2003-2012 by Jarno Elonen diff --git a/help/about_agi.html b/help/about_agi.html new file mode 100644 index 0000000..0fccb8d --- /dev/null +++ b/help/about_agi.html @@ -0,0 +1,19 @@ + + +About AGI + +

About AGI

+AGI (Adventure Game Interpreter) is the adventure game engine used by Sierra On-Line(tm) to create some of their early games. With the release of King's Quest 1 in the early 80's, it introduced the +gaming world to the concept of a 3D graphical adventure game, where the player could move a character around the screen, behind, in front of and over objects. Other commands could be typed in, just +like a text adventure. A number of other games that used AGI were subsequently released, such as Space Quest 1 & 2, Police Quest 1 and Leisure Suit Larry 1 to name a few. +

+The graphics were rather blocky, using a 160x200 resolution, which I believe is because of the graphics mode used by the IBM PCjr, for which the interpreter was originally written. AGI used the +internal speaker for sound on PCs, but on pretty much every other system (Mac, Amiga, Tandy, PCjr) it was capable of doing 3 voices. +

+

+A screenshot from Kings Quest 3

+Since late 1996 a number of people around the world have been working together to figure out the data formats used by AGI, with the intention of being able to view and edit the data. It has taken a +while, but we are now at the point where we can do this, and even create our own adventure games using the system. +

+Back to contents

+ diff --git a/help/about_agi_studio.html b/help/about_agi_studio.html new file mode 100644 index 0000000..283bbb4 --- /dev/null +++ b/help/about_agi_studio.html @@ -0,0 +1,47 @@ + + +About QT AGI Studio + +

About QT AGI Studio

+AGI Studio is a program which allows you to view, create and edit AGI games. +Its goal is to provide a friendly, easy to use interface to work with AGI games in a powerful, integrated environment. +

+Its features include:

+

    +
  • Viewing of view and picture resources +
  • Editing of view and picture resources and the WORDS.TOK and OBJECT files +
  • Listening to sound resources +
  • Compiling and decompiling of logic resources +
  • Adding, deleting, extracting and renumbering of resources +
  • Rebuilding of VOL files +
+

+QT AGI studio is an enhanced port of the Windows AGI Studio v.1.31 developed by Peter Kelly. It is designed to closely resemble the original program, however some (hopefully non-critical) features are missing and some new features are added. +

+The picture editor is a port of the MSDOS Picedit developed by Lance Ewing. +

+ The sound code was developed by Claudio Matsuoka. +

+QT AGI Studio is available from +http://agistudio.sourceforge.net/. +

+Please submit bug reports, suggestions etc. to the support database. +

+Here is the TODO list for future development. +

+


+This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License, version 2 or later, as published by the the Free Software Foundation. +

+This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +

+You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +


+

+Back to contents

+ diff --git a/help/about_help.html b/help/about_help.html new file mode 100644 index 0000000..34e8692 --- /dev/null +++ b/help/about_help.html @@ -0,0 +1,11 @@ + + +About this help + +

About this help

+The QT AGI studio online help was converted from the original (Windows) AGI Studio online help. Therefore, "I" in this help almost everywhere refers to Peter Kelly - the author of the Windows AGI studio. +

+The name "AGI studio" refers to the QT AGI Studio. There are a few differences between the QT port and the native Windows version, the relevant help text has been changed, but there is no list of the differences. +

+Back to contents

+ diff --git a/help/accept_input.html b/help/accept_input.html new file mode 100644 index 0000000..3e186e9 --- /dev/null +++ b/help/accept_input.html @@ -0,0 +1,16 @@ + + +accept.input + +

accept.input

+Category

+System commands

+Syntax

+

+accept.input();

+Description

+

+Allows the player to enter input, if they have been prevented from doing so. If the input prompt is hidden, it is displayed again (including any text that was on it).

+See also

+prevent.input

+ diff --git a/help/add_to_pic.html b/help/add_to_pic.html new file mode 100644 index 0000000..32da363 --- /dev/null +++ b/help/add_to_pic.html @@ -0,0 +1,20 @@ + + +add.to.pic + +

add.to.pic

+Category

+Object/view commands

+Syntax

+

+add.to.pic(VIEWNO,LOOPNO,CELNO,X,Y,PRI,MARGIN);

+Description

+

+This command allows you to add a view to the visual picture screen in memory. Cel CELNO of loop LOOPNO of view VIEWNO is drawn on the picture at X,Y with a priority of PRI. If MARGIN is 0, 1, 2 or 3, +the base line of the object (the bottom row of pixels of the cel) is given a priority of MARGIN. Since priority is taken into account, so you can use add.to.pic to add views behind other parts of the +picture. +

+Note that the view must be loaded before you use it with add.to.pic. This can be done with the load.view command.

+See also

+add.to.pic.v

+ diff --git a/help/add_to_pic_v.html b/help/add_to_pic_v.html new file mode 100644 index 0000000..53ef5ca --- /dev/null +++ b/help/add_to_pic_v.html @@ -0,0 +1,20 @@ + + +add.to.pic.v + +

add.to.pic.v

+Category

+Object/view commands

+Syntax

+

+add.to.pic.v(vVIEWNO,vLOOPNO,vCELNO,vX,vY,vPRI,vMARGIN);

+Description

+

+This command allows you to add a view to the visual picture screen in memory. Cel vCELNO of loop vLOOPNO of view vVIEWNO is drawn on the picture at vX,vY with a priority of vPRI. If vMARGIN is 0, 1, +2 or 3, the base line of the object (the bottom row of pixels of the cel) is given a priority of vMARGIN. Since priority is taken into account, so you can use add.to.pic.v to add views behind other +parts of the picture. +

+Note that the view must be loaded before you use it with add.to.pic.v. This can be done with the load.view command.

+See also

+add.to.pic

+ diff --git a/help/adding_resources.html b/help/adding_resources.html new file mode 100644 index 0000000..a2823ba --- /dev/null +++ b/help/adding_resources.html @@ -0,0 +1,11 @@ + + +Adding resources + +

Adding resources

+To add a resource, select 'Add' from the 'Resource' menu. Select the file you want to add. Once a file is selected, you will be prompted for the +resource type and number (the program will attempt to determine this from the name of the file). +

+In version 3 games, resources added or saved to the game are not compressed.

+Back to contents

+ diff --git a/help/addn.html b/help/addn.html new file mode 100644 index 0000000..75d46c2 --- /dev/null +++ b/help/addn.html @@ -0,0 +1,20 @@ + + +addn + +

addn

+Category

+Mathematical commands

+

+Syntax

+

+addn(vA,B);

+vA += B;

+vA = vA + B;

+Description

+

+B is added to vA. Since a var can only be from 0-255, if the result is greater than 255, then the value wraps around, e.g. 250 + 10 would give 4.

+

+See also

+addv

+ diff --git a/help/addv.html b/help/addv.html new file mode 100644 index 0000000..4846731 --- /dev/null +++ b/help/addv.html @@ -0,0 +1,19 @@ + + +addv + +

addv

+Category

+Mathematical commands

+

+Syntax

+

+addv(vA,vB);

+vA += vB;

+vA = vA + vB;

+Description

+

+vB is added to vA. Since a var can only be from 0-255, if the result is greater than 255, then the value wraps around, e.g. 250 + 10 would give 4.

+See also

+addn

+ diff --git a/help/agi-pic-template.pdf b/help/agi-pic-template.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4af6112e57e67a6a31a676eef7125530f6687d14 GIT binary patch literal 5273 zcmeHLdr%Wc7%wVc?$XPFL2E0v zwra-*t%DtZ3nBCv9(%Xh4Il5`w&}gwRW^topv`52w-RI^pF0N&E)p- zy>|E8FZ=uUi_xd)5=of?i)p*Lax`qzZ^TO55@L4bj`{N;6?JCJ ziB+M&L!7a9%}0+6=o-?zU-Qc4%hy&sUwe9N+w80D!(OI0rLEVd=r?p$TXfn3$yr&m z$7WF5@>fP}pTFyu1^2gh+_pwG{*i{Cym0qo)ZX*I>DHQNC0^pCwWfNe#nwpw*eXAH zy(nIDE?lu@b<4S*m2C|q|3N#q;>8+aHhhM^`Cw|(TUX{r?%B{aZD~__^Ttvxzv8ti zgWG1jajs=jOQ~Z^USKHspeT!*(6O;T;_QOJ&O^t_ObgYqm9*`k<4e`C`o+Yq`*!op zBllAFb=6fzG&DU9*mv<}D$AQao`7%2d&p;~ms2XtL!x>dTTo+XalO&P;yJ9DGo}bm zP)tBJMN=S2DKEirMv$PJ0Rg2%mY0A6?ExgS4xvgku@1O9dQmVLSg9C?`v>q$8#I^d z=`*2)RH0H34R)i61*F`qJ>4m#8(eltkG-P2vI^ED0aEFbfEx<+cnOZ^04NX`43a$a zM=I{X061CzaIL@r@EM%h0g5rSJ_aiR&_WfQG3ld9cB^_cQ;m|bQm}YUxM$Nd6q=2D zD3?6mJ#jqOXk&3ki5D<s(E%r6_{Xx*FBpbUKPcU&7VU8%1fg?q5h6aWSNiUfjKx`Sd;Z^rBCe z^cx@uzYqLAK>rSZ9Qb|kALGD%l50vlh?mp@Lx!p{34yi?W_y7vf*FX+g`63tN(v>0 zXRw^bDgn8Y!0;4Ka_CtxRj}Cw9^rTr=1HV{^C)kkC8re{O?O6h>ziAli-?dweaEyP zzI(i(uwvp3)yRGCE!=efxwY#X4WCWuBeG$1Q>+tu-EA~%c8gjIC_=#tZhTjQ$ec6OA?fb(R6VS%+h zpcV^}q~N+G&ai7(!S9m_zkW44dM{qGb!6L_V@nr>YNa51;CgIyEuL^_9X(*LGB|V4 zC-uXP*^dqvMWt0^J9o~db&nEG9aP6*bR9}fdgooFH`VxO)bBx3EkSjEbUKLYE|wPd z6aj(V_0;LSRK!PA%*{j$lpP>(#6T=}{PYa)dN(V zJ{m^^)wf1=3@p4VTV5OAJb2#K;D*}R+p`wYKW*ExBKfHwkBYAkR0brReFAo(GJ$8| z3`t_{CE^T?xpJJIo3*QY;1yJ2uG)bQ*XQ=mkOb!PCxbId7|N%Z9zmbsU@gO3Wn#s+ z^xT;s-6}XFhe_n@5>U$sRXohMV3kP{#JD^=%jcDs!%MtO5G{a|5i&V|d~KCvh3pEW z$O~R^PTsi^*P3Ka~( zK5_&JD=d9z3T3}>+U=4}_u&5=#x)2HiSf}F41>mkr!H953Mp1HkTA4&sSWL|HJRSBoWBC)A literal 0 HcmV?d00001 diff --git a/help/agi-pic-template.sxd b/help/agi-pic-template.sxd new file mode 100644 index 0000000000000000000000000000000000000000..e817d46ff0543bf1f5f4d3a48a12ccda1f424979 GIT binary patch literal 9509 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 Us>b(`DKdZy7WyI-)qU-M0J+I{qyPW_ literal 0 HcmV?d00001 diff --git a/help/allow_menu.html b/help/allow_menu.html new file mode 100644 index 0000000..d09eb2e --- /dev/null +++ b/help/allow_menu.html @@ -0,0 +1,17 @@ + + +allow.menu + +

allow.menu

+Category

+Extra commands

+Syntax

+

+allow.menu(A);

+Description

+

+This command determines whether the menu is activated or not.

+If A = 0 then the menu is turned off.
+If A = 1 then the menu is turned on.

+See also

+ diff --git a/help/animate_obj.html b/help/animate_obj.html new file mode 100644 index 0000000..0cbaab8 --- /dev/null +++ b/help/animate_obj.html @@ -0,0 +1,17 @@ + + +animate.obj + +

animate.obj

+Category

+Object/view commands

+Syntax

+

+animate.obj(oA);

+Description

+

+This tells the interpreter to activate oA. You must do this before doing anything with the object.

+See also

+unanimate.all

+Initializing objects

+ diff --git a/help/assignn.html b/help/assignn.html new file mode 100644 index 0000000..7b9d81d --- /dev/null +++ b/help/assignn.html @@ -0,0 +1,18 @@ + + +assignn + +

assignn

+Category

+Mathematical commands

+

+Syntax

+

+assignn(vA,B);

+vA = B;

+Description

+

+The value of vA is set to B.

+See also

+assignv

+ diff --git a/help/assignv.html b/help/assignv.html new file mode 100644 index 0000000..38ace76 --- /dev/null +++ b/help/assignv.html @@ -0,0 +1,18 @@ + + +assignv + +

assignv

+Category

+Mathematical commands

+

+Syntax

+

+assignv(vA,vB);

+vA = vB;

+Description

+

+The value of vA is set to the value of vB.

+See also

+assignn

+ diff --git a/help/block.html b/help/block.html new file mode 100644 index 0000000..d16e6eb --- /dev/null +++ b/help/block.html @@ -0,0 +1,22 @@ + + +block + +

block

+Category

+Object/view commands

+Syntax

+

+block(X1,Y1,X2,Y2);

+Description

+

+This sets up an invisible rectangular block on the screen with top-left co-ordinates X1,Y1 and bottom-right co-ordinates X2,Y2. Objects are not allowed to cross the borders of this block (unless they +are told to ignore blocks). The block can be removed using the unblock command. +

+Note: You can only have one block on the screen at a time. If a block already exists, and you use the block command again, the new block will be there but the old one will be gone.

+See also

+unblock

+ignore.blocks

+observe.blocks

+Controlling obstacles

+ diff --git a/help/call.html b/help/call.html new file mode 100644 index 0000000..ec16bc0 --- /dev/null +++ b/help/call.html @@ -0,0 +1,17 @@ + + +call + +

call

+Category

+Control flow commands

+Syntax

+

+call(A);

+Description

+

+Logic A is executed once. If it is not already loaded into memory, it is loaded before being called and then unloaded again afterwards.

+See also

+call.v

+load.logics

+ diff --git a/help/call_v.html b/help/call_v.html new file mode 100644 index 0000000..5d5f870 --- /dev/null +++ b/help/call_v.html @@ -0,0 +1,17 @@ + + +call.v + +

call.v

+Category

+Control flow commands

+Syntax

+

+call.v(vA);

+Description

+

+Logic vA is executed once. If it is not already loaded into memory, it is loaded before being called and then unloaded again afterwards.

+See also

+call

+load.logics

+ diff --git a/help/cancel_line.html b/help/cancel_line.html new file mode 100644 index 0000000..3a1fefa --- /dev/null +++ b/help/cancel_line.html @@ -0,0 +1,15 @@ + + +cancel.line + +

cancel.line

+Category

+System commands

+Syntax

+

+cancel.line();

+Description

+

+Clears any text that is on the input line.

+See also

+ diff --git a/help/center_posn.html b/help/center_posn.html new file mode 100644 index 0000000..14c0c09 --- /dev/null +++ b/help/center_posn.html @@ -0,0 +1,19 @@ + + +center.posn + +

center.posn

+Category

+Test commands / Object/view commands

+

+Syntax

+

+if (center.posn(oA,X1,Y1,X2,Y2)) { .....

+Description

+

+Returns true if the co-ordinates of the bottom-middle pixel of object oA are within the region (X1,Y1,X2,Y2).

+See also

+posn

+right.posn

+obj.in.box

+ diff --git a/help/clear_lines.html b/help/clear_lines.html new file mode 100644 index 0000000..9eeeddf --- /dev/null +++ b/help/clear_lines.html @@ -0,0 +1,16 @@ + + +clear.lines + +

clear.lines

+Category

+Display commands

+Syntax

+

+clear.lines(TOP,BOTTOM,COLOUR);

+Description

+

+Clears the lines from TOP to BOTTOM with the colour COLOUR. I have found that it will only use black (if COLOUR is 0) or white (if COLOUR is greater than 0).

+See also

+clear.text.rect

+ diff --git a/help/clear_text_rect.html b/help/clear_text_rect.html new file mode 100644 index 0000000..9d57039 --- /dev/null +++ b/help/clear_text_rect.html @@ -0,0 +1,18 @@ + + +clear.text.rect + +

clear.text.rect

+Category

+Display commands

+Syntax

+

+clear.text.rect(Y1,X1,Y2,X2,COLOUR);

+Description

+

+Clears the text rectangle with a top-left corner of X1,Y1 and a bottom-right corner of X2,Y2 with the colour COLOUR. I have found that it will only use black (if COLOUR is 0) or white (if COLOUR is +greater than 0). +

+See also

+clear.lines

+ diff --git a/help/close_dialogue.html b/help/close_dialogue.html new file mode 100644 index 0000000..64e5465 --- /dev/null +++ b/help/close_dialogue.html @@ -0,0 +1,18 @@ + + +close.dialogue + +

close.dialogue

+Category

+Display commands

+Syntax

+

+close.dialogue();

+Description

+

+This command supposedly disables the get.string and get.num commands when the prevent.input command has been used, but it does not seem to do this so I am +not sure what the command actually does. +

+See also

+open.dialogue

+ diff --git a/help/close_window.html b/help/close_window.html new file mode 100644 index 0000000..89fa9ff --- /dev/null +++ b/help/close_window.html @@ -0,0 +1,19 @@ + + +close.window + +

close.window

+Category

+Display commands

+Syntax

+

+close.window();

+Description

+

+If a window is left on the screen from a print command, it is removed.

+See also

+print

+print.v

+print.at

+print.at.v

+ diff --git a/help/commands_by_category.html b/help/commands_by_category.html new file mode 100644 index 0000000..97ee710 --- /dev/null +++ b/help/commands_by_category.html @@ -0,0 +1,20 @@ + + +Commands by category + +

Commands by category

+Test commands

+Mathematical commands

+Flag commads

+Control flow commands

+Picture commands

+Debugging commands

+Object/view commands

+Inventory item commands

+Sound commands

+Display commands

+Menu/Key commands

+System commands

+String commands

+Extra commands

+ diff --git a/help/commands_by_name.html b/help/commands_by_name.html new file mode 100644 index 0000000..b89a788 --- /dev/null +++ b/help/commands_by_name.html @@ -0,0 +1,213 @@ + + +Commands by name + + +

Commands by name

+ +Test commands

+ +equaln

+equalv

+lessn

+lessv

+greatern

+greaterv

+isset

+issetv

+has

+obj.in.room

+posn

+controller

+have.key

+said

+compare.strings

+obj.in.box

+center.posn

+right.posn

+ +Action commands

+ +accept.input

+add.to.pic.v

+add.to.pic

+addn

+addv

+allow.menu

+animate.obj

+assignn

+assignv

+block

+call.v

+call

+cancel.line

+clear.lines

+clear.text.rect

+close.dialogue

+close.window

+configure.screen

+current.cel

+current.loop

+current.view

+cycle.time

+decrement

+disable.item

+discard.pic

+discard.sound

+discard.view.v

+discard.view

+display.v

+display

+distance

+div.n

+div.v

+draw.pic

+draw

+drop

+echo.line

+enable.item

+end.of.loop

+erase

+fence.mouse

+fix.loop

+follow.ego

+force.update

+get.dir

+get.num

+get.posn

+get.priority

+get.room.v

+get.string

+get.v

+get

+graphics

+hide.mouse

+hold.key

+ignore.blocks

+ignore.horizon

+ignore.objs

+increment

+init.disk

+init.joy

+last.cel

+lindirectn

+lindirectv

+load.logics.v

+load.logics

+load.pic

+load.sound

+load.view.v

+load.view

+log

+menu.input

+mouse.posn

+move.obj.v

+move.obj

+mul.n

+mul.v

+new.room.v

+new.room

+normal.cycle

+normal.motion

+number.of.loops

+obj.status.v

+object.on.anything

+object.on.land

+object.on.water

+observe.blocks

+observe.horizon

+observe.objs

+open.dialogue

+overlay.pic

+parse

+pause

+player.control

+pop.scrip

+position.v

+position

+prevent.input

+print.at.v

+print.at

+print.v

+print

+program.control

+push.script

+put.v

+put

+quit

+random

+release.key

+release.loop

+release.priority

+reposition.to.v

+reposition.to

+reposition

+reset.scan.start

+reset.v

+reset

+restart.game

+restore.game

+return

+reverse.cycle

+reverse.loop

+rindirect

+save.game

+script.size

+set.cel.v

+set.cel

+set.cursor.char

+set.dir

+set.game.id

+set.horizon

+set.key

+set.loop.v

+set.loop

+set.menu.item

+set.menu

+set.pri.base

+set.priority.v

+set.priority

+set.scan.start

+set.simple

+set.string

+set.text.attribute

+set.upper.left

+set.view.v

+set.view

+set.v

+set

+shake.screen

+show.mem

+show.mouse

+show.obj.v

+show.obj

+show.pic

+show.pri.screen

+sound

+start.cycling

+start.motion

+start.update

+status.line.off

+status.line.on

+status

+step.size

+step.time

+stop.cycling

+stop.motion

+stop.sound

+stop.update

+submit.menu

+subn

+subv

+text.screen

+toggle.monitor

+toggle.v

+toggle

+trace.info

+trace.on

+unanimate.all

+unblock

+version

+wander

+word.to.string

+ diff --git a/help/compare_strings.html b/help/compare_strings.html new file mode 100644 index 0000000..182c2e5 --- /dev/null +++ b/help/compare_strings.html @@ -0,0 +1,16 @@ + + +compare.strings + +

compare.strings

+Category

+Test commands / String commands

+

+Syntax

+

+if (compare.strings(s1,s2)) { .....

+Description

+

+Compares strings s1 and s2 and returns true if they are the same. The comparison is not case-sensitive, and some characters such as space and exclamation marks are ignored.

+See also

+ diff --git a/help/configure_screen.html b/help/configure_screen.html new file mode 100644 index 0000000..84e8121 --- /dev/null +++ b/help/configure_screen.html @@ -0,0 +1,23 @@ + + +configure.screen + +

configure.screen

+Category

+Display commands

+Syntax

+

+configure.screen(PLAYTOP,INPUTLINE,STATUSLINE);

+Description

+

+Sets the location of certain items on screen:

+PLAYTOP is the top line of the playing area. This is normally set to 1. It should always be set to something between 0 and 3, since the playing area is 168 pixels high (21 lines) and should not go +off the screen. +

+INPUTLINE is the line on which the player is prompted for input. This is normally set to 22.

+STATUSLINE is the line on which the current score and sound on/off status are displayed. This is normally set to 0.

+Note that the menu always appears on line 0.

+See also

+status.line.on

+status.line.off

+ diff --git a/help/control_commands.html b/help/control_commands.html new file mode 100644 index 0000000..e847904 --- /dev/null +++ b/help/control_commands.html @@ -0,0 +1,15 @@ + + +Control flow commands + +

Control flow commands

+call.v

+call

+load.logics.v

+load.logics

+new.room.v

+new.room

+reset.scan.start

+return

+set.scan.start

+ diff --git a/help/controller.html b/help/controller.html new file mode 100644 index 0000000..f77b65e --- /dev/null +++ b/help/controller.html @@ -0,0 +1,17 @@ + + +controller + +

controller

+Category

+Test commands / Menu/Key commands

+

+Syntax

+

+if (controller(cA)) { .....

+Description

+

+Returns true if the menu item or key assigned to controller cA has been selected or pressed during the current cycle.

+See also

+Setting up menus and keys

+ diff --git a/help/controlling_obstacles.html b/help/controlling_obstacles.html new file mode 100644 index 0000000..15eec80 --- /dev/null +++ b/help/controlling_obstacles.html @@ -0,0 +1,63 @@ + + +Controlling obstacles + +

Controlling obstacles

+There are five main ways an object's movement around the screen can be limited:

+

    +
  • Control lines on the priority screen +
  • Blocks +
  • Land/water +
  • The horizon +
  • Other objects +
+

+For any of these, no part of the object's baseline (the bottom row of pixels of the object) can be on a part of the screen the object is not allowed on.

+Control lines on the priority screen

+

+On the priority screen, the first four colours (0-3) have special meaning. Colour 0 (black) is an unconditional barrier. No object is ever allowed to be on parts of the screen with a pixel of this +colour in the priority screen. +

+Colour 1 (dark blue) is a conditional barrier. Objects are not normally allowed to be on a conditional barrier, unless the ignore.blocks command is used to allow them to do so.

+Colour 2 (dark green) is a signal barrier. This can be used to test if ego is walking into a certain place. Whenever ego is touching a signal barrier, flag 3 is set.

+Colour 3(dark cyan) signifies water. This is explained shortly.

+Blocks

+

+You can set up an invisible rectangular block on the screen using the block command. The interpreter will not allow objects to cross the borders of the block (unless they are told to ignore +blocks). You can remove the block using the unblock command. Objects can be told to ignore blocks using the ignore.blocks command and be told to observe blocks by using +the objserve.blocks command. +

+Land/water

+

+Parts of the priority screen which are colour 3 (dark cyan) are considered to be "water". If you look at the priority screen of rooms that have lakes or rivers in them, you will usually see this. Parts +of the priority screen which are not colour 3 are considered to be "land". You do not have to use colour 3 to represent water - it could also represent some other surface such as ice, lava, sand, a +slippery floor, or whatever you need for that particular room. +

+Objects can be allowed only on water, only on land or on both. This is set be the object.on.water, object.on.land and object.on.anything +commands. +

+Whenever ego's baseline is completely on water, flag 0 is set.

+The horizon

+

+The horizon is an invisible horizontal line, usually near the top of the screen. Its position is set using the set.horizon command.

+Normally, objects can not go above the horizon. This can be changed using the ignore.horizon and observe.horizon commands.

+Other objects

+

+Objects are normally blocked by other objects on screen - that is, the baselines of objects are not allowed to touch each other. This can be changed, however, with the ignore.objs and +observe.objs commands. +

+See also

+block

+unblock

+ignore.blocks

+objserve.blocks

+object.on.water

+object.on.land

+object.on.anything

+set.horizon

+ignore.horizon

+observe.horizon

+ignore.objs

+observe.objs

+Objects

+ diff --git a/help/creating_new_games.html b/help/creating_new_games.html new file mode 100644 index 0000000..52cfed9 --- /dev/null +++ b/help/creating_new_games.html @@ -0,0 +1,23 @@ + + +Creating new games + +

Creating new games

+To create a new game, select "New" from the game menu. You can choose whether you want to create a completely "empty" game, or a game based on the template. Once you have done this, select the directory +you want the game to be in (if this directory already contains an AGI game, the program will ask if you want to erase it). +

+The template game is a game with only one room, and all the menus, keys etc. already set up for you, along with names for most variables used and comments here and there. It is recommended you choose +this option, as you can jump straight in and start programming your first room from here. For more information on the template game, see the readme.txt file in the template directory. +

+When you create a game, only the data files (and source code, if based on the template game) are placed in the directory you chose. +There is no interpreter there. To run the game, you will need to install an AGI interpreter and specify the interpreter command line in the "Settings" menu. You don't have to install it in the same directory with your game - enough that it will be accessible by PATH, or just specify the full path in the "Settings". The interpreter must be version 2.915 or higher (but not version 3). You can usually find out the version number of an interpreter when +you enter debug mode in a game. +

+See the files used by AGI section to see what files you need to copy into the game directory. If you copy the files into the template directory, then whenever you create a new game from +the template these will be copied also. +

+Note: If you are using a newly written AGI interpreter, then the version number will probably be different but new interpreters should +support this format. The files you have to copy over will also be different. +

+Back to contents

+ diff --git a/help/current_cel.html b/help/current_cel.html new file mode 100644 index 0000000..0cb9aa7 --- /dev/null +++ b/help/current_cel.html @@ -0,0 +1,19 @@ + + +current.cel + +

current.cel

+Category

+Object/view commands

+Syntax

+

+current.cel(oA,vB);

+Description

+

+vB is set to the number of the current cel of object oA.

+See also

+last.cel

+set.cel

+set.cel.v

+current.loop

+ diff --git a/help/current_loop.html b/help/current_loop.html new file mode 100644 index 0000000..979ad9a --- /dev/null +++ b/help/current_loop.html @@ -0,0 +1,19 @@ + + +current.loop + +

current.loop

+Category

+Object/view commands

+Syntax

+

+current.loop(oA,vB);

+Description

+

+vB is set to the number of the current loop of object oA.

+See also

+number.of.loops

+set.loop

+set.loop.v

+current.cel

+ diff --git a/help/current_view.html b/help/current_view.html new file mode 100644 index 0000000..b2bcd75 --- /dev/null +++ b/help/current_view.html @@ -0,0 +1,17 @@ + + +current.view + +

current.view

+Category

+Object/view commands

+Syntax

+

+current.view(oA,vB);

+Description

+

+vB is set to the number of the view currently assigned to object oA.

+See also

+set.view

+set.view.v

+ diff --git a/help/cycle_time.html b/help/cycle_time.html new file mode 100644 index 0000000..b7d861e --- /dev/null +++ b/help/cycle_time.html @@ -0,0 +1,19 @@ + + +cycle.time + +

cycle.time

+Category

+Object/view commands

+Syntax

+

+cycle.time(oA,vB);

+Description

+

+The delay (in interpreter cycles) between cel changes of object oA (when it is cycling) is set to vB. If vB is equal to 0, the cels do not change (even when the object is cycling). Note that an +object's cycle time is separate to it's step time. +

+See also

+step.time

+Cycling objects

+ diff --git a/help/cycling_objects.html b/help/cycling_objects.html new file mode 100644 index 0000000..ed4f01a --- /dev/null +++ b/help/cycling_objects.html @@ -0,0 +1,59 @@ + + +Cycling objects + +

Cycling objects

+The animation of an object is called "cycling". This is the successive display of several cels from the same loop in order. When you initialize an object, it cycles the cels in the first loop (loop 0) +by default. To change the loop number, use the set.loop command. To change the speed of cycling, use the cycle.time command. If you want to display a single cel without +animation, set the loop number and cel number you want to display using the set.loop and set.cel commands and then use the stop.cycling command (you can start +cycling again by using the start.cycling command). +

+Here is an example of initializing an object that displays cel 2 of loop 1 without animating:

+

+animate.obj(o2);
+load.view(4);
+set.view(o2,4);
+position(o2,80,120);
+set.loop(o2,1);
+set.cel(o2,2);
+draw(o2);
+stop.cycling(o2);
+
+

+The objects aren't updated on screen until the start of the next cycle (or until the force.update command is issued), so whatever changes you make to an object's position or appearance +do not take affect till then. +

+Normally when an object is moving around, it's loop number is determined by it's direction:

+

+Direction       Loop no
+---------------------------
+0 (not moving)  not changed
+1 (up)          3 (if loop 2 and 3 exist) otherwise not changed
+2 (up-right)    0
+3 (right)       0
+4 (down-right)  0
+5 (down)        2 (if loop 2 and 3 exist) otherwise not changed
+6 (down-left)   1 (if loop 1 exists) otherwise 0
+7 (left)        1 (if loop 1 exists) otherwise 0
+8 (up-left)     1 (if loop 1 exists) otherwise 0
+
+

+The direction is only chosen automatically if there are less than 5 loops in the view assigned to the object.

+To stop the interpreter from chosing a loop number based on the object's direction, use the fix.loop command. To let it chose the loop number, use the release.loop command.

+To play the animation in reverse, use the reverse.cycle command. To play it forwards again, use the normal.cycle command.

+To play the animation once and then stop cycling, use the end.of.loop or reverse.loop commands.

+See also

+set.loop

+set.loop.v

+set.cel

+set.cel.v

+cycle.time

+start.cycling

+stop.cycling

+force.update

+normal.cycle

+reverse.cycle

+end.of.loop

+reverse.loop

+Objects

+ diff --git a/help/data_used.html b/help/data_used.html new file mode 100644 index 0000000..948343b --- /dev/null +++ b/help/data_used.html @@ -0,0 +1,16 @@ + + +Data used by AGI + +

Data used by AGI

+Most data used by AGI is stored in resources. There are four types of resources, each storing a different type of data. Each AGI game can contain up to 256 resources of each type.

+VIEW resources - animations and sprites

+PICTURE resources - background pictures

+SOUND resources - sound effects and music

+LOGIC resources - scripts that determine what happens in the game

+Other data:

+The OBJECT file - list of inventory objects the player can get

+The WORDS.TOK file - list of words accepted by the game

+Files used by AGI

+Back to contents

+ diff --git a/help/debug_commands.html b/help/debug_commands.html new file mode 100644 index 0000000..a765ac4 --- /dev/null +++ b/help/debug_commands.html @@ -0,0 +1,13 @@ + + +Debugging commands + +

Debugging commands

+log

+obj.status.v

+show.mem

+show.pri.screen

+trace.info

+trace.on

+version

+ diff --git a/help/decrement.html b/help/decrement.html new file mode 100644 index 0000000..cdd8f8b --- /dev/null +++ b/help/decrement.html @@ -0,0 +1,18 @@ + + +decrement + +

decrement

+Category

+Mathematical commands

+

+Syntax

+

+decrement(vA);

+vA--;

+Description

+

+If the value of vA is greater than 0, then it is decreased by 1.

+See also

+increment

+ diff --git a/help/deleting_resources.html b/help/deleting_resources.html new file mode 100644 index 0000000..8dcc616 --- /dev/null +++ b/help/deleting_resources.html @@ -0,0 +1,10 @@ + + +Deleting resources + +

Deleting resources

+To delete a resource, click on the resource you wish to delete and select 'Delete' from the 'Resource' menu. Note: Once you have deleted a resource, it is permanently deleted. There is no +"undelete" feature. +

+Back to contents

+ diff --git a/help/disable_item.html b/help/disable_item.html new file mode 100644 index 0000000..efcdc81 --- /dev/null +++ b/help/disable_item.html @@ -0,0 +1,19 @@ + + +disable.item + +

disable.item

+Category

+Menu/Key commands

+Syntax

+

+disable.item(cA);

+Description

+

+Disables the menu item that is assigned to controller cA.

+All menu items are enabled again when the game is restarted, so if there are any items that need to be disabled permanently (such as separators) then they should be disabled again when the game is +restarted. +

+See also

+enable.item

+ diff --git a/help/discard_pic.html b/help/discard_pic.html new file mode 100644 index 0000000..1db50e8 --- /dev/null +++ b/help/discard_pic.html @@ -0,0 +1,17 @@ + + +discard.pic + +

discard.pic

+Category

+Picture commands

+Syntax

+

+discard.pic(vA);

+Description

+

+Picture resource vA is discarded from memory. If the picture is not already loaded, the interpreter generates an error.

+See also

+load.pic

+Drawing pictures

+ diff --git a/help/discard_sound.html b/help/discard_sound.html new file mode 100644 index 0000000..74b5efc --- /dev/null +++ b/help/discard_sound.html @@ -0,0 +1,16 @@ + + +discard.sound + +

discard.sound

+Category

+Extra commands

+Syntax

+

+discard.sound(A);

+Description

+

+This command discards sound A. +Does not work on Sierra's PC version of the interpreter.

+See also

+ diff --git a/help/discard_view.html b/help/discard_view.html new file mode 100644 index 0000000..dd0e721 --- /dev/null +++ b/help/discard_view.html @@ -0,0 +1,18 @@ + + +discard.view + +

discard.view

+Category

+Object/view commands

+Syntax

+

+discard.view(VIEWNUM);

+Description

+

+View VIEWNUM is discarded from memory. If the view is not already loaded, the interpreter generates an error. Make sure you do not have the view assigned to any objects before you discard it.

+See also

+discard.view.v

+load.view

+load.view.v

+ diff --git a/help/discard_view_v.html b/help/discard_view_v.html new file mode 100644 index 0000000..5651cc4 --- /dev/null +++ b/help/discard_view_v.html @@ -0,0 +1,18 @@ + + +discard.view.v + +

discard.view.v

+Category

+Object/view commands

+Syntax

+

+discard.view.v(vVIEWNUM);

+Description

+

+View vVIEWNUM is discarded from memory. If the view is not already loaded, the interpreter generates an error. Make sure you do not have the view assigned to any objects before you discard it.

+See also

+discard.view

+load.view

+load.view.v

+ diff --git a/help/display.html b/help/display.html new file mode 100644 index 0000000..fb51e5c --- /dev/null +++ b/help/display.html @@ -0,0 +1,17 @@ + + +display + +

display

+Category

+Display commands

+Syntax

+

+display(ROW,COLUMN,mMESSAGE);

+Description

+

+Displays the text of message mMESSAGE at the specified row and column.

+See also

+display.v

+set.text.attribute

+ diff --git a/help/display_commands.html b/help/display_commands.html new file mode 100644 index 0000000..66a6e49 --- /dev/null +++ b/help/display_commands.html @@ -0,0 +1,26 @@ + + +Display commands + +

Display commands

+For more information on displaying text, click here.

+clear.lines

+clear.text.rect

+close.dialogue

+close.window

+configure.screen

+display.v

+display

+graphics

+open.dialogue

+print.at.v

+print.at

+print.v

+print

+set.cursor.char

+set.text.attribute

+shake.screen

+status.line.off

+status.line.on

+text.screen

+ diff --git a/help/display_v.html b/help/display_v.html new file mode 100644 index 0000000..85d0366 --- /dev/null +++ b/help/display_v.html @@ -0,0 +1,17 @@ + + +display.v + +

display.v

+Category

+Display commands

+Syntax

+

+display(vROW,vCOLUMN,vMESSAGE);

+Description

+

+Displays the text of message number vMESSAGE at the location determined by the values of vROW and vCOLUMN.

+See also

+display

+set.text.attribute

+ diff --git a/help/displaying_text.html b/help/displaying_text.html new file mode 100644 index 0000000..8a9aa21 --- /dev/null +++ b/help/displaying_text.html @@ -0,0 +1,13 @@ + + +Displaying text on screen + +

Displaying text on screen

+For text display purposes, the AGI screen consists of 25 lines (numbered 0-24) and 40 columns (numbered 0-39). Each text character is 8 screen pixels (4 AGI pixels) wide and 8 screen pixels high. +Note that this gives a total screen resolution of 320x200, even though the area that pictures are displayed in and objects are placed is only 168 pixels high. The top line of the screen is normally +reserved for the status line and menu, and the bottom three lines are normally reserved for player input and other text display (in some early versions of the interpreter, text from commands like +print was displayed down here instead of in windows). +

+See also

+Display commands

+ diff --git a/help/distance.html b/help/distance.html new file mode 100644 index 0000000..186166b --- /dev/null +++ b/help/distance.html @@ -0,0 +1,18 @@ + + +distance + +

distance

+Category

+Object/view commands

+Syntax

+

+distance(oA,oB,vD);

+Description

+

+vD is set to the distance between objects oA and oB. The formula used for calculating the distance is abs(x1-x2) + abs(y1-y2) where x1,y1 and x2,y2 are the co-ordinates of the center of the baselines +of oA and oB. +

+If one or more of the objects is not on screen, the distance is 255.

+See also

+ diff --git a/help/div_n.html b/help/div_n.html new file mode 100644 index 0000000..107cedf --- /dev/null +++ b/help/div_n.html @@ -0,0 +1,18 @@ + + +div.n + +

div.n

+Category

+Mathematical commands

+Syntax

+

+div.n(vA,B);

+vA /= B;

+vA = vA / B;

+Description

+

+vA is divided by B. The result is rounded down. If you divide by 0, the interpreter will crash.

+See also

+div.v

+ diff --git a/help/div_v.html b/help/div_v.html new file mode 100644 index 0000000..b5ee8c5 --- /dev/null +++ b/help/div_v.html @@ -0,0 +1,18 @@ + + +div.v + +

div.v

+Category

+Mathematical commands

+Syntax

+

+div.n(vA,vB);

+vA /= vB;

+vA = vA / vB;

+Description

+

+vA is divided by vB. The result is rounded down. If you divide by 0, the interpreter will crash.

+See also

+div.n

+ diff --git a/help/draw.html b/help/draw.html new file mode 100644 index 0000000..4d66e0c --- /dev/null +++ b/help/draw.html @@ -0,0 +1,16 @@ + + +draw + +

draw

+Category

+Object/view commands

+Syntax

+

+draw(oA);

+Description

+

+Object oA is drawn on screen.

+See also

+erase

+ diff --git a/help/draw_pic.html b/help/draw_pic.html new file mode 100644 index 0000000..10dd4f4 --- /dev/null +++ b/help/draw_pic.html @@ -0,0 +1,20 @@ + + +draw.pic + +

draw.pic

+Category

+Picture commands

+Syntax

+

+draw.pic(vA);

+Description

+

+Picture vA is drawn. Only the visual and priority screens in memory updated - not the actual screen itself. To update the screen, use the show.pic command. Make sure the picture is loaded +into memory before drawing it. +

+See also

+overlay.pic

+load.pic

+Drawing pictures

+ diff --git a/help/drawing_pictures.html b/help/drawing_pictures.html new file mode 100644 index 0000000..9f9dcf2 --- /dev/null +++ b/help/drawing_pictures.html @@ -0,0 +1,35 @@ + + +Drawing pictures + +

Drawing pictures

+In order to draw a picture on the screen, you should use the following commands in the correct order:

+

+load.pic(vA);
+draw.pic(vA);
+discard.pic(vA);
+..
+show.pic();
+

+The interpreter stores two different screens in memory - the visual screen and the priority screen. When you use the first three commands above, you are updating both of these screens in memory. +However, you are not updating what is displayed on the actual screen that the player sees. This is only done when the show.pic command is used. You should do this directly after the first three +commands, unless you need to also set up some screen objects in between. +

+The reason the first parameter of load.pic, draw.pic and discard.pic is a variable is because most times these commands are used, the parameter given is v0 (the current room number). Most rooms you +see will have the following at the start: +

+

+load.pic(v0);
+draw.pic(v0);
+discard.pic(v0);
+
+

+If you want to load a picture other than the current room number, you will need to set the value of a variable to that number and then give the variable as the parameter.

+See also

+

+load.pic

+draw.pic

+overlay.pic

+discard.pic

+show.pic

+ diff --git a/help/drop.html b/help/drop.html new file mode 100644 index 0000000..b69a513 --- /dev/null +++ b/help/drop.html @@ -0,0 +1,15 @@ + + +drop + +

drop

+Category

+Inventory item commands

+Syntax

+

+drop(iITEM);

+Description

+

+The room number of inventory item iITEM is set to 0.

+See also

+ diff --git a/help/echo_line.html b/help/echo_line.html new file mode 100644 index 0000000..888d6f3 --- /dev/null +++ b/help/echo_line.html @@ -0,0 +1,17 @@ + + +echo.line + +

echo.line

+Category

+System commands

+Syntax

+

+echo.line();

+Description

+

+The previous line of input entered by the player is added to the input line (if there is already text on the input line, only the characters from the previous line after the number of characters +currently on the line are added). +

+See also

+ diff --git a/help/enable_item.html b/help/enable_item.html new file mode 100644 index 0000000..c1b56de --- /dev/null +++ b/help/enable_item.html @@ -0,0 +1,17 @@ + + +enable.item + +

enable.item

+Category

+Menu/Key commands

+Syntax

+

+enable.item(cA);

+Description

+

+Enables the menu item that is assigned to controller cA.

+All menu items are enabled again whenever the game is restarted.

+See also

+disable.item

+ diff --git a/help/end_of_loop.html b/help/end_of_loop.html new file mode 100644 index 0000000..b450f66 --- /dev/null +++ b/help/end_of_loop.html @@ -0,0 +1,17 @@ + + +end.of.loop + +

end.of.loop

+Category

+Object/view commands

+Syntax

+

+end.of.loop(oA,fB);

+Description

+

+Object oA is cycled in normal order until the last cel in the loop is reached. Flag fB is reset when the command is issued, and when the last cel is displayed fB is set.

+See also

+reverse.loop

+Cycling objects

+ diff --git a/help/equaln.html b/help/equaln.html new file mode 100644 index 0000000..08496a2 --- /dev/null +++ b/help/equaln.html @@ -0,0 +1,15 @@ + + +equaln + +

equaln

+Category

+Test commands / Mathematical commands

+Syntax

+if (equaln(vA,B)) { .....

+if (vA == B) { .....

+Description

+Returns true if vA is equal to B.

+See also

+equalv

+ diff --git a/help/equalv.html b/help/equalv.html new file mode 100644 index 0000000..ce7fabb --- /dev/null +++ b/help/equalv.html @@ -0,0 +1,17 @@ + + +equalv + +

equalv

+Category

+Test commands / Mathematical commands

+

+Syntax

+

+if (equalv(vA,vB)) { .....

+if (vA == vB) { .....

+Description

+Returns true if vA is equal to vB.

+See also

+equaln

+ diff --git a/help/erase.html b/help/erase.html new file mode 100644 index 0000000..69eaf4e --- /dev/null +++ b/help/erase.html @@ -0,0 +1,16 @@ + + +erase + +

erase

+Category

+Object/view commands

+Syntax

+

+erase(oA);

+Description

+

+Object oA is erased from the screen.

+See also

+draw

+ diff --git a/help/extra_commands.html b/help/extra_commands.html new file mode 100644 index 0000000..6abfa00 --- /dev/null +++ b/help/extra_commands.html @@ -0,0 +1,22 @@ + + +Extra commands + +

Extra commands

+

These miscellaneous extra commands where +'unknown170'-'unknown181' in previous versions +of AGI Studio.

+ +set.simple

+push.script

+pop.scrip

+hold.key

+set.pri.base

+discard.sound

+hide.mouse

+allow.menu

+show.mouse

+fence.mouse

+mouse.posn

+release.key

+ diff --git a/help/extracting_resources.html b/help/extracting_resources.html new file mode 100644 index 0000000..1f89255 --- /dev/null +++ b/help/extracting_resources.html @@ -0,0 +1,11 @@ + + +Extracting resources + +

Extracting resources

+To extract a resource, click on the resource you wish to extract and select 'Extract' from the 'Resource' menu.

+When the resource is extracted, it is saved to disk in its raw format (i.e. not converted to another format such as BMP or midi), except for the LOGIC resource. You can choose in the 'Settings' menu if you want to extract the LOGIC resources as text (i.e. the same way as you see them in the Logic editor) or raw. (the default is text). The 5 byte or 7 byte resource header used in the VOL files is not +saved as this is not part of the resource. In version 3 games, the resource is uncompressed before saving to disk. +

+Back to contents

+ diff --git a/help/fence_mouse.html b/help/fence_mouse.html new file mode 100644 index 0000000..a15b3e6 --- /dev/null +++ b/help/fence_mouse.html @@ -0,0 +1,20 @@ + + +fence.mouse + +

fence.mouse

+Category

+Extra commands

+Syntax

+

+fence.mouse(A,B,C,D);

+Description

+

+This command sets up a fence out of which the mouse cursor can not go. +Does not work with Sierra's PC version of the interpreter

+

+See also

+hide.mouse

+show.mouse

+mouse.posn

+ diff --git a/help/files_used.html b/help/files_used.html new file mode 100644 index 0000000..cc02353 --- /dev/null +++ b/help/files_used.html @@ -0,0 +1,20 @@ + + +Files used by AGI + +

Files used by AGI

+These are the files that contain the actual data for the game.

+Vol files (VOL.*): These files contain the resources. They are stored one after the other in the file, with a small header at the start of each resource identifying its size.

+Directory files (LOGDIR, PICDIR, VIEWDIR, SNDDIR): These store the locations of each resource in the VOL files.

+OBJECT and WORDS.TOK: See data used by AGI section

+In version 3, the VOL files have the game ID in front of them (e.g. KQ4VOL.0) and all the directory files are combined into one file (e.g. KQ4DIR)

+If you want to know the format of these files, check out AGI Specs.

+These are the files used by Sierra's original DOS interpreter. Other interpreters will use different files.

+

    +
  • AGI: The interpreter itself +
  • AGIDATA.OVL: Data used by the interpreter +
  • Other .OVL files: Graphics drivers +
  • SIERRA.COM: The loader file. Sometimes named after the game (e.g. SQ.COM). This loads the AGI file into memory, decrypts it, and then runs it. +

+Back to data used by AGI

+ diff --git a/help/fix_loop.html b/help/fix_loop.html new file mode 100644 index 0000000..7484b57 --- /dev/null +++ b/help/fix_loop.html @@ -0,0 +1,17 @@ + + +fix.loop + +

fix.loop

+Category

+Object/view commands

+Syntax

+

+fix.loop(oA);

+Description

+

+This stops the interpreter from choosing the loop number for object oA based on its direction. You can turn this back on again using the release.loop command.

+See also

+release.loop

+Cycling objects

+ diff --git a/help/flag_commands.html b/help/flag_commands.html new file mode 100644 index 0000000..3eff849 --- /dev/null +++ b/help/flag_commands.html @@ -0,0 +1,15 @@ + + +Flag commads + +

Flag commads

+reset.v

+reset

+set.v

+set

+toggle.v

+toggle

+Test commands

+isset

+issetv

+ diff --git a/help/follow_ego.html b/help/follow_ego.html new file mode 100644 index 0000000..c3155fc --- /dev/null +++ b/help/follow_ego.html @@ -0,0 +1,19 @@ + + +follow.ego + +

follow.ego

+Category

+Object/view commands

+Syntax

+

+follow.ego(oA,STEPSIZE,fDONEFLAG);

+Description

+

+Object oA moves towards ego (object 0) by STEPSIZE pixels every step. When the object is within STEPSIZE pixels of ego, it stops moving and flag fDONEFLAG is set. If STEPSIZE is 0, the current step +size of object oA is used. +

+See also

+step.size

+Moving objects

+ diff --git a/help/force_update.html b/help/force_update.html new file mode 100644 index 0000000..53b28bc --- /dev/null +++ b/help/force_update.html @@ -0,0 +1,18 @@ + + +force.update + +

force.update

+Category

+Object/view commands

+Syntax

+

+force.update(oA);

+Description

+

+Object oA is redrawn immediately, without waiting till the start of the next interpreter cycle.

+See also

+start.update

+stop.update

+Cycling objects

+ diff --git a/help/get.html b/help/get.html new file mode 100644 index 0000000..e12d555 --- /dev/null +++ b/help/get.html @@ -0,0 +1,16 @@ + + +get + +

get

+Category

+Inventory item commands

+Syntax

+

+get(iITEM);

+Description

+

+The room number of inventory item iITEM is set to 255, placing the item in the player's inventory.

+See also

+get.v

+ diff --git a/help/get_dir.html b/help/get_dir.html new file mode 100644 index 0000000..d55309c --- /dev/null +++ b/help/get_dir.html @@ -0,0 +1,18 @@ + + +get.dir + +

get.dir

+Category

+Object/view commands

+Syntax

+

+get.dir(oA,vDIR);

+Description

+

+vDIR is set to the direction object oA is currently travelling in. The value will be between 0 and 8:

+

+See also

+set.dir

+Moving objects

+ diff --git a/help/get_num.html b/help/get_num.html new file mode 100644 index 0000000..be16f1d --- /dev/null +++ b/help/get_num.html @@ -0,0 +1,16 @@ + + +get.num + +

get.num

+Category

+Mathematical commands

+Syntax

+

+get.num(mPROMPT,vNUM);

+Description

+

+The player is prompted to enter a number, with the prompt being mPROMPT. vNUM is set to the number the player entered. If no valid number number is entered, this is 0.

+See also

+get.string

+ diff --git a/help/get_posn.html b/help/get_posn.html new file mode 100644 index 0000000..9508064 --- /dev/null +++ b/help/get_posn.html @@ -0,0 +1,16 @@ + + +get.posn + +

get.posn

+Category

+Object/view commands

+Syntax

+

+get.posn(oA,vX,vY);

+Description

+

+vX and vY are set to the X and Y co-ordinates of object oA.

+See also

+Positioning objects

+ diff --git a/help/get_priority.html b/help/get_priority.html new file mode 100644 index 0000000..d773a76 --- /dev/null +++ b/help/get_priority.html @@ -0,0 +1,16 @@ + + +get.priority + +

get.priority

+Category

+Object/view commands

+Syntax

+

+get.priority(oA,vPRI);

+Description

+

+vPRI is set to the priority of object oA.

+See also

+Priorities

+ diff --git a/help/get_room_v.html b/help/get_room_v.html new file mode 100644 index 0000000..4c253fd --- /dev/null +++ b/help/get_room_v.html @@ -0,0 +1,15 @@ + + +get.room.v + +

get.room.v

+Category

+Inventory item commands

+Syntax

+

+get.room.v(vITEM,vROOM);

+Description

+

+vROOM is set to the room number of inventory item vITEM.

+See also

+ diff --git a/help/get_string.html b/help/get_string.html new file mode 100644 index 0000000..b1de556 --- /dev/null +++ b/help/get_string.html @@ -0,0 +1,16 @@ + + +get.string + +

get.string

+Category

+String commands

+Syntax

+

+get.string(sA,mB,Y,X,L);

+Description

+

+The user is prompted to enter a string. Message mB is used as the prompt, and displayed at column Y, row X. The maximum string length is L. Once the string has been entered, it is stored in string sA.

+See also

+get.num

+ diff --git a/help/get_v.html b/help/get_v.html new file mode 100644 index 0000000..5ccea33 --- /dev/null +++ b/help/get_v.html @@ -0,0 +1,16 @@ + + +get.v + +

get.v

+Category

+Inventory item commands

+Syntax

+

+get.v(vITEM);

+Description

+

+The room number of inventory item vITEM is set to 255, placing the item in the player's inventory.

+See also

+get

+ diff --git a/help/getting_started.html b/help/getting_started.html new file mode 100644 index 0000000..7b2770f --- /dev/null +++ b/help/getting_started.html @@ -0,0 +1,17 @@ + + +Getting started + +

Getting started

+The best way to get started with the AGI logic language is by looking at the code of existing games. At the moment, there is no complete tutorial available, so this is the best way to get a feel for the +language and how certain things are done. This help file is designed mainly as a reference, although it does contain a few general introductory topics. You should start by reading these, which will +hopefully give you an idea about what the main features of the system are. Also, there is some useful information in the readme.txt for the template game. +

+Partial AGI logic tutorials can be found at the following sites +(note that these links may become unavailable in the future): +

+

http://weremoose.tripod.com/Tutorials.html +

http://members.xoom.com/agi_filedump/ + +

+ diff --git a/help/gpl.txt b/help/gpl.txt new file mode 100644 index 0000000..ba2a398 --- /dev/null +++ b/help/gpl.txt @@ -0,0 +1,343 @@ +

+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    
+    Copyright (C) 19yy  
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  , 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+
\ No newline at end of file diff --git a/help/graphics.html b/help/graphics.html new file mode 100644 index 0000000..82253e2 --- /dev/null +++ b/help/graphics.html @@ -0,0 +1,16 @@ + + +graphics + +

graphics

+Category

+Display commands

+Syntax

+

+graphics();

+Description

+

+Switches the interpreter back to graphics mode if it was previously switched to text mode (using the text.screen command).

+See also

+text.screen

+ diff --git a/help/greatern.html b/help/greatern.html new file mode 100644 index 0000000..8c52a8a --- /dev/null +++ b/help/greatern.html @@ -0,0 +1,18 @@ + + +greatern + +

greatern

+Category

+Test commands / Mathematical commands

+

+Syntax

+

+if (greatern(vA,B)) { .....

+if (vA > B) {

+Description

+

+Returns true if vA is greater than B.

+See also

+greaterv

+ diff --git a/help/greaterv.html b/help/greaterv.html new file mode 100644 index 0000000..d1de8c9 --- /dev/null +++ b/help/greaterv.html @@ -0,0 +1,18 @@ + + +greaterv + +

greaterv

+Category

+Test commands / Mathematical commands

+

+Syntax

+

+if (greaterv(vA,vB)) { .....

+if (vA > vB) { .....

+Description

+

+Returns true if vA is greater than vB.

+See also

+greatern

+ diff --git a/help/has.html b/help/has.html new file mode 100644 index 0000000..c6fb0dc --- /dev/null +++ b/help/has.html @@ -0,0 +1,17 @@ + + +has + +

has

+Category

+Test commands / Inventory item commands

+

+Syntax

+

+if (has(iA)) { .....

+Description

+

+Returns true if the inventory item iA is in the player's inventory (i.e. the item's room number is 255).

+See also

+obj.in.room

+ diff --git a/help/have_key.html b/help/have_key.html new file mode 100644 index 0000000..d1c3ffb --- /dev/null +++ b/help/have_key.html @@ -0,0 +1,16 @@ + + +have.key + +

have.key

+Category

+Test commands

+

+Syntax

+

+if (have.key()) { .....

+Description

+

+Returns true if the user has pressed a key.

+See also

+ diff --git a/help/hide_mouse.html b/help/hide_mouse.html new file mode 100644 index 0000000..1b3eca7 --- /dev/null +++ b/help/hide_mouse.html @@ -0,0 +1,19 @@ + + +hide.mouse + +

hide.mouse

+Category

+Extra commands

+Syntax

+

+hide.mouse();

+Description

+

+This command hides the mouse cursor. +Does not work with Sierra's PC version of the interpreter

+See also

+show.mouse

+fence.mouse

+mouse.posn

+ diff --git a/help/hold_key.html b/help/hold_key.html new file mode 100644 index 0000000..5b48677 --- /dev/null +++ b/help/hold_key.html @@ -0,0 +1,16 @@ + + +hold.key + +

hold.key

+Category

+Extra commands

+Syntax

+

+hold.key();

+Description

+

+This command changes the way that ego is controlled. After calling hold.key(), Ego will only move when a direction key is maintained pressed. If the key is released, ego will stop walking. +See also

+release.key

+ diff --git a/help/ignore_blocks.html b/help/ignore_blocks.html new file mode 100644 index 0000000..b9e7806 --- /dev/null +++ b/help/ignore_blocks.html @@ -0,0 +1,18 @@ + + +ignore.blocks + +

ignore.blocks

+Category

+Object/view commands

+Syntax

+

+ignore.blocks(oA);

+Description

+

+Object oA is allowed to cross over conditional barriers (pixels set to colour 1 on the priority screen) and borders of blocks set up with the block command.

+See also

+observe.blocks

+block

+Controlling obstacles

+ diff --git a/help/ignore_horizon.html b/help/ignore_horizon.html new file mode 100644 index 0000000..62ba411 --- /dev/null +++ b/help/ignore_horizon.html @@ -0,0 +1,18 @@ + + +ignore.horizon + +

ignore.horizon

+Category

+Object/view commands

+Syntax

+

+ignore.horizon(oA);

+Description

+

+Object oA is allowed to go above the horizon.

+See also

+observe.horizon

+set.horizon

+Controlling obstacles

+ diff --git a/help/ignore_objs.html b/help/ignore_objs.html new file mode 100644 index 0000000..eca5fe0 --- /dev/null +++ b/help/ignore_objs.html @@ -0,0 +1,18 @@ + + +ignore.objs + +

ignore.objs

+Category

+Object/view commands

+Syntax

+

+ignore.objs(oA);

+Description

+

+Object oA is allowed to move through other objects, i.e. it's baseline is allowed to touch another object's baseline.

+If oA stops because it runs into another object, it will keep going once that object moves out of the way (provided it is not stopped or it's direction changed before then).

+See also

+observe.objs

+Controlling obstacles

+ diff --git a/help/increment.html b/help/increment.html new file mode 100644 index 0000000..c9e68e3 --- /dev/null +++ b/help/increment.html @@ -0,0 +1,18 @@ + + +increment + +

increment

+Category

+Mathematical commands

+

+Syntax

+

+increment(vA);

+vA++;

+Description

+

+If the value of vA is less than 255, then it is increased by 1.

+See also

+decrement

+ diff --git a/help/index.html b/help/index.html new file mode 100644 index 0000000..9002eb0 --- /dev/null +++ b/help/index.html @@ -0,0 +1,35 @@ + + +Contents + +

+QT AGI Studio +

QT AGI Studio help

+ +About AGI

+About AGI Studio

+About this help

+ +

Learning about AGI

+Data used by AGI

+Logic help

+

Working with AGI Studio

+Opening games

+Creating new games

+Viewing resources

+Adding resources

+Extracting resources

+Deleting resources

+Renumbering resources

+Rebuilding the VOL files

+

+Change settings

+

Tools

+View editor

+Logic editor

+Text editor

+Object editor

+WORDS.TOK editor

+Picture editor

+

+ diff --git a/help/indexabc.html b/help/indexabc.html new file mode 100644 index 0000000..f8b13de --- /dev/null +++ b/help/indexabc.html @@ -0,0 +1,274 @@ + + +Contents + + +

+ +

QT AGI Studio

+ +

Index

+

about_agi +

about_agi_studio +

about_help +

accept_input +

add_to_pic +

add_to_pic_v +

adding_resources +

addn +

addv +

allow_menu +

animate_obj +

assignn +

assignv +

block +

call +

call_v +

cancel_line +

center_posn +

clear_lines +

clear_text_rect +

close_dialogue +

close_window +

commands_by_category +

commands_by_name +

compare_strings +

configure_screen +

control_commands +

controller +

controlling_obstacles +

creating_new_games +

current_cel +

current_loop +

current_view +

cycle_time +

cycling_objects +

data_used +

debug_commands +

decrement +

deleting_resources +

disable_item +

discard_pic +

discard_sound +

discard_view +

discard_view_v +

display +

display_commands +

display_v +

displaying_text +

distance +

div_n +

div_v +

draw +

draw_pic +

drawing_pictures +

drop +

echo_line +

enable_item +

end_of_loop +

equaln +

equalv +

erase +

extra_commands +

extracting_resources +

fence_mouse +

files_used +

fix_loop +

flag_commands +

follow_ego +

force_update +

get +

get_dir +

get_num +

get_posn +

get_priority +

get_room_v +

get_string +

get_v +

getting_started +

graphics +

greatern +

greaterv +

has +

have_key +

hide_mouse +

hold_key +

ignore_blocks +

ignore_horizon +

ignore_objs +

increment +

indexabc +

init_disk +

init_joy +

initializing_objects +

inventory_commands +

isset +

issetv +

last_cel +

lessn +

lessv +

lindirectn +

lindirectv +

load_logics +

load_logics_v +

load_pic +

load_sound +

load_view +

load_view_v +

log +

logic_contents +

logic_descr +

logic_editor_main +

logic_syntax +

math_commands +

menu_commands +

menu_input +

more_agi_info +

mouse_posn +

move_obj +

move_obj_v +

moving_objects +

mul_n +

mul_v +

new_room +

new_room_v +

normal_cycle +

normal_motion +

number_of_loops +

obj_in_box +

obj_in_room +

obj_status_v +

object_commands +

object_descr +

object_editor_main +

object_on_anything +

object_on_land +

object_on_water +

objects +

observe_blocks +

observe_horizon +

observe_objs +

open_dialogue +

opening_games +

overlay_pic +

parse +

pause +

picture_commands +

picture_descr +

picture_editor_main +

player_control +

pop_scrip +

position +

position_v +

positioning_objects +

posn +

push_script +

prevent_input +

print +

print_at +

print_at_v +

print_v +

priorities +

program_control +

project_status +

put +

put_v +

quit +

random +

rebuilding_vol_files +

release_loop +

release_key +

release_priority +

renumbering_resources +

reposition +

reposition_to +

reposition_to_v +

reset +

reset_scan_start +

reset_v +

restart_game +

restore_game +

return +

reverse_cycle +

reverse_loop +

right_posn +

rindirect +

said +

save_game +

script_buffer +

script_size +

set +

set_cel +

set_cel_v +

set_cursor_char +

set_dir +

set_game_id +

set_horizon +

set_key +

set_loop +

set_loop_v +

set_menu +

set_menu_item +

set_pri_base +

set_priority +

set_priority_v +

set_scan_start +

set_simple +

set_string +

set_text_attribute +

set_upper_left +

set_v +

set_view +

set_view_v +

setting_up_menus_and_keys +

shake_screen +

show_mem +

show_mouse +

show_obj +

show_obj_v +

show_pic +

show_pri_screen +

sound +

sound_commands +

sound_descr +

special_flags +

special_variables +

start_cycling +

start_motion +

start_update +

status +

status_line_off +

status_line_on +

step_size +

step_time +

stop_cycling +

stop_motion +

stop_sound +

stop_update +

string_commands +

submit_menu +

subn +

subv +

system_commands +

test_commands +

text_editor_main +

text_screen +

todo +

toggle +

toggle_monitor +

toggle_v +

trace_info +

trace_mode +

trace_on +

types +

unanimate_all +

unblock +

version +

view_descr +

view_editor_main +

viewing_resources +

wander +

word_to_string +

wordstok_descr +

wordstok_editor_main + diff --git a/help/init_disk.html b/help/init_disk.html new file mode 100644 index 0000000..4b3e639 --- /dev/null +++ b/help/init_disk.html @@ -0,0 +1,15 @@ + + +init.disk + +

init.disk

+Category

+System commands

+Syntax

+

+init.disk();

+Description

+

+This command was presumably used to format a floppy disk (for saved game purposes) on Apple II and other versions of the interpreter. On the PC version, this command does nothing.

+See also

+ diff --git a/help/init_joy.html b/help/init_joy.html new file mode 100644 index 0000000..a160d7f --- /dev/null +++ b/help/init_joy.html @@ -0,0 +1,15 @@ + + +init.joy + +

init.joy

+Category

+System commands

+Syntax

+

+init.joy();

+Description

+

+Calibrates the joystick, if there is one connected to the computer.

+See also

+ diff --git a/help/initializing_objects.html b/help/initializing_objects.html new file mode 100644 index 0000000..5ded307 --- /dev/null +++ b/help/initializing_objects.html @@ -0,0 +1,28 @@ + + +Initializing objects + +

Initializing objects

+In order to initialize a screen object you must follow these steps:

+1. Animate the object. This is done using the animate.obj command. This tells the interpreter that you want to use this object. There are a limited number of objects that the +interpreter can use at any one time. This is set by a certain byte in the OBJECT file. There is currently no program that will edit this, but the template game allows for up to 16 objects (0-15) +which should be enough. Also, the more objects you use the slower the interpreter will run, but it is not really noticeable on today's machines. +

+2. Assign a view to the object. This is done using the set.view command. Each object must have a view assigned to it, and this is the view that is displayed on the screen wherever +the object is. One view can be assigned to multiple screen objects. You must have the view loaded in memory before you assign it. This can be done with the load.view command. +

+3. Position the object on screen. This is done using the position command.

+4. Draw the object. This is done using the draw command. If you do not do this the object will not be visible on screen.

+Here is an example:

+

+animate.obj(o2);
+load.view(4);
+set.view(o2,4);
+position(o2,80,120);
+draw(o2);
+

+This will result in an animation of view 4 being displayed at 80,120.

+See also

+

+Objects

+ diff --git a/help/inventory_commands.html b/help/inventory_commands.html new file mode 100644 index 0000000..bda7d49 --- /dev/null +++ b/help/inventory_commands.html @@ -0,0 +1,18 @@ + + +Inventory item commands + +

Inventory item commands

+drop

+get.room.v

+get.v

+get

+put.v

+put

+show.obj.v

+show.obj

+status

+Test commands

+has

+obj.in.room

+ diff --git a/help/isset.html b/help/isset.html new file mode 100644 index 0000000..106e106 --- /dev/null +++ b/help/isset.html @@ -0,0 +1,18 @@ + + +isset + +

isset

+Category

+Test commands / Flag commads

+

+Syntax

+

+if (isset(fA)) { .....

+if (fA) { .....

+Description

+

+Returns true if flag fA is set.

+See also

+issetv

+ diff --git a/help/issetv.html b/help/issetv.html new file mode 100644 index 0000000..505f49f --- /dev/null +++ b/help/issetv.html @@ -0,0 +1,17 @@ + + +issetv + +

issetv

+Category

+Test commands / Flag commads

+

+Syntax

+

+if (isset(vA)) { .....

+Description

+

+Returns true if the flag determined by the value of vA is set.

+See also

+isset

+ diff --git a/help/kq3.png b/help/kq3.png new file mode 100644 index 0000000000000000000000000000000000000000..8b812b853a3533656ee43f58b37c89b09fbaaf75 GIT binary patch literal 8037 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 literal 0 HcmV?d00001 diff --git a/help/last_cel.html b/help/last_cel.html new file mode 100644 index 0000000..cc97205 --- /dev/null +++ b/help/last_cel.html @@ -0,0 +1,19 @@ + + +last.cel + +

last.cel

+Category

+Object/view commands

+Syntax

+

+last.cel(oA,vB);

+Description

+

+vB is set to the number of the last cel of the current loop of object oA.

+See also

+current.cel

+set.cel

+set.cel.v

+number.of.loops

+ diff --git a/help/lessn.html b/help/lessn.html new file mode 100644 index 0000000..18c9a91 --- /dev/null +++ b/help/lessn.html @@ -0,0 +1,18 @@ + + +lessn + +

lessn

+Category

+Test commands / Mathematical commands

+

+Syntax

+

+if (lessn(vA,B)) { .....

+if (vA < B) { .....

+Description

+

+Returns true if vA is less than B.

+See also

+lessv

+ diff --git a/help/lessv.html b/help/lessv.html new file mode 100644 index 0000000..a070f89 --- /dev/null +++ b/help/lessv.html @@ -0,0 +1,18 @@ + + +lessv + +

lessv

+Category

+Test commands / Mathematical commands

+

+Syntax

+

+if (lessn(vA,vB)) { .....

+if (vA < vB) { .....

+Description

+

+Returns true if vA is less than vB.

+See also

+lessn

+ diff --git a/help/lindirectn.html b/help/lindirectn.html new file mode 100644 index 0000000..6d51f38 --- /dev/null +++ b/help/lindirectn.html @@ -0,0 +1,18 @@ + + +lindirectn + +

lindirectn

+Category

+Mathematical commands

+Syntax

+

+lindirectn(vA,B);

+*vA = B;

+Description

+

+The value of vC (where C is the value of vA) is set to B.

+See also

+lindirectv

+rindirect

+ diff --git a/help/lindirectv.html b/help/lindirectv.html new file mode 100644 index 0000000..a7f38f5 --- /dev/null +++ b/help/lindirectv.html @@ -0,0 +1,18 @@ + + +lindirectv + +

lindirectv

+Category

+Mathematical commands

+Syntax

+

+lindirectn(vA,vB);

+*vA = vB;

+Description

+

+The value of vC (where C is the value of vA) is set to vB.

+See also

+lindirectn

+rindirect

+ diff --git a/help/load_logics.html b/help/load_logics.html new file mode 100644 index 0000000..00f2321 --- /dev/null +++ b/help/load_logics.html @@ -0,0 +1,17 @@ + + +load.logics + +

load.logics

+Category

+Control flow commands

+Syntax

+

+load.logics(A);

+Description

+

+Loads logic A is into memory. You should do this if you are going to call it a lot, to save the interpreter having to load it and unload it every time it calls it.

+See also

+load.logics.v

+call

+ diff --git a/help/load_logics_v.html b/help/load_logics_v.html new file mode 100644 index 0000000..c73d2e6 --- /dev/null +++ b/help/load_logics_v.html @@ -0,0 +1,17 @@ + + +load.logics.v + +

load.logics.v

+Category

+Control flow commands

+Syntax

+

+load.logics.v(vA);

+Description

+

+Loads logic vA is into memory. You should do this if you are going to call it a lot, to save the interpreter having to load it and unload it every time it calls it.

+See also

+load.logics

+call

+ diff --git a/help/load_pic.html b/help/load_pic.html new file mode 100644 index 0000000..6412ca0 --- /dev/null +++ b/help/load_pic.html @@ -0,0 +1,19 @@ + + +load.pic + +

load.pic

+Category

+Picture commands

+Syntax

+

+load.pic(vA);

+Description

+

+Picture resource vA is loaded into memory.

+See also

+discard.pic

+draw.pic

+overlay.pic

+Drawing pictures

+ diff --git a/help/load_sound.html b/help/load_sound.html new file mode 100644 index 0000000..c5c9b25 --- /dev/null +++ b/help/load_sound.html @@ -0,0 +1,16 @@ + + +load.sound + +

load.sound

+Category

+Sound commands

+Syntax

+

+load.sound(SOUNDNO);

+Description

+

+Sound SOUNDNO is loaded into memory.

+See also

+sound

+ diff --git a/help/load_view.html b/help/load_view.html new file mode 100644 index 0000000..45ab73a --- /dev/null +++ b/help/load_view.html @@ -0,0 +1,20 @@ + + +load.view + +

load.view

+Category

+Object/view commands

+Syntax

+

+load.view(VIEWNUM);

+Description

+

+View VIEWNUM is loaded into memory. This is required before the view is assigned to any objects or used anywhere. It is not needed, however, for the show.obj command.

+See also

+load.view.v

+discard.view

+discard.view.v

+set.view

+set.view.v

+ diff --git a/help/load_view_v.html b/help/load_view_v.html new file mode 100644 index 0000000..ae26ad6 --- /dev/null +++ b/help/load_view_v.html @@ -0,0 +1,20 @@ + + +load.view.v + +

load.view.v

+Category

+Object/view commands

+Syntax

+

+load.view(vVIEWNUM);

+Description

+

+View vVIEWNUM is loaded into memory. This is required before the view is assigned to any objects or used anywhere. It is not needed, however, for the show.obj command.

+See also

+load.view

+discard.view

+discard.view.v

+set.view

+set.view.v

+ diff --git a/help/log.html b/help/log.html new file mode 100644 index 0000000..8c14cfb --- /dev/null +++ b/help/log.html @@ -0,0 +1,16 @@ + + +log + +

log

+Category

+Debugging commands

+

+Syntax

+

+log(mLOGMESSAGE);

+Description

+

+Writes the current room number (value of v0), the input line given by the player and message mLOGMESSAGE to a file called logfile in the game's directory.

+See also

+ diff --git a/help/logic-editor.png b/help/logic-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..595ae108289e01219223876454a5025173fec0ff GIT binary patch literal 9613 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 + +AGI Logic help + +

AGI Logic help

+Getting started

+General topics

+Logic syntax

+Types

+Objects

+Special variable

+Special flags

+Command reference

+Commands by name

+Commands by category

+


+Back to contents

+ diff --git a/help/logic_descr.html b/help/logic_descr.html new file mode 100644 index 0000000..1b8a388 --- /dev/null +++ b/help/logic_descr.html @@ -0,0 +1,15 @@ + + +Logic resources + +

Logic resources

+Logic resources are the guts of an AGI game. They are scripts that contain all the commands necessary to control the view, picture and sound resources and to receive and act on input from +the player, thus determining everything that happens in the game. Each room generally has its own logic which determines what happens in that room, and the game also has a few other logics to look +after things like initialization and error handling. +

+Games are programmed in a special language specific to AGI and compiled into logic resources. The logic programming language is similar to standard programming languages like C, but a lot less +powerful as it is designed for specific purpose. For more information on logic programming, click here. +

+You can edit logics with the Logic editor.

+Back to data used by AGI

+ diff --git a/help/logic_diag-directions.png b/help/logic_diag-directions.png new file mode 100644 index 0000000000000000000000000000000000000000..07c54a105e2f031c1eb8741512eaf6dd31fca7f6 GIT binary patch literal 2443 zcmeHH`#;lN9RIE{#TN0DMS7NMX;{lPW@@1kUEC(A&@SfI5T>kFgfxuus7WffqMn|H zXmoMuA#JEMCD(|ROUPZN?3sFg=;>d0IlcC*qtjT4006*%(@s|#r3Fe~<~kIUzuK=1{0}p*bedqGxHgEsV;dRZ zDeKt*fbs=`*tRB;F#!cd}MSC5Wi8%-Q3xND8y4NV%G{;N(otx z2n!qlg#lZ^RgD1V2S|Zt)z36E+WJ*()+$-z1=`YWyzr-Wfj?1xV1I+v5`sdp;nMCU z?CxbcKpraT3#c+DdVdsB93`4}dEKoij-5eMS3{nvL$)#&`zyByW1g z5!KEtYDzv#&Y&K_QyWW>Y-=-*&ZwqUn<%a4#&6 zmssQew60l1D}s9#Vm706D1xCD|uQO;o<8hoQQ+SXcs;M8NkCwh_R4J})J$5dOo1TuI@TBX`z?S{J# z@k5N}Y_1vg!}gHJ8)PKZmFi=bpIq-iSY{Ab7lfq^7KO%CrzF31A-ygz@^G^!@S{ue zKTAFzSJqQX+1mOD_|!pm_&idY6%HN!v?6PyC{($lpQEFG+1AP|InW2<-aBRQK3gGW zt4S+WSUTYCd))RSwy4VEkd%mt3TQZK|6Auqw-w5IYKuW>@7i0{UmA!_XQlN`W1F5x zAmS(Qb3-g73vd+2A6ma8T5uJe6`{ST3Akk#=AiG>OAV!zje!S-dDk{oE>Ex90e_J&cN zd-M0&-oCHBg^1Q%ZGN-8O{JEGU>>KO5gSbUb~H-Y;UJxhN^z43NtVGC-@gsEQ{;2y z`OT)ZK!#!0=pBDYw>I7In*5E~)lt)Zuh=-=xE;af&s#9!)%2e6oJn}2kwe&nuT9wB zcchuVRtbsV4lo8VRdPgoXR7f6Dbae!P_)Sw9=n-*3CG*WRU_a^m= zK{>qTB)eOj!{82emxGtvfse)pcR|a-CUO(cxaejng5nRgMfsj{pt@~T%HNG z?y|N`Uj>7G1i^sf8V@ILg_{I`e=wH+!gTD?hXZB%72e}h$HoyQ>#zeepvms!y?X$? zGMWH`>xSq6ais`MF-awBf@|ao`N=20om~!+iH#^p)faav40|iv#+^+G_F*5Pg)#w4 zgVpQp18Kg@T{K^R#z6!QZGtvOn453FDEdYOBh){P&9MyRgt7e@Xl5ANJN!^^5F5=1 z4jk@p9aYGozRCIf2GQ8z3Oy67H{HaWhB5WQY$W(#Fn9*d8*56yW3i^@X67^;DPQKO lU}?;=oD|yvSOPA>1cNoi7-Gs=E6Noyz~07zEVQOZ{{s;j?SudT literal 0 HcmV?d00001 diff --git a/help/logic_editor_main.html b/help/logic_editor_main.html new file mode 100644 index 0000000..0409c2c --- /dev/null +++ b/help/logic_editor_main.html @@ -0,0 +1,36 @@ + + +Logic editor + +

Logic editor

+The logic editor allows you to compile and decompile logic resources. To open an existing logic, double-click on it in the resources window, or to create a new one select 'Logic editor' +from the 'Tools' menu or the toolbar (you will be prompted for the logic number when you save or compile it). +

+It is designed to be easier to use than its DOS counterparts in that you can save your source code, compile your logic, add it to the game and run the game all with the press of one key, eliminating +the several steps and switching between applications previously required. It will also indicate any errors in the source code it encounters when compiling, so you can find them easily. +

+Previously, the syntax used for programming AGI logics has varied very slightly between compilers and has not been properly documented. Peter Kelly and other AGI developers have decided on a proper +syntax which will be supported by all logic compilers/decompilers. This syntax is documented in AGI specs. AGI Studio fully supports the syntax. +

+ +

Editing

+If you double-click on a logic in the resources window, the editor will be brought up. If the logic.X file exists in the source directory, this will be loaded. Otherwise it will try to load logicX.txt (the name convention used in the Windows AGI studio), if it also doesn't exist, then it will decompile the resource that is already in the game. +

+When the cursor is located in the middle of a highlighted AGI command, you can hit F1 (or choose the option from the help menu) to read an on-line help page that describes it. + +

Compiling

+To compile a logic, simply select compile from the file menu or press F9. Pressing F10 does the same thing except it runs the game after the logic has compiled successfully. Whenever you compile the logic, the source code and any open text files that are included with the #include command are saved. +

+When you compile the logic in AGI Studio, it is automatically added to the game. The source code is saved in a text file in the source directory of whatever game you are editing. You can specify in the "Settings" menu the location of the source directory - it can be a subdirectory of the game directory (the default: "src") but it can be also in a completely different place. The name of the file is logic.X where X is the +number of the logic. +

+

New room

+The option "new room" in the File menu allows building the new room template using a GUI +to specify the most common options. The design of the New Room menu was copied from +Joel McCormick's "AGI Base Logic Generator" utility. +

+---------------------------------------------- +

This is basically all you need to know about AGI Studio's logic editor. You will need to know how to program in the language though. Read the logic help. +

+Back to contents

+ diff --git a/help/logic_syntax.html b/help/logic_syntax.html new file mode 100644 index 0000000..903aa80 --- /dev/null +++ b/help/logic_syntax.html @@ -0,0 +1,189 @@ + + +Logic syntax + +

Logic syntax

+Action Commands

+

+Normal action commands are specified by the command name followed by brackets which contain the arguments, separated by commas. A semicolon is placed after the brackets. The brackets are required +even if there are no arguments. The arguments given must have the correct prefix for that type of argument as explained later in this document (this is to make sure the programmer does not use a var, +for example, when they think they are using a flag). +

+assign.v(v50,0);

+program.control();

+Multiple commands may be placed on the one line:

+reset(f6); reset(f7);

+Substitutions for the following action commands are available:

+

+increment(v30); 	v30++;
+decrement(v30); 	v30--;
+assignn(v30,4); 	v30 = 4;
+assignv(v30,v32); 	v30 = v32;
+addn(v30,4); 	v30 = v30 + 4; 	or 	v30 += 4;
+addv(v30,v32); 	v30 = v30 + v32; 	or 	v30 += v32;
+subn(v30,4); 	v30 = v30 - 4; 	or 	v30 -= 4;
+subv(v30,v32); 	v30 = v30 - v32; 	or 	v30 -= v32;
+mul.n(v30,4); 	v30 = v30 * 4; 	or 	v30 *= 4;
+mul.v(v30,v32); 	v30 = v30 * v32; 	or 	v30 *= v32;
+div.n(v30,4); 	v30 = v30 / 4; 	or 	v30 /= 4;
+div.v(v30,v32); 	v30 = v30 / v32; 	or 	v30 /= v32;
+lindirectn(v30,4); 	*v30 = 4;
+lindirectv(v30,v32); 	*v30 = v32;
+rindirect(v30,v32); 	v30 = *v32;
+

+IF structures and test commands

+An if structure looks like this:

+

+if (<test commands>) {
+  <action commands>
+}
+

+or like this :

+

+if (<test commands>) {
+  <action commands>
+}
+else {
+  <more action commands>
+}
+

+Carriage returns are not necessary:

+if (<test commands>) { <action Commands> } else { <more action commands> }

+Test commands are coded like action commands except there is no semicolon. They are separated by && or || for AND or OR.

+if (isset(f5) &&

+ greatern(v5,6)) { ......

+Again, carriage returns are not necessary within the if statement:

+if (lessn(v5,6) && (greatern(v5,2)) { .......

+if (isset(f90) && equalv(v32,v34)

+ && greatern(v34,20)) { .......

+A ! placed in front of a command signifies a NOT.

+if (!isset(f7)) {

+ ......

+Boolean expressions are not necessarily simplified so they must follow the rules set down by the file format. If test commands are to be ORred together, they must be placed in brackets.

+if ((isset(f1) || isset(f2)) {

+ ......

+if (isset(f1) && (isset(f2) || isset(f3))) {

+ ......

+if (isset(1) || (isset(2) && isset(3))) { is NOT legal

+Depending on the compiler, simplification of boolean expressions may be supported, so the above may not apply in all cases (although if these are rules are followed then the logic will work with all +compilers). +

+Substitutions for the following test commands are available:

+

+equaln(v30,4) 	v30 == 4
+equalv(v30,v32) 	v30 == v32
+greatern(v30,4) 	v30 > 4
+greaterv(v30,v32) 	v30 > v32
+lessn(v30,4) 	v30 < 4
+lessv(v30,v32) 	v30 < v32
+!equaln(v30,4) 	v30 != 4
+!equalv(v30,v32) 	v30 != v32
+!greatern(v30,4) 	v30 <= 4
+!greaterv(v30,v32) 	v30 <= v32
+!lessn(v30,4) 	v30 >= 4
+!lessv(v30,v32) 	v30 >= v32
+

+Also, flags can be tested for by just using the name of the flag:

+if (f6) { .....

+if (v7 > 0 && !f6) { .....

+Argument types

+There are 9 different types of arguments that commands use:

+

+Number 	(no prefix)
+Var 	(prefix "v")
+Flag 	(prefix "f")
+Message 	(prefix "m")
+Object 	(prefix "o")
+Inventory Item 	(prefix "i")
+String 	(prefix "s")
+Word 	(prefix "w")
+Controller 	(prefix "c")
+

+The said test command uses it's own special arguments which will be described later.

+Each of these types of arguments is given by the prefix and then a number from 0-255, e.g. v5, f6, m27, o2.

+The word type is words that the player has typed in, not words that are stored in the WORDS.TOK file. Strings are the temporary string variables stored in memory, not to be confused with messages +(that are stored in the logic resources). Controllers are menu items and keys. +

+Compilers can enforce type checking, so that the programmer must use the correct prefix for an argument so that they know they are using the right type. Decoders should display arguments with the +right type. +

+move.obj(so4,80,120,2,f66);

+if (obj.in.box(so2,30,60,120,40)) { .....

+A complete list of the commands and their argument types is available as part of AGI Specs.

+Messages and inventory items may be given in either numerical text format:

+print("He's not here.");

+print(m12);

+if (has("Jetpack")) { .....

+if (has(io9)) { .....

+Messages can also be split over multiple lines:

+

+print("This message is split "
+      "over multiple lines.");
+

+Quote marks must be used around messages and object names. This is important because some messages or object names may contain brackets or commas, which could confuse the compiler. This is also the +case for the said command which will be described shortly. +

+

+if (has("Buckazoid(s)")) { .....   // no ambiguity here about where
+                                   // the argument ends
+

+If quote marks are part of the message or inventory object, a \ should be placed in front of these. To use a \, \\ should be used. \n can also be used for a new line.

+The said test command uses different parameters to all the other commands. Where as the others use 8 bit arguments (0-255), said takes 16 bit arguments (0-65535). Also, the number of arguments in a +said command can vary. The numbers given in the arguments are the word group numbers from the WORDS.TOK file. +

+if (said(4,80)) { .....

+Words can also be given in place of the numbers:

+if (said("look")) { .....

+if (said("open","door")) { .....

+Quote marks must also be used around the words.

+Labels and the goto command

+Labels are given like this:

+Label1:

+The label name can contain letters, numbers, and the characters "_" and ".". No spaces are allowed.

+The goto command takes one parameter, the name of a label.

+goto(Label1);

+Comments

+There are three ways that comments can be used.

+// - rest of line is ignored

+[ - rest of line is ignored

+/* Text between these are ignored */

+The /*...*/ can be nested:

+

+/* comment start
+  print("Hello");    // won't be run
+  /*                 // a new comment start (will be ignored!)
+    v32 = 15;        // won't be run
+  */                 // uncomments the most inner comment
+  print("Hey!");     // won't be run, still inside comments
+*/                   // uncomments
+

+Defines

+To give vars, flags etc. proper names the #define command is used. The name of the define is given followed by the define value:

+#define ego o0

+#define room_descr "This is a large hall with tall pillars down each side."

+Then the define name can be used in place of the define value:

+draw(ego);

+print(room_descr);

+Define names can only be used in arguments of commands (including gotos and the v0 == 3 type syntax), although some compilers may allow you to use them anywhere.

+Defines must be defined in the file before they are used.

+The define name can contain letters, numbers, and the characters "_" and ".". No spaces are allowed.

+Including files

+You can include another file in your logic source code by using the #include command:

+#include "file.txt"

+When the compiler encounters the above line, it will replace it with the contents of file.txt.

+It is a good idea to have all the defines that you need for multiple logics in an #include file, so if you need to change the define value you only have to do it once (although you will need to +recompile all logics that use that define). +

+More on messages

+In some cases you may want to assign a specific number to a message so you can refer to it in other places. This is done by using the #message command, followed by the number of the message then the +message itself: +

+#message 4 "You can't do that now."

+Then you can give the message number as the parameter in commands:

+print(m4);

+Or embed the message in commands as normal and the number you assigned to it before will be used:

+print("You can't do that now.");

+#message can be used anywhere in the file, so you do not have to set the message before you use it.

+The return command

+The return command is just a normal action command (number 0), with no arguments. This must be the last command in every logic.

+ diff --git a/help/logo.bmp b/help/logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..ace3603147b1a626647cf99b1ad96a636add4db3 GIT binary patch literal 142134 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 EFCKg%d;kCd literal 0 HcmV?d00001 diff --git a/help/logo.png b/help/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..619f701ef6473696300f96a5ed1e1aaa4f9f7fcf GIT binary patch literal 4335 zcmVfTAersDKq^VpPD2GBGM(MVXj?H4jhON4+$w$}iD5vui8l(Lkwzy?tJsVHqJAz%Z@r0dR6JFF0hZUt1jaDNq%feSUD2kFvss%QH%=Y?pt9DpX@@X}d z(gNDQRg}_v5O9u#OuW{O3n-IdoS_MVXk=o7&k@=_!ix8MVNQGBE`#aD?r(uk*DhtSI@Y1y+=a ziMPNO$h4yQDJY5ppok0Y9m_R%Kf=(^S9p<@HgHOq4+2h{Xki4`+Si%BYs2KPPwXX+ zW67=f%oi$b#gS@(EpT*$4{~jaO*!3|(!~(*d_GosfjvL7YzHLgt!Y!zmnu^!=}Q&a z;Y%a8wPspj&TWFXgKh@X|$N3 z?4pG%VHk3$$t{VGiqcgSf=Iv;H(2d}qp5U_%gREZ{~+9M0Py?UEW>gZ*aH3!d5df> zNkJ=O1O|Z0xHn1Cy)O%ZpN#hvAz+akOpbrsHk9f%EA6S-2e#=~sU?ZV08l&JgWCQuzXWU9ge;3o1nm;91SkXMN~APn zZ+g}hXZ`0`in-AFZDEJj)BtE}udK`0{2kyqo{XP=jf^L5#ND!!;QVk40Qe~+T}S6W z@Vw+pEBce@Un65VeI0492!moSC0)lf0-nASTLAk@ty1AE`K{}O8bZf!@AMA>o1D)y z0*=4}_@ydM!b%mzT}Tf3rwN5cXrXL~LA zeL2xO!f}CtWbD~)p(QHdX@*{W7U`;RiQaBE0KW~_`bco)v`O{H08!_2RKSyQZP9Y* z{cc6WKV@;wvk~`r-Ff+M^I8J701nRT^r5dWW_7*C+wyi~Ac$Ohx%3kVSVj1qtk?kj z{1VaLhOxl68=e6wtSkJsmxr&;&r4+j0gr|@DD|LL_aI&1?+CTYec8piZFrWvy_2s3 zRtCZe;P)|@t1Q3;)^4r=y5E6Dqwy->CkDU-vFLB$PF!Vbhwq(TXt(g-JqCUl>2*$Z z!-+I1;F?$fHD_Oa0lh_g&a!QIzFzs%NJD;?st+pQfv6YBoUHj+EdXrh^p8Kk4*;f7 z)c0j|T~qS&3mnHdEIE7CJ}@OBT;xt+wrdFMrQ8M`BldR?BUXm2=%&|D)D z#sD~bmu1U2w1AcG#7&CWLqSBebf)nL`0ViJdcsYtu?qNz0idC*4(xIzP#JUS@`

Kacxw<$`F*A0#V8i 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 literal 0 HcmV?d00001 diff --git a/help/math_commands.html b/help/math_commands.html new file mode 100644 index 0000000..75c1ed2 --- /dev/null +++ b/help/math_commands.html @@ -0,0 +1,30 @@ + + +Mathematical commands + +

Mathematical commands

+addn

+addv

+assignn

+assignv

+decrement

+div.n

+div.v

+get.num

+increment

+lindirectn

+lindirectv

+mul.n

+mul.v

+random

+rindirect

+subn

+subv

+Test commands

+equaln

+equalv

+lessn

+lessv

+greatern

+greaterv

+ diff --git a/help/menu_commands.html b/help/menu_commands.html new file mode 100644 index 0000000..58556ff --- /dev/null +++ b/help/menu_commands.html @@ -0,0 +1,16 @@ + + +Menu/Key commands + +

Menu/Key commands

+For information on setting up menu items and keys, click here.

+disable.item

+enable.item

+menu.input

+set.key

+set.menu.item

+set.menu

+submit.menu

+Test commands

+controller

+ diff --git a/help/menu_input.html b/help/menu_input.html new file mode 100644 index 0000000..e6c5789 --- /dev/null +++ b/help/menu_input.html @@ -0,0 +1,20 @@ + + +menu.input + +

menu.input

+Category

+Menu/Key commands

+Syntax

+

+menu.input();

+Description

+

+This brings up the menu at the end of the current interpreter cycle. The next cycle does not start until the user has selected an item from the menu, or pressed ESC to exit the menu.

+Flag 14 (or menu_enabled in the template game) must be set for this command to work.

+ESC is usually the key that activates the menu, but this is not built in to the interpreter so to do this you need assign the ESC key to a controller using set.key, and then test for that +controller to activate the menu (this is already done in the template game). +

+See also

+Settings up menus and keys

+ diff --git a/help/mouse_posn.html b/help/mouse_posn.html new file mode 100644 index 0000000..4394fa7 --- /dev/null +++ b/help/mouse_posn.html @@ -0,0 +1,19 @@ + + +mouse.posn + +

mouse.posn

+Category

+Category

+Extra commands

+

+mouse.posn(x,y);

+Description

+

+This command stores position of the mouse pointer into variables x and y. +Does not work with Sierra's PC version of the interpreter

+See also

+hide.mouse

+show.mouse

+fence.mouse

+ diff --git a/help/move_obj.html b/help/move_obj.html new file mode 100644 index 0000000..b7121c2 --- /dev/null +++ b/help/move_obj.html @@ -0,0 +1,26 @@ + + +move.obj + +

move.obj

+Category

+Object/view commands

+Syntax

+

+move.obj(oA,X,Y,STEPSIZE,fDONEFLAG);

+Description

+

+Object oA moves from its current location to X,Y by STEPSIZE pixels every step. fDONEFLAG is reset when the command is issued, and set when the object reaches its destination. If STEPSIZE is 0, the +current step size of object oA is used. If object oA is ego (object 0), the interpreter executes the program.control command. +

+Warning: If your program is relying on the flag fDONEFLAG to be set before continuing with something, such as going to the next part of a cutscene, make sure that the object will always be able to +reach its destination. It is possible that it could get caught behind a barrier or something, and not be able to get where it needs to go, in which case the game might sit there forever doing +nothing. This is more of a problem when the object being moved is ego - it might work fine from where you test it, but it may be possible for the player to move ego into such a position where they +will get stuck when being moved. +

+See also

+move.obj.v

+step.size

+normal.motion

+Moving objects

+ diff --git a/help/move_obj_v.html b/help/move_obj_v.html new file mode 100644 index 0000000..3b36438 --- /dev/null +++ b/help/move_obj_v.html @@ -0,0 +1,25 @@ + + +move.obj.v + +

move.obj.v

+Category

+Object/view commands

+Syntax

+

+move.obj.v(oA,vX,vY,STEPSIZE,fDONEFLAG);

+Description

+

+Object oA moves from its current location to vX,vY by STEPSIZE pixels every step. fDONEFLAG is reset when the command is issued, and set when the object reaches its destination. If STEPSIZE is 0, the +current step size of object oA is used. If object oA is ego (object 0), the interpreter executes the program.control command. +

+Warning: If your program is relying on the flag fDONEFLAG to be set before continuing with something, such as going to the next part of a cutscene, make sure that the object will always be able to +reach its destination. It is possible that it could get caught behind a barrier or something, and not be able to get where it needs to go, in which case the game might sit there forever doing +nothing. This is more of a problem when the object being moved is ego - it might work fine from where you test it, but it may be possible for the player to move ego into such a position where they +will get stuck when being moved. +

+See also

+move.obj

+step.size

+Moving objects

+ diff --git a/help/moving_objects.html b/help/moving_objects.html new file mode 100644 index 0000000..427eb14 --- /dev/null +++ b/help/moving_objects.html @@ -0,0 +1,35 @@ + + +Moving objects + +

Moving objects

+Each object on screen has a direction it is moving in. This is a numerical value from 0 to 8:

+

+When an object is moving normally (and has a direction greater than 0), it will continue moving until it is told to stop, move in another direction, or runs into an obstacle +(such as a control line, a block, or another object). +

+An object's direction can be changed using the set.dir command. The get.dir command will allow you to find out what its current direction is. The direction of ego (object 0) is +always stored in v6. To stop an object's movement, use stop.motion. +

+There are several commands which will make an object move in different ways:

+move.obj/move.obj.v

+wander

+follow.ego

+The normal.motion command will make the object to move in the way described above after it has been moving from one of these three commands.

+An object's step size (the number of pixels moved each step) and step time (the number of interpreter cycles between steps) can be set with the step.size and step.time +commands. +

+See also

+set.dir

+get.dir

+stop.motion

+start.motion

+move.obj

+move.obj.v

+wander

+follow.ego

+normal.motion

+step.size

+step.time

+Objects

+ diff --git a/help/mul_n.html b/help/mul_n.html new file mode 100644 index 0000000..1a78947 --- /dev/null +++ b/help/mul_n.html @@ -0,0 +1,19 @@ + + +mul.n + +

mul.n

+Category

+Mathematical commands

+Syntax

+

+mul.n(vA,B);

+vA *= B;

+vA = vA * B;

+Description

+

+vA is multiplied by B. Since a var can only be from 0-255, if the result is greater than 255, then the value wraps around, e.g. 100 * 3 would give 44.

+

+See also

+mul.v

+ diff --git a/help/mul_v.html b/help/mul_v.html new file mode 100644 index 0000000..e3d5c38 --- /dev/null +++ b/help/mul_v.html @@ -0,0 +1,18 @@ + + +mul.v + +

mul.v

+Category

+Mathematical commands

+Syntax

+

+mul.v(vA,vB);

+vA *= vB;

+vA = vA * vB;

+Description

+

+vA is multiplied by vB. Since a var can only be from 0-255, if the result is greater than 255, then the value wraps around, e.g. 100 * 3 would give 44.

+See also

+mul.n

+ diff --git a/help/new_room.html b/help/new_room.html new file mode 100644 index 0000000..e3fce8a --- /dev/null +++ b/help/new_room.html @@ -0,0 +1,36 @@ + + +new.room + +

new.room

+Category

+Control flow commands

+Syntax

+

+new.room(ROOMNO);

+Description

+

+Switches to a new room, ROOMNO.

+The following things automatically happen when this command is used:

+

    +
  • All objects are unanimated +
  • All resources except logic 0 are discarded< +
  • player.control command is executed +
  • unblock command is executed +
  • horizon is set to 36 +
  • v1 (prev_room_no) is set to the value of v0 (room_no) +
  • v0 (room_no) is assigned to the new room number +
  • v16 (ego_view_no) is set to the view number assigned to ego +
  • The logic for the new room is loaded (logic ROOMNO) +
  • If ego was touching an edge of the screen, it is placed on the opposite side +
  • Flag 5 (new_room) is set (this is reset after the first cycle in the new room) +
  • Execution jumps to the start of logic 0 +
+See also

+new.room.v

+player.control

+unblock

+set.horizon

+Special variables

+Special flags

+ diff --git a/help/new_room_v.html b/help/new_room_v.html new file mode 100644 index 0000000..0e7521a --- /dev/null +++ b/help/new_room_v.html @@ -0,0 +1,36 @@ + + +new.room.v + +

new.room.v

+Category

+Control flow commands

+Syntax

+

+new.room(vROOMNO);

+Description

+

+Switches to a new room, vROOMNO.

+The following things automatically happen when this command is used:

+

    +
  • All objects are unanimated +
  • All resources except logic 0 are discarded +
  • player.control command is executed +
  • unblock command is executed +
  • horizon is set to 36 +
  • v1 (prev_room_no) is set to the value of v0 (room_no) +
  • v0 (room_no) is assigned to the new room number +
  • v16 (ego_view_no) is set to the view number assigned to ego +
  • The logic for the new room is loaded (logic vROOMNO) +
  • If ego was touching an edge of the screen, it is placed on the opposite side +
  • Flag 5 (new_room) is set (this is reset after the first cycle in the new room) +
  • Execution jumps to the start of logic 0 +
+See also

+new.room

+player.control

+unblock

+set.horizon

+Special variables

+Special flags

+ diff --git a/help/normal_cycle.html b/help/normal_cycle.html new file mode 100644 index 0000000..6c9554a --- /dev/null +++ b/help/normal_cycle.html @@ -0,0 +1,19 @@ + + +normal.cycle + +

normal.cycle

+Category

+Object/view commands

+Syntax

+

+normal.cycle(oA);

+Description

+

+This tells the interpeter to cycle object oA in normal order, so the cels are shown from first to last. To turn cycling off, use the stop.cycling command.

+See also

+reverse.cycle

+stop.cycling

+start.cycling

+Cycling objects

+ diff --git a/help/normal_motion.html b/help/normal_motion.html new file mode 100644 index 0000000..d433f79 --- /dev/null +++ b/help/normal_motion.html @@ -0,0 +1,19 @@ + + +normal.motion + +

normal.motion

+Category

+Object/view commands

+Syntax

+

+normal.motion(oA);

+Description

+

+Object oA moves normally. That is, if the object was wandering or following ego, or it was moving to a location specified by a move.obj command, it continues in the direction it was +travelling, until it is told to stop, move in another direction or runs into an obstacle. +

+See also

+move.obj

+Moving objects

+ diff --git a/help/notes b/help/notes new file mode 100644 index 0000000..98c2ae5 --- /dev/null +++ b/help/notes @@ -0,0 +1,6 @@ + picedit 22 + +view 76 +or 79 + +preview view descr 101 diff --git a/help/number_of_loops.html b/help/number_of_loops.html new file mode 100644 index 0000000..27694e8 --- /dev/null +++ b/help/number_of_loops.html @@ -0,0 +1,19 @@ + + +number.of.loops + +

number.of.loops

+Category

+Object/view commands

+Syntax

+

+number.of.loops(oA,vB);

+Description

+

+vB is set to the number of loops in the view currently assigned to object oA.

+See also

+set.loop

+set.loop.v

+current.loop

+last.cel

+ diff --git a/help/obj_in_box.html b/help/obj_in_box.html new file mode 100644 index 0000000..0898e71 --- /dev/null +++ b/help/obj_in_box.html @@ -0,0 +1,19 @@ + + +obj.in.box + +

obj.in.box

+Category

+Test commands / Object/view commands

+

+Syntax

+

+if (obj.in.box(oA,X1,Y1,X2,Y2)) { .....

+Description

+

+Returns true if all of the bottom row of pixels of object oA are within the region (X1,Y1,X2,Y2).

+See also

+posn

+right.posn

+center.posn

+ diff --git a/help/obj_in_room.html b/help/obj_in_room.html new file mode 100644 index 0000000..219a9c8 --- /dev/null +++ b/help/obj_in_room.html @@ -0,0 +1,17 @@ + + +obj.in.room + +

obj.in.room

+Category

+Test commands / Inventory item commands

+

+Syntax

+

+if (obj.in.room(iA,vB)) { .....

+Description

+

+Returns true if the room number if inventory item iA is equal to vB.

+See also

+has

+ diff --git a/help/obj_status_v.html b/help/obj_status_v.html new file mode 100644 index 0000000..2299b82 --- /dev/null +++ b/help/obj_status_v.html @@ -0,0 +1,16 @@ + + +obj.status.v + +

obj.status.v

+Category

+Debugging commands

+Syntax

+

+obj.status.v(oA);

+Description

+

+Shows stats about an object - its co-ordinates, size, priority and step size.

+See also

+Objects

+ diff --git a/help/object-editor.png b/help/object-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..c0bcd3191fd2082afba0e1baa1c6b75c6d15e485 GIT binary patch literal 9356 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 QTSfpxQA45p(X&_o1Fw)Cy8r+H literal 0 HcmV?d00001 diff --git a/help/object_commands.html b/help/object_commands.html new file mode 100644 index 0000000..d82e289 --- /dev/null +++ b/help/object_commands.html @@ -0,0 +1,80 @@ + + +Object/view commands + +

Object/view commands

+For more information on objects, click here.

+add.to.pic.v

+add.to.pic

+animate.obj

+block

+current.cel

+current.loop

+current.view

+cycle.time

+discard.view.v

+discard.view

+distance

+draw

+end.of.loop

+erase

+fix.loop

+follow.ego

+force.update

+get.dir

+get.posn

+get.priority

+ignore.blocks

+ignore.horizon

+ignore.objs

+last.cel

+load.view.v

+load.view

+move.obj.v

+move.obj

+normal.cycle

+normal.motion

+number.of.loops

+object.on.anything

+object.on.land

+object.on.water

+observe.blocks

+observe.horizon

+observe.objs

+position.v

+position

+release.loop

+release.priority

+reposition.to.v

+reposition.to

+reposition

+reverse.cycle

+reverse.loop

+set.cel.v

+set.cel

+set.dir

+set.horizon

+set.loop.v

+set.loop

+set.priority.v

+set.priority

+set.upper.left

+set.view.v

+set.view

+start.cycling

+start.motion

+start.update

+step.size

+step.time

+stop.cycling

+stop.motion

+stop.update

+unanimate.all

+unblock

+wander

+Test commands

+posn

+obj.in.box

+center.posn

+right.posn

+ diff --git a/help/object_descr.html b/help/object_descr.html new file mode 100644 index 0000000..f79b69d --- /dev/null +++ b/help/object_descr.html @@ -0,0 +1,19 @@ + + +The OBJECT file + +

The OBJECT file

+The OBJECT file contains a list of inventory items (objects) that the player may possess during the game. Each item is numbered, and has a room number assigned to it. This room number is the room in +which the object can be found. +

+It is not necessary to use these room numbers - it is up to the programmer to decide, but if they are used then the obj.in.room command can be used to find out if the object is in the current room +when the player tries to get it. +

+Room 255 is the player's inventory, so any inventory items the player is to have at the start of the game should have their room number set to this.

+Note: Do not confuse inventory objects with screen objects. These are two completely different things. Inventory objects (or "inventory items") are things that the player carries +round with them during the game. Screen objects are views that are displayed on screen and represent things like characters and props. All the commands in the logic programming language +that are called (something).obj refer to screen objects, except for show.obj and show.obj.v. Usually when the word "object" is used in the logic programming documentation it means screen object. +

+You can edit the OBJECT file with the Object editor

+Back to data used by AGI

+ diff --git a/help/object_editor_main.html b/help/object_editor_main.html new file mode 100644 index 0000000..ff76d5d --- /dev/null +++ b/help/object_editor_main.html @@ -0,0 +1,25 @@ + + +Object editor + +

Object editor

+The Object editor allows you to create and edit the object file, which is used to store the names of inventory items available to the player during the game. For more information on the object file, +click here. +

+To load the Object editor, select the option from the "Tools" menu or the toolbar. When you do this, it will load the object file of the current game (if a game is open). You can then open a different +file if you wish. +

+

+Most of the editing is pretty self-explanatory. There are a few things, however than need explanation:

+All objects MUST have a name. The default name for an object that does not have a proper name is '?'. When you delete an object and it is not the last one in the list, it will be replaced with '?'. This +is because moving the other objects up in the list would require re-compilation of all logics that refer to those objects, so it is better to leave the other object numbers as they are. +

+The object file must contain at least one object. A new object file will just contain the object '?'.

+

Encryption

+In early versions of the interpreter (those before 2.411), the object file was not encrypted. The editor allows you to specify whether or not you want to encrypt the file. Just select 'Encrypted file' +from the 'Options' menu. When opening a file, the editor automatically detects whether or not the file is encrypted. +

+

Saving

+Note: When saving a file, it does not necessarily have to be called object. It must have this name, however, for the interpreter to use it.

+Back to contents

+ diff --git a/help/object_on_anything.html b/help/object_on_anything.html new file mode 100644 index 0000000..f87a897 --- /dev/null +++ b/help/object_on_anything.html @@ -0,0 +1,18 @@ + + +object.on.anything + +

object.on.anything

+Category

+Object/view commands

+Syntax

+

+object.on.anything(oA);

+Description

+

+Object oA is allowed to be on land or water.

+See also

+object.on.water

+object.on.land

+Controlling obstacles

+ diff --git a/help/object_on_land.html b/help/object_on_land.html new file mode 100644 index 0000000..2ed676f --- /dev/null +++ b/help/object_on_land.html @@ -0,0 +1,18 @@ + + +object.on.land + +

object.on.land

+Category

+Object/view commands

+Syntax

+

+object.on.land(oA);

+Description

+

+Object oA is not allowed to be on water (pixels with a priority of 3).

+See also

+object.on.water

+object.on.anything

+Controlling obstacles

+ diff --git a/help/object_on_water.html b/help/object_on_water.html new file mode 100644 index 0000000..4a41aff --- /dev/null +++ b/help/object_on_water.html @@ -0,0 +1,18 @@ + + +object.on.water + +

object.on.water

+Category

+Object/view commands

+Syntax

+

+object.on.water(oA);

+Description

+

+Object oA is only allowed to be on water (pixels with a priority of 3).

+See also

+object.on.land

+object.on.anything

+Controlling obstacles

+ diff --git a/help/objects.html b/help/objects.html new file mode 100644 index 0000000..034d246 --- /dev/null +++ b/help/objects.html @@ -0,0 +1,19 @@ + + +Objects + +

Objects

+Objects (sometimes as referred to as "screen objects", and not to be confused with "inventory objects") are what provide the animation in AGI games. They can represent various things such as characters, +background animations or still props. Each object has a view assigned to it, and can be placed anywhere on screen and moved around. +

+Object 0, commonly referred to as "ego", is special. This is the object that the player moves around using the arrow keys.

+Topics

+Initializing objects

+Cycling objects

+Positioning objects

+Moving objects

+Controlling obstacles

+Priorities

+See also

+Object/view commands

+ diff --git a/help/observe_blocks.html b/help/observe_blocks.html new file mode 100644 index 0000000..03c31e8 --- /dev/null +++ b/help/observe_blocks.html @@ -0,0 +1,18 @@ + + +observe.blocks + +

observe.blocks

+Category

+Object/view commands

+Syntax

+

+observe.blocks(oA);

+Description

+

+Object oA is prevented from crossing over conditional barriers (pixels set to colour 1 on the priority screen) and borders of blocks set up with the block command.

+See also

+ignore.blocks

+block

+Controlling obstacles

+ diff --git a/help/observe_horizon.html b/help/observe_horizon.html new file mode 100644 index 0000000..90203bc --- /dev/null +++ b/help/observe_horizon.html @@ -0,0 +1,18 @@ + + +observe.horizon + +

observe.horizon

+Category

+Object/view commands

+Syntax

+

+observe.horizon(oA);

+Description

+

+Object oA is not allowed to go above the horizon.

+See also

+ignore.horizon

+set.horizon

+Controlling obstacles

+ diff --git a/help/observe_objs.html b/help/observe_objs.html new file mode 100644 index 0000000..7eb6d54 --- /dev/null +++ b/help/observe_objs.html @@ -0,0 +1,17 @@ + + +observe.objs + +

observe.objs

+Category

+Object/view commands

+Syntax

+

+observe.objs(oA);

+Description

+

+Object oA is prohibited from moving through other objects, i.e. its baseline is not allowed to touch another object's baseline.

+See also

+ignore.objs

+Controlling obstacles

+ diff --git a/help/open_dialogue.html b/help/open_dialogue.html new file mode 100644 index 0000000..eef6324 --- /dev/null +++ b/help/open_dialogue.html @@ -0,0 +1,18 @@ + + +open.dialogue + +

open.dialogue

+Category

+Display commands

+Syntax

+

+open.dialogue();

+Description

+

+This command supposedly enables the get.string and get.num commands when the prevent.input command has been used, but they seem to be enabled anyway so I am +not sure what the command actually does. +

+See also

+close.dialogue

+ diff --git a/help/opening_games.html b/help/opening_games.html new file mode 100644 index 0000000..37e59f6 --- /dev/null +++ b/help/opening_games.html @@ -0,0 +1,13 @@ + + +Opening games + +

Opening games

+Before you can work on a game, you must open it. To do this, select 'Open' from the 'File' menu and then select directory containing the game you want to edit. This directory must contain a valid AGI +version 2 or version 3 game. +

+Any changes you make to the game will be written to disk whenever you perform an operation such as adding or deleting a resource. In the built-in editors, the game is updated when you save or compile +the resource. +

+Back to contents

+ diff --git a/help/overlay_pic.html b/help/overlay_pic.html new file mode 100644 index 0000000..6ba1f98 --- /dev/null +++ b/help/overlay_pic.html @@ -0,0 +1,23 @@ + + +overlay.pic + +

overlay.pic

+Category

+Picture commands

+Syntax

+

+overlay.pic(vA);

+Description

+

+overlay.pic does the same thing as draw.pic, except that the visual and priority screens are not cleared. This means that picture vA is drawn on top of the existing picture. Note that +because fills only work on white surfaces, fills in picture vA which are not on a white part of the existing picture wont work. It's generally best not to use fills in pictures that you intend to +overlay. +

+Remember to use show.pic to update the screen once the picture has been overlayed.

+Make sure the picture is loaded into memory before overlaying it.

+See also

+draw.pic

+load.pic

+Drawing pictures

+ diff --git a/help/parse.html b/help/parse.html new file mode 100644 index 0000000..bbf9b2a --- /dev/null +++ b/help/parse.html @@ -0,0 +1,15 @@ + + +parse + +

parse

+Category

+String commands

+Syntax

+

+parse(sA);

+Description

+

+Parses string sA as if it were entered by the player.

+See also

+ diff --git a/help/pause.html b/help/pause.html new file mode 100644 index 0000000..3792f65 --- /dev/null +++ b/help/pause.html @@ -0,0 +1,18 @@ + + +pause + +

pause

+Category

+System commands

+Syntax

+

+pause();

+Description

+

+Pauses the game. This appears to be the same as the following command:

+print(" Game paused.\n"

+ "Press Enter to continue.");

+See also

+print

+ diff --git a/help/picture-editor.png b/help/picture-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..9e8393a456b15d5aed563b61802165999c3abd5e GIT binary patch literal 10003 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 H{N4WpY1&ou literal 0 HcmV?d00001 diff --git a/help/picture-viewing.png b/help/picture-viewing.png new file mode 100644 index 0000000000000000000000000000000000000000..8597e8ee5a73ef616bafb13e6738a7c264acf731 GIT binary patch literal 5824 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 Fe*o^Xm^c6c literal 0 HcmV?d00001 diff --git a/help/picture_commands.html b/help/picture_commands.html new file mode 100644 index 0000000..4efec49 --- /dev/null +++ b/help/picture_commands.html @@ -0,0 +1,11 @@ + + +Picture commands + +

Picture commands

+discard.pic

+draw.pic

+load.pic

+overlay.pic

+show.pic

+ diff --git a/help/picture_descr.html b/help/picture_descr.html new file mode 100644 index 0000000..08e1a43 --- /dev/null +++ b/help/picture_descr.html @@ -0,0 +1,24 @@ + + +Picture resources + +

Picture resources

+Picture resources are full-screen images, usually used for backgrounds. They are vector-based rather than bitmaps, which means they are drawn using drawing commands such as lines and +brushes, rather than by plotting pixels. +

+Each picture has two images (screens) - the visual screen and the priority screen. The visual screen is what the player sees when playing the game. Views are placed on top of +the pictures during the game and can be moved around the screen. The priority screen is what makes the game appear to be 3-dimensional. On the AGI screen, there are 12 priority bands in which objects +can be placed. The priority given to different parts of the picture (i.e. the colour of the pixels on the priority screen) determines where in 3-dimensional space objects appear. For example, a tree +placed right at the front of the screen would be given a priority of 15 (the highest priority). A wall which is far away in the background would be given a priority of 4 (the lowest priority). If an +object with a priority of 12 is displayed on the screen, it would be behind the tree but in front of the wall. The priority of a view is usually determined by its y-position. +

+Colours 0, 1, 2 and 3 on the priority screen are used for "control lines" which determine where the ego (the object controlled by the player) can walk.

+ +Partial AGI picture tutorials can be found at the following sites +(note that these links may become unavailable in the future): +

+

http://weremoose.tripod.com/Tutorials.html +

http://www.iki.fi/jterho/agi/ +

+Back to data used by AGI

+ diff --git a/help/picture_editor_main.html b/help/picture_editor_main.html new file mode 100644 index 0000000..15dc232 --- /dev/null +++ b/help/picture_editor_main.html @@ -0,0 +1,236 @@ + + +Picture editor + +

Picture editor

+Note: this help is an updated conversion from the help text of the original (MSDOS) Picedit developed by Lance Ewing. Therefore, the word "I" in this text refers to Lance Ewing. + +

+ +

+ +

+To use the picture editor, simply double-click on a picture resource in the main window or select 'Picture Editor' from the 'Tools' menu or toolbar. You can have several picture editor windows up at a time.

+The picture editor looks like this: (the picture part of the screenshot is cut to reduce the image size)

+ +

+

Components of the picture editor window

+ +

Status line

+ +The status line shows current X position of mouse cursor, current Y position of mouse cursor and priority band that corresponds to the current Y position. The small color box on the right shows priority color that would masks an objects if it were located where the mouse cursor currently is. + +

Drawing area

+ +This is pretty self explanatory. See the tool selection below. + +

Tool selection

+ +The tool buttons +

+Line: This line tool is what has been called the absolute line in the AGI +picture documentation. It draws a line from one point to any other point +on the screen. Once you click on the picture surface, a virtual line +follows the mouse cursor until you click on the next point. This is very +much how most graphics packages work. The virtual line will continue this +behaviour until you press the right hand mouse button on the picture +surface. The tool remains "chosen" and you can continue +drawing lines without re-selecting the tool until you click the secondary +mouse button. The same applies to all the tools. +

The AGI picture code used is 0xF6. +

+Pen: The pen tool is what has been called the relative line in the AGI +picture documentation. I called it pen firstly because its nice and short, +and secondly because when you think about it, the relative line is used for +finer details, which is what I associate with pen drawing. The pen tool +operates very much like the line tool except that it has a restriction on +the length of the line which is reflected by the fact that the virtual line +will only follow the cursor to its boundary. Right clicking turns the tool +off as was mentioned for line above. The AGI picture code used is 0xF7. +

+Step: A strange name for a strange tool. This tool is what I called the +x-corner and y-corner in the AGI picture documentation for want of a better +name. I called it step because the nature of this tool makes it very easy +to draw 'steps'. The behaviour of this tool is a bit different from the +previously mentioned tools in that the destination point must lie on a +certain line. The virtual line once again reflects this and will only let +you draw a line to an acceptable destination. I have combined both the +0xF4 and the 0xF5 picture codes into this one tool. The codes used depends +of the direction taken by the first line. This means that initially you +have a choice of going vertical OR horizontal, but once that first click +is made, the program restrict you to one plane from then on. Right clicking +once again turns the tool off. +

+Fill: This needs no explanation. Choose a colour, click on a white spot and +it fills it in for you. Right clicking on the picture surface once again +turns the tool off. The AGI picture code used is 0xF8. +

+If you click on non-white spot, the area will be re-filled with the new +color. This option is somewhat buggy. Remember: save early, save often. +

+Brush: This tool is the most involved tool. It corresponds with codes 0xF9 +and 0xFA. An artist will set up the desired brush characteristics with the +brush state interface, select the brush tool, and then start using it. It +doesn't necessarily have to be done in this order, the program is quite +robust in this respect. You can even change the brush characteristics half +way through using the brush tool and every thing will be taken care of. Once +again, right clicking on the picture surface disables the tool. AGI picture +code 0xF9 is used to say what characteristics to give the brush, and code +0xFA gives the positions and pattern if it is needed. +

+ +

The palette buttons

+ +The palette buttons are used to change the colour of the visual colour and +the priority colour. Left clicking on the palette bar changes the visual +colour. Right clicking on the palette bar changes the priority colour. The +AGI picture codes used are 0xF0 for visual colour, and 0xF2 for priority +colour. +

+The 'off' button is directly related to the palette buttons. It turns off +visual or priority drawing depending on which mouse button is pressed. The +left mouse button disabled visual drawing, the right mouse button disables +priority drawing. It is important to realise that even though both the +visual and priority colours may be turned off, the buffer still accepts +drawing actions and places them in the buffer, they just won't be able to +be seen on the picture surface or in AGI when you final incorporate it +into an AGI program. Usually the off button is used to turn off one of +the colours so that work can be done on only one of the screens. The AGI +picture codes used are 0xF1 for disabling the visual colour and 0xF3 for +disabling the priority colour. + +

The brush state interface

+ + This was briefly mentioned in the brush tool section. What it does is allow +you to set the size of the brush (with the up and down arrows), set the +shape of the brush (either square or circle), and set whether it is solid +or like a spray. The brush state interface lies between the off button and +the navigation buttons. When the brush tool is used, the state shown by this +interface is what is used. + +

The navigation buttons and buffer position edit field

+ + +The navigation buttons allow the artist to navigate backwards and forwards +through the picture code action by action. You cannot end up in the middle +of the data for a drawing action because this could potentially cause all +sorts of problems. The four navigation buttons operate as follows: +

+

    +
  • Home (<<): This button takes you to the start of the picture code buffer. +
  • Left (<) : This button takes you back to the start of the previous drawing + action. +
  • Right (>): This button take you to the start of the next drawing action. +
  • End (>>) : This button takes you to the end of the picture code. +
+

+ As the navigation buttons are used, the value in the buffer position edit +field will change. This field gives the offset in bytes from the start of +the picture code. You can click on this field and enter a value to go +directly to this position in the buffer. This means that you don't have to +waste time using the navigation buttons. Of course, the value you enter might +be in the middle of a drawing action. For this reason, the program searches +backwards from the position entered until it finds the start of the drawing +action that includes the entered position as part of its data. It would not +do to allow data to be added to the picture code in the middle of an existing +drawing action. +

+ The navigation buttons and buffer position edit field allow you to go back +and make changes to existing data or insert something that you forgot to +draw. As we shall see by the next section, in combination with the delete +button, these features can be very powerful. +

+ +

The Delete button

+ + We all make mistakes and this button is provided because of that fact. If +you make a mistake and want to remove it, all you have to do is go back to +that point in the picture code and push the delete button. Warning!! This +will delete the whole action. This means that if the mistake is only in +part of the action, you will have to redraw the whole action to fix it up. +It is probably a good idea to split big actions up into smaller segments +because of this. Most actions are reasonably short anyway. This editor is +very much drawing action based as you have probably gathered by now. +

+ The power of using this button is that you can experiment with various +things such as the colour of an object like a table top. All you would do is +navigate to the 0xF0 code that sets the colour of the table top, push the +delete button, and the push the desired new colour on the palette bar. To see +the change, move back to the end of the picture. +

+ +

The Wipe button

+ +Wipes everything starting from the current position up to the end of the picture. + +

The buffer contents display field

+You are probably asking how you are supposed to know what action you are +currently at when you are navigating through the picture code buffer. The +purpose of the buffer contents display field is to make this known to you. +Of course, the picture surface also reflects where you are since it only +draws up to the point that you are at in the buffer. However, knowing exactly +where you are requires a look at the actual data itself which is what this +field displays. The drawing action that you are currently at is the one that +starts at the left hand side of the buffer contents display field. The field +shows six bytes. For this reason, it is sometimes possible to see the start +of the next action. This is why I've made the distinction that the current +drawing action is the one that starts at the left hand side. You can also +use the 'View Data' option in the 'Utilities' menu to look at the data currently +in the picture code buffer. + +

View Data

+ +The 'View Data' option is quite useful. It allows you to browse through the +data contained in the picture code buffer. You can use this option to get +a better idea of where abouts you currently are in the picture code. +You can turn on comments to see what drawing actions correspond to hex codes. + +

The background tracing option

+ + This option has the potential to save artists a lot of time, and can make +artists out of laymen. You can specify a BMP file (or any other file format +supported by QT) to use as the background +in order to trace various details on it when drawing a picture. This facility +treats the white visual colour and red priority colour as a transparent +colour. All other colours are drawn on top of this image. Initially you start +with the whole image being displayed on both the visual and priority screens. +As you draw the trace the background image, it will gradually disappear until +only the white parts of your final picture will be showing the background +image. +

+The background image should have a width of 320 pixels and height of 168 pixels. It can be bigger, but the rest of the image will be cut off. +

+When you load the background image, the checkbutton 'Background' is automatically switched on. At any stage you can switch back to normal to see the white parts of the screen as they should be. + +

The priority lines

+ +This option allows to turn on/off the priority lines. + +

Zoom in/out

+You can zoom in or out of the picture to a maximum of 4x. The default zoom is 2x.

+ +

Keyboard shortcuts

+

+

+ L, l, F1: Line tool
+ P, p, F2: Pen tool
+ S, s, F3: Step tool
+ F, f, F4: Fill tool
+ B, b, F5: Brush tool
+
+ Home, Left, Right, and End keys:  Same as the navigation buttons.
+
+ Del key: Same as the delete button
+
+ F10: Toggle the background picture
+
+ TAB: switch between visual and priority screens
+
+

Back to contents

+ \ No newline at end of file diff --git a/help/player_control.html b/help/player_control.html new file mode 100644 index 0000000..0b433a2 --- /dev/null +++ b/help/player_control.html @@ -0,0 +1,16 @@ + + +player.control + +

player.control

+Category

+System commands

+Syntax

+

+player.control();

+Description

+

+Allows the player to move ego (object 0) around with the arrow keys, after they have been prevented from doing so by the program.control command.

+See also

+program.control

+ diff --git a/help/pop_script.html b/help/pop_script.html new file mode 100644 index 0000000..e5b0597 --- /dev/null +++ b/help/pop_script.html @@ -0,0 +1,16 @@ + + +pop.script + +

pop.script

+Category

+Extra commands

+Syntax

+

+pop.script();

+Description

+

+This command is used if you want to load something and then unload it, so it does not use too much of the interpreter script. +See also

+push.script

+ diff --git a/help/position.html b/help/position.html new file mode 100644 index 0000000..57d5d9d --- /dev/null +++ b/help/position.html @@ -0,0 +1,22 @@ + + +position + +

position

+Category

+Object/view commands

+Syntax

+

+position(oA,X,Y);

+Description

+

+The position on the screen of object oA is changed to X,Y. The position command should only be used if the object is not on screen (either it has not been drawn yet, or it has been erased). To change +the position of an object that is already on screen, use the reposition.to command. +

+See also

+position.v

+reposition.to

+reposition.to.v

+reposition

+Positioning objects

+ diff --git a/help/position_v.html b/help/position_v.html new file mode 100644 index 0000000..84adba4 --- /dev/null +++ b/help/position_v.html @@ -0,0 +1,22 @@ + + +position.v + +

position.v

+Category

+Object/view commands

+Syntax

+

+position.v(oA,vX,vY);

+Description

+

+The position on the screen of object oA is changed to vX,vY. The position command should only be used if the object is not on screen (either it has not been drawn yet, or it has been erased). To +change the position of an object that is already on screen, use the reposition.to.v command. +

+See also

+position

+reposition.to

+reposition.to.v

+reposition

+Positioning objects

+ diff --git a/help/positioning_objects.html b/help/positioning_objects.html new file mode 100644 index 0000000..5e986ba --- /dev/null +++ b/help/positioning_objects.html @@ -0,0 +1,17 @@ + + +Positioning objects + +

Positioning objects

+There are five commands which allow you to position objects on screen:

+position

+position.v

+reposition

+reposition.to.v

+reposition

+Also, the get.posn command will store an objects position in two variables.

+Note: The position of an object is always taken from its bottom-left corner.

+See also

+

+Objects

+ diff --git a/help/posn.html b/help/posn.html new file mode 100644 index 0000000..50a9bfe --- /dev/null +++ b/help/posn.html @@ -0,0 +1,19 @@ + + +posn + +

posn

+Category

+Test commands / Object/view commands

+

+Syntax

+

+if (posn(oA,X1,Y1,X2,Y2)) { .....

+Description

+

+Returns true if the co-ordinates of the bottom-left pixel of object oA are within the region (X1,Y1,X2,Y2).

+See also

+right.posn

+center.posn

+obj.in.box

+ diff --git a/help/prevent_input.html b/help/prevent_input.html new file mode 100644 index 0000000..994adbb --- /dev/null +++ b/help/prevent_input.html @@ -0,0 +1,16 @@ + + +prevent.input + +

prevent.input

+Category

+System commands

+Syntax

+

+prevent.input();

+Description

+

+Hides the input prompt and prevents the player from entering input.

+See also

+accept.input

+ diff --git a/help/pridemo-1.pmg b/help/pridemo-1.pmg new file mode 100644 index 0000000000000000000000000000000000000000..001cf07591c3ff2e7aa94ce85450d0fb4b26d794 GIT binary patch literal 25106 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 literal 0 HcmV?d00001 diff --git a/help/pridemo-1.png b/help/pridemo-1.png new file mode 100644 index 0000000000000000000000000000000000000000..68729b14b7cbd7717ebbe2ebcead4f91205f701c GIT binary patch literal 2277 zcmVV>IGcGYOVIUwJ#ydI(E>d`DDKc+fLCp&l2sA(vAV}$}e0>%D9Ug!LDfwl3o#3Q@UR$3)4)gasf6uMY z!WS>SIFeHCF+GgW#3vmH$uZw4r&ATr$SI|Qgk z84X28re(uWLQ=l;>Bab}EzhvBit%N{K{8FhUQDM3Fch_#kl~W};_(Ul{3EDy7s zzts@07Oc=(OTt>AmD+Q?NTb&mU~<2-%B-C4(9M-*UE;3eP_}fAqW&GR_%G)mB+|1gVF%7xi-O zDkM((qs~awZBiQdCvTsVc6~&fTDMZVAB}KYaxGI@LJeP*?=8<&(!a7y2kCpl$&^l) zdRWrdi|M^_j1;Umg^kh&yTA+pA7po(yG>pE=WlHZV-Dd+>6!$JwoNA;U{@j2zWnp~ z0D!MIYtLbN8OBJ*skj`78_imVB=&O%M@rEyHKb=$GKU}d0C|@YoNALP`IqWBsAAbT z0^fO4HElzn^IXKZNqP6bsqbm)b#9yVOvUyeL9#ZbwLsgY`?R zC?Xz5+7INVjNPR2da5{6J_)UqJE;I`*>|O=D|~#TEoX!>r?Iptzj*CEQ0s|mH4EzK zwVKGp@z6+FbJTg(p(;B)Hnoz56=zC;koLaR4r})4#e)tU=|P5cA-nEA^B{#RNx~lb zu9&vjQSay>z=|Ci3+!ilt1r_2E}H%D=^;L~W;r-V@et}UUB3BBgWFq5q4fWHpo7j% z34T1J-RE~Iq#pq^&?xvh6|ycKnuYfGdm|*j%QI5Zj>5k5QB-S9|F?bBUkYdKsLuvh z_kKDJtv(wK#!o}pnOLqhj_iGGs)1gF>tGyt{dCdfowE~K`RgqMM<~?!Z%IWt(ocry zo$`4Vr=6WZI+v6@>y$>XfyVoMvj2D4o}Vm-tXrY?4<%t*T9)uaVWhZrWH}9*ow8sQ z6@=`|oufvSVI8TF;XKQ)vecs-&%W__Zkdk67h_q+u^I62`>vbS=zjsAL8hEW9l{@t zqQzG+;hPHzIAc^?eTLJRVLLk|gZdsTR_=t!7dvLJI zG}Z;?i{PEHClzoPTK(X`XMBnrc~1HI;dCSmPMu4`!8hvtNB{tEU4A|vNJ!56-b%2P zFy1D}c?co(ULU*>&%7+B?nn=-c<|de^1yqr5ib^r!;X*|<+L#hbt{dgj?)|>v{u8V zgn>*UeU7nkcjh>_b7ZTIKI@2$<{CMOh4f!~_I8HUKtkG`N#o9uy~7#*;VsKW-3ZC= zRpRbAXCA<235Xvr@`;D`c?{)9y#-@y(@bVZz8C8fj;ko7hq3@hapHObu$41DmO#i_ zwGvDCviW~DI|etGp+c($oS?edKFV`^cS^G(cK<1)B6SBCX?EV~;Rk7;(TVsMkrx!Zg;=$eUl(9%e}EJ{uu>>3r8h8baF+`O|We zjvQN5&y^aAw46r`tzAhNL&?b!(!V=7^(Ozri4q2JHi;tu$c^I2u*01^f+-(S%`F26r7f53JIk&n36 zsz=_t1r$3_%K`v!|7|p?RBi7|X_I<+`!{uWA0L&bn*R#7SBMiKJ6@1@AFHUpGbQI% z){?gJx>n45`FW>9k*I?Pa7qB1)#Wiy97$2lspfp$X8`#4d;q|Os5kk{lxe2N^ZP@%XJ(XL5(B(qRU!q9(m))Uf4J?(2FlaM~r`T zT+`vycY0yRk$q)Nshq2X_;XXF!x+H|0nc)721U_%_LZ|s#-O-xQ6Wc$4t<(X+0h$K z_9CZ7ZHTqfobO9&_P=hKE%qYDr<^v0J(eRWIqwUA=!p@Nmnl$k-tTt+Se7O6O}`8~ z{Mc!H$Qj{_54Cf!EV4iO-H$*BkMXS$dod=Kk2eXW|*a%to zg+tz+YQ|zOt6%Q`FhkAEYCjRZ3dw(qm{kb?Y}@C4H&qMGobnTH>SE8m}L4S-kcy>dX5-zqRCKN{%B-Iy?N*Ak|;B zfhs=O2iVv1mjcG1+RqM3p@urWcriW)4@E)K9GMp0=S)i;_RA-mb$0Sx81Uf57!SVm z(Q9SnO~RPAaux|GePthJq;MM3tVCz|BYI)ay@ykZ^*q0409Xu{TUH3IQpqU^)0NMY zG-X1jt1wZ$=AK**!kL8X3wvM6h2)pe-T`=vGe*Ty&Yg9wJ7m>Ak1Qc(R+f_%vY>c< zN=Tt6=T=2E@d8JdP@4)5x}FkB(eUMy99cd9I3=Xu$eHf#$M8BkCu*dv!neUG3KP>|zUk&n1Z2$lO2XskIMF-FX0SW{Z;P>N&00000NkvXXu0mjfJ?=lf literal 0 HcmV?d00001 diff --git a/help/pridemo-2.png b/help/pridemo-2.png new file mode 100644 index 0000000000000000000000000000000000000000..34f78c61d22277937c3c248037013500bcb925d4 GIT binary patch literal 1356 zcmV-S1+)5zP)V>IGcGYOVIUwJ(8m^5QXs+fsf{30w2NQ9BG3M zd<23G=4b@e)CTR{5hDw?KtHXg_eCz3Jwx&Fx`hDww0tcCX`i>+8$i-Pkswec2owpz zSbGD0av#tCU*DFw;+C{UWs$Bna)eXK(~o`Hm`e>A6WM3luGjC^(^T&NCQf8Nc{X$D zYTG8a)MO&dmg>f=@D?W*ZrL|$)PDzmvZ&+-&)MJN&kiUffoLExmhAwCX#mm**A zsklUSk@Z5}XXWQZ{M!A^4n@Z9=u6~q^oWcjbR<#~#)@eL4t7AGNDwFz1d2>dt?9b) z)7ZV+7v32S}LOK$e zZ@0P^gn1dOF)YY)p~wiV$#bE|Xsjs|IBErfiHtz9_~E>^0}}}XMS?()Ah1V9V6!_4 zOe6>t2?9&23d==RU?M?aB41!XivmRkX+@zxkxyt#p+J!&aCO44_(Kj}aKW2EZx5GnMa z6E%??)m7~C$kh$Xx8-tMF10o#mfJGl%q(qLohNsiQ)i0=ORKoF*)@H0^3J{E6<-td zNPT>B9~M39d?C_WE;UuOPo1hnhIGcZ(vpWoZ#uzGKUN98*4vK!tR@6BNS=-lYh!bn zWoYWCZT&nFJdrP$zF*#kwo7qzBGaPDWv$c1wxsr*$W7b>$iCFdi4;P)v^iyCQ>qD( zF0NFYB3@a zN-B=RTDg3bR*~mx^WXOqT$0)RI94dHQ#B!wGo#upo(+r)EfW-}&*)xo%BfHJi)gDJ zX`fa~t58&=-y^p(=ayN`gR7|!g;HRt(`O}82$fSI_9+hiG@CC;^G++|*7>NbY2^v_ zXG%+wyKAl* + +print + +

print

+Category

+Display commands

+Syntax

+

+print(mA);

+Description

+

+Message A is displayed in a window. If f15 is not set, then the window remains for 1/2 * v21 seconds (provided v21 is greater than 0) or until a key is pressed. If f15 is set, then the window remains +until a close.window command is issued. +

+See also

+print.v

+print.at

+print.at.v

+close.window

+ diff --git a/help/print_at.html b/help/print_at.html new file mode 100644 index 0000000..eec8d13 --- /dev/null +++ b/help/print_at.html @@ -0,0 +1,21 @@ + + +print.at + +

print.at

+Category

+Display commands

+Syntax

+

+print.at(mA,X,Y,W);

+Description

+

+Message A is displayed in a window with top left coordinates of X,Y and width W. If f15 is not set, then the window remains for 1/2 * v21 seconds (provided v21 is greater than 0) or until a key is +pressed. If f15 is set, then the window remains until a close.window command is issued. +

+See also

+print

+print.v

+print.at.v

+close.window

+ diff --git a/help/print_at_v.html b/help/print_at_v.html new file mode 100644 index 0000000..bcdc861 --- /dev/null +++ b/help/print_at_v.html @@ -0,0 +1,21 @@ + + +print.at.v + +

print.at.v

+Category

+Display commands

+Syntax

+

+print.at.v(vA,vX,vY,vW);

+Description

+

+Message number vA is displayed in a window with top left coordinates of vX,vY and width vW. If f15 is not set, then the window remains for 1/2 * v21 seconds (provided v21 is greater than 0) or until +a key is pressed. If f15 is set, then the window remains until a close.window command is issued. +

+See also

+print

+print.v

+print.at

+close.window

+ diff --git a/help/print_v.html b/help/print_v.html new file mode 100644 index 0000000..1b986d2 --- /dev/null +++ b/help/print_v.html @@ -0,0 +1,21 @@ + + +print.v + +

print.v

+Category

+Display commands

+Syntax

+

+print.v(vA);

+Description

+

+Message number vA is displayed in a window. If f15 is not set, then the window remains for 1/2 * v21 seconds (provided v21 is greater than 0) or until a key is pressed. If f15 is set, then the window +remains until a close.window command is issued. +

+See also

+print

+print.at

+print.at.v

+close.window

+ diff --git a/help/priorities.html b/help/priorities.html new file mode 100644 index 0000000..4b05515 --- /dev/null +++ b/help/priorities.html @@ -0,0 +1,47 @@ + + +Priorities + +

Priorities

+The AGI screen is divided vertically into 12 priority bands (4-15). Objects with a higher priority are displayed on top of objects with a lower priority. Different parts of a picture can also be +given different priorities. So something in the far distance would have a priority of 4 (everything else would go on top of this) and something right at the front of the screen would have a priority +of 15 (nothing will go on top of this except objects with a priority of 15). +

+This is best explained graphically:

+

+Here you can see both the visual and priority screens. As you can see, ego has a priority of 13 (magenta) but the bottom part of ego is on a part of the screen with a priority of 15 (white). Thus, +that part of ego is not drawn. The floor and some of the walls have a priority of 4 (red) because nothing needs to be drawn behind them. +

+If the priority of an object and the part of the screen it is on are the same, the object goes on top. If two objects that have the same priority overlap, the object with the higher number goes on +top. +

+Normally, the priority of an object is determined by its vertical position on screen:

+

+Priority Y Range
+-----------------
+4        0-47
+5        48-59
+6        60-71
+7        72-83
+8        84-95
+9        96-107
+10       108-119
+11       120-131
+12       132-143
+13       144-155
+14       156-167
+15       -
+
+(note that 167 is the max. Y value an object can have)

+To set an object's priority so it will remain constant wherever the object is on screen, use the set.priority or set.priority.v commands. To change it back so the +priority is dependent on the object's position, use the release.priority command. +

+An object's priority can be determined using the get.priority command.

+See also

+

+set.priority

+set.priority.v

+release.priority

+get.priority

+Objects

+ diff --git a/help/program_control.html b/help/program_control.html new file mode 100644 index 0000000..dbb0ae1 --- /dev/null +++ b/help/program_control.html @@ -0,0 +1,19 @@ + + +program.control + +

program.control

+Category

+System commands

+Syntax

+

+program.control();

+Description

+

+Prevents the player from moving ego (object 0) around with the arrow keys. After this command has been executed, ego can only be moved by using the various object movement commands that are available +such as move.obj. If ego is already moving, it continues in its current direction. +

+The player can be given control of ego again by using the player.control command.

+See also

+player.control

+ diff --git a/help/project_status.html b/help/project_status.html new file mode 100644 index 0000000..556ed05 --- /dev/null +++ b/help/project_status.html @@ -0,0 +1,13 @@ + + +Project status + +

Project Status

+Since February 1998, I have not done any work on AGI Studio as I have lost interest in AGI. However in April 1999 I discovered there was a group of people who were interested in further developing +the program, to add features to it that were not in existing versions. Therefore, I decided to release the source code for the program. +

+This release, version 1.31a, is available at http://www.ozemail.com.au/~ptrkelly/agi with the accompanying source code. See the file README.TXT for more information about the source code.

+This program may be distributed under the terms of the GNU General Public License. For details, see the file COPYING.TXT that comes with the program.

+I will add links to the page mentioned above to other versions of AGI Studio as they become available.

+-Peter Kelly, 1 May 1999

+ diff --git a/help/push_script.html b/help/push_script.html new file mode 100644 index 0000000..414072d --- /dev/null +++ b/help/push_script.html @@ -0,0 +1,16 @@ + + +push.script + +

push.script

+Category

+Extra commands

+Syntax

+

+push.script();

+Description

+

+This command is used if you want to load something and then unload it, so it does not use too much of the interpreter script. +See also

+pop.script

+ diff --git a/help/put.html b/help/put.html new file mode 100644 index 0000000..cbf912c --- /dev/null +++ b/help/put.html @@ -0,0 +1,16 @@ + + +put + +

put

+Category

+Inventory item commands

+Syntax

+

+put(iITEM,ROOM);

+Description

+

+The room number of inventory item iITEM is set to ROOM.

+See also

+put.v

+ diff --git a/help/put_v.html b/help/put_v.html new file mode 100644 index 0000000..cb75446 --- /dev/null +++ b/help/put_v.html @@ -0,0 +1,16 @@ + + +put.v + +

put.v

+Category

+Inventory item commands

+Syntax

+

+put.v(vITEM,vROOM);

+Description

+

+The room number of inventory item vITEM is set to vROOM.

+See also

+put

+ diff --git a/help/quit.html b/help/quit.html new file mode 100644 index 0000000..740bca7 --- /dev/null +++ b/help/quit.html @@ -0,0 +1,15 @@ + + +quit + +

quit

+Category

+System commands

+Syntax

+

+quit(nCONFIRM);

+Description

+

+Quits the game. If nCONFORM is 1, then the game will quit instantly. If nCONFIRM is 0 (or anything else), the user will be prompted first.

+See also

+ diff --git a/help/random.html b/help/random.html new file mode 100644 index 0000000..6b2cb99 --- /dev/null +++ b/help/random.html @@ -0,0 +1,15 @@ + + +random + +

random

+Category

+Mathematical commands

+Syntax

+

+random(A,B,vC);

+Description

+

+The value of vC is set to a random number between A and B. If A is greater than B, then the number chosen is in the 0-255 range.

+See also

+ diff --git a/help/rebuilding_vol_files.html b/help/rebuilding_vol_files.html new file mode 100644 index 0000000..4f5d042 --- /dev/null +++ b/help/rebuilding_vol_files.html @@ -0,0 +1,16 @@ + + +Rebuilding the VOL files + +

Rebuilding the VOL files

+This is the process of taking all the resources in a game and putting them in new VOL files. The time it takes depends on the size of the game, whether or not the resources are compressed, and the +speed of your computer. Usually its between 1 and 20 seconds. +

+Note that the original AGI games were designed to be able to run from 360k floppy disks, where each VOL file went on a different disk. Because of this, each resource was carefully put on the right +disk to minimise disk-swapping. When AGI Studio rebuilds the VOL files, it does not take any of this into account. This will not be a problem unless you then want to go and run the game off 360k +floppies (the rebuilt files will may be too big to fit anyway). +

+In version 3 games, the resources are not compressed when the VOL files are rebuilt so the game will be a bit bigger if it was previously compressed.

+To rebuild the VOL files, select 'Rebuild VOL files' from the 'Resource' menu.

+Back to contents

+ diff --git a/help/release_key.html b/help/release_key.html new file mode 100644 index 0000000..32ddeee --- /dev/null +++ b/help/release_key.html @@ -0,0 +1,16 @@ + + +release.key + +

release.key

+Category

+Extra commands

+Syntax

+

+release.key();

+Description

+

+This command restablishes the default control of Ego. It is normally used after a call to hold.key().

+See also

+hold.key

+ diff --git a/help/release_loop.html b/help/release_loop.html new file mode 100644 index 0000000..0d85c99 --- /dev/null +++ b/help/release_loop.html @@ -0,0 +1,17 @@ + + +release.loop + +

release.loop

+Category

+Object/view commands

+Syntax

+

+release.loop(oA);

+Description

+

+This enables the interpreter to choose the loop number of an object based on its direction.

+See also

+fix.loop

+Cycling objects

+ diff --git a/help/release_priority.html b/help/release_priority.html new file mode 100644 index 0000000..516f70c --- /dev/null +++ b/help/release_priority.html @@ -0,0 +1,18 @@ + + +release.priority + +

release.priority

+Category

+Object/view commands

+Syntax

+

+release.priority(oA);

+Description

+

+If object oAs priority was previously set, it is released which means that the priority now depends on the position of the object.

+See also

+set.priority

+set.priority.v

+Priorities

+ diff --git a/help/renumbering_resources.html b/help/renumbering_resources.html new file mode 100644 index 0000000..9ba05f5 --- /dev/null +++ b/help/renumbering_resources.html @@ -0,0 +1,8 @@ + + +Renumbering resources + +

Renumbering resources

+To renumber a resource, select the resource you wish to renumber and select 'Renumber' from the 'Resource' menu.

+Back to contents

+ diff --git a/help/reposition.html b/help/reposition.html new file mode 100644 index 0000000..3b9eaad --- /dev/null +++ b/help/reposition.html @@ -0,0 +1,27 @@ + + +reposition + +

reposition

+Category

+Object/view commands

+Syntax

+

+reposition(oA,vDX,vDY);

+Description

+

+Object oA is repositioned relative to its current co-ordinates. Its new co-ordinates are X+vDX,Y+vDY where X,Y is its current position. If vDX or vDY are greater than 127, they are treated as a +negative number (vDX-256 or vDY-256). +

+For example:

+v254 = 5;

+v255 = 252;

+reposition(o1,v254,v255)

+would reposition object 1 to X+5,Y-4.

+See also

+reposition.to

+reposition.to.v

+position

+position.v

+Positioning objects

+ diff --git a/help/reposition_to.html b/help/reposition_to.html new file mode 100644 index 0000000..e3d094d --- /dev/null +++ b/help/reposition_to.html @@ -0,0 +1,22 @@ + + +reposition.to + +

reposition.to

+Category

+Object/view commands

+Syntax

+

+reposition.to(oA,X,Y);

+Description

+

+The position on the screen of object oA is changed to X,Y. The reposition.to command should be used for objects that are currently on the screen. reposition.to does the same job as +position, but it erases the object before moving it and draws it again afterwards. +

+See also

+reposition.to.v

+reposition

+position

+position.v

+Positioning objects

+ diff --git a/help/reposition_to_v.html b/help/reposition_to_v.html new file mode 100644 index 0000000..5da74c9 --- /dev/null +++ b/help/reposition_to_v.html @@ -0,0 +1,22 @@ + + +reposition.to.v + +

reposition.to.v

+Category

+Object/view commands

+Syntax

+

+reposition.to.v(oA,vX,vY);

+Description

+

+The position on the screen of object oA is changed to vX,vY. The reposition.to command should be used for objects that are currently on the screen. reposition.to.v does the same job as +position.v, but it erases the object before moving it and draws it again afterwards. +

+See also

+reposition.to

+reposition

+position

+position.v

+Positioning objects

+ diff --git a/help/reset.html b/help/reset.html new file mode 100644 index 0000000..8de9719 --- /dev/null +++ b/help/reset.html @@ -0,0 +1,16 @@ + + +reset + +

reset

+Category

+Flag commads

+Syntax

+

+reset(fA);

+Description

+

+Flag fA is reset.

+See also

+reset.v

+ diff --git a/help/reset_scan_start.html b/help/reset_scan_start.html new file mode 100644 index 0000000..5584fbd --- /dev/null +++ b/help/reset_scan_start.html @@ -0,0 +1,16 @@ + + +reset.scan.start + +

reset.scan.start

+Category

+Control flow commands

+Syntax

+

+reset.scan.start();

+Description

+

+Tells the interpreter to start execution of the logic from the start of the logic.

+See also

+set.scan.start

+ diff --git a/help/reset_v.html b/help/reset_v.html new file mode 100644 index 0000000..c8869a2 --- /dev/null +++ b/help/reset_v.html @@ -0,0 +1,16 @@ + + +reset.v + +

reset.v

+Category

+Flag commads

+Syntax

+

+reset.v(vA);

+Description

+

+Flag fB (where B is the value of vA) is reset.

+See also

+reset

+ diff --git a/help/restart_game.html b/help/restart_game.html new file mode 100644 index 0000000..3e9951b --- /dev/null +++ b/help/restart_game.html @@ -0,0 +1,15 @@ + + +restart.game + +

restart.game

+Category

+System commands

+Syntax

+

+restart.game();

+Description

+

+Restarts the game, taking the player back to the beginning.

+See also

+ diff --git a/help/restore_game.html b/help/restore_game.html new file mode 100644 index 0000000..6e46b2e --- /dev/null +++ b/help/restore_game.html @@ -0,0 +1,18 @@ + + +restore.game + +

restore.game

+Category

+System commands

+Syntax

+

+restore.game();

+Description

+

+Restores the game, which basically means reading information from a file (which was saved earlier) about the current status of everything in the game. The user is prompted for a saved game directory, +and then chooses from up to 12 available saved games. +

+See also

+save.game

+ diff --git a/help/return.html b/help/return.html new file mode 100644 index 0000000..c9772ab --- /dev/null +++ b/help/return.html @@ -0,0 +1,16 @@ + + +return + +

return

+Category

+Control flow commands

+Syntax

+

+return();

+Description

+

+Ends execution of the current logic and returns to the logic that called it (or in the case of logic 0, goes on to the next interpreter cycle).

+This command is required at the end of every logic.

+See also

+ diff --git a/help/reverse_cycle.html b/help/reverse_cycle.html new file mode 100644 index 0000000..54d2271 --- /dev/null +++ b/help/reverse_cycle.html @@ -0,0 +1,19 @@ + + +reverse.cycle + +

reverse.cycle

+Category

+Object/view commands

+Syntax

+

+reverse.cycle(oA);

+Description

+

+This tells the interpeter to cycle object oA in reverse order, so the cels are shown from last to first. To turn cycling off, use the stop.cycling command.

+See also

+normal.cycle

+stop.cycling

+start.cycling

+Cycling objects

+ diff --git a/help/reverse_loop.html b/help/reverse_loop.html new file mode 100644 index 0000000..4f833c5 --- /dev/null +++ b/help/reverse_loop.html @@ -0,0 +1,17 @@ + + +reverse.loop + +

reverse.loop

+Category

+Object/view commands

+Syntax

+

+end.of.loop(oA,fB);

+Description

+

+Object oA is cycled in reverse order until the first cel in the loop is reached. Flag fB is reset when the command is issued, and when the first cel is displayed fB is set.

+See also

+end.of.loop

+Cycling objects

+ diff --git a/help/right_posn.html b/help/right_posn.html new file mode 100644 index 0000000..dbec401 --- /dev/null +++ b/help/right_posn.html @@ -0,0 +1,19 @@ + + +right.posn + +

right.posn

+Category

+Test commands / Object/view commands

+

+Syntax

+

+if (right.posn(oA,X1,Y1,X2,Y2)) { .....

+Description

+

+Returns true if the co-ordinates of the bottom-right pixel of object oA are within the region (X1,Y1,X2,Y2).

+See also

+posn

+center.posn

+obj.in.box

+ diff --git a/help/rindirect.html b/help/rindirect.html new file mode 100644 index 0000000..bf44a21 --- /dev/null +++ b/help/rindirect.html @@ -0,0 +1,18 @@ + + +rindirect + +

rindirect

+Category

+Mathematical commands

+Syntax

+

+rindirect(vA,vB);

+vA = *vB;

+Description

+

+The value of vA is set to vC (where C is the value of vB).

+See also

+lindirectv

+lindirectn

+ diff --git a/help/said.html b/help/said.html new file mode 100644 index 0000000..d968b07 --- /dev/null +++ b/help/said.html @@ -0,0 +1,36 @@ + + +said + +

said

+Category

+Test commands

+

+Syntax

+

+if (said("word1","word2"...."wordn")) { .....

+Description

+

+The said test command is different to all other commands in the language in that it accepts a special type of parameter and can have any number of parameters. It is used to test if the player has +entered certain words. +

+First, the process of parsing player input needs to be explained. When the player enters a command, the interpreter does the following things with it:

+

    +
  • Removes certain punctuation characters +
  • Assigns each word entered a number starting from 1. When doing this, it tries to find the longest sequence of characters that match a word in the WORDS.TOK file (so for example if the words "door", +"knob" and "door knob" were in the WORDS.TOK file and the player entered "turn door knob" then the words would be "turn" and "door knob" instead of "turn", "door" and "knob"). Words in group 0 (usually things like +"a", "my", "the") are skipped (not assigned numbers). +
  • If one or more words that are not in the WORDS.TOK file are found, it will set v9 (unknown_word_no in the template game) to the first unknown word.

    +Note: The above is based purely on observation. I am not sure if the interpreter does exactly this, or in this order.

    +Once the player input has been received, flag 2 (input_recieved in the template game) is set and flag 4 (input_parsed in the template game) is reset.

    +When the said test command is used, it goes through each word given as a parameter and compares it with the corresponding word entered by the player. If they are the same (or are in the same word +group), then it continues onto the next word. The comparison is not case sensitive. If all the words are the same, and there are no entered words left over, then the said command returns true and +sets flag 4. +

    +There are a couple of special word groups:

    +Word group 1: "anyword" - if this word is given as a parameter, then any word will do. So if you test for said("eat","anyword") then the result will be true if the player enters "eat cake", "eat chocolate", +"eat worm", "eat sword", etc. +

    +Word group 9999: "rol" (rest of line) - this means the rest of the line. If you test for said("kill","rol") then the result will be true if the player enters "kill lion", "kill lion with sword", etc.

    + + diff --git a/help/save_game.html b/help/save_game.html new file mode 100644 index 0000000..309951f --- /dev/null +++ b/help/save_game.html @@ -0,0 +1,18 @@ + + +save.game + +

    save.game

    +Category

    +System commands

    +Syntax

    +

    +save.game();

    +Description

    +

    +Saves the game, which basically means writing all the information about the current status of everything in the game to a file so that it can be restored later. The user is prompted for a saved game +directory, and then is asked to choose from one of 12 save game slots to save the game in. +

    +See also

    +restore.game

    + diff --git a/help/script_buffer.html b/help/script_buffer.html new file mode 100644 index 0000000..5da948d --- /dev/null +++ b/help/script_buffer.html @@ -0,0 +1,21 @@ + + +The script buffer + +

    The script buffer

    +I am not completely sure exactly what the script buffer does or how it works. I believe it holds code that is stored in a saved game and then executed when the game is restored in order to put the +interpreter in the same state of execution as it was when the game was saved. I suppose it would contain things like what resources have to be loaded, etc. +

    +When you use certain commands, such as load.view and add.to.pic, they increase the current script size. This means that when you save the game, information about commands that have been used to set +up the screen and other aspects of the game can be re-executed when the game is loaded. So if you use some of these commands repeatedly, they can exceed the maximum script buffer size and crash the +interpreter. Therefore, it is important to keep an eye on the script size (this can be done with the show.mem command). +

    +For example, I was working on a part of a game where the player walks through a door and a small room appears on the side of the screen. I was originally using overlay.pic to draw the room (and erase +it again afterwards when the player walked out of it), but I noticed that if the player walked in and out of the room a few times the game would crash (with a "script buffer overflow" error). It turned +out that every time the load.pic, overlay.pic and discard.pic commands were executed, the script size was increased and it eventually got too big. Instead, I decided to simply use a view for the room +instead of overlaying a picture. +

    +So the script buffer is something to watch out for and can be the cause of many problems if you are not aware of it. The maximum script size can be changed using the script.size +command (the default size being 50), but this will not completely solve problems where the script size can be increased by certain command being used repeatedly. +

    + diff --git a/help/script_size.html b/help/script_size.html new file mode 100644 index 0000000..dfa1218 --- /dev/null +++ b/help/script_size.html @@ -0,0 +1,15 @@ + + +script.size + +

    script.size

    +Category

    +System commands

    +Syntax

    +

    +script.size(SIZE);

    +Description

    +

    +The maximum script size is set to SIZE. For more information, click here

    +See also

    + diff --git a/help/set.html b/help/set.html new file mode 100644 index 0000000..2f648aa --- /dev/null +++ b/help/set.html @@ -0,0 +1,16 @@ + + +set + +

    set

    +Category

    +Flag commads

    +Syntax

    +

    +set(fA);

    +Description

    +

    +Flag fA is set.

    +See also

    +set.v

    + diff --git a/help/set_cel.html b/help/set_cel.html new file mode 100644 index 0000000..2ebed5c --- /dev/null +++ b/help/set_cel.html @@ -0,0 +1,23 @@ + + +set.cel + +

    set.cel

    +Category

    +Object/view commands

    +Syntax

    +

    +set.cel(oA,B);

    +Description

    +

    +The current cel of object oA is set to B. If an invalid cel number is given, the interpreter will generates an error (the number of the last cel in a loop can be determined using the +last.cel command). +

    +See also

    +set.cel.v

    +current.cel

    +last.cel

    +set.loop

    +set.loop.v

    +Cycling objects

    + diff --git a/help/set_cel_v.html b/help/set_cel_v.html new file mode 100644 index 0000000..c9749e6 --- /dev/null +++ b/help/set_cel_v.html @@ -0,0 +1,23 @@ + + +set.cel.v + +

    set.cel.v

    +Category

    +Object/view commands

    +Syntax

    +

    +set.cel.v(oA,vB);

    +Description

    +

    +The current cel of object oA is set to vB. If an invalid cel number is given, the interpreter will generates an error (the number of the last cel in a loop can be determined using the +last.cel command). +

    +See also

    +set.cel

    +current.cel

    +last.cel

    +set.loop

    +set.loop.v

    +Cycling objects

    + diff --git a/help/set_cursor_char.html b/help/set_cursor_char.html new file mode 100644 index 0000000..d8b5448 --- /dev/null +++ b/help/set_cursor_char.html @@ -0,0 +1,15 @@ + + +set.cursor.char + +

    set.cursor.char

    +Category

    +Display commands

    +Syntax

    +

    +set.cursor.char(mCHAR);

    +Description

    +

    +The cursor character (the character displayed at the end of the player input line) is set to the first character of message mCHAR.

    +See also

    + diff --git a/help/set_dir.html b/help/set_dir.html new file mode 100644 index 0000000..7c8acc0 --- /dev/null +++ b/help/set_dir.html @@ -0,0 +1,21 @@ + + +set.dir + +

    set.dir

    +Category

    +Object/view commands

    +Syntax

    +

    +set.dir(oA,vDIR);

    +Description

    +

    +The direction of object oA is changed ot vDIR. vDIR must be between 0 and 8:

    +

    +You can not set the direction of ego (object 0). Instead, change the value of v6 to the direction you want.

    +To find out what direction an object is currently travelling in, use the get.dir command.

    +See also

    +get.dir

    +start.motion

    +Moving objects

    + diff --git a/help/set_game_id.html b/help/set_game_id.html new file mode 100644 index 0000000..875eee2 --- /dev/null +++ b/help/set_game_id.html @@ -0,0 +1,20 @@ + + +set.game.id + +

    set.game.id

    +Category

    +System commands

    +Syntax

    +

    +set.game.id(mID);

    +Description

    +

    +Sets the game ID to mID. This is a short name, up to 6 characters, that identifies the game, such as KQ2, SQ2, GR, MG etc. When the game ID is set like this, the interpreter checks it agains it's own +internal game ID and if they don't match, it quits. This was to make sure games weren't run with the wrong interpreter. Once the game ID is set, saved games include it in their filenames (e.g. SQSG.1). +

    +There is a simple way around the game ID checking problem - simply don't use this command, and the interpreter won't find the wrong one and quit. This is especially important with new games, so that +they can be run using interpreters from different games, which of course will have different IDs (although they must be the right interpreter version). Saved games will just be called SG.1, SG.2 etc. +but that is not a real problem. +

    + diff --git a/help/set_horizon.html b/help/set_horizon.html new file mode 100644 index 0000000..fdf3968 --- /dev/null +++ b/help/set_horizon.html @@ -0,0 +1,20 @@ + + +set.horizon + +

    set.horizon

    +Category

    +Object/view commands

    +Syntax

    +

    +set.horizon(Y);

    +Description

    +

    +The horizon's vertical position is set to Y. The horizon is an invisible horizontal line, usually near the top of the screen. The default value for the horizon (when the new.room command +is used) is 36. Objects are not allowed above the horizon, unless you use the ignore.horizon command. +

    +See also

    +ignore.horizon

    +observe.horizon

    +Controlling obstacles

    + diff --git a/help/set_key.html b/help/set_key.html new file mode 100644 index 0000000..c074e72 --- /dev/null +++ b/help/set_key.html @@ -0,0 +1,66 @@ + + +set.key + +

    set.key

    +Category

    +Menu/Key commands

    +Syntax

    +

    +set.key(nCODE1,CODE2,cA);

    +Description

    +

    +The key determined by the combination of nCODE1 and nCODE2 is assigned to controller cA. You can assign multiple menu items and keys to the one controller, for example most game functions like save, +restore, quit etc. usually have both a menu item and a key. +

    +To assign a key by it's ASCII code, set nCODE1 to the ASCII code you need (these can be obtained from an ASCII chart) and leave nCODE2 as 0. There are a few special codes:

    +

    +nCODE1  Key
    + 1-26   CTRL-A-Z
    + 8      Backspace (CTRL-H)
    + 9      Tab (CTRL-I)
    + 13     Enter (CTRL-M)
    + 27     Esc
    + 32     Space
    +
    +However, there are some keys and key combinations which use extended codes. For these, nCODE1 should be 0 and nCODE2 should be one of the values listed below (these are all standard PC-Keyboard +codes, taken from the Epson GW-BASIC 3.20 manual.) +

    +

    +nCODE2   Key
    + 3       CTRL-@
    + 15      SHIFT-TAB
    + 16-25   ALT-Q W E R T Y U I O P
    + 30-38   ALT-A S D F G H J K L
    + 44-50   ALT-Z X C V B N M
    + 59-68   F1-F10
    + 71      HOME*
    + 72      UP*
    + 73      PAGE UP*
    + 75      LEFT*
    + 77      RIGHT*
    + 79      END*
    + 80      DOWN*
    + 81      PAGE DOWN*
    + 82      INS
    + 83      DEL
    + 84-93   SHIFT-F1-F10
    + 94-103  CTRL-F1-F10
    + 104-113 ALT-F1-F10
    + 115     CTRL-LEFT
    + 116     CTRL-RIGHT
    + 117     CTRL-END
    + 118     CTRL-PAGE DOWN
    + 119     CTRL-HOME
    + 120-131 ALT-1 2 3 4 5 6 7 8 9 - =
    + 132     CTRL-PAGE UP
    + 133-134 F11 F12**
    + 135-136 SHIFT-F11 F12**
    + 137-138 CTRL-F11 F12**
    + 139-140 ALT-F11 F12**
    +
    +* - These codes can not actually be assigned as they are used for moving ego around, but were listed here for completeness.

    +** - I was not able to get these codes to work.

    +See also

    +Setting up menus and keys

    + diff --git a/help/set_loop.html b/help/set_loop.html new file mode 100644 index 0000000..c97eade --- /dev/null +++ b/help/set_loop.html @@ -0,0 +1,23 @@ + + +set.loop + +

    set.loop

    +Category

    +Object/view commands

    +Syntax

    +

    +set.loop(oA,B);

    +Description

    +

    +The current loop of object oA is set to B. If an invalid loop number is given, the interpreter generates an error. If the current cel of the object is greater than the last cel in loop B, then the +current cel is set to 0. +

    +See also

    +set.loop.v

    +current.loop

    +number.of.loops

    +set.cel

    +set.cel.v

    +Cycling objects

    + diff --git a/help/set_loop_v.html b/help/set_loop_v.html new file mode 100644 index 0000000..7c583e7 --- /dev/null +++ b/help/set_loop_v.html @@ -0,0 +1,23 @@ + + +set.loop.v + +

    set.loop.v

    +Category

    +Object/view commands

    +Syntax

    +

    +set.loop.v(oA,vB);

    +Description

    +

    +The current loop of object oA is set to vB. If an invalid loop number is given, the interpreter generates an error. If the current cel of the object is greater than the last cel in loop vB, then the +current cel is set to 0. +

    +See also

    +set.loop

    +current.loop

    +number.of.loops

    +set.cel

    +set.cel.v

    +Cycling objects

    + diff --git a/help/set_menu.html b/help/set_menu.html new file mode 100644 index 0000000..15ce147 --- /dev/null +++ b/help/set_menu.html @@ -0,0 +1,17 @@ + + +set.menu + +

    set.menu

    +Category

    +Menu/Key commands

    +Syntax

    +

    +set.menu(mNAME);

    +Description

    +

    +Tells the interpreter to create a menu with the name mNAME. One or more set.menu.item commands should follow, which add items to that menu.

    +See also

    +set.menu.item

    +Setting up menus and keys

    + diff --git a/help/set_menu_item.html b/help/set_menu_item.html new file mode 100644 index 0000000..48e3ea8 --- /dev/null +++ b/help/set_menu_item.html @@ -0,0 +1,19 @@ + + +set.menu.item + +

    set.menu.item

    +Category

    +Menu/Key commands

    +Syntax

    +

    +set.menu.item(mNAME,cA);

    +Description

    +

    +Adds an item with the name mNAME to the menu previously created using the set.menu command. The item is assigned to controller cA, so when the user selects it from the menu the test +command controller(cA) will be true. +

    +See also

    +set.menu.item

    +Setting up menus and keys

    + diff --git a/help/set_pri_base.html b/help/set_pri_base.html new file mode 100644 index 0000000..61d7e1a --- /dev/null +++ b/help/set_pri_base.html @@ -0,0 +1,15 @@ + + +set.pri.base + +

    set.pri.base

    +Category

    +Extra commands

    +Syntax

    +

    +set.pri.base(A);

    +Description

    +

    +This command affects the priority base of the AGI interpreter. King?s Quest 4 uses this function to affect the table so the "base" (priorities <= 4) is bigger or larger at the top.

    +See also

    + diff --git a/help/set_priority.html b/help/set_priority.html new file mode 100644 index 0000000..1b497a5 --- /dev/null +++ b/help/set_priority.html @@ -0,0 +1,22 @@ + + +set.priority + +

    set.priority

    +Category

    +Object/view commands

    +Syntax

    +

    +set.priority(oA,PRI);

    +Description

    +

    +Object oA's priority is set to PRI. The object keeps this priority wherever it goes on the screen.

    +To change it back so the priority is dependent on the object's position, use the release.priority command.

    +Note: If the object's priority is 15, it ignores all control lines and blocks, and thus can move anywhere on the screen below the horizon. If the object is ego (object 0), then flags 0 and 3 are no +longer set according to whether ego is on a control line of colour 3 or 2. After this, if the object's priority is released or set to something lower than 15, it returns to it's normal behaviour. +

    +See also

    +set.priority.v

    +release.priority

    +Priorities

    + diff --git a/help/set_priority_v.html b/help/set_priority_v.html new file mode 100644 index 0000000..84d3ded --- /dev/null +++ b/help/set_priority_v.html @@ -0,0 +1,22 @@ + + +set.priority.v + +

    set.priority.v

    +Category

    +Object/view commands

    +Syntax

    +

    +set.priority.v(oA,vPRI);

    +Description

    +

    +Object oA's priority is set to vPRI. The object keeps this priority wherever it goes on the screen.

    +To change it back so the priority is dependent on the object's position, use the release.priority command.

    +Note: If the object's priority is 15, it ignores all control lines and blocks, and thus can move anywhere on the screen below the horizon. If the object is ego (object 0), then flags 0 and 3 are no +longer set according to whether ego is on a control line of colour 3 or 2. After this, if the object's priority is released or set to something lower than 15, it returns to its normal behaviour. +

    +See also

    +set.priority

    +release.priority

    +Priorities

    + diff --git a/help/set_scan_start.html b/help/set_scan_start.html new file mode 100644 index 0000000..3e731f0 --- /dev/null +++ b/help/set_scan_start.html @@ -0,0 +1,16 @@ + + +set.scan.start + +

    set.scan.start

    +Category

    +Control flow commands

    +Syntax

    +

    +set.scan.start();

    +Description

    +

    +Tells the intepreter to start execution of this logic from the current point, instead of from the start of the logic.

    +See also

    +reset.scan.start

    + diff --git a/help/set_simple.html b/help/set_simple.html new file mode 100644 index 0000000..94ca64f --- /dev/null +++ b/help/set_simple.html @@ -0,0 +1,32 @@ + + +set.simple + +

    set.simple

    +Category

    +Extra commands

    +Syntax

    +set.simple(A);

    + +Description

    +

    +This command modifies the behavior of the commands restore.game() and save.game().

    + +After calling set.simple(n), where n is a string number (ie: if n == 2 then s2) restore.game() will automatically (without any prompt) restore a savegame with the name stored in string number n and save.game() will automatically save a savegame with the name of string number n.

    + +Note: make sure that at least one savegame is present when you call restore.game() or save.game() (that is, when saving a game too).

    + +Example:

    + + +set.string(s1,"test");
    +set.simple(1); +

    + +This will automatically load the savegame named "test".

    + +See also

    +restore.game

    +save.game

    + + diff --git a/help/set_string.html b/help/set_string.html new file mode 100644 index 0000000..43072e3 --- /dev/null +++ b/help/set_string.html @@ -0,0 +1,15 @@ + + +set.string + +

    set.string

    +Category

    +String commands

    +Syntax

    +

    +set.string(sA,mB);

    +Description

    +

    +Sets string sA to message mB.

    +See also

    + diff --git a/help/set_text_attribute.html b/help/set_text_attribute.html new file mode 100644 index 0000000..3cd536f --- /dev/null +++ b/help/set_text_attribute.html @@ -0,0 +1,19 @@ + + +set.text.attribute + +

    set.text.attribute

    +Category

    +Display commands

    +Syntax

    +

    +set.text.attribute(FG,BG);

    +Description

    +

    +Sets the foreground and background colours for display and display.v. The background colour can only be black (if BG is 0) or white (if BG is greater than 0). If the +background is white, all text will be displayed with a black foreground. Otherwise, the text will be displayed with the foreground specified by FG (0-15). +

    +See also

    +display

    +display.v

    + diff --git a/help/set_upper_left.html b/help/set_upper_left.html new file mode 100644 index 0000000..afa348a --- /dev/null +++ b/help/set_upper_left.html @@ -0,0 +1,15 @@ + + +set.upper.left + +

    set.upper.left

    +Category

    +Object/view commands

    +Syntax

    +

    +set.upper.left(A,B);

    +Description

    +

    +The purpose of this command is not currently known.

    +See also

    + diff --git a/help/set_v.html b/help/set_v.html new file mode 100644 index 0000000..9e470ba --- /dev/null +++ b/help/set_v.html @@ -0,0 +1,16 @@ + + +set.v + +

    set.v

    +Category

    +Flag commads

    +Syntax

    +

    +set.v(vA);

    +Description

    +

    +Flag fB (where B is the value of vA) is set.

    +See also

    +set

    + diff --git a/help/set_view.html b/help/set_view.html new file mode 100644 index 0000000..9090dd0 --- /dev/null +++ b/help/set_view.html @@ -0,0 +1,19 @@ + + +set.view + +

    set.view

    +Category

    +Object/view commands

    +Syntax

    +

    +set.view(oA,B);

    +Description

    +

    +View B is assigned to object oA. The view must be loaded in order to do this. If you wish, you can have one view assigned to several objects.

    +See also

    +set.view.v

    +load.view

    +load.view.v

    +current.view

    + diff --git a/help/set_view_v.html b/help/set_view_v.html new file mode 100644 index 0000000..6cc6558 --- /dev/null +++ b/help/set_view_v.html @@ -0,0 +1,19 @@ + + +set.view.v + +

    set.view.v

    +Category

    +Object/view commands

    +Syntax

    +

    +set.view.v(oA,vB);

    +Description

    +

    +View vB is assigned to object oA. The view must be loaded in order to do this. If you wish, you can have one view assigned to several objects.

    +See also

    +set.view

    +load.view

    +load.view.v

    +current.view

    + diff --git a/help/setting_up_menus_and_keys.html b/help/setting_up_menus_and_keys.html new file mode 100644 index 0000000..4885896 --- /dev/null +++ b/help/setting_up_menus_and_keys.html @@ -0,0 +1,37 @@ + + +Setting up menus and keys + +

    Setting up menus and keys

    +For a list of menu/key related commands, click here.

    +About controllers

    +

    +A controller is an event that has occured due to the user selecting a menu item or pressing a key. There are 50 controllers available (numbered from 0-49), and menu items and keys are assigned to +them. To test whether the event has occured, use the controller test command, like this: +

    +

    +if (controller(c2)) {
    +  quit(0);
    +}
    +

    +The above example tests for controller 2 (which could be assigned to "quit" on the menu), and if it has occured, it quits the game.

    +Setting up menus

    +First use the set.menu command to create a menu. Then use the set.menu.item command to add items to it. Repeat this process until all the menus have been set up, and then +use the submit.menu command to initialize it, making it available for use. Here is an example of creating a menu: +

    +

    +set.menu("File");
    +set.menu.item("Restart",c1);
    +set.menu.item("Quit",c2);
    +set.menu("Help");
    +set.menu.item("About");
    +submit.menu();
    +

    +The second parameter of the set.menu.item command is the controller that the menu item is being assigned to. You can assign multiple menu items and keys to the one controller, for +example most game functions like save, restore, quit etc. usually have both a menu item and a key. +

    +The menu can be brought up using the menu.input command.

    +Setting up keys

    +

    +Use the set.key command.

    + diff --git a/help/settings.html b/help/settings.html new file mode 100644 index 0000000..7f45d5c --- /dev/null +++ b/help/settings.html @@ -0,0 +1,49 @@ + + +Settings + +

    +

    Settings

    + +The 'Settings' menu (in the 'Game' menu) allow to configure various aspects +of the program. + +

    General

    + +

    Default resource type : the default resource type when the resource window is opened. + +

    GUI style: the general "look-and-feel" of the program GUI +(currently only the standard QT GUI styles are available) + +

    Picedit style: allows to split the Picture Editor window in two windows +(tools and picture separately) in case if one big window doesn't fit the screen. + +

    Extract logic as: how to extract logic files when the option "Extract resource" is used. + + +

    Directories

    + +

    Logic source directory : the place for the logic sources (also the default starting directory for "read file" and "save file" options for various resources) +

      +
    • When "Game_dir" is selected, the source directory is a subdirectory of the game directory +
    • When "Full path" is selected, the source directory can be anywhere +
    + +

    Template: the directory which contains the template game. + +

    Help: the directory which contains the help files. + +

    Logic editor

    + +Settings which affect the way the decompiled logic is displayed. + +

    Interpreter

    + +The AGI interpreter command line. Either the interpreter command must be in your PATH, +or specify the full path for it. The interpreter will be invoked with the current directory +same as your game directory, so there is no need to specify the game directory. + +
    +The settings are saved in a file ~/.agistudio (in your home directory) in the plain text format so you can edit this file if you feel like it. + + diff --git a/help/shake_screen.html b/help/shake_screen.html new file mode 100644 index 0000000..8a3fa73 --- /dev/null +++ b/help/shake_screen.html @@ -0,0 +1,15 @@ + + +shake.screen + +

    shake.screen

    +Category

    +Display commands

    +Syntax

    +

    +shake.screen(A);

    +Description

    +

    +Shakes the screen A times.

    +See also

    + diff --git a/help/show_mem.html b/help/show_mem.html new file mode 100644 index 0000000..e62e95b --- /dev/null +++ b/help/show_mem.html @@ -0,0 +1,20 @@ + + +show.mem + +

    show.mem

    +Category

    +Debugging commands

    +Syntax

    +

    +show.mem();

    +Description

    +

    +Shows memory stats:

    +heapsize: Amount of available memory

    +now: Currently used memory

    +max: Maximum amount of memory that has been used

    +rm.0, etc: ?

    +max script: maximum script size (click here for more info)

    +See also

    + diff --git a/help/show_mouse.html b/help/show_mouse.html new file mode 100644 index 0000000..57b4f03 --- /dev/null +++ b/help/show_mouse.html @@ -0,0 +1,19 @@ + + +show.mouse + +

    show.mouse

    +Category

    +Extra commands

    +Syntax

    +

    +show.mouse()

    +Description

    +

    +is command makes the mouse cursor appear on the screen. +Does not work with Sierra's PC version of the interpreter

    +See also

    +hide.mouse

    +fence.mouse

    +mouse.posn

    + diff --git a/help/show_obj.html b/help/show_obj.html new file mode 100644 index 0000000..309c28e --- /dev/null +++ b/help/show_obj.html @@ -0,0 +1,22 @@ + + +show.obj + +

    show.obj

    +Category

    +Inventory item commands

    +Syntax

    +

    +show.obj(VIEWNO);

    +Description

    +

    +Cel 0 of loop 0 of view VIEWNO is shown at the bottom of the screen, with the view's description displayed above. Both dissapear when a key is pressed. The view does not need to be loaded in order to +use this command. +

    +The command does not actually have anything to do with screen objects (which are normally referred to as just "objects"). It is meant for when the player examines an inventory item - each item should +have a view with a picture of it and a description, which is displayed using show.obj when the player examines it. Inventory items were sometimes called "objects", which is why the command was called +show.obj. +

    +See also

    +show.obj.v

    + diff --git a/help/show_obj_v.html b/help/show_obj_v.html new file mode 100644 index 0000000..f2cad40 --- /dev/null +++ b/help/show_obj_v.html @@ -0,0 +1,22 @@ + + +show.obj.v + +

    show.obj.v

    +Category

    +Inventory item commands

    +Syntax

    +

    +show.obj.v(vVIEWNO);

    +Description

    +

    +Cel 0 of loop 0 of view vVIEWNO is shown at the bottom of the screen, with the view's description displayed above. Both dissapear when a key is pressed. The view does not need to be loaded in order to +use this command. +

    +The command does not actually have anything to do with screen objects (which are normally referred to as just "objects"). It is meant for when the player examines an inventory item - each item should +have a view with a picture of it and a description, which is displayed using show.obj when the player examines it. Inventory items were sometimes called "objects", which is why the command was called +show.obj. +

    +See also

    +show.obj

    + diff --git a/help/show_pic.html b/help/show_pic.html new file mode 100644 index 0000000..4765b92 --- /dev/null +++ b/help/show_pic.html @@ -0,0 +1,16 @@ + + +show.pic + +

    show.pic

    +Category

    +Picture commands

    +Syntax

    +

    +show.pic();

    +Description

    +

    +The visual screen held in memory is updated on the actual screen.

    +See also

    +Drawing pictures

    + diff --git a/help/show_pri_screen.html b/help/show_pri_screen.html new file mode 100644 index 0000000..3a53f91 --- /dev/null +++ b/help/show_pri_screen.html @@ -0,0 +1,16 @@ + + +show.pri.screen + +

    show.pri.screen

    +Category

    +Debugging commands

    +Syntax

    +

    +show.pri.screen();

    +Description

    +

    +Displays the priority screen.

    +See also

    +Priorities

    + diff --git a/help/sound.html b/help/sound.html new file mode 100644 index 0000000..fb17189 --- /dev/null +++ b/help/sound.html @@ -0,0 +1,18 @@ + + +sound + +

    sound

    +Category

    +Sound commands

    +Syntax

    +

    +sound(SOUNDNO,fDONEFLAG);

    +Description

    +

    +Sound SOUNDNO is played. fDONEFLAG is reset when the command is issued, and set when the sound finishes playing or is stopped with the stop.sound command.

    +The sound must be loaded before it is played. This can be done with the load.sound command.

    +See also

    +load.sound

    +stop.sound

    + diff --git a/help/sound_commands.html b/help/sound_commands.html new file mode 100644 index 0000000..76ec762 --- /dev/null +++ b/help/sound_commands.html @@ -0,0 +1,9 @@ + + +Sound commands + +

    Sound commands

    +load.sound

    +sound

    +stop.sound

    + diff --git a/help/sound_descr.html b/help/sound_descr.html new file mode 100644 index 0000000..b82a7b4 --- /dev/null +++ b/help/sound_descr.html @@ -0,0 +1,12 @@ + + +Sound resources + +

    Sound resources

    +Sound resources contain all the sound effects and music used in a game. They consist of three musical voices plus one sound effect voice. The format is based on the sound capabilities of the +IBM PC Junior, for which the interpreter was originally written. On standard PCs only the first music voice is played, because the only sound device available to the PC at the time was the internal +speaker. There is no sound card support in the original PC version of the interpreter, but hopefully any new interpreters that are written will support this. +

    +Other systems such as Macintosh and Amiga supported the other voices as well.

    +Back to data used by AGI

    + diff --git a/help/special_flags.html b/help/special_flags.html new file mode 100644 index 0000000..2ff247e --- /dev/null +++ b/help/special_flags.html @@ -0,0 +1,67 @@ + + +Special flags + +

    Special flags

    +Some flags have special meaning to the interpreter:

    +

    +Flag Define name in template game Meaning (when set)
    +---------------------------------------------------------------------------
    +                                  This indicates that ego's baseline (the
    + 0   ego_on_water                 bottom row of pixels) is completely on
    +                                  water (pixels with a priority of 3)
    +
    + 1   ego_hidden                   Ego is completely hidden by something
    +                                  else on screen
    +
    + 2   input_received               Input has been received from the player
    +
    +                                  All or part of ego's baseline (the bottom
    + 3   ego_touching_signal_line     row of pixels) is touching a signal line
    +                                  (pixels with a priority of 2)
    +
    +                                  The input received from the player has
    + 4   input_parsed                 been parsed (the said command has
    +                                  returned true at some point)
    +
    + 5   new_room                     This is the the first cycle in a new room
    +
    + 6   game_restarted               This is the first cycle since the game
    +                                  has been restarted
    +
    + 7   script_buffer_blocked        Prevents the interpreter from writing to
    +                                  the script buffer
    +
    + 8   joystick_sensitivity_set     Indicates that v15 specifies the joystick
    +                                  sensitivity
    +
    + 9   sound_on                     The sound is on
    +
    + 10  trace_enabled                Trace mode is enabled
    +
    + 11  first_logic0_cycle           This is the first time logic 0 has been
    +                                  executed
    +
    + 12  game_restored                This is the first cycle since a game has
    +                                  been restored
    +
    +                                  The player is allowed to select an
    +                                  inventory item in the inventory screen.
    + 13  inventory_select_enabled     When the item has been selected, v25
    +                                  (selected_inventory_item) is set to the
    +                                  number of the item selected (or 255 if
    +                                  ESC is pressed).
    +
    + 14  menu_enabled                 The menu is enabled
    +
    +                                  Windows created by print and similar
    +                                  commands remain on screen until the
    +                                  close.window command is used. If this
    + 15  windows_remain               flag is not set, the windows remain on
    +                                  screen until the user presses a key or
    +                                  for the time specified by v21
    +                                  (window_close_time).
    +
    +See also

    +Special variables

    + diff --git a/help/special_variables.html b/help/special_variables.html new file mode 100644 index 0000000..6e647b2 --- /dev/null +++ b/help/special_variables.html @@ -0,0 +1,93 @@ + + +Special variables + +

    Special variables

    +Some variables have special meaning to the interpreter:

    +

    +Var Define name in template game Description
    +-------------------------------------------------------------------
    + 0  room_no                      Number of the current room
    +
    + 1  prev_room_no                 Number of the previous room
    +
    + 2  ego_edge_code                Which edge of the screen ego is touching
    +                                 0: not touching edge
    +                                 1: horizon
    +                                 2: right edge
    +                                 3: bottom edge
    +                                 4: left edge
    +
    + 3  score                        Current score
    +
    + 4  object_touching_edge         Number of an object other than ego that is
    +                                 touching the edge.
    +
    + 5  object_edge_code             See ego_edge_code
    +
    + 6  ego_dir                      Direction of ego's motion (see "Moving
    +                                 Objects" for a list of directions).
    +
    + 7  max_score                    Maxmimum score
    +
    + 8  free_memory                  The number of 256-byte lots of free memory
    +                                 available for resources.
    +
    +                                 If the player has entered an unknown word,
    + 9  unknown_word_no              this is set to the number of that word
    +                                 (i.e. 2 if it's the second word entered).
    +                                 Otherwise, this is 0.
    +
    + 10 cycle_delay                  Delay between interpreter cycles (*1/20
    +                                 second)
    +
    +                                 Number of seconds on the interpreter's
    + 11 clock_seconds                clock (the clock is reset when the game
    +                                 starts).
    +
    + 12 clock_minutes                Number of minutes on the interpreter's
    +                                 clock
    +
    + 13 clock_hours                  Number of hours on the interpreter's clock
    +
    + 14 clock_days                   Number of days on the interpreter's clock
    +
    + 15 joystick_sensitivity         Sensitivity of the joystick
    +
    + 16 ego_view_no                  Number of the view assigned to ego
    +
    + 17 error_code                   What type of error has occured
    +
    + 18 error_information            Extra information about the error
    +
    + 19 key_pressed                  The ASCII code of the key that has just
    +                                 been pressed, if any
    +
    + 20 computer_type                Type of computer (0=PC)
    +
    +                                 Number of half-seconds to wait before
    + 21 window_close_time            closing a window (if 0, the window remains
    +                                 on screen until the user presses a key).
    +
    + 22 sound_type                   Sound generator type. (PC=1,Tandy=3)
    +
    + 23 sound_volume                 Volume of the sound
    +
    + 24 (unknown)                    Always seems to be set to 41
    +
    +                                 If the player has selected an inventory
    + 25 selected_inventory_item      item from the inventory screen, this is
    +                                 set to the number of that item (or 255 if
    +                                 ESC was pressed).
    +
    +                                 Video mode:
    +                                 0: CGA (black-cyan-magenta-white CGA
    +                                 palette)
    + 26 video_mode                   1: RGB (blue-yellow-red-green CGA palette)
    +                                 2: Hercules
    +                                 3: EGA
    +                                 4: VGA
    +
    +See also

    +Special flags

    + diff --git a/help/start_cycling.html b/help/start_cycling.html new file mode 100644 index 0000000..f033329 --- /dev/null +++ b/help/start_cycling.html @@ -0,0 +1,21 @@ + + +start.cycling + +

    start.cycling

    +Category

    +Object/view commands

    +Syntax

    +

    +start.cycling(oA);

    +Description

    +

    +This tells the interpreter to start cycling object oA. If the object was previously cycling in reverse order before it was stopped, then it will continue to cycle in reverse order. Otherwise, it will +cycle in normal order. To turn cycling off, use the stop.cycling command. +

    +See also

    +stop.cycling

    +normal.cycle

    +reverse.cycle

    +Cycling objects

    + diff --git a/help/start_motion.html b/help/start_motion.html new file mode 100644 index 0000000..19d76f4 --- /dev/null +++ b/help/start_motion.html @@ -0,0 +1,22 @@ + + +start.motion + +

    start.motion

    +Category

    +Object/view commands

    +Syntax

    +

    +start.motion(oA);

    +Description

    +

    +I am not quite sure what this command does. The name implies that object oA starts to move, but this does not seem to work (instead you have to use set.dir to set the direction of the +object to something other than 0). +

    +If oA is ego (object 0), the player.control command is issued by the interpreter.

    +See also

    +stop.motion

    +set.dir

    +player.control

    +Moving objects

    + diff --git a/help/start_update.html b/help/start_update.html new file mode 100644 index 0000000..9704abb --- /dev/null +++ b/help/start_update.html @@ -0,0 +1,17 @@ + + +start.update + +

    start.update

    +Category

    +Object/view commands

    +Syntax

    +

    +start.update(oA);

    +Description

    +

    +This tells the interpreter to update object oA at the start of every cycle.

    +See also

    +stop.update

    +force.update

    + diff --git a/help/status.html b/help/status.html new file mode 100644 index 0000000..65d7b6b --- /dev/null +++ b/help/status.html @@ -0,0 +1,17 @@ + + +status + +

    status

    +Category

    +Inventory item commands

    +Syntax

    +

    +status();

    +Description

    +

    +Displays the inventory screen. This is a text mode screen with the text "You are carrying:" on the top line and a list of the items in the player's inventory (those with a room number of 255) below. If +there are no items in the player's inventory, "nothing" is displayed. +

    +See also

    + diff --git a/help/status_line_off.html b/help/status_line_off.html new file mode 100644 index 0000000..29bd6f3 --- /dev/null +++ b/help/status_line_off.html @@ -0,0 +1,19 @@ + + +status.line.off + +

    status.line.off

    +Category

    +Display commands

    +Syntax

    +

    +status.line.off();

    +Description

    +

    +Turns the status line off. The status line is usually on the top line of the screen (although this can be changed with configure.screen), and displays the current score and sound +on/off status. When it is turned off, the line is blank. +

    +See also

    +status.line.on

    +configure.screen

    + diff --git a/help/status_line_on.html b/help/status_line_on.html new file mode 100644 index 0000000..cd6cd38 --- /dev/null +++ b/help/status_line_on.html @@ -0,0 +1,19 @@ + + +status.line.on + +

    status.line.on

    +Category

    +Display commands

    +Syntax

    +

    +status.line.on();

    +Description

    +

    +Turns the status line on. The status line is usually on the top line of the screen (although this can be changed with configure.screen), and displays the current score and sound +on/off status. +

    +See also

    +status.line.off

    +configure.screen

    + diff --git a/help/step_size.html b/help/step_size.html new file mode 100644 index 0000000..0317b35 --- /dev/null +++ b/help/step_size.html @@ -0,0 +1,20 @@ + + +step.size + +

    step.size

    +Category

    +Object/view commands

    +Syntax

    +

    +step.size(oA,vB);

    +Description

    +

    +The step size of oA (the number of pixels it moves each step) is set to vB.

    +See also

    +step.time

    +move.obj

    +move.obj.v

    +follow.ego

    +Moving objects

    + diff --git a/help/step_time.html b/help/step_time.html new file mode 100644 index 0000000..e3225fe --- /dev/null +++ b/help/step_time.html @@ -0,0 +1,20 @@ + + +step.time + +

    step.time

    +Category

    +Object/view commands

    +Syntax

    +

    +step.time(oA,vB);

    +Description

    +

    +The delay (in interpreter cycles) between steps (movements) of object oA is set to vB. For example, if the step time is set to 2, the object will only move every second cycle. Note that an object's +step time is independent from its cycle time. +

    +See also

    +step.size

    +cycle.time

    +Moving objects

    + diff --git a/help/stop_cycling.html b/help/stop_cycling.html new file mode 100644 index 0000000..fa65499 --- /dev/null +++ b/help/stop_cycling.html @@ -0,0 +1,19 @@ + + +stop.cycling + +

    stop.cycling

    +Category

    +Object/view commands

    +Syntax

    +

    +stop.cycling(oA);

    +Description

    +

    +This tells the interpreter to stop cycling object oA. To turn cycling back on, use the start.cycling command.

    +See also

    +start.cycling

    +normal.cycle

    +reverse.cycle

    +Cycling objects

    + diff --git a/help/stop_motion.html b/help/stop_motion.html new file mode 100644 index 0000000..636bf0a --- /dev/null +++ b/help/stop_motion.html @@ -0,0 +1,18 @@ + + +stop.motion + +

    stop.motion

    +Category

    +Object/view commands

    +Syntax

    +

    +stop.motion(oA);

    +Description

    +

    +Object oA stops moving. If the object is ego (object 0), the program.control command is issued by the interpreter.

    +See also

    +start.motion

    +program.control

    +Moving objects

    + diff --git a/help/stop_sound.html b/help/stop_sound.html new file mode 100644 index 0000000..757d6cc --- /dev/null +++ b/help/stop_sound.html @@ -0,0 +1,16 @@ + + +stop.sound + +

    stop.sound

    +Category

    +Sound commands

    +Syntax

    +

    +stop.sound();

    +Description

    +

    +If a sound is playing, it is stopped. The flag that was given as the second parameter of the sound command is set when this happens.

    +See also

    +sound

    + diff --git a/help/stop_update.html b/help/stop_update.html new file mode 100644 index 0000000..3ff0539 --- /dev/null +++ b/help/stop_update.html @@ -0,0 +1,17 @@ + + +stop.update + +

    stop.update

    +Category

    +Object/view commands

    +Syntax

    +

    +stop.update(oA);

    +Description

    +

    +This tells the interpreter not to update object oA at the start of every cycle. The object remains on screen, unchanged.

    +See also

    +start.update

    +force.update

    + diff --git a/help/string_commands.html b/help/string_commands.html new file mode 100644 index 0000000..f33a688 --- /dev/null +++ b/help/string_commands.html @@ -0,0 +1,12 @@ + + +String commands + +

    String commands

    +get.string

    +parse

    +set.string

    +word.to.string

    +Test commands

    +compare.strings

    + diff --git a/help/submit_menu.html b/help/submit_menu.html new file mode 100644 index 0000000..cae4e9b --- /dev/null +++ b/help/submit_menu.html @@ -0,0 +1,20 @@ + + +submit.menu + +

    submit.menu

    +Category

    +Menu/Key commands

    +Syntax

    +

    +submit.menu();

    +Description

    +

    +Initializes the menus set up with the set.menu and set.menu.item commands, allowing them to be used. This command can only be used once, and after that the menus can not +be changed. +

    +See also

    +set.menu

    +set.menu.item

    +Setting up menus and keys

    + diff --git a/help/subn.html b/help/subn.html new file mode 100644 index 0000000..0d259c2 --- /dev/null +++ b/help/subn.html @@ -0,0 +1,18 @@ + + +subn + +

    subn

    +Category

    +Mathematical commands

    +Syntax

    +

    +subn(vA,B);

    +vA -= B;

    +vA = vA - B;

    +Description

    +

    +B is subtracted from vA. Since a var can only be from 0-255, if the result is less than 0, then the value wraps around, e.g. 10 - 12 would give 254.

    +See also

    +subv

    + diff --git a/help/subv.html b/help/subv.html new file mode 100644 index 0000000..7b48e31 --- /dev/null +++ b/help/subv.html @@ -0,0 +1,18 @@ + + +subv + +

    subv

    +Category

    +Mathematical commands

    +Syntax

    +

    +subv(vA,vB);

    +vA -= vB;

    +vA = vA - vB;

    +Description

    +

    +vB is subtracted from vA. Since a var can only be from 0-255, if the result is less than 0, then the value wraps around, e.g. 10 - 12 would give 254.

    +See also

    +subn

    + diff --git a/help/system_commands.html b/help/system_commands.html new file mode 100644 index 0000000..63f352a --- /dev/null +++ b/help/system_commands.html @@ -0,0 +1,22 @@ + + +System commands + +

    System commands

    +accept.input

    +cancel.line

    +echo.line

    +init.disk

    +init.joy

    +pause

    +player.control

    +prevent.input

    +program.control

    +quit

    +restart.game

    +restore.game

    +save.game

    +script.size

    +set.game.id

    +toggle.monitor

    + diff --git a/help/test.html b/help/test.html new file mode 100644 index 0000000..aa86711 --- /dev/null +++ b/help/test.html @@ -0,0 +1,19 @@ + + + + test1 + + + +

    test1

    + + + +
    +
    helen
    + + +Last modified: Sun Mar 19 21:22:28 IST 2000 + + + diff --git a/help/test_commands.html b/help/test_commands.html new file mode 100644 index 0000000..76da0df --- /dev/null +++ b/help/test_commands.html @@ -0,0 +1,24 @@ + + +Test commands + +

    Test commands

    +equaln

    +equalv

    +lessn

    +lessv

    +greatern

    +greaterv

    +isset

    +issetv

    +has

    +obj.in.room

    +posn

    +controller

    +have.key

    +said

    +compare.strings

    +obj.in.box

    +center.posn

    +right.posn

    + diff --git a/help/text_editor_main.html b/help/text_editor_main.html new file mode 100644 index 0000000..b1a702f --- /dev/null +++ b/help/text_editor_main.html @@ -0,0 +1,13 @@ + + +Text editor + +

    Text editor

    +The text editor is included so you can edit text files without having to switch to another application such as notepad. This is especially handy when you are doing logic programming and you need to +edit a file which is included in your logic using the #include command. It is also integrated with the logic editor - if a text file is used in a logic with the #include command and it contains an +error, the compiler will bring up the text editor with the appropriate file and hilight the appropriate line so you can fix the error. Note that when you compile a logic, all open text files that are +referred to by that logic are automatically saved. +

    +Usage of the text editor is pretty self explanatory - it is very similar in operation to programs like notepad. You can open it from the Tools menu or the toolbar.

    +Back to contents

    + diff --git a/help/text_screen.html b/help/text_screen.html new file mode 100644 index 0000000..b6dbf58 --- /dev/null +++ b/help/text_screen.html @@ -0,0 +1,19 @@ + + +text.screen + +

    text.screen

    +Category

    +Display commands

    +Syntax

    +

    +text.screen();

    +Description

    +

    +Switches the interpreter to text mode (40x25). This should only be used to display text on screen, and not to use menus, print statements, receive commands from the player or manipulate graphics as +it does not have proper support for these things. It is handy for displaying text on a blank screen because you do not lose the graphics screen when you use it. +

    +Once you have finished in text mode, you should use the graphics command to switch back.

    +See also

    +graphics

    + diff --git a/help/todo.html b/help/todo.html new file mode 100644 index 0000000..fc317ee --- /dev/null +++ b/help/todo.html @@ -0,0 +1,60 @@ + + +TODO list + +

    TODO (QT AGI Studio v1.3.0)

    + +This is not a development plan but rather an unsorted list of ideas. You are welcome to contribute. :-) + +

    resources: +

      +
    • extract view, picture and sound resources in different (not only raw) formats (partially implemented for the picture - preview "save as") +
    • opening resource editors without opening the game +
    • editing several games simultaneously +
    + +

    view: +

      +
    • better painting tools (fix fill bugs, implement select + move and select + copy-paste) +
    • import views from different image formats +
    • views containing text (option to set fonts/colors/etc) +
    + +

    text/logic: +

      +
    • enhance the text/logic editor, adding common editor functions, like +indent, replace, insert file, copy block to file, etc. (Integrate QtScite?) +
    • highlight the line with the compilation error +
    • a possibility to define an external editor (such as Emacs) while still having the option to compile /save_all /compile_all +
    • "shortcuts" to automatically generate some commonly used pieces of code, for example defining a new inventory object and placing it on screen (this particular option needs to work together with the picture, view, words and objects editor, so it could use some kind of drag&drop as well) +
    + +

    picture: +

      +
    • improve ways to edit already existing pictures (modify existing commands, translate operations) +
    • fix the elusive crash bugs related to opening some background images +
    • options to make the editing more convenient and more like the other editors +(copy/paste, dragging objects, etc) +
    + +

    sound: +

      +
    • sound editor +
    • sound converters +
    + +

    general: +

      +
    • optional autosave +
    • improve the online help (search by keywords) +
    • enhance the appearance (let the user choose fonts/colors) +
    • MDI mode perhaps? +
    • port to other Unix platforms +
    • improve the compilation/installation process +
    • check the available AGI hacks (256 colour pic, etc), think if some of them +can be incorporated into the program +
    + +
    +

    + diff --git a/help/toggle.html b/help/toggle.html new file mode 100644 index 0000000..e2bf7f8 --- /dev/null +++ b/help/toggle.html @@ -0,0 +1,16 @@ + + +toggle + +

    toggle

    +Category

    +Flag commads

    +Syntax

    +

    +toggle(fA);

    +Description

    +

    +If flag fA is set, then it is reset. Otherwise it is set.

    +See also

    +toggle.v

    + diff --git a/help/toggle_monitor.html b/help/toggle_monitor.html new file mode 100644 index 0000000..b43c3cf --- /dev/null +++ b/help/toggle_monitor.html @@ -0,0 +1,21 @@ + + +toggle.monitor + +

    toggle.monitor

    +Category

    +System commands

    +Syntax

    +

    +toggle.monitor();

    +Description

    +

    +Switched between CGA and RGB graphics modes. This is only useful when the interpreter is running in one of these modes (either it is running on a computer with a CGA graphics adapter or the +interpreter has been loaded with the -C or -R parameters). Note that although Sierra's DOS interpreter will run in these modes, newer interpreters may not. +

    +This command does not really have any practical use. It was available from a menu item in Sierra's AGI games (the menu item was only present when running in these modes). The template game does not +include this menu item, however. If you do want to run the game in these modes, just type sierra -c or sierra -r at the DOS prompt (assuming you are using Sierra's interpreter). CGA mode uses the +black-cyan-magenta-white CGA colour palette while RGB mode uses the blue-yellow-red-green CGA palette. +

    +See also

    + diff --git a/help/toggle_v.html b/help/toggle_v.html new file mode 100644 index 0000000..1c03bf6 --- /dev/null +++ b/help/toggle_v.html @@ -0,0 +1,16 @@ + + +toggle.v + +

    toggle.v

    +Category

    +Flag commads

    +Syntax

    +

    +toggle.v(vA);

    +Description

    +

    +If flag fB (where B is the value of vA) is set, then it is reset. Otherwise it is set.

    +See also

    +toggle

    + diff --git a/help/trace_info.html b/help/trace_info.html new file mode 100644 index 0000000..5335b70 --- /dev/null +++ b/help/trace_info.html @@ -0,0 +1,18 @@ + + +trace.info + +

    trace.info

    +Category

    +Debugging commands

    +Syntax

    +

    +trace.info(LOGNUM,TOP,HEIGHT);

    +Description

    +

    +Sets up trace mode. LOGNUM is the number of the logic containing trace commands. TOP and HEIGHT are the top line number of the trace window and the number of lines it takes up.

    +This command should be used before trace mode is enabled or turned on.

    +See also

    +trace.on

    +Trace mode

    + diff --git a/help/trace_mode.html b/help/trace_mode.html new file mode 100644 index 0000000..bb5c391 --- /dev/null +++ b/help/trace_mode.html @@ -0,0 +1,17 @@ + + +Trace mode + +

    Trace mode

    +The AGI Interpreter has a built in trace mode, which is useful for examining the operation of logics and tracking down problems. When it is turned on (either by the game issuing the +trace.on command or by the player pressing the SCROLL LOCK key), a window is displayed on the screen showing commands and their parameters as they are executed. +

    +Before trace mode is used, the trace.info command must be used to initialize trace mode. It is not necessary to use this, but if it is not used then the command names will not be +displayed in the trace window (only the command numbers). Flag 10 must be set in order to enable trace mode. +

    +The user can then activate trace mode by using the SCROLL LOCK key. Pressing this key while trace mode is on will turn it off.

    +See also

    +

    +trace.info

    +trace.on

    + diff --git a/help/trace_on.html b/help/trace_on.html new file mode 100644 index 0000000..16fc459 --- /dev/null +++ b/help/trace_on.html @@ -0,0 +1,18 @@ + + +trace.on + +

    trace.on

    +Category

    +Debugging commands

    +Syntax

    +

    +trace.on();

    +Description

    +

    +Turns trace mode on. This does the same thing as the player pressing the SCROLL LOCK key.

    +Trace mode must be enabled (by setting flag 10) before using this command.

    +See also

    +trace.info

    +Trace mode

    + diff --git a/help/types.html b/help/types.html new file mode 100644 index 0000000..59a680e --- /dev/null +++ b/help/types.html @@ -0,0 +1,74 @@ + + +Types + +

    Types

    +There are 9 different types are accepted by AGI commands. Each argument in a command is of a certain type. For example, the first argument of the addn command is a variable and the second +argument is a number. +

    +When using an argument, you must give the prefix for the type before the actual number, e.g. v3 for variable 3. This is to make sure you know what type you are using.

    +Numbers +(no prefix)

    +These are integer values which can have a value from 0 to 255.

    +Variables (also known as "vars") +(Prefix: v)

    +Each of these can contain an integer value from 0 to 255, thus being the AGI equivalent of a byte (or unsigned char). There are 256 variables (numbered from 0 to 255) available. Variables 0-26 have +special meaning to the interpreter (click here for more info). +

    +See also: Mathematical commands

    +Flags +(Prefix: f)

    +These can either be set or not set (some documentation refers to them of having a value of 0 or 1, 0 meaning not set and 1 meaning set). They are the AGI equivalent of a boolean type. There are 256 +flags (numbered from 0 to 255) available. Flags 0-15 have special meaning to the interpreter (click here for more info). +

    +See also: Flag commads

    +Messages +(Prefix: m)

    +Each logic can contain up to 255 messages, which are text that is used by commands like print to give the user information. Each message is numbered (starting from 1) and can be as long as +you like. When you give a message as a parameter for a command, you can either use a specific message number or give the message surrounded by quote marks (and let the compiler give the message a +number), e.g.: +

    +print("He's not here."); - giving the actual message

    +print(m2); - giving the message number

    +If you use the message number as in the second example, you must tell the compiler what that message will actually be. This is done using the message command:

    +#message 2 "He's not here."

    +You're probably wondering why you would want to give a message a specific number. This is because you can refer to this in other message by using %m and then the message number, e.g:

    +print("%m2 But he'll be back soon.");

    +The message is stored like this in the logic resource, but when the interpreter displays it it will replace %m2 with message 2, so the text "He's not here. But he'll be back soon." will be displayed. +Also, commands like print.v use a message number determined by the value of a variable, so when using these command you sometimes need to know the numbers of certain messages. +

    +You can also include other things in messages:

    +%vN Value of var N

    +%wN Nth word that the player typed in

    +%sN String N

    +%gN Message N from logic 0

    +When using %v, you can place a | after the number and then another number which determines the minimum number of digits for the var. For example, if you use %v40|2 and the value of v40 is 8, then +the %v40|2 will be replaced with 08. If the value of v40 was 100 or more, all three digits would be displayed. +

    +These inclusions can also be used in the descriptions in view resources.

    +Objects +(Prefix: o)

    +For a description of objects, click here.

    +See also: Object/view commands

    +Inventory items +(Prefix: i)

    +Inventory items are things that the player can carry around with them. Their names are stored in the OBJECT file. A game contain up to 256 objects (numbered from 0-255). Each object used by the game +must be present in the OBJECT file. +

    +Every object has a room number which is a value from 0-255. If the room number is 255, it is in the player's inventory.

    +See also: Inventory item commands

    +Strings +(Prefix: s)

    +Up to 12 different strings can be used by the game. These can be up to 40 characters long. The first character of string 0 is used as the prompt character (">" or "]" in most games).

    +See also: String commands

    + Words +(Prefix: w)

    +These are the words that the player has typed in, starting from 1. This list of words does not include words that are in group 0 (usually things like "the", "this", "with" etc.). So if the player types +"unlock the door with the key" then word 1 will be "unlock", word 2 will be "door" and word 3 will be "key" (assuming "the" and "with" are in group 0). Words can be converted to strings with the +word.to.string command. +

    +Controllers +(Prefix: c)

    +These are menu and key events. You can assign a menu item or key to a controller and then test to see when that item was selected or that key was pressed.

    +See also: Setting up menus and keys

    + diff --git a/help/unanimate_all.html b/help/unanimate_all.html new file mode 100644 index 0000000..69aff5c --- /dev/null +++ b/help/unanimate_all.html @@ -0,0 +1,16 @@ + + +unanimate.all + +

    unanimate.all

    +Category

    +Object/view commands

    +Syntax

    +

    +unanimate.all();

    +Description

    +

    +This deactivates all screen objects.

    +See also

    +animate.obj

    + diff --git a/help/unblock.html b/help/unblock.html new file mode 100644 index 0000000..9291847 --- /dev/null +++ b/help/unblock.html @@ -0,0 +1,17 @@ + + +unblock + +

    unblock

    +Category

    +Object/view commands

    +Syntax

    +

    +unblock();

    +Description

    +

    +This removes the block set up on the screen by the block command.

    +See also

    +block

    +Controlling obstacles

    + diff --git a/help/version.html b/help/version.html new file mode 100644 index 0000000..154fd43 --- /dev/null +++ b/help/version.html @@ -0,0 +1,15 @@ + + +version + +

    version

    +Category

    +Debugging commands

    +Syntax

    +

    +version();

    +Description

    +

    +Displays the interpreter version.

    +See also

    + diff --git a/help/view-description.png b/help/view-description.png new file mode 100644 index 0000000000000000000000000000000000000000..898f88422198d6017d4cb2ac9c41e946a1e43d5e GIT binary patch literal 3883 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 literal 0 HcmV?d00001 diff --git a/help/view-editor.png b/help/view-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..7cc2459eee0c54c47f689a364e0dd5f1a0424bcd GIT binary patch literal 9161 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 literal 0 HcmV?d00001 diff --git a/help/view_descr.html b/help/view_descr.html new file mode 100644 index 0000000..7703278 --- /dev/null +++ b/help/view_descr.html @@ -0,0 +1,23 @@ + + +View resources + +

    View resources

    +View resources contain some of the graphics for the game. Unlike the picture resources which are full-screen background images, view resources are smaller 'sprites' used in the game, such as +animations. They are also stored as bitmaps, whereas pictures are stored in vector format. +

    +Each view resource consists of one or more "loops". Each loop in the resource consists of one or more "cels" (frames). Thus several animations can be stored in one view, or a view can just be used for a +single image. The maximum number of loops supported by the interpreter is 255 (0-254) and the maximum number of cels in each is loop 255 (0-254). +

    +Views have a number of useful features:

    +Transparency: Each cel has a transparent colour. When the view is shown on the screen, pixels of this colour will show to the background.

    +Mirroring: You can set one loop to be a "mirror" of another, which means that all the cels in that loop will be mirror images of the corresponding cels in the other loop. This is handy if you +have drawn an animation of a character walking right, and also want to have an animation of it walking left - you only have to do half the work (and the view takes up less memory). +

    +Description: This is used when a view is a picture of an inventory item. When the view is displayed using the show.obj command (i.e. when the player "examines" an object), the first cel of the +first loop is displayed on screen along with the description. +

    +AGI Studio supports up to 16 loops (0-15) and 32 cels in each loop (0-31).

    +You can edit Views with the view editor.

    +Back to data used by AGI

    + diff --git a/help/view_editor_main.html b/help/view_editor_main.html new file mode 100644 index 0000000..4500bd9 --- /dev/null +++ b/help/view_editor_main.html @@ -0,0 +1,66 @@ + + +View editor + +

    View editor

    +The view editor supports all features of view resources. You can have up to 16 loops, 32 cels (in each loop), any width/height and a description.

    +For more information on view resources, click here.

    +To use the view editor, simply double-click on a view resource in the main window or select 'View Editor' from the 'Tools' menu or toolbar. You can have several view editor windows up at a time.

    +The view editor looks like this:

    +

    +

    Components of the view editor window

    +Drawing area

    +This is pretty self explanatory. You can draw in either selected colour using the left or right mouse button.

    +Colour Palette

    +This allows you to select drawing colours. You can assign colours to the left or right mouse button by clicking that button on the appropriate colour.

    +Loop/cel change

    +The current loop and cel are displayed here. Click the left/right buttons to change loops/cels.

    +Width/height change

    +This is the width and height of the current cel. Note that the image is 2*width pixels wide on the screen as each AGI pixel is two normal pixels wide. To change the width or height, click on the +appropriate buttons or type in a new value. +

    +The maximum cel size is 160x168 (the size of the AGI playing screen).

    +Zoom in/out

    +You can zoom in or out of the view to a maximum of 10x. The default zoom is 2x.

    +Tool selection

    +This allows you to select the tool you want to use in the drawing area.

    +Shift cel

    +You can shift the cel up, down, left or right using these buttons.

    +Mirroring

    +To mirror a loop, just select the number of the loop you want to mirror. Note that when you do this, you lose the current loop and it is replaced with the mirror of the other loop. Always make sure +that you change to the "target" loop before doing this. +

    +When loops are mirrored, any change you make to either loop will be replicated in the other. When you select "No other loop", the cels in both loops remain the same but you can now modify them +independently. +

    +Transparency

    +Clicking the "set" button will change the transparent colour of this cel to the colour that is assigned to the left mouse button.

    +Description

    +If you want a description, check the description check box and click the 'Edit' button to edit or change it. Note that lines are separated by "\n". The description editor looks like this:

    +

    +Shortcut Keys

    +These keys can be used with the view editor: +

    +

    +Q       previous loop
    +W       next loop
    +A       previous cel
    +S       next cel
    +Z       zoom out
    +X       zoom in
    +T       set transparent colour
    +D       select draw tool
    +F       select fill tool
    +I       shift cel up
    +K       shift cel down
    +J       shift cel left
    +L       shift cel right
    +CTRL-C  copy cel
    +CTRL-V  paste cel
    +
    +

    A couple of notes

    +At present, the undo feature is available only for clearing, pasting and filling a cel. There is no multiple undo. +

    Importing view images from other programs using 'copy'/'paste' is not available. The 'copy' and 'paste' functions work only to copy and paste cels between different loops or view editor windows. +

    +Back to contents

    + diff --git a/help/viewing_resources.html b/help/viewing_resources.html new file mode 100644 index 0000000..12b3afe --- /dev/null +++ b/help/viewing_resources.html @@ -0,0 +1,19 @@ + + +Viewing resources + +

    Viewing resources

    +To view a resource, just select it from the list in the resources window. You will see the resource in the preview window. At present this can only be done for view resources and +picture resources. +

    +When you click on a view resource, you will see the something like this:

    +

    +To change loops or cels, just click on the apprioriate left/right buttons. +

    +When you click on a picture resource, you will see the something like this:

    +

    +To view the visual or priority screen, select the appropriate radio button.

    + +The picture viewer also allows you to save the currently displayed screen as a BMP file or any other image format supported by QT library.

    +Back to contents

    + diff --git a/help/wander.html b/help/wander.html new file mode 100644 index 0000000..8acc805 --- /dev/null +++ b/help/wander.html @@ -0,0 +1,16 @@ + + +wander + +

    wander

    +Category

    +Object/view commands

    +Syntax

    +

    +wander(oA);

    +Description

    +

    +Object oA wanders randomly around the screen.

    +See also

    +Moving objects

    + diff --git a/help/word_to_string.html b/help/word_to_string.html new file mode 100644 index 0000000..bf20589 --- /dev/null +++ b/help/word_to_string.html @@ -0,0 +1,15 @@ + + +word.to.string + +

    word.to.string

    +Category

    +String commands

    +Syntax

    +

    +word.to.string(wA,sB);

    +Description

    +

    +This command is supposed to convert a word to a string, but I have not been able to get it to work.

    +See also

    + diff --git a/help/wordstok-editor.png b/help/wordstok-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..79df761fc8847ce03c752b4e23c18f446aaf6230 GIT binary patch literal 10873 zcmZ`<1yoz@vJFz8Xn|5FP$;3rtq@#W+$})y;_gsfT8b5d6c4V2;7))-3#G-~2@XMv z1=p8*?|b*H|Nie~t*rIsWO8!OH?#NbnK@A!YVt(*)c61ZfJjk6MhgJI=tRFK@i5Ux z{**et0sx)^6lGq6eKP+n_*Xyc&YC$|8YOu2Mh>$c&+@xi_dK?Rn?BDnKQ`enD;{1G zb1kODNoT@Rtx4-9+Byohn!5LUpBq2ch0P4s{!s2FjeqwW`(cJGfxvW#z6lOC4mKus z%1E*=9`@K|FTKZsEr@SnoNqyVoDX$-%8#03rJ`690U)TLfHRTwKI%N4CWDv|xx z{_dUUFij728bA<3S_t|#U%3FWZgazw<*{{8t zD9bC2sSYklxT#56%nprdw$H1_PnWn{+8FN7>DPA$&_k z*tuPWau&o?Ccjamx{bHit(_n39>ySBr<%@YdiRl5Ox3wvC)-y~FKEA^-BPo68i1K6 zCV17?)5FQg2y|b@5x$buKPkNSlDtTvt&afC9>aMDd+Xp6 zQr~+{(uC4+t6m$cA%V;JdCP*HqMU@_OJV)H4$IrdtRmT7tDFb5C$yKV!p9Z#2gg(O zPuv#I+!t}_Gn#eDaWo}b)0`;gp;@iHwaeSFNXW&wH(WnfpHy8fyXzUnP!Uhkg+~U3Uq-=A$$|Nss2bnrf0f8?S-i-^P!}imvN+k#+cPENAEu*OJ$H zRNgm4_Ounq$XIhfBAq>}jO?i)kdZkPej{Uv@&E!OVtU%_j!z`}`VB32pTGkfRI<3D zDL2Xk_jE`T(yt4@y4*|cf78Rkx}4Z1*B*j00*_Y>kM~_RpfnqED#Vj~gxfQ+?pHy_ zyAd1oChU4al@88`bdS_*Zsz@iT$S(e^wxt{{=@nnXIJr&VuyPkB$7>MqYb+<>*Vye zJ+sX8cct2~N`t|(!i=f+sPU?clk^7Ji<5Kifvmd;Rm#FIF7K6egQy|5vpM2zt}Do= zq9!@5PRYKJT`N54f*u|vk!_c?kv%3TSs7vx1DW-soao5CRt=f;!v{bhcN+)L{R)#b zVN{UmNq~1^WKRTfA3G>m2MC;BBqyEqSc(c>qM{_d3`JS}82C8YYehEJ9??q~m*Oqh zf1bmlcQLVj97eD)%$-;lH)C}r*e*886+4V0!;ORWRR2Zr)%EcKck0r8v&w?koySnB zgM=v;AeRQm7le|pm=JQ2MZKP@22QTm5c;dx98XN9K7ihTKS?Z#cDYh=kgt2BqbEj5bAe_TE2%2@HN(_DKioU z@poIE|A1g`%!jrrF7cr#H)Yg?df(A?@7j4!@#ST-k;fX>=2K!JMJ^$^>~_5%HuqEJ zbyKHA8oF6w)P7u#X}h-hcnFv9m9ivPHtR|n`@TY>Q~{!h`-LQA-}}O5(3)g`Yq@2*?Zp$aea`s+C}^T6gc15XDBMet2%%%O%(c~y1S9$pF~6Jf2s-h zHR8Insr~&}*eih}?d7!O+qNXOa729ZL45EHBvaT_BDflHlV4l12Oq6NMnxh{Yuipg zbC|rP9k`T_jx6`n{DqD}_wTQOQJ^anO_(;_FmQ}~iklXG7rLgOd8M*@ca?|sL3ccPKi{L|g z=b4+i8qxB=FkH}@1;*RKpb)Gz9uzAJ_thK7uyj&F!HV>y2QZ+#^ z0eP*Ukv(T5?^$=CG*(Mk>t&mL1L?=e_q|XNRT)b$w})HX%p?Y*nX8!gacK-DuNBW?Zk*$oKAY z^LMZgyRQW#vS*Q=lvKY-PG%kQRaWNAkOf$4H~7<0GFVo|(sJ=<2iiR<#S6wthTQjS z4`(f0;O;MMjQOmiEMw0ledL`@UjliHmO0#@iVEi)4D*YLqJn)V3mf^osi6YSl%(l= zUO>@JCF>cz#;C}FEH>@p&wE$e3_wdw&tI?f5N1L7bv*QU&v%h7bynL7N$7iy1>Y6E47FHCgl>GrB2CZ}M`Yn(clyrr zv3haP=P*w;DMGSKB@e3;PEBvGJ1&3Obg=kmJ+E^%@d{Nb9yQWjjNvQaQTi6?=&!!G z$l$M<;B?Si>_(b!^yhfsy4F>2wnmz6LFCo^g#i5SJ=|5M-Lq!kk?$X`%ez~0)#{`b zV)%yQWdZqmr+OcGqW?9GY08SmVvx4(0w;;OiR0yxci+nn_Dy3J%FpG&Izi2Img;+! zbYoLZ>+MbJF|)`19_#yq!hDw8uf)F@1bJoC2DY@7N({S>mjrBpE(LQ^To$-?>5`JQ z*Xv0yr?GsG74?s7;Z7I`zq`q-O}YD}t)XkVxEY&Y>uadmdpdd*3GI&lTG2)Q&BOGo z5=IS=-$rioo|+PBQ?so4p{YT9Z48Mv+}9i45@LT+^wfg4W|TK-eg_?V&}*-8?kcU4 zkQ6~xRf_naTn>cysuMecQei(??1~Lam)hLpotiMW(n?Th+EmFr4_IrmxUV+@GSI!+ z{WjRDjvy0q8rMdhXDZ+gJ0gxprJ0JC&eyf)amY7ynp{+A8FY)_n!W8hG+wI5-hy1i zE|6G>`x`70@%z5uT5ea7C;uF968ti_f`v`K{O!%G0U{Kw;4rRsgJ9GFcG#NV%` z*mY=|$^ZoR(4hY4kx3#8TeQL1B;_o7wf(YC?n>VK-;7H z29Wn+9?Tu&f*~ao)8bUgoF#h+op_jQ95ZHHiI_4+czR_MB|=u45BGM!xX18ltdMUz zb|CijxBYZq-V~k{CKTv zvy|WCET{B``jtWpwQ#p3oWZbwMhw77z(UZ{g?I)87m&+r)F@Z>OmtH~Qak!9Qj;PZ z|M@uv1~ealU{foAW+rFl8GPwuQtjfYCHDwr@WMQdu-U=*j&JuEP#!P$pNm2lAA{pb zNxK)s0NYYygMw&E(=jkDU_`66UM`jU-bCB&pSa58e!s(U|P72J69 zf!<`^lY>*P8?~}m^(SBut_i4KZH{0r9LVyQx`CRyPlSKgV;(Cpm9Xbo!hf8k;?4Kjp z46!V9^>)-n|2SrJkNT#X_|>coUuO!V*ukp_33W=pKS}7fU657r^O*a0jk^lfb6`CC zwbs3b#q|m!gkp>Z@Rk9B8ImkDzV(jBwtI*6mwp$Mzj2uFO7HJ)4jLZDZ!R*YrBdxY z*N(wvd6l<@hD+bL&7NRD|IV!9tcVcb%2_SPcfXi3nG7O(w$! zv$E%rgF}e{D}^62TeWl?VG031<3+z^>m-TX^-LMir`J<>J%k+UVTEq7a7%zhW z3+C?h>&1hxD=$HFpQT?UKIcaXT~be17Z@Dr+oHdy2Y1=k?|m?1RQWhDY!S@!wky`Y z+a_=H>|)f!%g7uCe}j8^`&4D|`y()T$jfWDrN!8_U*7?g%t}aO3cdMa2({P6c)b)=8!lt?o&p+}tu-T9l9=$#P&0J|Z;5|o(`0DyPy1T)ZYNk1?HT6e=ax@$J{2DZP0in^J1#a0h`J4Wa8J@dyy`V2dI9;I zS)BB zJ)6Li()bIB{gc-G666*nn#txYc&>cd}I*@|M9q*pB-gtkn-D0v6)jHv^`wke+i zM9MGc4?O7kM+tXw>D^w4CMh(6CaLSlIh%ScIiaz$#@&fDZ&wc4IISd}6D@zP0~u7j z*QH`DJbtTkRb)iOk#{i4>m3=rH{gt`q4}Vgx`vHLD_TpP2x|<$YGP1u#?L?50!o)W zZwMO7#lAQt<|(vqsiDA2xds`Wwd&bx;09BMIW!~6^}~>e2LmUP+9UeMVmW_2E>qea?AXpduaHr}3ZBE2*rcOKZmUmj zeATsF(am#U80z|3Nwn=t8Fjb}dBE8lcpQ5_%nYm&u4gBkkrYD$K?lhle$|@Nx54K? zrh=%FN^UEH(Ig~~YRP9_+U}oDVodWh>2CZgXRgr#xWt@>@3T5OGdf%z1KQC1WPeNO zFeS#v%iH08SvWd|pTWn!G`Q%4f*k=utkGM~SONGp7EPB8_)h;HQH$oG@bQvq1}+%I z;&K|TGZwKus%v^hHPpqJPUgiYDy7mVuDb%{TU0ot7y$Mm;+?FRZ=`(b&RXw|WgFhS zArLb3f!T1}Y89=r#!US|wnEs1UwXHIp0SBACMm0g_GTYx-L91u|307&!uYZwbU6ef zbA`DEDqQ7rJaukQ^h*BHT14@l>D|y#SFYQ$iaZnIzDz;975}l85Yf=AhgGy+N1NMI zl%Dc{%I8Sz)QJuJYt!*mqg$DtHrhuLxIK1lpocyAQ`Cn;2>ck{Oe<5^X_!Kry;mmh zgi$s%R=J=<^Pa%5xlJplZC}6fvcLdQI3w4N1;H-o7KZPvx5Bms2nCmVTVP>e`#XvH zsg<~X_EXqyHdF+9)mZjqSWP|1MQ4L~^Ht1OjXI27WwoK)bmxL&f}*L6m;sh_s7i2osYrUcGTh6NM|dmJ9%)ZLY8ESx!)fS(^H~B| zH(r{+lhBt9orZ}B4D3E>tp4O!Wk4rD{K0*8iA4w3%zeIrB7W5&^J?!E>9XPN<_4S$ z;FcyQj3ZwMW{zyj&z9bSyG&HSL3PER<)5ADcS+9`apfV~p9G=Ia`!laP?0AcMO8j9 z8o-F4$ykZ?49@L<(e5V*LZpCR=4W9^?Mn@>Yo_vu*BH58f5-fP9ufN9l^cjGi(p>S zCkEUuUzllVF^9Ckn4J0Xa@t(+|Y?7kaQ%x9Dc zvl7CIias1w+K;G@HsNu^5($OjiKp5n5g(3nKtI{aG~=F1vC>)tJC zbY)@A!*JTM%Fb$f=m%*k8SEk|VqiY31PXimR&Dl3dE{055Cp0++}{5jSZyX$7@;UT z_^q!BDzD9S6@tF8f5{YVsGP72=E#!|#hL(Hg1dVis_w<0Rz;+(M&P3nhfwug<)F-wNa`n6rxt>A=^GBqhqS$M> z1!7<)gIGu|wn(Hx!`O%ov>@?si_$N;2v6VbEEbk)tV}Mic|$I_uhn?^l!R-rzg!4Zd{3 z9U(Un>0_VQ4_q;1viMZe!s{lK8#%3!xK@zH!Sdb^{N8Z2qckeTOz7+9KFeUtNf2VG zq&=<&Q6uGUTGsN@8*P1{p|d;2@pis(3-=k`rjIFk^7L&~wnuPO?|Eup;h|LfWU@5T zi@Pbajy%$pv!DZ*mxeTZfilrkl#|`4ZW9Z*K4A^C17qDe4C(hKC{q3%Ues8`soKF6 zD21nejYC>$lyq>s%YmjtM9N4ru_Gq+dNaR4W0<*6q(Z6t7qb#BU%h3~i9QUlhMA$( znyV0^hL~dN!;6S(a&f)iaLtI&NZVg{r2?N6SxuyMATj1b)k^vT7EMAVzoPINBYozY zwlb>ea2|wAJv>(myzO*}OUog`3pNZHdJbuP*h`A{2>0~=68JA8K_Utzjm@a|5s_29 z&tGNZ*q@Smr@!So5lYZwTvQ!{8F!M9a+4kmkw5IXydTnV}?pnpK&m7W*Q zcVs<4q`+~Zr@aW~KidNHQ#MT>6(^GHPI{L0Mx7t^yyq3CMjgUFw~7WiDW|R1uWR8M z)1UCVEQ`jg;Y>s?f=82RBr+w7hNvz>8C%Wk?cj<)rmgAp3);4V@=o&CZV+P$8>a5<(ls=ZV2TUEsF(A8j91~At~>{pwo3F9bA6#!lnq-^y!y5AI{=ays%qt_s#VM`damrMKi`T*t_D-oJ=KBtvOW zDfd$lysGaD>|N4+>z0&`Qx^#+@z+_CJ}YS85uZvevxN)X#u6vCtp?FGkm zE=4VhoP^T+hW1z<%+S4Gh~tI*{3{Z9C8s27i$FaJPZgBiL~rU~VfijKu3;KX=9$spU@^|&CDhUJ=8bgSV+kL)OFdXgX=>T$ zN2fNnba&cI*fvu3(%J`H39XpWbr7gr&K?Gx=nqYFf_O zXVz<$b|Q75x3V}@C)gaOF-Tp`w)F*BH6d78%IF7JkfP@N;F$4q5dbV4l_(CSbLL$p z`M;|(G!YWev#*v)6l%O2d7P^LO19R!E;Ueu+%=L7cPRkUos^m8_af7tC|4OFseN!m zr8J(V5qq-|P2wrdWqT7Bh1 z`fP4H7}!rdV#6}BbALqIrAeO|Q}khouapc-axqfiQ9wJ2b;xjXEr$`|!}V0+gavZk zfZ+v@IN8dj0|Y!r*JFRBK|6hFr}fLxxfJ)-{C4r8wSY$n?SG`eNC^n<3$?5*DRSG) z^Vc$r%lZ$~r~hj@gja1_&01mIVw$u6Lnf=%R!_5X&J z?~Pj5uz|ZBzfgdj-tbo{Fgg{;e*Y*}VeAnf8fHZG{q26tUgHZ1{+sNaC z(8#UppASMB%Pbxx^bP#>A0b5MK})vPB>BxF6af^N+D?w{lkiu&xWq?uyGjl5J7CyQ zPi5Xts34*yeD_VN&w)$5dr|M8C$!ON^1!w0C+1q^GArOA}Q!#nHX4b9mvn zcT7fEU^gl)!TPPSr}nz?)J|tf8iraSWub2L#-%vNXpEl$z-{yszt4Tw+c*6GTunBx zh=OPI+Pz&|3~jzGxRy+yv-;24(xMg(6QN*xq*>7`F)&6F5l2zAicWp$HNIFDZS})a zH7iM|V+m}T$h+K%UrO1RUPi`rlW>WxZBP4sP~s`HZR)26)!W(a-YUN^oumz(LO-EW zJFPnpK_g1mhAzxNs(Ktwk$l`owRgpuhwPX_qe~zqGK^)J;Bgj!(Cfd6*|Am-HM+;3 zDoZv*S0caENO`(@_Z%1yJ%bgZM+n3O=(dpnwK(nUe=TaL4rH0~`$(7OF@Ytqpew+i zS7$+IQV*ccuLsTxcQ^-`KV}o0BWw{}Cbj!WwTU*0bN?h&Z0HxAK+00x)T`pBDc|W_ zmC1u=#aR>m2MTF(ix&^rZ^AQ%w_DeXt8pD)G>uN4ouPHXN9fp=hTEsNub)?hI7V}8 zN&DfbS2r*sm1*Qk^ds{a#K|7EQB4Nhs-Vqfc^npbiwe_U&|hn<(LxQ zh-*}lg=BVYRw+2j%Ih_hDJWJNxY-oR$9L95&!qHzN^%yM-BOs;E zW+b1&)v?+BS5TI2voZl}`#QtqeK~Wc{{NOyHR=$Nwx^XSXk}+COq# zW)yj}M>uOvpl1vj)CG|>G8uHK+A29KK(~>6xqSJwI|7MQZq8`AI{4m3ScCBKs{tA| z#!}btP8~f9I0fWWmT~GO6G(wV%d7-Tgz68(^2{?$ad*q5-eA(P`i-d3KCveHi2!`i zKb{5f$}${C>lnzVPak z^(1r~78k1WxfUJzXfg6J_PD&hej^{>zk2ssIY1>|u7-S;yd>mb?LpavOm9LAP;{u@ z1lvAU=Mv*fsY=9>3-f9G6wA(9sRiD583BuyD^6xeKGU5@IDqgas<>+{FX-7sYM_d& zWbg&aH*5;CrP$Tbxywihq{2H$tv8T*Fi_#uCHE~nkEF!$hx=XhJ}+b^$Hu!E2*8t9 z4UJ6V@1YT6%qXriwk|BTyr1OAfL31W;MtHH$(Ahf!LMZ+n(fVrz&XaH7ySNjb($50 zkpxgjh0$!Oiq3C8L20ye3@|}BqttpVVL~4g-W!-pS7Lx{Tt?TJ(AF(m^cz#^#?Ty--zC)wfyupE@3IC86mF*F!A`Gu-F1&mCl?h|#>P0qZW zg_9{K92JHo{XE!p5xQLlbADagY*FBTc{N71!60%!XLM&AN{sQSlmTK-t@@$7yYNhOIeEX13V=+4L*yk#biTpN~q)aa*@uXwQ~a zq^7-j6vRcq*}3J0yl7C>R8BG400Q4pP7c8n<>tR0wLWut;yv@~=U9>6JSFDO6wcPl zxsQdK6N4)?0Z!6_1t{b|x~VY4-T6OT+Mg$1GSS(G)5SUFla!CKn34fXw!@iG8Ab4? z)vO3HY_RrHU;)#!d$$yT)NZqS0n`R8;9^v!?}~0s3X|ZZsALPdOBivEaK%`ccE{TVO_@cS?Xt#Nf5r=mb92xihGM-G8`Kj;LW10VHHMo? zl>3690asg`zf;pLxV)k+zxHm%N_Yf!CGODhi?qyLwk&5T2EB;L-`r`vZFf&C0X(XO zj+I=FpQC$9Yy4yY*D^oqXHSLujj4LgH?LWqEUcB{U|Q*@7l_@*T5DpFMt-(S;yNDT zuz%k9`r!P(>l~`DbSo{ZNz;`=R_!py+2;?myhX9XnOC zZ5An>-hJm8CcgdoGMnRE<@Pg0Q!+_$=$?Ozr8-lMq_LTLik z{J?o93N}S zf}{BPi;m%dZ=^}+Nx#ba(ekP`N+=R4n|qe-;Cj>Xx6Ijo;868T-eEUIzrP`7+}&JNz>L(&&w7d>m>4ogQA&d~q|> zNjCJbiDZh6tyELv=1?MYnz2P*cr_k^HD@~)vVBXc_+c=0sGoIhvu%bu6K5-U$o_^V z8%&j9AMO~-gBS?f-;A`PsL%*HMzIkx(rQZc_L+Jh2PkFPb@-)|qSxdq6*WtBzMA~z z{<2Z{S*t>giM)mAJT+}qDc&*g6UX-h59YAC9C4jdM?14S1EI$oRYIxBSqwq_g)F4{ z&4(r6zW!_rNPq8>=8<|jge)GeI{a9^Npca_0>k(#Nep_%AVTb_-CO_Io3!SSP^ znkx~(or0MlHpii~ChwL7Ubb#;ia&}>swROj0qHPdSxfX*6Htl>QF(W}Q4fmSw=wz7Hm5^LoLeizeiGMU$ z(*rz&;ZxwH*MU24oK_sVy7}uA^XVL(cpDy+X?AP)cp36Z-{_u+iu6@43pfxvZ7y<43AoSAD8AZoa$yK z>3CR6_f;xTxEeKEH--`LJMeYBWCDm>6{cJ}yXRXUO&C%bK*Bu=bmwcB7tDiOIG+igB78!JsqwMwf)2}Glo!RLLbL)JLUZ%X%;9M~(wbyUy7#*aUPBF&T z&_^MZ)%x-bI`e8Lzj*v@2KrI0pqGJd1>e6xuP+Dzj>CWR^l8%TKn$AM6UxB23xUb! z=>7>ByS*f$r`!PY00-z;0QDf#;6%sKu;a=}NeSXoyJNCf)}3G&C*4>~Fa)8qey3oY zuUaAEEs$uQ=my=>K}FdTBwqdc&{l*TFEQcOFC>%SKS4~-#%RB7X2a23??cSuqtwCx zN)#DN#Ylg}hO$xnqV{Jzlz!Bl*AJYhDHnMRGP2@Z9b3=H2q{e7Eqk25I03;{cLWoc z7GIpnl_k8)80!P=9P)gErlL!1Hru=Q(RI6n$Z3HDm}^(E!7rrUcqXNCU4704qU>Ql zKeVqf%qiay$)972YS~-8Dp|$kkDf7&2tBJURfxn+kn7%y@tI|3W}1dN zaUEMSL(7ZyC|tWBO4ib-rzg9-BxDfwa(^p!vH|`~Iey8&fJ}fv-U`UTu(Cd2Cdozz zqvVsj#zBVFJ}N;(@wb#9D7c6YU{GP?;OXhvki!$QQ<7q<3kS70&U$690@w-+^7UVi zl?=XH4Pgc=gJS>gt-sLsznR@C^=sPD-P}#_Dj+0fE?th>XyP3eU__U80xKl>#|Imu hB~L=Yi1|JJ7G71$pYzILw15OC%Bsm!zIpfYzW`=(3C#ci literal 0 HcmV?d00001 diff --git a/help/wordstok_descr.html b/help/wordstok_descr.html new file mode 100644 index 0000000..31a2d71 --- /dev/null +++ b/help/wordstok_descr.html @@ -0,0 +1,21 @@ + + +The WORDS.TOK file + +

    The WORDS.TOK file

    +The words.tok file contains a list of all the words that the game accepts. These words are sorted into groups of synonyms, and each group has a number. It is generally best to have several synonyms +in each group, as this can reduce the "type 'till you bleed" frustration that is typical in many parser-based games by making the input more flexible. +

    +There are three groups that have special meaning:

    +Group 0: Words in this group are ignored. Examples of these sorts of words are "a", "the", "with", "my" etc. When the player types in "poke the bush with the stick", it is the same as typing in "poke +bush stick". +

    +Group 1: This group should contain only one word, "anyword". It can be used to respond to general statements such as "kill anyword", e.g. if the player types "kill alligator", "kill girl" or "kill +plant" then the statement said("kill","anyword") will be TRUE. +

    +Group 9999: This group should contain only one word, "rol". rol means rest of line, e.g. if the player types "fight", "fight beast" or "fight beast with sword" then the statement said("fight","rol") +will be TRUE. +

    +You can edit the words.tok file with the WORDS.TOK editor

    +Back to data used by AGI

    + diff --git a/help/wordstok_editor_main.html b/help/wordstok_editor_main.html new file mode 100644 index 0000000..ab10ad4 --- /dev/null +++ b/help/wordstok_editor_main.html @@ -0,0 +1,49 @@ + + +WORDS.TOK editor + +

    WORDS.TOK editor

    + The words.tok editor allows you to create and edit the words.tok file, which is used to store the words that the game accepts. For more information on the words.tok file, click here.

    +To load the words.tok editor, select the option from the 'Tools' menu or the toolbar. When you do this, it will load the words.tok file of the current game (if a game is open). You can then open a +different file if you wish. +

    +

    +

    Editing

    +Down the left hand side of the window is the list of word groups. These are groups of synonyms. The words in each group are shown, separated by a |. To see more of each group, slide the middle +separator to the right. +

    +Clicking on one of these groups will bring up the contents of the word group in the right-hand pane. To edit a word, just click on it and it will appear in the edit box below. You can also add or +delete words here. +

    +You can add or delete word groups as well as changing their number. It does not really matter which word groups have which numbers, other than groups 0, 1 and 9999. You may, however want to structure +your groups so that for example the first 20 or so are for general game functions, the next 20 or so are the names of inventory objects and the other words are put after that. Its up to you how you +do this. +

    +Your word group structure may become important when you want to merge this file with others.

    +

    Merging

    +The words.tok editor has the ability to merge files. This means combining two words.tok files by taking words from each file. To merge another file into the current one, select 'Merge' from the 'File' +menu. +

    +When merging a file, if a word exists in the merge file that is already in the current file (and in a different group), you will be asked if you wish to replace it or not. When merging files you +should be careful about which words you replace as some commands may no longer be recognised by the game. You may need to recompile some or all logics after merging so that they refer to the right +word groups in the right places. +

    +You shouldn't need to merge files that often, but when you do it is worth comparing the two files closely. If you're not careful, merging can alter the way commands are understood. For example, "glasses" +may be synonymous with "spectacles" at first, but depending on what is in the merge file you might end up with "glasses" being synonymous with "beer mugs". +

    +Note that the merge file (the one you are merging into the current file) is not modified in any way. The changes to the current file made by merging are only saved to disk when you save the file.

    +

    Finding words

    +A search feature has been added to help locate words without having to look through the word group. You can search for all or part of a word, and the find dialog will step through all the occurrences +of the text. +

    Saving

    +

    +Note: When saving a file, it does not necessarily have to be called words.tok. It must have this name, however, for the interpreter to use it.

    +If you try to save a file containing empty word groups, these will not be saved as the file format does not allow for empty groups. The program will not let you save a file if it does not have any +groups. The only reason empty groups are allowed is because they can make editing a bit more convenient. +

    A note about valid words

    +

    +To my knowledge, the only characters in words recognised by the interpreter are letters, numbers and spaces. The letters are all lower case, as the parser input is not case sensitive. If you enter a +word with any characters other than these, they will be automatically removed. Uppercase letters are converted to lower case. +

    +Back to contents

    + diff --git a/packaging/README.Packaging b/packaging/README.Packaging new file mode 100644 index 0000000..e8d17cb --- /dev/null +++ b/packaging/README.Packaging @@ -0,0 +1,6 @@ +This directory contains packaging scripts for a few systems. +If package this software to anothor system, please submit +the scripts to us through the project support site so that +we can add them here. + +- Jarno Elonen diff --git a/packaging/agistudio.desktop b/packaging/agistudio.desktop new file mode 100644 index 0000000..5c31cb8 --- /dev/null +++ b/packaging/agistudio.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Name=QT AGI Studio +Exec=agistudio +Icon=qtagistudio +Type=Application +Terminal=false +Categories=Development;Qt; diff --git a/packaging/debian/agistudio.doc-base b/packaging/debian/agistudio.doc-base new file mode 100644 index 0000000..0f8e82e --- /dev/null +++ b/packaging/debian/agistudio.doc-base @@ -0,0 +1,10 @@ +Document: agistudio +Title: QT AGI Studio User's Manual +Author: Peter Kelly, Helen Zommer +Abstract: This manual describes the user interface + of QT AGI Studio, an adventure game IDE. +Section: Apps/Programming + +Format: HTML +Index: /usr/share/agistudio/help/index.html +Files: /usr/share/agistudio/help/*.html diff --git a/packaging/debian/agistudio.install b/packaging/debian/agistudio.install new file mode 100644 index 0000000..6d855a6 --- /dev/null +++ b/packaging/debian/agistudio.install @@ -0,0 +1,4 @@ +src/agistudio usr/bin +help usr/share/agistudio +template usr/share/agistudio +debian/agistudio.xpm usr/share/agistudio diff --git a/packaging/debian/agistudio.xpm b/packaging/debian/agistudio.xpm new file mode 100644 index 0000000..6323eeb --- /dev/null +++ b/packaging/debian/agistudio.xpm @@ -0,0 +1,37 @@ +/* XPM */ +static char * agistudio_xpm[] = { +"24 24 10 1", +" c None", +". c #7F0000", +"+ c #00FFFF", +"@ c #999999", +"# c #4C4C4C", +"$ c #FFFF00", +"% c #000000", +"& c #FF0000", +"* c #7F007F", +"= c #191919", +" ", +" .. ", +" .... ", +" ++..@ ", +" ++++++ ", +" ++++++++ ", +" ######$$ ", +" ####$$$$$$ ", +" ####$$$$@@ ", +" ##$$$%%%% ", +" @$$$%$$$% ", +" &&&%$$%*% ", +" &&&&&%$%&**% ", +" &&&&&&%&&&**% ", +" &&$$&&&%&&&**% ", +" &&$$&&& %&&&**% ", +" &&$$&&& %&&&**= ", +" &&$$&&& %&&&*% ", +" &&$$$$& =&&&% ", +" &&..$$$$ %%% ", +" ......$$ ", +" ++++++@@ ", +" ++++++@ ", +" "}; diff --git a/packaging/debian/changelog b/packaging/debian/changelog new file mode 100644 index 0000000..fcb653b --- /dev/null +++ b/packaging/debian/changelog @@ -0,0 +1,141 @@ +agistudio (1.3.0-1) unstable; urgency=low + + * New upstream release. + + -- Jarno Elonen Sat, 25 Apr 2012 17:32:00 +0300 + +agistudio (1.2.4-1) unstable; urgency=low + + * New upstream release. + + -- Jarno Elonen Wed, 08 Apr 2009 01:37:29 +0300 + +agistudio (1.2.3+svn20070518-1) unstable; urgency=low + + * New upstream release (from SVN). + - GCC 4.3 build patch (Closes: #417080) + + * Orphaning the package. + + -- Jarno Elonen Fri, 18 May 2007 12:30:08 +0300 + +agistudio (1.2.3-1) unstable; urgency=low + + * New upstream release. + + -- Jarno Elonen Thu, 18 Mar 2007 02:25:02 +0300 + +agistudio (1.2.2-1) unstable; urgency=low + + * New upstream release. (Closes: #358291) + + -- Jarno Elonen Thu, 22 Mar 2006 21:53:23 +0300 + +agistudio (1.2.1-5) unstable; urgency=low + + * QT ABI transition + + -- Jarno Elonen Thu, 1 Sep 2005 22:24:15 +0300 + +agistudio (1.2.1-4) unstable; urgency=low + + * Added a watch file + + * REALLY changed maintainer email address + + * Moved menu pixmap away from /usr/X11 + + -- Jarno Elonen Sun, 10 Oct 2004 03:01:09 +0300 + +agistudio (1.2.1-3) unstable; urgency=low + + * Copyrights update + * Changed maintainer email address + * Updated 'Section' to match the override file + + -- Jarno Elonen Fri, 16 Jan 2004 11:01:47 +0200 + +agistudio (1.2.1-2) unstable; urgency=low + + * Fixed some bad code that crashed GCC 3.3 on Alpha + (Thanks to Riku Voipio for notifying me about the + problem and to Falk Hueffner for pointing out the reason) + + * Updated an URL in documentation as requested by Juha Terho + + * Cleaned up some compiler warnings + + * Changed Section to 'devel' - Agistudio is neither a + game nor a generic X11 application + + * Changed build options for tmake to generate a + release version (-O2, most notably) instead of debug + + -- Jarno Elonen Thu, 11 Sep 2003 19:57:00 +0300 + +agistudio (1.2.1-1) unstable; urgency=low + + * New upstream release. + - Midi export + + * Fixed Build-Depends and upgraded Standards-Version + + -- Jarno Elonen Fri, 8 Aug 2003 10:07:44 +0300 + +agistudio (1.2-1) unstable; urgency=low + + * New upstream release. + + -- Jarno Elonen Sat, 17 May 2003 15:03:49 +0300 + +agistudio (1.1-1) unstable; urgency=low + + * New upstream version. + + * Previous patches merged to upstream. + + -- Jarno Elonen Sun, 6 Apr 2003 21:05:39 +0300 + +agistudio (1.0-3) unstable; urgency=low + + * Added context sensitive help on AGI commands + to the logic editor + + * Added syntax highlight with command detection + + * Text search now selects found text + + * Enhanced logic parser (comment removal, whitespace handling) + + -- Jarno Elonen Fri, 28 Mar 2003 23:02:51 +0200 + +agistudio (1.0-2) unstable; urgency=low + + * Added review for logics + + * Embedded the preview window into the + resource window to remove annoying popups + + * Nonpropotional font for text editor, too, + not just logics + + * Added a priority mask color display to + the picture editor + + * Some smaller usability fixes + + -- Jarno Elonen Sun, 23 Mar 2003 18:55:59 +0200 + +agistudio (1.0-1) unstable; urgency=low + + * Initial Release. + + * Ported upstream source to QT 3.1 + + * changed editor font to non-propotional + + * changed default interpreter to Nagi + (more AGI compatibile than Sarien) + + -- Jarno Elonen Sat, 1 Mar 2003 11:00:43 +0200 + diff --git a/packaging/debian/control b/packaging/debian/control new file mode 100644 index 0000000..097f74e --- /dev/null +++ b/packaging/debian/control @@ -0,0 +1,15 @@ +Source: agistudio +Section: x11 +Priority: optional +Maintainer: Debian QA Group +Build-Depends: debhelper (>= 4.0.0), tmake, libqt4-dev, libqt4-qt3support +Standards-Version: 3.6.1.1 + +Package: agistudio +Architecture: any +Depends: ${shlibs:Depends} +Recommends: scummvm|nagi|sarien +Description: IDE for creating early Sierra style AGI games + AGI (Adventure Game Interpreter) is the adventure game engine used by + Sierra On-Line(tm) to create some of their early games. QT AGI Studio + is a program which allows you to view, create and edit AGI games. diff --git a/packaging/debian/copyright b/packaging/debian/copyright new file mode 100644 index 0000000..0218b90 --- /dev/null +++ b/packaging/debian/copyright @@ -0,0 +1,35 @@ +QT AGI Studio was debianized by Jarno Elonen in 2003 +from source files available at + + http://agistudio.sourceforge.net/ + +Upstream authors: + Helen Zommer + Jarno Elonen + Claudio Matsuoka + Peter Kelly (orig. Agistudio in Pascal) + Lance Ewing (the DOS Picedit) + Nat Budin (Win32 fixes) + +Upstream copyright: + 2000, 2002, 2003 Helen Zommer + 2003 Jarno Elonen + 1999 Claudio Matsuoka + 2000 Nat Budin + + (Peter Kelly and Lance Ewing are not included in this + list since while a great part of the logic and ideas + are based on their work, QT Agistudio has been + rewritten in C++.) + +QT AGI Studio is distributed under the terms of the +GNU General Public License. + +On Debian GNU/Linux system you can find a copy of GPL in +/usr/share/common-licenses/GPL' + + +The packager has placed his own packaging works into the Public +Domain and licenses those works that are modifications to existing +copyrighted works (some packaging scripts, modified upstream +sources etc.) under the same license as the original ones. diff --git a/packaging/debian/dirs b/packaging/debian/dirs new file mode 100644 index 0000000..ae0ee86 --- /dev/null +++ b/packaging/debian/dirs @@ -0,0 +1,3 @@ +usr/bin +usr/share/agistudio/help +usr/share/agistudio/template/src diff --git a/packaging/debian/docs b/packaging/debian/docs new file mode 100644 index 0000000..e67a9bf --- /dev/null +++ b/packaging/debian/docs @@ -0,0 +1,2 @@ +README +relnotes diff --git a/packaging/debian/menu b/packaging/debian/menu new file mode 100644 index 0000000..aad3a11 --- /dev/null +++ b/packaging/debian/menu @@ -0,0 +1,4 @@ +?package(agistudio):needs="X11" section="Apps/Programming" \ + title="Agistudio" \ + icon="/usr/share/agistudio/agistudio.xpm" \ + command="/usr/bin/agistudio" diff --git a/packaging/debian/rules b/packaging/debian/rules new file mode 100755 index 0000000..90ef908 --- /dev/null +++ b/packaging/debian/rules @@ -0,0 +1,95 @@ +#!/usr/bin/make -f +# Build rules for "QT AGI Studio", modified from +# the sample debian/rules (GNU copyright 1997 to 1999 +# by Joey Hess) + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatibility version to use. +export DH_COMPAT=4 + + + +CFLAGS = -Wall -g + +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) + CFLAGS += -O0 +else + CFLAGS += -O2 +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +configure: configure-stamp +configure-stamp: + dh_testdir + cd src; qmake-qt4 agistudio.pro -o Makefile + touch configure-stamp + + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + cd src; $(MAKE) + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + + -cd src; $(MAKE) clean + -rm src/Makefile + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + dh_install + mkdir -p $(CURDIR)/debian/agistudio/usr/share/applications + install -m 644 $(CURDIR)/packaging/agistudio.desktop $(CURDIR)/debian/agistudio/usr/share/applications/ + mkdir -p $(CURDIR)/debian/agistudio/usr/share/pixmaps + install -m 644 $(CURDIR)/packaging/qtagistudio.xpm $(CURDIR)/debian/agistudio/usr/share/pixmaps/ + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot +# dh_installdebconf + dh_installdocs + dh_installexamples + dh_installmenu +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit +# dh_installcron + dh_installman agistudio.1 +# dh_installinfo +# dh_undocumented + dh_installchangelogs + dh_link + dh_strip + dh_compress + dh_fixperms +# dh_makeshlibs + dh_installdeb +# dh_perl + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/packaging/qtagistudio.xpm b/packaging/qtagistudio.xpm new file mode 100644 index 0000000..d4be2c5 --- /dev/null +++ b/packaging/qtagistudio.xpm @@ -0,0 +1,40 @@ +/* XPM */ +static char * agistudio_icon_xpm[] = { +"32 32 5 1", +" c None", +". c #000000", +"+ c #FF5050", +"@ c #A00000", +"# c #0000A0", +" ", +" ", +" ........ ", +" ........ ", +" ................ ", +" ................ ", +" ........++++ ", +" ........++++ ", +" ....++++@@@@ ", +" ....++++@@@@ ", +" ....++++++++++++ ", +" ....++++++++++++ ", +" ....++++++++ ", +" ....++++++++ ", +" ....++++++++ ", +" ....++++++++ ", +" ....++++++++ ", +" ....++++++++ ", +" ++++ ", +" ++++ ", +" #### ", +" #### ", +" ############ ", +" ############ ", +" ############ ", +" ############ ", +" ################ ", +" ################ ", +" #################### ", +" #################### ", +" ########################+++ ", +" ########################+++ "}; diff --git a/packaging/rpm/agistudio.spec b/packaging/rpm/agistudio.spec new file mode 100644 index 0000000..f5bcc49 --- /dev/null +++ b/packaging/rpm/agistudio.spec @@ -0,0 +1,39 @@ +Summary: AGI integrated development environment +Name: agistudio +Version: 1.3.0 +Release: 0 +Copyright: GPL +Group: Development/Tools +Source: agistudio-1.3.0.tar.gz +URL: http://agistudio.sourceforge.net/ +%description +AGI (Adventure Game Interpreter) is the adventure game engine used by +Sierra On-Line(tm) to create some of their early games. QT AGI Studio +is a program which allows you to view, create and edit AGI games. +%prep +%setup +%build +cd src +qmake-qt4 agistudio.pro -o Makefile +make RPM_OPT_FLAGS="$RPM_OPT_FLAGS" + +%install +mkdir -p /usr/local/agistudio/bin +mkdir -p /usr/local/bin +install -m 755 -o 0 -g 0 src/agistudio /usr/local/agistudio//bin/agistudio +ln -fs /usr/local/agistudio/bin/agistudio /usr/local/bin/agistudio +install -m 755 -d -o 0 -g 0 template /usr/local/agistudio/template +install -m 755 -d -o 0 -g 0 help /usr/local/agistudio/help +install -m 755 -o 0 -g 0 README /usr/local/agistudio/README +install -m 755 -o 0 -g 0 relnotes /usr/local/agistudio/relnotes +cp help/* /usr/local/agistudio/help +cp -r template/* /usr/local/agistudio/template + +%files +/usr/local/agistudio/bin/agistudio +/usr/local/bin/agistudio +/usr/local/agistudio/template +/usr/local/agistudio/help +/usr/local/agistudio/relnotes +/usr/local/agistudio/README + diff --git a/relnotes b/relnotes new file mode 100644 index 0000000..bf1ec98 --- /dev/null +++ b/relnotes @@ -0,0 +1,44 @@ +Release notes for QT AGI Studio version 1.3.0 (2012-08-25) + +- new features: + * ported to QT4 + * bitmap import for picture resources (vectorization) + * replaced old game open dialog with QT4 native + * more useful/complete template game (more like an example now) + * monospace font in logic editor + +- bug fixes: + * fixed a long-standing random startup crash + * wider position text area in picture editor + +- cleaner compilation, again + +Release notes for QT AGI Studio version 1.2.4 (2009-04-09) + +- cleaner compilation ("const char*" fixes etc.) + +Release notes for QT AGI Studio version 1.2.3 (2007-03-18) + +- new features: + * bitmap export for views (sprites) + +Release notes for QT AGI Studio version 1.2.1 (2003-08-08) + +- new features: + * midi export + +Release notes for QT AGI Studio version 1.2 (2003-05-17) + +- new features: + * logic editor: show line numbers + * documented the previously unknown commands + +- bug fixes: + * compiler: support for new AGI commands and empty blocks + to make LSL1 decompilable (thanks to Andreas J. Bathe + for reporting this) + * logic editor: fixed occasional crash with decompiled logics + +- other: + * Included a printable picture template for drafting AGI + pictures with a pencil diff --git a/src/agicommands.cpp b/src/agicommands.cpp new file mode 100644 index 0000000..d610885 --- /dev/null +++ b/src/agicommands.cpp @@ -0,0 +1,266 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "agicommands.h" + + +const char *ArgTypePrefix[9] = {"","v","f","m","o","i","s","w","c"}; +const char *ArgTypeName[9] = {"number","var","flag","message","object", + "inventory item","string","word","controller"}; + + + +CommandStruct TestCommand[19] = { + { "", 0 , { 0,0,0,0,0,0,0 } }, //dummy + { "equaln", 2, { atVar,atNum,0,0,0,0,0 } }, + { "equalv", 2, { atVar,atVar,0,0,0,0,0 } }, + { "lessn", 2, { atVar,atNum,0,0,0,0,0 } }, + { "lessv", 2, { atVar,atVar,0,0,0,0,0 } }, + { "greatern", 2, { atVar,atNum,0,0,0,0,0 } }, + { "greaterv", 2, { atVar,atVar,0,0,0,0,0 } }, + { "isset", 1, { atFlag,0,0,0,0,0,0 } }, + { "issetv", 1, { atVar,0,0,0,0,0,0 } }, + { "has", 1, { atIObj,0,0,0,0,0,0 } }, + { "obj.in.room", 2, { atIObj,atVar,0,0,0,0,0 } }, + { "posn", 5, { atSObj,atNum,atNum,atNum,atNum,0,0 } }, + { "controller", 1, { atCtrl,0,0,0,0,0,0 } }, + { "have.key", 0, { 0,0,0,0,0,0,0 } }, + { "said", 0, { 0,0,0,0,0,0,0 } }, // special command so we don't need to set the right argument types for it + { "compare.strings", 2, { atStr,atStr,0,0,0,0,0 } }, + { "obj.in.box", 5, { atSObj,atNum,atNum,atNum,atNum,0,0 } }, + { "center.posn", 5, { atSObj,atNum,atNum,atNum,atNum,0,0 } }, + { "right.posn", 5, { atSObj,atNum,atNum,atNum,atNum,0,0 } } + +}; + + +CommandStruct AGICommand[182] = { + + { "return", 0, { 0,0,0,0,0,0,0 } }, + { "increment", 1, { atVar,0,0,0,0,0,0 } }, + { "decrement", 1, { atVar,0,0,0,0,0,0 } }, + { "assignn", 2, { atVar,atNum,0,0,0,0,0 } }, + { "assignv", 2, { atVar,atVar,0,0,0,0,0 } }, + { "addn", 2, { atVar,atNum,0,0,0,0,0 } }, + { "addv", 2, { atVar,atVar,0,0,0,0,0 } }, + { "subn", 2, { atVar,atNum,0,0,0,0,0 } }, + { "subv", 2, { atVar,atVar,0,0,0,0,0 } }, + { "lindirectv", 2, { atVar,atVar,0,0,0,0,0 } }, + { "rindirect", 2, { atVar,atVar,0,0,0,0,0 } }, + { "lindirectn", 2, { atVar,atNum,0,0,0,0,0 } }, + { "set", 1, { atFlag,0,0,0,0,0,0 } }, + { "reset", 1, { atFlag,0,0,0,0,0,0 } }, + { "toggle", 1, { atFlag,0,0,0,0,0,0 } }, + { "set.v", 1, { atVar,0,0,0,0,0,0 } }, + { "reset.v", 1, { atVar,0,0,0,0,0,0 } }, + { "toggle.v", 1, { atVar,0,0,0,0,0,0 } }, + { "new.room", 1, { atNum,0,0,0,0,0,0 } }, + { "new.room.v", 1, { atVar,0,0,0,0,0,0 } }, + { "load.logics", 1, { atNum,0,0,0,0,0,0 } }, + { "load.logics.v", 1, { atVar,0,0,0,0,0,0 } }, + { "call", 1, { atNum,0,0,0,0,0,0 } }, + { "call.v", 1, { atVar,0,0,0,0,0,0 } }, + { "load.pic", 1, { atVar,0,0,0,0,0,0 } }, + { "draw.pic", 1, { atVar,0,0,0,0,0,0 } }, + { "show.pic", 0, { 0,0,0,0,0,0,0 } }, + { "discard.pic", 1, { atVar,0,0,0,0,0,0 } }, + { "overlay.pic", 1, { atVar,0,0,0,0,0,0 } }, + { "show.pri.screen", 0, { 0,0,0,0,0,0,0 } }, + { "load.view", 1, { atNum,0,0,0,0,0,0 } }, + { "load.view.v", 1, { atVar,0,0,0,0,0,0 } }, + { "discard.view", 1, { atNum,0,0,0,0,0,0 } }, + { "animate.obj", 1, { atSObj,0,0,0,0,0,0 } }, + { "unanimate.all", 0, { 0,0,0,0,0,0,0 } }, + { "draw", 1, { atSObj,0,0,0,0,0,0 } }, + { "erase", 1, { atSObj,0,0,0,0,0,0 } }, + { "position", 3, { atSObj,atNum,atNum,0,0,0,0 } }, + { "position.v", 3, { atSObj,atVar,atVar,0,0,0,0 } }, + { "get.posn", 3, { atSObj,atVar,atVar,0,0,0,0 } }, + { "reposition", 3, { atSObj,atVar,atVar,0,0,0,0 } }, + { "set.view", 2, { atSObj,atNum,0,0,0,0,0 } }, + { "set.view.v", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "set.loop", 2, { atSObj,atNum,0,0,0,0,0 } }, + { "set.loop.v", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "fix.loop", 1, { atSObj,0,0,0,0,0,0 } }, + { "release.loop", 1, { atSObj,0,0,0,0,0,0 } }, + { "set.cel", 2, { atSObj,atNum,0,0,0,0,0 } }, + { "set.cel.v", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "last.cel", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "current.cel", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "current.loop", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "current.view", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "number.of.loops", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "set.priority", 2, { atSObj,atNum,0,0,0,0,0 } }, + { "set.priority.v", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "release.priority", 1, { atSObj,0,0,0,0,0,0 } }, + { "get.priority", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "stop.update", 1, { atSObj,0,0,0,0,0,0 } }, + { "start.update", 1, { atSObj,0,0,0,0,0,0 } }, + { "force.update", 1, { atSObj,0,0,0,0,0,0 } }, + { "ignore.horizon", 1, { atSObj,0,0,0,0,0,0 } }, + { "observe.horizon", 1, { atSObj,0,0,0,0,0,0 } }, + { "set.horizon", 1, { atNum,0,0,0,0,0,0 } }, + { "object.on.water", 1, { atSObj,0,0,0,0,0,0 } }, + { "object.on.land", 1, { atSObj,0,0,0,0,0,0 } }, + { "object.on.anything", 1, { atSObj,0,0,0,0,0,0 } }, + { "ignore.objs", 1, { atSObj,0,0,0,0,0,0 } }, + { "observe.objs", 1, { atSObj,0,0,0,0,0,0 } }, + { "distance", 3, { atSObj,atSObj,atVar,0,0,0,0 } }, + { "stop.cycling", 1, { atSObj,0,0,0,0,0,0 } }, + { "start.cycling", 1, { atSObj,0,0,0,0,0,0 } }, + { "normal.cycle", 1, { atSObj,0,0,0,0,0,0 } }, + { "end.of.loop", 2, { atSObj,atFlag,0,0,0,0,0 } }, + { "reverse.cycle", 1, { atSObj,0,0,0,0,0,0 } }, + { "reverse.loop", 2, { atSObj,atFlag,0,0,0,0,0 } }, + { "cycle.time", 2, { atSObj,atVar,0,0,0,0,0 } }, // arg2 Num??? + { "stop.motion", 1, { atSObj,0,0,0,0,0,0 } }, + { "start.motion", 1, { atSObj,0,0,0,0,0,0 } }, + { "step.size", 2, { atSObj,atVar,0,0,0,0,0 } }, // arg2 Num??? + { "step.time", 2, { atSObj,atVar,0,0,0,0,0 } }, // arg2 Num??? + { "move.obj", 5, { atSObj,atNum,atNum,atNum,atFlag,0,0 } }, + { "move.obj.v", 5, { atSObj,atVar,atVar,atNum,atFlag,0,0 } }, // arg 3 var??? + { "follow.ego", 3, { atSObj,atNum,atFlag,0,0,0,0 } }, + { "wander", 1, { atSObj,0,0,0,0,0,0 } }, + { "normal.motion", 1, { atSObj,0,0,0,0,0,0 } }, + { "set.dir", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "get.dir", 2, { atSObj,atVar,0,0,0,0,0 } }, + { "ignore.blocks", 1, { atSObj,0,0,0,0,0,0 } }, + { "observe.blocks", 1, { atSObj,0,0,0,0,0,0 } }, + { "block", 4, { atNum,atNum,atNum,atNum,0,0,0 } }, + { "unblock", 0, { 0,0,0,0,0,0,0 } }, + { "get", 1, { atIObj,0,0,0,0,0,0 } }, + { "get.v", 1, { atVar,0,0,0,0,0,0 } }, + { "drop", 1, { atIObj,0,0,0,0,0,0 } }, + { "put", 2, { atIObj,atVar,0,0,0,0,0 } }, + { "put.v", 2, { atVar,atVar,0,0,0,0,0 } }, + { "get.room.v", 2, { atVar,atVar,0,0,0,0,0 } }, + { "load.sound", 1, { atNum,0,0,0,0,0,0 } }, + { "sound", 2, { atNum,atFlag,0,0,0,0,0 } }, + { "stop.sound", 0, { 0,0,0,0,0,0,0 } }, + { "print", 1, { atMsg,0,0,0,0,0,0 } }, + { "print.v", 1, { atVar,0,0,0,0,0,0 } }, + { "display", 3, { atNum,atNum,atMsg,0,0,0,0 } }, + { "display.v", 3, { atVar,atVar,atVar,0,0,0,0 } }, + { "clear.lines", 3, { atNum,atNum,atNum,0,0,0,0 } }, + { "text.screen", 0, { 0,0,0,0,0,0,0 } }, + { "graphics", 0, { 0,0,0,0,0,0,0 } }, + { "set.cursor.char", 1, { atMsg,0,0,0,0,0,0 } }, + { "set.text.attribute", 2, { atNum,atNum,0,0,0,0,0 } }, + { "shake.screen", 1, { atNum,0,0,0,0,0,0 } }, + { "configure.screen", 3, { atNum,atNum,atNum,0,0,0,0 } }, + { "status.line.on", 0, { 0,0,0,0,0,0,0 } }, + { "status.line.off", 0, { 0,0,0,0,0,0,0 } }, + { "set.string", 2, { atStr,atMsg,0,0,0,0,0 } }, + { "get.string", 5, { atStr,atMsg,atNum,atNum,atNum,0,0 } }, + { "word.to.string", 2, { atWord,atStr,0,0,0,0,0 } }, + { "parse", 1, { atStr,0,0,0,0,0,0 } }, + { "get.num", 2, { atMsg,atVar,0,0,0,0,0 } }, + { "prevent.input", 0, { 0,0,0,0,0,0,0 } }, + { "accept.input", 0, { 0,0,0,0,0,0,0 } }, + { "set.key", 3, { atNum,atNum,atCtrl,0,0,0,0 } }, + { "add.to.pic", 7, { atNum,atNum,atNum,atNum,atNum,atNum,atNum } }, + { "add.to.pic.v", 7, { atVar,atVar,atVar,atVar,atVar,atVar,atVar } }, + { "status", 0, { 0,0,0,0,0,0,0 } }, + { "save.game", 0, { 0,0,0,0,0,0,0 } }, + { "restore.game", 0, { 0,0,0,0,0,0,0 } }, + { "init.disk", 0, { 0,0,0,0,0,0,0 } }, + { "restart.game", 0, { 0,0,0,0,0,0,0 } }, + { "show.obj", 1, { atNum,0,0,0,0,0,0 } }, + { "random", 3, { atNum,atNum,atVar,0,0,0,0 } }, + { "program.control", 0, { 0,0,0,0,0,0,0 } }, + { "player.control", 0, { 0,0,0,0,0,0,0 } }, + { "obj.status.v", 1, { atVar,0,0,0,0,0,0 } }, + { "quit", 1, { atNum,0,0,0,0,0,0 } }, // 0 args for 2.089 + { "show.mem", 0, { 0,0,0,0,0,0,0 } }, + { "pause", 0, { 0,0,0,0,0,0,0 } }, + { "echo.line", 0, { 0,0,0,0,0,0,0 } }, + { "cancel.line", 0, { 0,0,0,0,0,0,0 } }, + { "init.joy", 0, { 0,0,0,0,0,0,0 } }, + { "toggle.monitor", 0, { 0,0,0,0,0,0,0 } }, + { "version", 0, { 0,0,0,0,0,0,0 } }, + { "script.size", 1, { atNum,0,0,0,0,0,0 } }, + { "set.game.id", 1, { atMsg,0,0,0,0,0,0 } }, + { "log", 1, { atMsg,0,0,0,0,0,0 } }, + { "set.scan.start", 0, { 0,0,0,0,0,0,0 } }, + { "reset.scan.start", 0, { 0,0,0,0,0,0,0 } }, + { "reposition.to", 3, { atSObj,atNum,atNum,0,0,0,0 } }, + { "reposition.to.v", 3, { atSObj,atVar,atVar,0,0,0,0 } }, + { "trace.on", 0, { 0,0,0,0,0,0,0 } }, + { "trace.info", 3, { atNum,atNum,atNum,0,0,0,0 } }, + { "print.at", 4, { atMsg,atNum,atNum,atNum,0,0,0 } }, // 3 args before 2.440 + { "print.at.v", 4, { atMsg,atVar,atVar,atVar,0,0,0 } }, // 3 args before 2.440 + { "discard.view.v", 1, { atVar,0,0,0,0,0,0 } }, + { "clear.text.rect", 5, { atNum,atNum,atNum,atNum,atNum,0,0 } }, + { "set.upper.left", 2, { 0,0,0,0,0,0,0 } }, // ????? + { "set.menu", 1, { atMsg,0,0,0,0,0,0 } }, + { "set.menu.item", 2, { atMsg,atCtrl,0,0,0,0,0 } }, + { "submit.menu", 0, { 0,0,0,0,0,0,0 } }, + { "enable.item", 1, { atCtrl,0,0,0,0,0,0 } }, + { "disable.item", 1, { atCtrl,0,0,0,0,0,0 } }, + { "menu.input", 0, { 0,0,0,0,0,0,0 } }, + { "show.obj.v", 1, { atVar,0,0,0,0,0,0 } }, + { "open.dialogue", 0, { 0,0,0,0,0,0,0 } }, + { "close.dialogue", 0, { 0,0,0,0,0,0,0 } }, + { "mul.n", 2, { atVar,atNum,0,0,0,0,0 } }, + { "mul.v", 2, { atVar,atVar,0,0,0,0,0 } }, + { "div.n", 2, { atVar,atNum,0,0,0,0,0 } }, + { "div.v", 2, { atVar,atVar,0,0,0,0,0 } }, + { "close.window", 0, { 0,0,0,0,0,0,0 } }, + + // The formerly unknown commands + { "set.simple", 1, {0,0,0,0,0,0,0 } }, // unknown 170 + { "push.script", 0, {0,0,0,0,0,0,0 } }, // unknown 171 + { "pop.script", 0, {0,0,0,0,0,0,0 } }, // unknown 172 + { "hold.key", 0, {0,0,0,0,0,0,0 } }, // unknown 173 + { "set.pri.base", 1, {0,0,0,0,0,0,0 } }, // unknown 174 + { "discard.sound", 1, {0,0,0,0,0,0,0 } }, // unknown 175 + { "hide.mouse", 0, {0,0,0,0,0,0,0 } }, // unknown 176 - 1 arg for 3.002.086 + { "allow.menu", 1, {0,0,0,0,0,0,0 } }, // unknown 177 + { "show.mouse", 0, {0,0,0,0,0,0,0 } }, // unknown 178 + { "fence.mouse", 4, {0,0,0,0,0,0,0 } }, // unknown 179 + { "mouse.posn", 2, {0,0,0,0,0,0,0 } }, // unknown 180 + { "release.key", 0, {0,0,0,0,0,0,0 } } // unknown 181 +}; + + +int NumAGICommands = 181; // not counting return() + +void CorrectCommands(double VerNum) +{ + + if(VerNum <= 2.089){ + AGICommand[134].NumArgs = 0; //quit + } + if(VerNum < 2.400){ + AGICommand[151].NumArgs = 3; // print.at + AGICommand[152].NumArgs = 3; // print.at.v + } + if(VerNum <= 3.002086){ + AGICommand[176].NumArgs = 1; + } + if(VerNum <= 2.089)NumAGICommands = 155; + else if (VerNum <= 2.272)NumAGICommands = 161; + else if (VerNum <= 2.440)NumAGICommands = 169; + else if (VerNum <= 2.917)NumAGICommands = 173; + else if (VerNum <= 2.936)NumAGICommands = 175; + else if (VerNum <= 3.002086)NumAGICommands = 177; + else NumAGICommands = 181; + +} diff --git a/src/agicommands.h b/src/agicommands.h new file mode 100644 index 0000000..eac005b --- /dev/null +++ b/src/agicommands.h @@ -0,0 +1,53 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef AGI_COMMANDS_H +#define AGI_COMMANDS_H + +//argument types +#define atNum 0 +#define atVar 1 +#define atFlag 2 +#define atMsg 3 +#define atSObj 4 +#define atIObj 5 +#define atStr 6 +#define atWord 7 +#define atCtrl 8 + +extern const char *ArgTypePrefix[9] ; +extern const char *ArgTypeName[9] ; + +typedef struct { + const char *Name; + char NumArgs; + char argTypes[7]; +}CommandStruct; + +#define NumTestCommands 18 +extern int NumAGICommands; //changes in different AGI interpreter versions + +extern CommandStruct TestCommand[19]; //tests for different flags, etc +extern CommandStruct AGICommand[182]; //all the other + + +extern void CorrectCommands(double VerNum); + +#endif diff --git a/src/agiplay.cpp b/src/agiplay.cpp new file mode 100644 index 0000000..8d42ca0 --- /dev/null +++ b/src/agiplay.cpp @@ -0,0 +1,291 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * AGI player for i386 Linux and OSS + * Written by Claudio Matsuoka + * Sun Mar 21 13:27:35 EST 1999 + * + * Based on the format of the AGI SOUND resource as described by + * Lance Ewing + * + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#endif + +#include "game.h" +#include "menu.h" + + +#ifdef __linux__ +#include + +#define WAVEFORM_SIZE 64 +#define ENV_DECAY 800 +#define ENV_SUSTAIN 160 + +struct agi_note { + unsigned char dur_lo; + unsigned char dur_hi; + unsigned char frq_0; + unsigned char frq_1; + unsigned char vol; +}; + +struct channel_info { + struct agi_note *ptr; + int end; + int freq; + int phase; + int vol; + int env; + int timer; +}; + + +static int audio_fd; +static short *buffer; +static struct channel_info chn[4]; + +static int waveform[WAVEFORM_SIZE] = { + 0, 8, 16, 24, 32, 40, 48, 56, + 64, 72, 80, 88, 96, 104, 112, 120, + 128, 136, 144, 152, 160, 168, 176, 184, + 192, 200, 208, 216, 224, 232, 240, 255, + 0,-248,-240,-232,-224,-216,-208,-200, + -192,-184,-176,-168,-160,-152,-144,-136, + -128,-120,-112,-104, -96, -88, -80, -72, + -64, -56, -48, -40, -32, -24, -16, -8 /* Ramp up */ +}; + + + +int init_sound () +{ + int i; + + /* Set sound device to 16 bit, 22 kHz mono */ + + if ((audio_fd = open ("/dev/audio", O_WRONLY)) == -1) + return -1; + + i = AFMT_S16_NE; /* Native endian */ + ioctl (audio_fd, SNDCTL_DSP_SETFMT, &i); + i = 0; + ioctl (audio_fd, SNDCTL_DSP_STEREO, &i); + i = 22000; + ioctl (audio_fd, SNDCTL_DSP_SPEED, &i); + + buffer = (short *)calloc (2, 2048); + + return 0; +} + + +void close_sound () +{ + free (buffer); + close (audio_fd); +} + + +void mix_channels (int s) +{ + register int i, p; + int c, b, m; + + /* Size is in 16-bit samples */ + memset (buffer, 0, s << 1); + + /* Now build the sound for each channel */ + for (c = 0; c < 3; c++) { + if (!chn[c].vol) + continue; + + p = chn[c].phase; + m = chn[c].vol * chn[c].env >> 16; + + /* Build a sound buffer. The format is signed 16 bit mono, + * native-endian samples */ + for (i = 0; i < s; i++) { + + /* Interpolate to get a sample from the waveform */ + b = waveform[p >> 8] + (((waveform[((p >> 8) + 1) % WAVEFORM_SIZE] - + waveform[p >> 8]) * (p & 0xff)) >> 8); + + /* Add to the buffer, processing the envelope */ + buffer[i] += (b * m) >> 3; + + p += 11860 * 4 / chn[c].freq; + p %= WAVEFORM_SIZE << 8; + } + + /* Update the channel phase */ + chn[c].phase = p; + + /* Update the envelope */ + if (chn[c].env > chn[c].vol * ENV_SUSTAIN) + chn[c].env -= ENV_DECAY; + + } +} + + +void dump_buffer (int i) +{ + for (i <<= 1; i -= write (audio_fd, buffer, i); ) {} +} + + +void stop_note (int i) +{ + chn[i].vol = 0; +} + + +void play_note (int i, int freq, int vol) +{ + chn[i].freq = freq; + chn[i].phase = 0; + chn[i].vol = vol; + chn[i].env = 0x10000; +} + + +void play_song (unsigned char *song, int size) +{ + int i, playing; + + /* Initialize channel pointers */ + for (i = 0; i < 4; i++) { + chn[i].ptr = (struct agi_note *)(song + (song[i << 1] | (song[(i << 1) + 1] << 8))); + chn[i].timer = 0; + chn[i].end = 0; + } + + int step=0; + Q3ProgressDialog progress( "Playing...", "Cancel", (size+16)/5,0, 0, TRUE ); + progress.setMinimumDuration(0); + + for (playing = 1; playing; ) { + int freq; + + for (playing = i = 0; i < 4; i++) { + playing |= !chn[i].end; + + if (chn[i].end) + continue; + + if ((--chn[i].timer) <= 0) { + if (chn[i].ptr >= (struct agi_note *)song + size) + break; + stop_note (i); + freq = ((chn[i].ptr->frq_0 & 0x3f) << 4) + | (int)(chn[i].ptr->frq_1 & 0x0f); + if (freq) { + unsigned char v = chn[i].ptr->vol & 0x0f; + play_note (i, freq, v == 0xf ? 0 : 0xff - (v << 1)); + } + chn[i].timer = ((int)chn[i].ptr->dur_hi << 8) | + chn[i].ptr->dur_lo; + if (chn[i].timer == 0xffff) { + chn[i].end = 1; + chn[i].vol = 0; + } + chn[i].ptr++; + + progress.setProgress( step++ ); + if ( progress.wasCancelled() ){ + playing=false; + break; + } + } + } + + mix_channels (400); + dump_buffer (400); + } + +} +#endif + +void play_sound(int ResNum) +{ + + +#ifdef __linux__ + if (init_sound () != 0) { + menu->errmes("Can't initialize sound !"); + return; + } + + int err = game->ReadResource(SOUND,ResNum); + if(err)return; + + play_song(ResourceData.Data,ResourceData.Size); + + close_sound (); +#else + menu->errmes("Sound currently works only under Linux !"); + return; +#endif + +} + +void play_sound(char *filename) +{ + +#ifdef __linux__ + if (init_sound () != 0) { + menu->errmes("Can't initialize sound !"); + return; + } + + FILE *fptr=fopen(filename,"rb"); + if(fptr==NULL){ + menu->errmes("Can't open file %s !",filename); + return; + } + struct stat buf; + fstat(fileno(fptr),&buf); + ResourceData.Size=buf.st_size; + fread(ResourceData.Data,ResourceData.Size,1,fptr); + fclose(fptr); + + play_song(ResourceData.Data,ResourceData.Size); + + close_sound (); +#else + menu->errmes("Sound currently works only under Linux !"); + return; +#endif + + +} diff --git a/src/agistudio.aps b/src/agistudio.aps new file mode 100644 index 0000000000000000000000000000000000000000..346da7c2eacb58018b108006ec914b1472d86c17 GIT binary patch literal 18054 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 IZfeed0l-JWZ~y=R literal 0 HcmV?d00001 diff --git a/src/agistudio.dsp b/src/agistudio.dsp new file mode 100644 index 0000000..3f61139 --- /dev/null +++ b/src/agistudio.dsp @@ -0,0 +1,670 @@ +# Microsoft Developer Studio Project File - Name="agistudio" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=agistudio - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "agistudio.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "agistudio.mak" CFG="agistudio - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "agistudio - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "agistudio - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".." +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c +# ADD CPP /nologo /MDd /W3 /O1 /I "$(QTDIR)\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "QT_DLL" /D "QT_THREAD_SUPPORT" /D "UNICODE" /D "NO_DEBUG" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib imm32.lib wsock32.lib winmm.lib $(QTDIR)\lib\qt-mt230nc.lib $(QTDIR)\lib\qtmain.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "$(QTDIR)\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "QT_DLL" /D "QT_THREAD_SUPPORT" /D "UNICODE" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib imm32.lib winmm.lib wsock32.lib imm32.lib wsock32.lib winmm.lib $(QTDIR)\lib\qt-mt230nc.lib $(QTDIR)\lib\qtmain.lib /nologo /subsystem:windows /debug /machine:I386 /nodefaultlib:"libc" /nodefaultlib:"msvcrt" /pdbtype:sept +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "agistudio - Win32 Release" +# Name "agistudio - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\agicommands.cpp +# End Source File +# Begin Source File + +SOURCE=.\agiplay.cpp +# End Source File +# Begin Source File + +SOURCE=.\bpicture.cpp +# End Source File +# Begin Source File + +SOURCE=.\dir.cpp +# End Source File +# Begin Source File + +SOURCE=.\game.cpp +# End Source File +# Begin Source File + +SOURCE=.\helpwindow.cpp +# End Source File +# Begin Source File + +SOURCE=.\linklist.cpp +# End Source File +# Begin Source File + +SOURCE=.\logcompile.cpp +# End Source File +# Begin Source File + +SOURCE=.\logdecode.cpp +# End Source File +# Begin Source File + +SOURCE=.\logedit.cpp +# End Source File +# Begin Source File + +SOURCE=.\logic.cpp +# End Source File +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# Begin Source File + +SOURCE=.\menu.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_dir.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_helpwindow.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_logedit.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_menu.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_objedit.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_options.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_picedit.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_preview.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_resources.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_roomgen.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_viewedit.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_wordsedit.cpp +# End Source File +# Begin Source File + +SOURCE=.\moc_wutil.cpp +# End Source File +# Begin Source File + +SOURCE=.\object.cpp +# End Source File +# Begin Source File + +SOURCE=.\objedit.cpp +# End Source File +# Begin Source File + +SOURCE=.\options.cpp +# End Source File +# Begin Source File + +SOURCE=.\picedit.cpp +# End Source File +# Begin Source File + +SOURCE=.\picture.cpp +# End Source File +# Begin Source File + +SOURCE=.\preview.cpp +# End Source File +# Begin Source File + +SOURCE=.\resources.cpp +# End Source File +# Begin Source File + +SOURCE=.\roomgen.cpp +# End Source File +# Begin Source File + +SOURCE=.\util.cpp +# End Source File +# Begin Source File + +SOURCE=.\view.cpp +# End Source File +# Begin Source File + +SOURCE=.\viewedit.cpp +# End Source File +# Begin Source File + +SOURCE=.\words.cpp +# End Source File +# Begin Source File + +SOURCE=.\wordsedit.cpp +# End Source File +# Begin Source File + +SOURCE=.\wutil.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\agicommands.h +# End Source File +# Begin Source File + +SOURCE=.\dir.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing dir.h... +InputPath=.\dir.h + +"moc_dir.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe dir.h -o moc_dir.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing dir.h... +InputPath=.\dir.h + +"moc_dir.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe dir.h -o moc_dir.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\game.h +# End Source File +# Begin Source File + +SOURCE=.\global.h +# End Source File +# Begin Source File + +SOURCE=.\helpwindow.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing helpwindow.h... +InputPath=.\helpwindow.h + +"moc_helpwindow.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe helpwindow.h -o moc_helpwindow.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing helpwindow.h... +InputPath=.\helpwindow.h + +"moc_helpwindow.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe helpwindow.h -o moc_helpwindow.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\linklist.h +# End Source File +# Begin Source File + +SOURCE=.\logedit.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing logedit.h... +InputPath=.\logedit.h + +"moc_logedit.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe logedit.h -o moc_logedit.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing logedit.h... +InputPath=.\logedit.h + +"moc_logedit.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe logedit.h -o moc_logedit.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\logic.h +# End Source File +# Begin Source File + +SOURCE=.\menu.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing menu.h... +InputPath=.\menu.h + +"moc_menu.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe menu.h -o moc_menu.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing menu.h... +InputPath=.\menu.h + +"moc_menu.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe menu.h -o moc_menu.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\object.h +# End Source File +# Begin Source File + +SOURCE=.\objedit.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing objedit.h... +InputPath=.\objedit.h + +"moc_objedit.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe objedit.h -o moc_objedit.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing objedit.h... +InputPath=.\objedit.h + +"moc_objedit.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe objedit.h -o moc_objedit.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\options.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing options.h... +InputPath=.\options.h + +"moc_options.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe options.h -o moc_options.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing options.h... +InputPath=.\options.h + +"moc_options.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe options.h -o moc_options.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\picedit.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing picedit.h... +InputPath=.\picedit.h + +"moc_picedit.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe picedit.h -o moc_picedit.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing picedit.h... +InputPath=.\picedit.h + +"moc_picedit.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe picedit.h -o moc_picedit.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\picture.h +# End Source File +# Begin Source File + +SOURCE=.\preview.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing preview.h... +InputPath=.\preview.h + +"moc_preview.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe preview.h -o moc_preview.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing preview.h... +InputPath=.\preview.h + +"moc_preview.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe preview.h -o moc_preview.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\resources.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing resources.h... +InputPath=.\resources.h + +"moc_resources.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe resources.h -o moc_resources.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing resources.h... +InputPath=.\resources.h + +"moc_resources.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe resources.h -o moc_resources.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\roomgen.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing roomgen.h... +InputPath=.\roomgen.h + +"moc_roomgen.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe roomgen.h -o moc_roomgen.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing roomgen.h... +InputPath=.\roomgen.h + +"moc_roomgen.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe roomgen.h -o moc_roomgen.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\util.h +# End Source File +# Begin Source File + +SOURCE=.\view.h +# End Source File +# Begin Source File + +SOURCE=.\viewedit.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing viewedit.h... +InputPath=.\viewedit.h + +"moc_viewedit.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe viewedit.h -o moc_viewedit.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing viewedit.h... +InputPath=.\viewedit.h + +"moc_viewedit.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe viewedit.h -o moc_viewedit.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\words.h +# End Source File +# Begin Source File + +SOURCE=.\wordsedit.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing wordsedit.h... +InputPath=.\wordsedit.h + +"moc_wordsedit.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe wordsedit.h -o moc_wordsedit.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing wordsedit.h... +InputPath=.\wordsedit.h + +"moc_wordsedit.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe wordsedit.h -o moc_wordsedit.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\wutil.h + +!IF "$(CFG)" == "agistudio - Win32 Release" + +# Begin Custom Build - Moc'ing wutil.h... +InputPath=.\wutil.h + +"moc_wutil.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe wutil.h -o moc_wutil.cpp + +# End Custom Build + +!ELSEIF "$(CFG)" == "agistudio - Win32 Debug" + +# Begin Custom Build - Moc'ing wutil.h... +InputPath=.\wutil.h + +"moc_wutil.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + %QTDIR%\bin\moc.exe wutil.h -o moc_wutil.cpp + +# End Custom Build + +!ENDIF + +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\agistudio.rc +# End Source File +# Begin Source File + +SOURCE=.\icon1.ico +# End Source File +# End Group +# Begin Group "Interfaces" + +# PROP Default_Filter "ui" +# End Group +# Begin Source File + +SOURCE=.\license.txt +# End Source File +# End Target +# End Project diff --git a/src/agistudio.dsw b/src/agistudio.dsw new file mode 100644 index 0000000..78d144e --- /dev/null +++ b/src/agistudio.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "agistudio"=".\agistudio.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/src/agistudio.kdevelop b/src/agistudio.kdevelop new file mode 100644 index 0000000..5a38bd2 --- /dev/null +++ b/src/agistudio.kdevelop @@ -0,0 +1,114 @@ + + + + Jarno Elonen + elonen@iki.fi + $VERSION$ + KDevTrollProject + C++ + + Qt + + . + false + QT AGI Studio is a program which allows you to view, create and edit AGI games. AGI (Adventure Game Interpreter) is the adventure game engine used by Sierra On-Line(tm) to create some of their early games. + + KDevClearCase + KDevDoxygen + KDevdistpart + KDevPerforce + KDevVisualBoyAdvance + + + + + + + + + + + false + *.o,*.lo,CVS + + + + + gtk + gnustep + python + php + perl + + + ../help/ + + + + + + + + + true + false + true + true + + + false + true + + + + + + + + + + + + + + + + false + 1 + false + + + + + agistudio + + false + + + + + + + false + + + .h + .cpp + true + + + + true + 2 + + + -f + + -dP + + -f + -u3 -p + + + + diff --git a/src/agistudio.pro b/src/agistudio.pro new file mode 100644 index 0000000..c8ac8f8 --- /dev/null +++ b/src/agistudio.pro @@ -0,0 +1,63 @@ +TEMPLATE = app +CONFIG = qt warn_on release thread +#CONFIG = qt warn_on debug thread +# DEFINES += QT_DLL QT_THREAD_SUPPORT # win32 +QMAKE_CXXFLAGS += -Wno-unused-result +HEADERS = agicommands.h \ + dir.h \ + game.h \ + global.h \ + helpwindow.h \ + linklist.h \ + logedit.h \ + logic.h \ + menu.h \ + midi.h \ + object.h \ + objedit.h \ + options.h \ + picedit.h \ + picture.h \ + preview.h \ + resources.h \ + roomgen.h \ + util.h \ + view.h \ + viewedit.h \ + words.h \ + wordsedit.h \ + wutil.h \ + bmp2agipic.h +SOURCES = agicommands.cpp \ + agiplay.cpp \ + bpicture.cpp \ + dir.cpp \ + game.cpp \ + helpwindow.cpp \ + linklist.cpp \ + logcompile.cpp \ + logdecode.cpp \ + logedit.cpp \ + logic.cpp \ + main.cpp \ + menu.cpp \ + midi.cpp \ + object.cpp \ + objedit.cpp \ + options.cpp \ + picedit.cpp \ + picture.cpp \ + preview.cpp \ + resources.cpp \ + roomgen.cpp \ + util.cpp \ + view.cpp \ + viewedit.cpp \ + words.cpp \ + wordsedit.cpp \ + wutil.cpp \ + bmp2agipic.cpp +TARGET = agistudio + +#The following line was inserted by qt3to4 +QT += qt3support diff --git a/src/agistudio.rc b/src/agistudio.rc new file mode 100644 index 0000000..d767b93 --- /dev/null +++ b/src/agistudio.rc @@ -0,0 +1,72 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "icon1.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/app_icon.xpm b/src/app_icon.xpm new file mode 100644 index 0000000..72f7183 --- /dev/null +++ b/src/app_icon.xpm @@ -0,0 +1,40 @@ +/* XPM */ +static const char * app_icon[] = { +"32 32 5 1", +" c None", +". c #000000", +"+ c #FF5050", +"@ c #A00000", +"# c #0000A0", +" ", +" ", +" ........ ", +" ........ ", +" ................ ", +" ................ ", +" ........++++ ", +" ........++++ ", +" ....++++@@@@ ", +" ....++++@@@@ ", +" ....++++++++++++ ", +" ....++++++++++++ ", +" ....++++++++ ", +" ....++++++++ ", +" ....++++++++ ", +" ....++++++++ ", +" ....++++++++ ", +" ....++++++++ ", +" ++++ ", +" ++++ ", +" #### ", +" #### ", +" ############ ", +" ############ ", +" ############ ", +" ############ ", +" ################ ", +" ################ ", +" #################### ", +" #################### ", +" ########################+++ ", +" ########################+++ "}; diff --git a/src/back.xpm b/src/back.xpm new file mode 100644 index 0000000..2e1b656 --- /dev/null +++ b/src/back.xpm @@ -0,0 +1,27 @@ +/* XPM */ +static const char *back[] = { +/* columns rows colors chars-per-pixel */ +"16 16 5 1", +" c black", +". c #808080808080", +"X c #C0C0C0C0C0C0", +"o c gray100", +"O c None", +/* pixels */ +"OOOOOOOOOOOOOOOO", +"OOOOOOO OOOOOOOO", +"OOOOOO OOOOOOOO", +"OOOOO o OOOOOOOO", +"OOOO oo O", +"OOO ooXooooooo O", +"OO ooXXXXXXXXX O", +"OOO oXXXXXXXXX O", +"OOO. oX O", +"OOOO. o .......O", +"OOOOO. .OOOOOOO", +"OOOOOO. .OOOOOOO", +"OOOOOOO..OOOOOOO", +"OOOOOOOO.OOOOOOO", +"OOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOOOOO" +}; diff --git a/src/bmp2agipic.cpp b/src/bmp2agipic.cpp new file mode 100644 index 0000000..601811e --- /dev/null +++ b/src/bmp2agipic.cpp @@ -0,0 +1,413 @@ +/* + * Bitmap to (Sierra) AGI picture resource converter + * Copyright (C) 2012 Jarno Elonen + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "bmp2agipic.h" + +#include + +#include +#include +#include + +#include +#include + +static const int AGI_WIDTH = 160; +static const int AGI_HEIGHT = 168; +static const int N_COLORS = 16; +static const unsigned char COLOR_NONE = 255; + +const QColor ega[] = { + QColor(0x00, 0x00, 0x00), // black + QColor(0x00, 0x00, 0xA0), // blue + QColor(0x00, 0xA0, 0x00), // green + QColor(0x00, 0xA0, 0xA0), // cyan + QColor(0xA0, 0x00, 0x00), // red + QColor(0xA0, 0x00, 0xA0), // magenta + QColor(0xA0, 0x50, 0x00), // brown + QColor(0xA0, 0xA0, 0xA0), // light grey + QColor(0x50, 0x50, 0x50), // dark grey + QColor(0x50, 0x50, 0xFF), // light blue + QColor(0x50, 0xFF, 0x50), // light green + QColor(0x50, 0xFF, 0xFF), // light cyan + QColor(0xFF, 0x50, 0x50), // light red + QColor(0xFF, 0x50, 0xFF), // light magenta + QColor(0xFF, 0xFF, 0x50), // yellow + QColor(0xFF, 0xFF, 0xFF) // white +}; + +typedef unsigned char AGIPic[AGI_WIDTH][AGI_HEIGHT]; + +struct Coord { + Coord( int _x, int _y ) : x(_x), y(_y) {} + int x, y; +}; + +struct CoordColor { + CoordColor( int _x, int _y, unsigned char _c ) : x(_x), y(_y), c(_c) {} + int x, y; + unsigned char c; +}; + + + +// Quantize given image to EGA palette and reshape to AGI native AGI_WIDTHxAGI_HEIGHT +void QuantizeAGI( const QImage& img, AGIPic& out ) +{ + #define SQUARE(x) ((x)*(x)) + + assert(img.width() == AGI_WIDTH || img.width() == AGI_WIDTH*2 ); + assert(img.height() >= AGI_HEIGHT ); + + int xstep = (img.width() == AGI_WIDTH) ? 1 : 2; + for ( int y=0; y=AGI_WIDTH || y<0 || y>=AGI_HEIGHT ) + return dummy; + else + return pic[x][y]; +} + +// Returns true if neighborhood is solid, suitable for floodfill +bool isOnFloodFillArea( AGIPic& pic, int x, int y ) +{ + if ( agiPix(pic, x,y) == COLOR_NONE ) + return false; + for ( int dx=-1; dx<=1; ++dx ) + for ( int dy=-1; dy<=1; ++dy ) + if ( agiPix(pic, x,y) != agiPix(pic, x+dx,y+dy)) + return false; + return true; +} + +bool has4NeighborOfColor( AGIPic& pic, int x, int y, unsigned char c ) +{ + return \ + (x0 && agiPix(pic,x-1,y+0) == c) || + (y0 && agiPix(pic,x+0,y-1) == c); +} + +// Trace how long a line continues to given direction (excluding starting pixel) +int traceToDir( AGIPic& pic, int x, int y, int dx, int dy, unsigned char c, int max ) +{ + assert(c != COLOR_NONE); // could cause infinite trace + int cnt = -1; + do + { + cnt++; + if ( cnt >= max ) + break; + x+=dx; + y+=dy; + } while ( agiPix(pic,x, y) == c ); + return cnt; +} + +int count8NeighborOfColor( AGIPic& pic, int x, int y, unsigned char c ) +{ + int res = 0; + for ( int dx=-1; dx<=1; ++dx ) + for ( int dy=-1; dy<=1; ++dy ) + if ( dx!=0 || dy!=0 ) + if ( agiPix(pic,x+dx,y+dy) == c ) + res++; + return res; +} + + +// Flood fill area with color COLOR_NONE, but +// leave border pixels of previous COLOR_NONE areas +// untouched so that we'll get proper fill borders later. +void floodFillEmpty( AGIPic& pic, int x, int y ) +{ + std::queue q; + q.push(Coord(x,y)); + + const unsigned char visited = COLOR_NONE-1; + const unsigned char src_color = pic[x][y]; + assert( src_color != COLOR_NONE ); + assert( src_color != visited ); + + while ( !q.empty()) + { + Coord c = q.front(); + q.pop(); + if ( agiPix(pic, c.x, c.y) == src_color && + !has4NeighborOfColor(pic,c.x,c.y, COLOR_NONE )) + { + agiPix(pic, c.x, c.y) = visited; + q.push(Coord(c.x+1, c.y+0)); + q.push(Coord(c.x-1, c.y+0)); + q.push(Coord(c.x+0, c.y+1)); + q.push(Coord(c.x+0, c.y-1)); + } + } + + for (int y=0; y& singlePoints, Coord& minCoord ) +{ + // Find pixel with the least neighbors of color i + // (i.e. most probable end of line) + int minCount = 0xFF; + + for (int y=y0; y singlePoints; + + while (true) // loop until no pixels of color i are found + { + Coord minCoord(-1,-1); + int minCount = findBestLineStartFromArea( pic, 0,0, AGI_WIDTH,AGI_HEIGHT, color, singlePoints, minCoord ); + if ( minCount == 0xFF ) // No more lines found + break; + +newTrace: + // Start tracing the line + int x=minCoord.x, y=minCoord.y; + assert( agiPix(pic,x,y) == color ); + *res += char( 0xF7 ); // Relative line command + *res += char( x ); // Starting x + *res += char( y ); // Starting y + agiPix(pic,x,y) = COLOR_NONE; + + // Trace a line + while (true) + { + // Find out direction into which the line continues the longest + int max=0, maxdx=0xFF,maxdy=0xFF; + for ( int dx=-1; dx<=1; ++dx ) + for ( int dy=-1; dy<=1; ++dy ) + if ( dx != 0 || dy != 0 ) + { + int len = traceToDir( pic, x,y, dx,dy, color, AGI_WIDTH ); + if ( len > max ) + { + max = len; + maxdx = dx; + maxdy = dy; + } + } + + if ( max==0 ) // Nowhere to go, end the trace + { + // Just for aesthetic reasons, try to start the next + // line nearby the end of the last one + minCount = findBestLineStartFromArea( pic, x-5,y-5, 10,10, color, singlePoints, minCoord ); + if ( minCount == 0xFF ) + break; // Not found, do a full pic scan + else + goto newTrace; // New line in the neighborhood, start from there + } + + if ( max>6 ) // Clamp to maximum length of relative line + max=6; + + int stepx = maxdx*max; + int stepy = maxdy*max; + + assert(abs(stepx) <= 7); + assert(abs(stepy) <= 7); + + // Write out the relative line stepping byte + unsigned char chr = + (((stepx<0)?1:0) << 7) | // x sign + (abs(stepx) << 4) | // Xdisp + (((stepy<0)?1:0) << 3) | // y sign + (abs(stepy) << 0); // Ydisp + + assert((chr&0xF0) != 0xF0); // Must not be mistaken for a draw command + + *res += char(chr); + + // Clear the line + while (max>=0) + { + agiPix(pic,x+maxdx*max,y+maxdy*max) = COLOR_NONE; + --max; + } + + // Move pointer to the new end + x += stepx; + y += stepy; + } + } + // When all continuous lines are drawn, + // write out single points as a brush/plot/pen operation + if ( singlePoints.size()>0 ) + { + *res += char( 0xFA ); // Pen command + for ( int i=0; i<(int)singlePoints.size(); ++i ) + { + assert( (unsigned char)singlePoints[i].x < 0xF0); + assert( (unsigned char)singlePoints[i].y < 0xF0); + *res += char( singlePoints[i].x ); + *res += char( singlePoints[i].y ); + } + } + } +} + +// Convert either a visual or a priority image and write to res +void oneChannelToAGIPicture( const QImage& chan, QByteArray* res, bool isPri ) +{ + unsigned char pic[AGI_WIDTH][AGI_HEIGHT]; + QuantizeAGI( chan, pic ); + + + // We're doing one channel at a time, disable the other one first + *res += char( isPri ? 0xF1 : 0xF3 ); + + // Clear the default color, no sense in filling/drawing with it: + unsigned default_color = isPri ? 4 : 15; // 4=red for pri, 15=white for visual + for (int y=0; y floodFills; + for ( int c=N_COLORS-1; c>=0; --c ) + for (int y=0; y +#include + +// Converts bitmaps (pic and pri) into an AGI "picture" resource. +// Returns NULL if success, or error message otherwise. +// Pri image may be null (QImage.isNull(). +const char* bitmapToAGIPicture( const QImage& pic, const QImage& pri, QByteArray* res ); + +#endif diff --git a/src/bpicture.cpp b/src/bpicture.cpp new file mode 100644 index 0000000..5e4fb9e --- /dev/null +++ b/src/bpicture.cpp @@ -0,0 +1,545 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * Almost all of the picture processing code is taken from showpic.c + * by Lance Ewing + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "game.h" +#include "menu.h" +#include "picture.h" + + +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include +#include + +BPicture *ppicture; + +//******************************************** +//"bytemap" picture for preview - it is not going to be edited, +//so there is no need for the linked list and other things from the Picture class + +BPicture::BPicture() +{ + + picture = (byte **)malloc(MAX_H*sizeof(byte *)); + priority = (byte **)malloc(MAX_H*sizeof(byte *)); + for(int i=0;i 319) return; + if (vy > 199) return; + picture[vy][vx] = picColour; + picture[vy][vx+1] = picColour; +} + +/************************************************************************** +** priPSet +** +** Draws a pixel in the priority screen. +**************************************************************************/ +void BPicture::priPSet(word x, word y) +{ + word vx, vy; + + vx = (x << 1); + vy = y; + if (vx > 319) return; + if (vy > 199) return; + priority[vy][vx] = priColour; + priority[vy][vx+1] = priColour; +} + +/************************************************************************** +** pset +** +** Draws a pixel in each screen depending on whether drawing in that +** screen is enabled or not. +**************************************************************************/ +void BPicture::pset(word x, word y) +{ + if (picDrawEnabled) picPSet(x, y); + if (priDrawEnabled) priPSet(x, y); +} + +/************************************************************************** +** picGetPixel +** +** Get colour at x,y on the picture page. +**************************************************************************/ +byte BPicture::picGetPixel(word x, word y) +{ + word vx, vy; + + vx = (x << 1); + vy = y; + if (vx > 319) return(4); + if (vy > 199) return(4); + + return (picture[vy][vx]); +} + +/************************************************************************** +** priGetPixel +** +** Get colour at x,y on the priority page. +**************************************************************************/ +byte BPicture::priGetPixel(word x, word y) +{ + word vx, vy; + + vx = (x << 1); + vy = y; + if (vx > 319) return(4); + if (vy > 199) return(4); + + return (priority[vy][vx]); +} + +/************************************************************************** +** round +** +** Rounds a float to the closest int. Takes into actions which direction +** the current line is being drawn when it has a 50:50 decision about +** where to put a pixel. +**************************************************************************/ +int BPicture::round(float aNumber, float dirn) +{ + if (dirn < 0) + return ((aNumber - floor(aNumber) <= 0.501)? (int)floor(aNumber) : (int)ceil(aNumber)); + return ((aNumber - floor(aNumber) < 0.499)? (int)floor(aNumber) : (int)ceil(aNumber)); +} + +/************************************************************************** +** drawline +** +** Draws an AGI line. +**************************************************************************/ +void BPicture::drawline(word x1, word y1, word x2, word y2) +{ + int height, width; + float x, y, addX, addY; + + height = (y2 - y1); + width = (x2 - x1); + addX = (height==0?height:(float)width/abs(height)); + addY = (width==0?width:(float)height/abs(width)); + + if (abs(width) > abs(height)) { + y = y1; + addX = (width == 0? 0 : (width/abs(width))); + for (x=x1; x!=x2; x+=addX) { + pset(round(x, addX), round(y, addY)); + y+=addY; + } + pset(x2,y2); + } + else { + x = x1; + addY = (height == 0? 0 : (height/abs(height))); + for (y=y1; y!=y2; y+=addY) { + pset(round(x, addX), round(y, addY)); + x+=addX; + } + pset(x2,y2); + } + +} + +/************************************************************************** +** okToFill +**************************************************************************/ +bool BPicture::okToFill(byte x, byte y) +{ + if (!picDrawEnabled && !priDrawEnabled) return false; + if (picColour == 15) return false; + if (!priDrawEnabled) return (picGetPixel(x, y) == 15); + if (priDrawEnabled && !picDrawEnabled) return (priGetPixel(x, y) == 4); + return (picGetPixel(x, y) == 15); +} + +/************************************************************************** +** agiFill +**************************************************************************/ +void BPicture::agiFill(word x, word y) +{ + byte x1, y1; + rpos = spos = 0; + + qstore(x); + qstore(y); + + // printf("fill %d %d\n",x,y); + + for (;;) { + + x1 = qretrieve(); + y1 = qretrieve(); + + // printf("x1=%d y1=%d\n"); + + if ((x1 == EMPTY) || (y1 == EMPTY)) + break; + else { + + if (okToFill(x1,y1)) { + + pset(x1, y1); + + if (okToFill(x1, y1-1) && (y1!=0)) { + qstore(x1); + qstore(y1-1); + } + if (okToFill(x1-1, y1) && (x1!=0)) { + qstore(x1-1); + qstore(y1); + } + if (okToFill(x1+1, y1) && (x1!=159)) { + qstore(x1+1); + qstore(y1); + } + if (okToFill(x1, y1+1) && (y1!=167)) { + qstore(x1); + qstore(y1+1); + } + + } + + } + + } + +} + +/************************************************************************** +** xCorner +** +** Draws an xCorner (drawing action 0xF5) +**************************************************************************/ +void BPicture::xCorner(byte **data) +{ + byte x1, x2, y1, y2; + + x1 = *((*data)++); + y1 = *((*data)++); + + pset(x1,y1); + + for (;;) { + x2 = *((*data)++); + if (x2 >= 0xF0) break; + drawline(x1, y1, x2, y1); + x1 = x2; + y2 = *((*data)++); + if (y2 >= 0xF0) break; + drawline(x1, y1, x1, y2); + y1 = y2; + } + + (*data)--; +} + +/************************************************************************** +** yCorner +** +** Draws an yCorner (drawing action 0xF4) +**************************************************************************/ +void BPicture::yCorner(byte **data) +{ + byte x1, x2, y1, y2; + + x1 = *((*data)++); + y1 = *((*data)++); + + pset(x1, y1); + + for (;;) { + y2 = *((*data)++); + if (y2 >= 0xF0) break; + drawline(x1, y1, x1, y2); + y1 = y2; + x2 = *((*data)++); + if (x2 >= 0xF0) break; + drawline(x1, y1, x2, y1); + x1 = x2; + } + + (*data)--; +} + +/************************************************************************** +** relativeDraw +** +** Draws short lines relative to last position. (drawing action 0xF7) +**************************************************************************/ +void BPicture::relativeDraw(byte **data) +{ + byte x1, y1, disp; + char dx, dy; + + x1 = *((*data)++); + y1 = *((*data)++); + + pset(x1, y1); + + for (;;) { + disp = *((*data)++); + if (disp >= 0xF0) break; + dx = ((disp & 0xF0) >> 4) & 0x0F; + dy = (disp & 0x0F); + if (dx & 0x08) dx = (-1)*(dx & 0x07); + if (dy & 0x08) dy = (-1)*(dy & 0x07); + drawline(x1, y1, x1 + dx, y1 + dy); + x1 += dx; + y1 += dy; + } + + (*data)--; +} + +/************************************************************************** +** fill +** +** Agi flood fill. (drawing action 0xF8) +**************************************************************************/ +void BPicture::fill(byte **data) +{ + byte x1, y1; + + for (;;) { + if ((x1 = *((*data)++)) >= 0xF0) break; + if ((y1 = *((*data)++)) >= 0xF0) break; + agiFill(x1, y1); + } + + (*data)--; +} + +/************************************************************************** +** absoluteLine +** +** Draws long lines to actual locations (cf. relative) (drawing action 0xF6) +**************************************************************************/ +void BPicture::absoluteLine(byte **data) +{ + byte x1, y1, x2, y2; + + x1 = *((*data)++); + y1 = *((*data)++); + + pset(x1, y1); + + for (;;) { + if ((x2 = *((*data)++)) >= 0xF0) break; + if ((y2 = *((*data)++)) >= 0xF0) break; + drawline(x1, y1, x2, y2); + x1 = x2; + y1 = y2; + } + + (*data)--; +} + + +#define plotPatternPoint() \ + if (patCode & 0x20) { \ + if ((splatterMap[bitPos>>3] >> (7-(bitPos&7))) & 1) pset(x1, y1); \ + bitPos++; \ + if (bitPos == 0xff) bitPos=0; \ + } else pset(x1, y1) + +/************************************************************************** +** plotPattern +** +** Draws pixels, circles, squares, or splatter brush patterns depending +** on the pattern code. +**************************************************************************/ +void BPicture::plotPattern(byte x, byte y) +{ + static char circles[][15] = { /* agi circle bitmaps */ + {0x80}, + {0xfc}, + {0x5f, 0xf4}, + {0x66, 0xff, 0xf6, 0x60}, + {0x23, 0xbf, 0xff, 0xff, 0xee, 0x20}, + {0x31, 0xe7, 0x9e, 0xff, 0xff, 0xde, 0x79, 0xe3, 0x00}, + {0x38, 0xf9, 0xf3, 0xef, 0xff, 0xff, 0xff, 0xfe, 0xf9, 0xf3, 0xe3, 0x80}, + {0x18, 0x3c, 0x7e, 0x7e, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x7e, + 0x7e, 0x3c, 0x18} + }; + + static byte splatterMap[32] = { /* splatter brush bitmaps */ + 0x20, 0x94, 0x02, 0x24, 0x90, 0x82, 0xa4, 0xa2, + 0x82, 0x09, 0x0a, 0x22, 0x12, 0x10, 0x42, 0x14, + 0x91, 0x4a, 0x91, 0x11, 0x08, 0x12, 0x25, 0x10, + 0x22, 0xa8, 0x14, 0x24, 0x00, 0x50, 0x24, 0x04 + }; + + static byte splatterStart[128] = { /* starting bit position */ + 0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48, + 0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d, + 0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf, + 0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1, + 0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce, + 0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed, + 0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6, + 0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51, + 0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7, + 0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf, + 0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0, + 0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49, + 0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2, + 0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3, + 0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1 + }; + + int circlePos = 0; + byte x1, y1, penSize, bitPos = splatterStart[patNum]; + + penSize = (patCode&7); + + if (x<((penSize/2)+1)) x=((penSize/2)+1); + else if (x>160-((penSize/2)+1)) x=160-((penSize/2)+1); + if (y=168-penSize) y=167-penSize; + + for (y1=y-penSize; y1<=y+penSize; y1++) { + for (x1=x-((int)ceil((float)penSize/2)); x1<=x+((int)floor((float)penSize/2)); x1++) { + if (patCode & 0x10) { /* Square */ + plotPatternPoint(); + } + else { /* Circle */ + if ((circles[patCode&7][circlePos>>3] >> (7-(circlePos&7)))&1) { + plotPatternPoint(); + } + circlePos++; + } + } + } + +} + + +/************************************************************************** +** plotBrush +** +** Plots points and various brush patterns. +**************************************************************************/ +void BPicture::plotBrush(byte **data) +{ + byte x1, y1; + + for (;;) { + if (patCode & 0x20) { + if ((patNum = *((*data)++)) >= 0xF0) break; + patNum = (patNum >> 1 & 0x7f); + } + if ((x1 = *((*data)++)) >= 0xF0) break; + if ((y1 = *((*data)++)) >= 0xF0) break; + plotPattern(x1, y1); + } + + (*data)--; +} + +//**************************************************** +void BPicture::show(byte *picdata,int picsize) +{ + byte *data = picdata; + bool stillDrawing = true; + byte action; + + for(int i=0;i +#else +#include +#include +#endif + +#include + + +//********************************************************* +void OpenGameDir( QWidget *parent, bool newgame ) +{ + QString title("Open game"); + if(newgame) + title = "New game"; + QString dir = QFileDialog::getExistingDirectory(parent, title); + if ( dir.isNull()) + return; + + //close the currently edited game + if(game->isOpen) + { + menu->close_game(); + if(game->isOpen)return; + } + + std::string name = dir.toLocal8Bit().data(); + + if(newgame) + { + int game_exists; + sprintf(tmp,"%s/*vol.?",name.c_str()); //check for an existing game +#ifdef _WIN32 + struct _finddata_t c_file; + long hFile; + game_exists = !((hFile = _findfirst(tmp,&c_file)) == -1L); + if (game_exists) _findclose(hFile); +#else + glob_t globbuf; + glob(tmp, 0, NULL, &globbuf); + game_exists = globbuf.gl_pathc>0; +#endif + if (game_exists) { + sprintf(tmp,"There seems to be already an AGI game in %s !\nDo you want to erase it ?",name.c_str()); + switch ( QMessageBox::warning( parent, "New game", + tmp, + "Yes", + "No", + "Cancel", + 0, 2) ) { + case 0: // yes + break; + case 1: // no + return; + default: // cancel + return; + } + } + } + + int err; + if(newgame) + { + if(menu->templ) + err = game->from_template(name); + else + err = game->newgame(name); + } + else + err = game->open(name); + if(!err) + menu->show_resources(); +} diff --git a/src/dir.h b/src/dir.h new file mode 100644 index 0000000..3b9cd66 --- /dev/null +++ b/src/dir.h @@ -0,0 +1,28 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef DIR_H +#define DIR_H + +#include + +void OpenGameDir( QWidget *parent=0, bool newgame=false ); + +#endif diff --git a/src/downarrow_x.xpm b/src/downarrow_x.xpm new file mode 100644 index 0000000..59f65fb --- /dev/null +++ b/src/downarrow_x.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *downarrow_x[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +" c black", +". c None", +/* pixels */ +"................", +"...... ......", +"...... ......", +"...... ......", +"...... ......", +"...... ......", +"...... ......", +" ", +" ", +". .", +".. ..", +"... ...", +".... ....", +"..... .....", +"...... ......", +"....... ......." +}; diff --git a/src/forward.xpm b/src/forward.xpm new file mode 100644 index 0000000..12ee236 --- /dev/null +++ b/src/forward.xpm @@ -0,0 +1,27 @@ +/* XPM */ +static const char *forward[] = { +/* columns rows colors chars-per-pixel */ +"16 16 5 1", +" c black", +". c #808080808080", +"X c #C0C0C0C0C0C0", +"o c gray100", +"O c None", +/* pixels */ +"OOOOOOOOOOOOOOOO", +"OOOOOOOOOOOOOOOO", +"OOOOOOOOO OOOOOO", +"OOOOOOOOO OOOOO", +"OOOOOOOOO o OOOO", +"OO oo OOO", +"OO oooooooXoo OO", +"OO XXXXXXXXXoo O", +"OO XXXXXXXXXo OO", +"OO Xo .OO", +"OO....... o .OOO", +"OOOOOOOO. .OOOO", +"OOOOOOOO. .OOOOO", +"OOOOOOOO..OOOOOO", +"OOOOOOOO.OOOOOOO", +"OOOOOOOOOOOOOOOO" +}; diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..acdcd89 --- /dev/null +++ b/src/game.cpp @@ -0,0 +1,1591 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * A big part of this code was adapted from the Windows AGI Studio + * developed by Peter Kelly. + * + * LZW decompression code belongs to Lance Ewing. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "menu.h" +#include "util.h" +#include "resources.h" +#include "agicommands.h" + +#include +#include +#include +#ifdef _WIN32 +#include +#include +#include +#undef TEXT +#include "game.h" +#define TEXT 6 +#else +#include +#include +#include "game.h" +#endif +#include +#include +#include +#include + +#include +#include +#include + +const char *ResTypeName[4] = {"logic","picture","view","sound"}; +const char *ResTypeAbbrv[4] = {"log","pic","view","snd"}; +static const char *files[5] = {"vol.0","viewdir","logdir","snddir","picdir"}; +Game *game; + +static TResource CompressedResource; + +/******************************* LZW variables ****************************/ +#define MAXBITS 12 +#define TABLE_SIZE 18041 +#define START_BITS 9 + +static int BITS, MAX_VALUE, MAX_CODE; +static unsigned int *prefix_code; +static byte *append_character; +static byte decode_stack[4000]; /* Holds the decoded string */ +static int input_bit_count=0; /* Number of bits in input bit buffer */ +static unsigned long input_bit_buffer=0L; +//******************************************* + +const char EncryptionKey[] = "Avis Durgan"; +TResourceInfo ResourceInfo[4][256]; + +TResource ResourceData; +/* global buffer used for all resource I/0 ! (for this reason it wouldn't be + wise to run several I/O operations simultaneously, like clicking compile + very fast in several logic editor windows ("compile all" is ok - it is + sequential) - fortunately the program works too fast to allow the user + to do it...) */ + +//******************************************* +Game::Game() +{ + ResourceData.Data = (byte *)malloc(MaxResourceSize); + defaults(); + read_settings(); +} + +//******************************************* +int Game::open(string name) +{ + byte DirData[3080]; + int CurResType,CurResNum,NumDirEntries; + long DirSize=-1,DirOffset=-1; + byte byte1,byte2,byte3; + FILE *fptr; + + dir=name; + + ID = FindAGIV3GameID(dir.c_str()); // 'V2' if not found + if(ID.length() == 0)return 1; + + isV3 = (ID != "V2"); + bool ErrorOccured = false; + + for(CurResType = 0;CurResType <= 3;CurResType++){ + for(CurResNum = 0;CurResNum <= 255; CurResNum++){ + ResourceInfo[CurResType][CurResNum].Exists = false; + } + } + + if(!isV3){ + //for V2 game: open logdir, picdir, viewdir, snddir + for(CurResType = 0;CurResType <= 3; CurResType++){ + string DIRFilename = dir + "/"+ResTypeAbbrv[CurResType] + "dir"; + fptr=fopen(DIRFilename.c_str(),"rb"); + if(fptr==NULL){ + menu->errmes("Error: can't open %s !",DIRFilename.c_str()); + ErrorOccured = true; + break; + } + else{ + struct stat buf; + fstat(fileno(fptr),&buf); + int size=buf.st_size; + if(size > 768){ + menu->errmes("Error: %s is too big (should not be mode than 768 bytes) !",DIRFilename.c_str()); + ErrorOccured = true; + break; + } + else{ //read resource info + fread(DirData,size,1,fptr); + for(CurResNum = 0;CurResNum <= size/3 -1;CurResNum++){ + byte1 = DirData[CurResNum*3]; + byte2 = DirData[CurResNum*3+1]; + byte3 = DirData[CurResNum*3+2]; + if (!(byte1==0xff && byte2==0xff && byte3==0xff)){ + ResourceInfo[CurResType][CurResNum].Loc = (byte1 % 16)*0x10000 + byte2*0x100 + byte3; + sprintf(ResourceInfo[CurResType][CurResNum].Filename,"vol.%d",byte1/16); + ResourceInfo[CurResType][CurResNum].Exists = true; + } + } + } + fclose(fptr); + } + } + } + else{ //V3 game: open [GAME_ID]dir (e.g. grdir, mhdir) + string DIRFilename = dir + "/"+ID + "dir"; + fptr=fopen(DIRFilename.c_str(),"rb"); + if(fptr==NULL){ + menu->errmes("Error: can't open %s ! ",DIRFilename.c_str()); + ErrorOccured = true; + } + else{ + struct stat buf; + fstat(fileno(fptr),&buf); + int size=buf.st_size; + if(size > 3080){ + menu->errmes("Error: %s is too big (should not be mode than 3080 bytes) !",DIRFilename.c_str()); + ErrorOccured = true; + } + else{ + fread(DirData,size,1,fptr); + //read resource info + for(CurResType = 0;CurResType <= 3;CurResType++){ + if(!ErrorOccured){ + switch(CurResType){ + case LOGIC: + DirOffset = DirData[0] + DirData[1]*256; + DirSize = DirData[2] + DirData[3]*256 - DirOffset; + break; + case PICTURE: + DirOffset = DirData[2] + DirData[3]*256; + DirSize = DirData[4] + DirData[5]*256 - DirOffset; + break; + case VIEW: + DirOffset = DirData[4] + DirData[5]*256; + DirSize = DirData[6] + DirData[7]*256 - DirOffset; + break; + case SOUND: + DirOffset = DirData[6] + DirData[7]*256; + DirSize = size - DirOffset; + break; + } + if(DirOffset < 0 || DirSize < 0){ + menu->errmes("Error: DIR file is invalid."); + ErrorOccured = true; + break; + } + else if(DirOffset + DirSize > size){ + menu->errmes("Error: Directory is beyond end of %s file !",DIRFilename.c_str()); + ErrorOccured = true; + break; + } + else{ + if (DirSize > 768)NumDirEntries = 256; + else NumDirEntries = DirSize/3; + if (NumDirEntries > 0){ + for(CurResNum = 0;CurResNum < NumDirEntries;CurResNum++){ + byte1 = DirData[DirOffset+CurResNum*3]; + byte2 = DirData[DirOffset+CurResNum*3+1]; + byte3 = DirData[DirOffset+CurResNum*3+2]; + if (!(byte1==0xff && byte2==0xff && byte3==0xff)){ + ResourceInfo[CurResType][CurResNum].Loc = (byte1 % 16)*0x10000 + byte2*0x100 + byte3; + sprintf(ResourceInfo[CurResType][CurResNum].Filename,"%svol.%d",ID.c_str(),byte1/16); + ResourceInfo[CurResType][CurResNum].Exists = true; + } + } + } + } + } + } + } + fclose(fptr); + } + } + + if(!ErrorOccured){ + AGIVersionNumber = GetAGIVersionNumber(); + //printf("AGIVersion = %f\n",AGIVersionNumber); + CorrectCommands(AGIVersionNumber); + isOpen = true; + make_source_dir(); + menu->status->message(dir.c_str()); + return 0; + } + else return 1; +} + +//******************************************* +int copy(char *src,char *dest) + //copy src file to dest file (to avoid using an external 'cp' command) +{ + FILE *filer, *filew; + size_t numr; + char buffer[1024]; + + filer=fopen(src,"rb"); + if(!filer) + { + menu->errmes("Can't open src file %s !",src); + return 1; + } + filew=fopen(dest,"wb"); + if(!filew) + { + menu->errmes("Can't open dst file %s !",dest); + return 1; + } + + while(feof(filer)==0) + { + if((numr=fread(buffer,1,1024,filer))!=1024) + { + if(ferror(filer)!=0) + { + menu->errmes("read file error: %s !",src); + return 1; + } + } + if(fwrite(buffer,1,numr,filew) != numr) + { + menu->errmes("write file error: %s !",dest); + return 1; + } + } + + fclose(filew); + fclose(filer); + return 0; +} + +//******************************************* + +int Game::from_template(string name) + //create a new game (in 'name' directory) from template +{ + + int i; + char *ptr; + struct stat buf; + char *cfilename; + + dir = name; + make_source_dir(); + + //check if template directory contains *dir files and vol.0 + for(i=0;i<5;i++){ + sprintf(tmp,"%s/%s",templatedir.c_str(),files[i]); + if(stat(tmp,&buf)){ + menu->errmes("AGI Studio error", "Can't read %s in template directory %s !",files[i],templatedir.c_str()); + return 1; + } + } + + sprintf(tmp,"%s/*",templatedir.c_str()); +#ifdef _WIN32 + struct _finddata_t c_file; + long hFile; + if ((hFile = _findfirst(tmp, &c_file)) != -1L) do { + sprintf(tmp2,"%s/%s",templatedir.c_str(),c_file.name); + cfilename = tmp2; +#else + glob_t globbuf; + glob(tmp, 0, NULL, &globbuf); + for(i=0;i<(int)globbuf.gl_pathc;i++){ //copy template game files + cfilename = globbuf.gl_pathv[i]; +#endif + ptr=strrchr(cfilename,'/'); + if(ptr){ + if(!strcmp(ptr,"/src"))continue; + if(!strcmp(ptr,"/."))continue; + if(!strcmp(ptr,"/.."))continue; + sprintf(tmp,"%s%s",name.c_str(),ptr); + } + else{ + if(!strcmp(cfilename,"/src"))continue; + if(!strcmp(cfilename,"/."))continue; + if(!strcmp(cfilename,"/.."))continue; + sprintf(tmp,"%s/%s",name.c_str(),cfilename); + } + if(copy(cfilename,tmp))return 1; +#ifdef _WIN32 + } while (_findnext(hFile, &c_file) == 0); + _findclose(hFile); +#else + } + globfree(&globbuf); +#endif + + sprintf(tmp,"%s/src/*",templatedir.c_str()); +#ifdef _WIN32 + if ((hFile = _findfirst(tmp, &c_file)) != -1L) do { + sprintf(tmp2,"%s/src/%s",templatedir.c_str(),c_file.name); + cfilename = tmp2; +#else + glob(tmp, 0, NULL, &globbuf); + for(i=0;i<(int)globbuf.gl_pathc;i++){ //copy template src subdirectory + cfilename = globbuf.gl_pathv[i]; +#endif + ptr=strrchr(cfilename,'/'); + if(ptr){ + if(!strcmp(ptr,"/."))continue; + if(!strcmp(ptr,"/.."))continue; + sprintf(tmp,"%s%s",srcdir.c_str(),ptr); + } + else{ + if(!strcmp(cfilename,"/."))continue; + if(!strcmp(cfilename,"/.."))continue; + sprintf(tmp,"%s/%s",srcdir.c_str(),cfilename); + } + if(copy(cfilename,tmp))return 1; +#ifdef _WIN32 + } while (_findnext(hFile, &c_file) == 0); + _findclose(hFile); +#else + } + globfree(&globbuf); +#endif + + return open(name); + +} + +//******************************************* +void Game::make_source_dir() + //create directory for sources (extracting logic, etc) +{ + + if(reldir) + srcdir=dir+"/"+srcdirname; //srcdir is inside the game directory + else + srcdir=srcdirname; //srcdir can be anywhere + +#ifdef _WIN32 + int ret=_mkdir(srcdir.c_str()); +#else + int ret=mkdir(srcdir.c_str(),0xfff); +#endif + if(ret==-1 && errno != EEXIST){ + menu->errmes("Can't create the source directory %s !\nlogic text files will not be saved.",srcdirname.c_str()); + } + +} + +//******************************************* +int Game::newgame(string name) + //create an empty game in 'name' directory +{ + + static byte BlankObjectFile[8] = {0x42,0x76,0x79,0x70,0x20,0x44,0x4A,0x72}; + static byte BlankWordsFile [72] = { +0x00,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x9E,0x00,0x00,0x01,0x11,0x06,0x08,0x10,0x0D,0x9B,0x00, +0x01,0x00,0x0D,0x10,0x93,0x27,0x0F,0x00}; + + static const char* files[5] = {"vol.0","viewdir","logdir","snddir","picdir"}; + FILE *fptr; + int i,j; + + dir = name; + + for(i=0;i<5;i++){ + sprintf(tmp,"%s/%s",name.c_str(),files[i]); + fptr=fopen(tmp,"wb"); //create empty game files + if(fptr==NULL){ + menu->errmes("Can't create file %s !",files[i]); + return 1; + } + fclose(fptr); + } + sprintf(tmp,"%s/object",dir.c_str()); + fptr=fopen(tmp,"wb"); + fwrite(BlankObjectFile,8,1,fptr); + fclose(fptr); + sprintf(tmp,"%s/words.tok",dir.c_str()); + fptr=fopen(tmp,"wb"); + fwrite(BlankWordsFile,72,1,fptr); + fclose(fptr); + make_source_dir(); + + isOpen = true; + isV3 = false; + ID = ""; + AGIVersionNumber = 2.917; + for(int _i = 0;_i <= 3;_i++){ + for(j = 0;j <= 255; j++){ + ResourceInfo[_i][j].Exists = false; + } + } + menu->status->message(dir.c_str()); + return 0; +} + +//******************************************* +string Game::FindAGIV3GameID(const char *name) + //compare the prefix for vol.0 and dir - if they are same and non-NULL + //it is a V3 game +{ + string ID1; + char *ptr; + char *cfilename; + + ID1 = "V2"; //default for V2 games + +#ifdef _WIN32 + struct _finddata_t c_file; + long hFile; +#else + glob_t globbuf; +#endif + char dirString[10]="", volString[10]=""; + + sprintf(tmp,"%s/*dir",name); +#ifdef _WIN32 + if ((hFile = _findfirst(tmp, &c_file)) == -1L) { +#else + if (glob (tmp, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf)) { + globfree(&globbuf); +#endif + return ID1; + } + +#ifdef _WIN32 + cfilename = c_file.name; +#else + cfilename = globbuf.gl_pathv[0]; +#endif + if((ptr=strrchr(cfilename,'/')))ptr++; + else ptr=cfilename; + strncpy (dirString, ptr, strlen (ptr) - 3); + +#ifdef _WIN32 + _findclose(hFile); +#else + globfree(&globbuf); +#endif + + sprintf(tmp,"%s/*vol.0",name); + +#ifdef _WIN32 + if ((hFile = _findfirst(tmp, &c_file)) == -1L) { +#else + if (glob (tmp, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf)) { + globfree(&globbuf); +#endif + return ID1; + } + +#ifdef _WIN32 + cfilename = c_file.name; +#else + cfilename = globbuf.gl_pathv[0]; +#endif + if((ptr=strrchr(cfilename,'/')))ptr++; + else ptr=cfilename; + strncpy (volString, ptr, strlen (ptr) - 5); + +#ifdef _WIN32 + _findclose(hFile); +#else + globfree(&globbuf); +#endif + + if ((strcmp(volString, dirString) == 0) && (volString != NULL)) + ID1=volString; + + return ID1; +} + +//******************************************************* +double Game::GetAGIVersionNumber(void) +{ + double VerNum; + int ResPos,x; + byte VerLen; + bool ISVerNum; + char VerNumText[16]; + string InFileName = dir + "/agidata.ovl"; + char VersionNumBuffer[] = "A_CDE_GHI"; + double ret = 2.917; + // This is what we use if we can't find the version number. + // Version 2.917 is the most common interpreter and + // the one that all the "new" AGI games should be based on. + + ResourceData.Size = 0; + FILE *fptr=fopen(InFileName.c_str(),"rb"); + if(fptr!=NULL){ + struct stat buf; + fstat(fileno(fptr),&buf); + int size=buf.st_size; + if(size < MaxResourceSize){ + ResourceData.Size = size; + fread(ResourceData.Data,ResourceData.Size,1,fptr); + } + fclose(fptr); + } + + if(ResourceData.Size > 0){ + ResPos = 0; + VerLen = 0; + while(ResPos < ResourceData.Size && VerLen == 0){ + memcpy(VersionNumBuffer,&ResourceData.Data[ResPos],9); + ResPos++; + ISVerNum = true; + if (VersionNumBuffer[1]=='.'){ + if(VersionNumBuffer[0]<'0'||VersionNumBuffer[2]>'9')ISVerNum = false; + for(x=2;x<=4;x++){ + if(VersionNumBuffer[x]<'0'||VersionNumBuffer[x]>'9')ISVerNum = false; + } + if (ISVerNum && (VersionNumBuffer[0]<='2')) VerLen=5; // 2.xxx format + if(VersionNumBuffer[5] != '.') ISVerNum = false; + for(x=6;x<=8;x++){ // 3.xxx.xxx format + if(VersionNumBuffer[x]<'0'||VersionNumBuffer[x]>'9')ISVerNum = false; + } + if(ISVerNum)VerLen=9; + } + else ISVerNum = false; + if (VerLen>0){ + if (VersionNumBuffer[5] == '.'){ + strcpy(VerNumText,VersionNumBuffer); + strcpy(VerNumText+5,VersionNumBuffer+6); // remove second . + } + else{ + strncpy(VerNumText,VersionNumBuffer,VerLen); + VerNumText[VerLen]=0; + } + VerNum=atof(VerNumText); + if(VerNum!=0){ + ret = VerNum; + break; + } + } + } + } + return ret; +} + +//*************************************** +int Game::GetResourceSize(char ResType_c,int ResNum) +{ + byte lsbyte,msbyte; + int ResType = ResType_c; + + if(ResourceInfo[ResType][ResNum].Exists){ + sprintf(tmp,"%s/%s",dir.c_str(),ResourceInfo[ResType][ResNum].Filename); + FILE *fptr=fopen(tmp,"rb"); + if(fptr!=NULL){ + struct stat buf; + fstat(fileno(fptr),&buf); + int size=buf.st_size; + if(size >= ResourceInfo[ResType][ResNum].Loc+5){ + fseek(fptr,ResourceInfo[ResType][ResNum].Loc,SEEK_SET); + fread(&lsbyte,1,1,fptr); + fread(&msbyte,1,1,fptr); + if(lsbyte == 0x12 && msbyte == 0x34){ + fread(&lsbyte,1,1,fptr); + fread(&lsbyte,1,1,fptr); + fread(&msbyte,1,1,fptr); + return (msbyte*256 + lsbyte); + } + } + fclose(fptr); + } + } + return -1; +} + +//*************************************** +int Game::ReadResource(char ResType_c, int ResNum) + //read a resource number ResNum from the vol file +{ + byte msbyte,lsbyte; + int ResType = (int)ResType_c; + + if(isV3){ + return ReadV3Resource(ResType,ResNum); + } + + sprintf(tmp,"%s/%s",dir.c_str(),ResourceInfo[ResType][ResNum].Filename); + FILE *fptr=fopen(tmp,"rb"); + if(fptr==NULL){ + menu->errmes("Error reading file %s/%s",dir.c_str(),ResourceInfo[ResType][ResNum].Filename); + return 1; + } + + struct stat buf; + fstat(fileno(fptr),&buf); + int size=buf.st_size; + if(ResourceInfo[ResType][ResNum].Loc > size){ + menu->errmes("Error: %s: Specified resource location is past end of file",ResourceInfo[ResType][ResNum].Filename); + return 1; + } + + fseek(fptr,ResourceInfo[ResType][ResNum].Loc,SEEK_SET); + fread(&msbyte,1,1,fptr); + fread(&lsbyte,1,1,fptr); + if(!(msbyte==0x12 && lsbyte==0x34)){ + menu->errmes("Error: %s: Resource signature not found",ResourceInfo[ResType][ResNum].Filename); + return 1; + } + + fseek(fptr,ResourceInfo[ResType][ResNum].Loc+3,SEEK_SET); + fread(&lsbyte,1,1,fptr); + fread(&msbyte,1,1,fptr); + ResourceData.Size = msbyte * 256 + lsbyte; + + if(ResourceData.Size==0){ + menu->errmes("Error: %s: Resource size 0 !",ResourceInfo[ResType][ResNum].Filename); + return 1; + } + + fread(ResourceData.Data, ResourceData.Size,1,fptr); + fclose(fptr); + return 0; + +} + +//*************************************** +FILE * Game::OpenPatchVol(int PatchVol,int *filesize) +{ + FILE *fptr; + + if(isV3) + sprintf(tmp,"%s/%svol.%d",dir.c_str(),ID.c_str(),PatchVol); + else + sprintf(tmp,"%s/vol.%d",dir.c_str(),PatchVol); + fptr = fopen(tmp,"a+b"); + if(fptr==NULL)return NULL; + struct stat buf; + fstat(fileno(fptr),&buf); + *filesize=buf.st_size; + return fptr; + +} +//*********************************************** +static int RewriteDirFile(FILE *dir,int dirsize) + //used for V3 games +{ + byte DirData[4][768]; + int CurResType; + byte lsbyte,msbyte; + int Offset[4],Size[4]; + byte OffsetArray[8]; + + fseek(dir,0,SEEK_SET); + for(CurResType=3;CurResType>=0;CurResType--){ + fseek(dir,CurResType*2,SEEK_SET); + fread(&lsbyte,1,1,dir); + fread(&msbyte,1,1,dir); + Offset[CurResType]=(msbyte<<8)|lsbyte; + if(CurResType == 3) + Size[CurResType]=dirsize-Offset[CurResType]; + else + Size[CurResType]=Offset[CurResType+1]-Offset[CurResType]; + if(Offset[CurResType]>dirsize || Size[CurResType]>768 || Offset[CurResType]+Size[CurResType]>dirsize){ + menu->errmes("DIR file is invalid"); + fclose(dir); + return 1; + } + + } + for(CurResType =0;CurResType<=3;CurResType++){ + fseek(dir,Offset[CurResType],SEEK_SET); + memset(DirData[CurResType],0xff,768); + fread(DirData[CurResType],Size[CurResType],1,dir); + } + + OffsetArray[0] = 8; + OffsetArray[1] = 0; + Offset[0] = 8; + + for(CurResType =1;CurResType<=3;CurResType++){ + Offset[CurResType] = Offset[CurResType-1] + 768; + OffsetArray[CurResType*2] = Offset[CurResType] % 256; + OffsetArray[CurResType*2+1] = Offset[CurResType] / 256; + } + fseek(dir,0,SEEK_SET); + fwrite(OffsetArray,8,1,dir); + for(CurResType =0;CurResType<=3;CurResType++){ + fwrite(DirData[CurResType],768,1,dir); + } + fflush(dir); + + return 0; + +} + +//*********************************************** +FILE * Game::OpenDirUpdate(int *dirsize,int ResType) +{ + FILE *fptr; + + if(isV3) + dirname = dir + "/" + ID + "dir"; + else + dirname = dir + "/" + ResTypeAbbrv[ResType] + "dir"; + + fptr = fopen(dirname.c_str(),"r+b"); + if(fptr==NULL){ + menu->errmes("Error writing file %s ! ",dirname.c_str()); + return NULL; + } + struct stat buf; + fstat(fileno(fptr),&buf); + *dirsize=buf.st_size; + return fptr; +} + +//*********************************************** +int Game::AddResource(int ResType,int ResNum) +{ + FILE *fptr,*dirf; + int filesize,dirsize; + int PatchVol; + byte ResHeader[7],DirByte[3]; + int off; + byte lsbyte,msbyte; + + if((dirf = OpenDirUpdate(&dirsize,ResType))==NULL)return 1; + + PatchVol = 0; + fptr = OpenPatchVol(PatchVol,&filesize); //open vol.0 + if(fptr==NULL){ + menu->errmes("Can't open vol.%d !",PatchVol); + return 1; + } + + do{ + if(filesize + ResourceData.Size > 1048000){ +//current volume is too big (to fit a diskette) - create the next one + fclose(fptr); + PatchVol++; + fptr=OpenPatchVol(PatchVol,&filesize); + if(fptr==NULL){ + if(isV3) + menu->errmes("Can't open %svol.%d !",ID.c_str(),PatchVol); + else + menu->errmes("Can't open vol.%d !",PatchVol); + return 1; + } + } + }while(filesize + ResourceData.Size > 1048000); + + //write the resource to the patch volume and update the DIR file + if(isV3){ + if(RewriteDirFile(dirf,dirsize)){ + fclose(dirf); + fclose(fptr); + return 1; + } + } + else{ + if(ResNum*3 > dirsize){ + DirByte[1] = 0xff; + fseek(dirf,dirsize,SEEK_SET); + do{ + fwrite(&DirByte[1],1,1,dirf); + }while(ftell(dirf)!=ResNum*3); + } + } + fseek(fptr,filesize,SEEK_SET); + off = ftell(fptr); + DirByte[0] = PatchVol*0x10 + off / 0x10000; + DirByte[1] = (off % 0x10000) / 0x100; + DirByte[2] = off % 0x100; + ResourceInfo[ResType][ResNum].Exists = true; + ResourceInfo[ResType][ResNum].Loc = off; + if(isV3)sprintf(ResourceInfo[ResType][ResNum].Filename,"%svol.%d",ID.c_str(),PatchVol); + else sprintf(ResourceInfo[ResType][ResNum].Filename,"vol.%d",PatchVol); + int n=0; + ResHeader[n++] = 0x12; + ResHeader[n++] = 0x34; + ResHeader[n++] = PatchVol; + ResHeader[n++] = ResourceData.Size % 256; + ResHeader[n++] = ResourceData.Size / 256; + if(isV3){ + ResHeader[n++] = ResourceData.Size % 256; // no compression so compressed size + ResHeader[n++] = ResourceData.Size / 256; // and uncompressed size are the same + } + fwrite(ResHeader,n,1,fptr); + fwrite(ResourceData.Data,ResourceData.Size,1,fptr); + + if(isV3){ + fseek(dirf,ResType*2,SEEK_SET); + fread(&lsbyte,1,1,dirf); + fread(&msbyte,1,1,dirf); + off = (msbyte<<8)|lsbyte; + fseek(dirf,off+ResNum*3,SEEK_SET); + fwrite(DirByte,3,1,dirf); + fclose(dirf); + } + else{ + fseek(dirf,ResNum*3,SEEK_SET); + fwrite(DirByte,3,1,dirf); + fclose(dirf); + } + fflush(fptr); + + return 0; +} + +//************************************************ +int Game::DeleteResource(int ResType,int ResNum) +{ + FILE *dirf; + int dirsize; + byte lsbyte,msbyte; + int off; + + if((dirf = OpenDirUpdate(&dirsize,ResType))==NULL)return 1; + + if(isV3){ + if(dirsize<8){ + menu->errmes("Error: %s file invalid!",dirname.c_str()); + fclose(dirf); + return 1; + } + fseek(dirf,ResType*2,SEEK_SET); + fread(&lsbyte,1,1,dirf); + fread(&msbyte,1,1,dirf); + off = (msbyte<<8)|lsbyte; + if(dirsize < off+ResNum*3+2){ + menu->errmes("Error: %s file invalid!",dirname.c_str()); + fclose(dirf); + return 1; + } + fseek(dirf,off+ResNum*3,SEEK_SET); + } + else{ + if(dirsize < ResNum*3 + 2){ + menu->errmes("Error: %s file invalid!",dirname.c_str()); + fclose(dirf); + return 1; + } + fseek(dirf,ResNum*3,SEEK_SET); + } + byte b = 0xff; + fwrite(&b,1,1,dirf); + fwrite(&b,1,1,dirf); + fwrite(&b,1,1,dirf); + ResourceInfo[ResType][ResNum].Exists = false; + fclose(dirf); + + return 0; +} + +//************************************************ +int Game::RebuildVOLfiles() +{ + int step=0,steps=0; + int ResType,ResNum,VolFileNum; + byte b=0xff,byte1,byte2,byte3; + FILE *dirf=NULL,*fptr; + byte ResHeader[7]; + long off; +#define MaxVOLFileSize 1023*1024 + TResourceInfo NewResourceInfo[4][256]; + int ResourceNum[4]; + bool cancel=false; + char tmp1[1024]; + int DirOffset[4]; +#ifdef _WIN32 + struct _finddata_t c_file; + long hFile; +#endif + char volname[8]="vol"; + + if(isV3){ + sprintf(volname,"%svol",ID.c_str()); + } + + for(ResType = 0; ResType <= 3;ResType++){ + ResourceNum[ResType]=0; + for(ResNum=0;ResNum<256;ResNum++){ + if(ResourceInfo[ResType][ResNum].Exists){ + steps++; //number of steps for the progress bar (if necessary) + ResourceNum[ResType]=ResNum; + } + } + } + + Q3ProgressDialog progress( "Rebuilding VOL files...", "Cancel", steps,0, 0, TRUE ); //shows up if the operation is taking more than 3 sec + //(so it never shows up...) + + ResHeader[0]=0x12; + ResHeader[1]=0x34; + + VolFileNum=0; + sprintf(tmp,"%s/%s.%d.new",dir.c_str(),volname,VolFileNum); + if((fptr=fopen(tmp,"wb"))==NULL){ + menu->errmes("Error creating file %s ! ",tmp); + progress.cancel(); + return 1; + } + + if(isV3){ + sprintf(tmp,"%s/%sdir.new",dir.c_str(), ID.c_str()); + if((dirf=fopen(tmp,"wb"))==NULL){ + menu->errmes("Error creating file %s ! ",tmp); + progress.cancel(); + return 1; + } + for (ResType = 0;ResType<=3;ResType++){ + DirOffset[ResType] = 8 + ResType*0x300; + byte1 = DirOffset[ResType] % 0x100; + byte2 = DirOffset[ResType] / 0x100; + fwrite(&byte1,1,1,dirf); + fwrite(&byte2,1,1,dirf); + } + for(ResType = 0; ResType <= 3;ResType++){ + for(ResNum=0;ResNum<256;ResNum++){ + fwrite(&b,1,1,dirf); + fwrite(&b,1,1,dirf); + fwrite(&b,1,1,dirf); + } + } + fflush(dirf); + fseek(dirf,0,SEEK_SET); + } + + for(ResType = 0; ResType <= 3;ResType++){ + if(!isV3){ + sprintf(tmp,"%s/%sdir.new",dir.c_str(), ResTypeAbbrv[ResType]); + if((dirf=fopen(tmp,"wb"))==NULL){ + menu->errmes("Error creating file %s !",tmp); + progress.cancel(); + return 1; + } + for(ResNum=0;ResNumerrmes("Error saving %s.%d !",ResTypeAbbrv[ResType],ResNum); + progress.cancel(); + return 1; + } + off=ftell(fptr); + if(off + ResourceData.Size + 5 > MaxVOLFileSize){ + fclose(fptr); + VolFileNum++; + sprintf(tmp,"%s/%s.%d.new",dir.c_str(),volname,VolFileNum); + if((fptr=fopen(tmp,"wb"))==NULL){ + menu->errmes("Error creating file %s !",tmp); + progress.cancel(); + return 1; + } + off=ftell(fptr); + } + NewResourceInfo[ResType][ResNum].Exists = true; + NewResourceInfo[ResType][ResNum].Loc = off; + sprintf(NewResourceInfo[ResType][ResNum].Filename,"%s.%d",volname,VolFileNum); + byte1 = VolFileNum*0x10 + off / 0x10000; + byte2 = (off % 0x10000) / 0x100; + byte3 = off % 0x100; + ResHeader[2] = VolFileNum; + ResHeader[3] = ResourceData.Size % 256; + ResHeader[4] = ResourceData.Size / 256; + if(isV3){ + ResHeader[5] = ResourceData.Size % 256; + ResHeader[6] = ResourceData.Size / 256; + fwrite(ResHeader,7,1,fptr); + } + else{ + fwrite(ResHeader,5,1,fptr); + } + + fwrite(ResourceData.Data,ResourceData.Size,1,fptr); + if(isV3) + fseek(dirf,DirOffset[ResType]+ResNum*3,SEEK_SET); + else + fseek(dirf,ResNum*3,SEEK_SET); + fwrite(&byte1,1,1,dirf); + fwrite(&byte2,1,1,dirf); + fwrite(&byte3,1,1,dirf); + progress.setProgress( step++ ); + if ( progress.wasCancelled() ){ + cancel=true; + break; + } + } + if(!isV3) + fclose(dirf); + + if ( progress.wasCancelled() ){ + cancel=true; + break; + } + } + progress.setProgress( steps ); + + fclose(fptr); + if(isV3)fclose(dirf); + + + if(cancel)return 1; + + //cleanup temporary files + if(isV3){ + sprintf(tmp,"%s/%sdir.new",dir.c_str(), ID.c_str()); + sprintf(tmp1,"%s/%sdir",dir.c_str(), ID.c_str()); + rename(tmp,tmp1); + } + else{ + for(ResType = 0; ResType <= 3;ResType++){ + sprintf(tmp,"%s/%sdir.new",dir.c_str(), ResTypeAbbrv[ResType]); + sprintf(tmp1,"%s/%sdir",dir.c_str(), ResTypeAbbrv[ResType]); + rename(tmp,tmp1); + } + } + + QDir d( dir.c_str()); + + // Delete old VOLs... + QStringList list = d.entryList( + QString(volname) + ".?;" + QString(volname) + ".??" ); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) + d.remove( *it ); + + // ...and replace them with the new ones: + list = d.entryList( QString(volname) + ".*.new" ); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) + { + QString new_name = *it; + new_name.replace(".new", ""); + d.rename( *it, new_name ); + } + + memcpy(ResourceInfo,NewResourceInfo,sizeof(ResourceInfo)); + QMessageBox::information( menu, "AGI studio","Rebuilding is complete !"); + return 0; +} + +//*********************************************** +//V3 decompression code from QT AGI Utilities + +static void initLZW() +{ + if(prefix_code==NULL){ + prefix_code = (unsigned int *)malloc(TABLE_SIZE*sizeof(unsigned int)); + append_character = (byte *)malloc(TABLE_SIZE*sizeof(byte)); + } +} + +static void resetLZW() +{ + input_bit_count=0; + input_bit_buffer=0L; +} + + +/*************************************************************************** +** setBITS +** +** Purpose: To adjust the number of bits used to store codes to the value +** passed in. +***************************************************************************/ +static int setBITS(int value) +{ + if (value == MAXBITS) return TRUE; + + BITS = value; + MAX_VALUE = (1 << BITS) - 1; + MAX_CODE = MAX_VALUE - 1; + return FALSE; +} + +/*************************************************************************** +** decode_string +** +** Purpose: To return the string that the code taken from the input buffer +** represents. The string is returned as a stack, i.e. the characters are +** in reverse order. +***************************************************************************/ +static byte *decode_string(byte *buffer,unsigned int code) +{ + int i; + + i=0; + while (code > 255) { + *buffer++ = append_character[code]; + code=prefix_code[code]; + if (i++>=4000) { + menu->errmes("Fatal error during code expansion !"); + return NULL; + } + } + *buffer=code; + return(buffer); +} +/*************************************************************************** +** input_code +** +** Purpose: To return the next code from the input buffer. +***************************************************************************/ +static unsigned int input_code(byte **input) +{ + unsigned int return_value; + + while (input_bit_count <= 24) { + input_bit_buffer |= (unsigned long) *(*input)++ << input_bit_count; + input_bit_count += 8; + } + + return_value = (input_bit_buffer & 0x7FFF) % (1 << BITS); + input_bit_buffer >>= BITS; + input_bit_count -= BITS; + return(return_value); +} + +/*************************************************************************** +** expand +** +** Purpose: To uncompress the data contained in the input buffer and store +** the result in the output buffer. The fileLength parameter says how +** many bytes to uncompress. The compression itself is a form of LZW that +** adjusts the number of bits that it represents its codes in as it fills +** up the available codes. Two codes have special meaning: +** +** code 256 = start over +** code 257 = end of data +***************************************************************************/ +static void expand(byte *input, byte *output, int fileLength) +{ + int next_code, new_code, old_code; + int character, /* counter=0, index, */ BITSFull /*, i */; + byte *string, *endAddr; + + BITSFull = setBITS(START_BITS); /* Starts at 9-bits */ + next_code = 257; /* Next available code to define */ + + endAddr = (byte *)((long)output + (long)fileLength); + + old_code = input_code(&input); /* Read in the first code */ + character = old_code; + new_code = input_code(&input); + + while ((output < endAddr) && (new_code != 0x101)) { + + if (new_code == 0x100) { /* Code to "start over" */ + next_code = 258; + BITSFull = setBITS(START_BITS); + old_code = input_code(&input); + character = old_code; + *output++ = (char)character; + new_code = input_code(&input); + } + else { + if (new_code >= next_code) { /* Handles special LZW scenario */ + *decode_stack = character; + string = decode_string(decode_stack+1, old_code); + } + else + string = decode_string(decode_stack, new_code); + + /* Reverse order of decoded string and store in output buffer. */ + character = *string; + while (string >= decode_stack) + *output++ = *string--; + + if (next_code > MAX_CODE) + BITSFull = setBITS(BITS + 1); + + prefix_code[next_code] = old_code; + append_character[next_code] = character; + next_code++; + old_code = new_code; + + new_code = input_code(&input); + } + } +} + +//*********************************************** +static void convertLOG(byte *logBuf, int logLen) +{ + int startPos, endPos, i, avisPos=0, numMessages; + + /* Find the start and end of the message section */ + startPos = *logBuf + (*(logBuf+1))*256 + 2; + numMessages = logBuf[startPos]; + endPos = logBuf[startPos+1] + logBuf[startPos+2]*256; + logBuf += (startPos + 3); + startPos = (numMessages * 2) + 0; + + /* Encrypt the message section so that it compiles with AGIv2 */ + for (i=startPos; i> 4) + ((oldData & 0x0F) << 4); + else + outData = data; + + if ((outData == 0xF0) || (outData == 0xF2)) { + *out++ = outData; + if (mode == NORMAL) { + data = picBuf[bufPos++]; + *out++ = (data & 0xF0) >> 4; + mode = ALTERNATE; + } + else { + *out++ = (data & 0x0F); + mode = NORMAL; + } + } + else + *out++ = outData; + + oldData = data; + } + + *outLen = int(out - outBuf); +} +//*********************************************** +int Game::ReadV3Resource(char ResourceType1_c, int ResourceID1) +{ + + byte msbyte,lsbyte; + bool ResourceIsPicture; + byte VolNumByte; + int ResourceType1 = (int)ResourceType1_c; + + if(CompressedResource.Data==NULL) + CompressedResource.Data=(byte *)malloc(MaxResourceSize); + + + sprintf(tmp,"%s/%s",dir.c_str(),ResourceInfo[ResourceType1][ResourceID1].Filename); + FILE *fptr=fopen(tmp,"rb"); + if(fptr==NULL){ + menu->errmes("Error reading file %s/%s",dir.c_str(),ResourceInfo[ResourceType1][ResourceID1].Filename); + return 1; + } + + struct stat buf; + fstat(fileno(fptr),&buf); + int size=buf.st_size; + if(ResourceInfo[ResourceType1][ResourceID1].Loc > size){ + menu->errmes("Error: %s: Specified resource location is past end of file",ResourceInfo[ResourceType1][ResourceID1].Filename); + return 1; + } + fseek(fptr,ResourceInfo[ResourceType1][ResourceID1].Loc,SEEK_SET); + fread(&msbyte,1,1,fptr); + fread(&lsbyte,1,1,fptr); + if(!(msbyte==0x12 && lsbyte==0x34)){ + menu->errmes("Error: %s: Resource signature not found",ResourceInfo[ResourceType1][ResourceID1].Filename); + return 1; + } + fread(&VolNumByte,1,1,fptr); + ResourceIsPicture = ((VolNumByte & 0x80) == 0x80); + fread(&lsbyte,1,1,fptr); + fread(&msbyte,1,1,fptr); + ResourceData.Size = msbyte * 256 + lsbyte; + fread(&lsbyte,1,1,fptr); + fread(&msbyte,1,1,fptr); + CompressedResource.Size = msbyte * 256 + lsbyte; + fread(CompressedResource.Data,CompressedResource.Size,1,fptr); + + if(ResourceIsPicture){ + DecompressPicture(CompressedResource.Data,ResourceData.Data,CompressedResource.Size,&ResourceData.Size); + } + else if(CompressedResource.Size != ResourceData.Size){ + initLZW(); + resetLZW(); + expand(CompressedResource.Data,ResourceData.Data,ResourceData.Size); + if (ResourceType1 == LOGIC) convertLOG( ResourceData.Data,ResourceData.Size); + } + else{ + ResourceData.Size = CompressedResource.Size; + memcpy( ResourceData.Data, CompressedResource.Data,ResourceData.Size); + } + + return 0; + +} +//********************************************************* +void Game::defaults() +{ + + res_default=VIEW; + save_logic_as_text=true; + show_elses_as_gotos=false; + show_all_messages=true; + show_special_syntax=true; + reldir=true; + srcdirname="src"; +#ifdef _WIN32 + command="sarien -e -H 0 ./"; + char abspath[256]; // absolute path to the program file + _fullpath(abspath,_pgmptr,255); + char *mydir = (char *)(malloc(strlen(abspath)+1)); // will store the program's directory + strcpy(mydir,abspath); + char *lastslash = 0; + lastslash = strrchr(mydir,'\\'); + if (!lastslash) + lastslash = strrchr(mydir,'/'); + *lastslash = '\0'; + char templatedir_c[256]; + char helpdir_c[256]; + sprintf(templatedir_c,"%s/template",mydir); + sprintf(helpdir_c,"%s/help",mydir); + templatedir = templatedir_c; + helpdir = helpdir_c; +#else + command="nagi ./ || sarien -e -H 0 ./"; + templatedir="/usr/share/agistudio/template"; + helpdir="/usr/share/agistudio/help"; +#endif + picstyle=P_ONE; +} +//********************************************************* +void Game::read_settings() + //read ~/.agistudio file +{ + char *home; + FILE *fptr; + int n; + char *ptr; + +#ifdef _WIN32 + home = (char *)malloc(256); + GetWindowsDirectoryA(home,256); +#else + home = getenv("HOME"); +#endif + if(!home)home=getenv("home"); + if(!home)return; + + sprintf(tmp,"%s/.agistudio",home); + fptr=fopen(tmp,"rb"); + if(!fptr)return; + + while(fgets(tmp,MAX_TMP,fptr)!=NULL){ + if((ptr=strchr(tmp,0x0a)))*ptr=0; + if((ptr=strchr(tmp,0x0d)))*ptr=0; + if(!strncmp(tmp,"res_default=",12)){ + res_default=atoi(tmp+12); + } + else if(!strncmp(tmp,"save_logic_as_text=",20)){ + n=atoi(tmp+20); + save_logic_as_text=(n==1); + } + else if(!strncmp(tmp,"show_all_messages=",18)){ + n=atoi(tmp+18); + show_all_messages=(n==1); + } + else if(!strncmp(tmp,"show_elses_as_gotos=",20)){ + n=atoi(tmp+20); + show_elses_as_gotos=(n==1); + } + else if(!strncmp(tmp,"show_special_syntax=",20)){ + n=atoi(tmp+20); + show_special_syntax=(n==1); + } + else if(!strncmp(tmp,"reldir=",8)){ + n=atoi(tmp+8); + reldir=(n==1); + } + else if(!strncmp(tmp,"command=",8)){ + command=string(tmp+8); + } + else if(!strncmp(tmp,"srcdirname=",11)){ + srcdirname=string(tmp+11); + } + else if(!strncmp(tmp,"template=",9)){ + templatedir=string(tmp+9); + } + else if(!strncmp(tmp,"help=",5)){ + helpdir=string(tmp+5); + } + else if(!strncmp(tmp,"picstyle=",9)){ + picstyle=atoi(tmp+9); + } + } + + fclose(fptr); + +} + +//********************************************************* +void Game::save_settings() + //save ~/.agistudio file +{ + + char *home; + FILE *fptr; + +#ifdef _WIN32 + home = (char *)malloc(256); + GetWindowsDirectoryA(home,256); +#else + home = getenv("HOME"); +#endif + if(!home)home=getenv("home"); + if(!home){ + menu->errmes("Can't determine HOME environment variable !\nSettings were not saved."); + return; + } + + sprintf(tmp,"%s/.agistudio",home); + fptr=fopen(tmp,"wb"); + if(!fptr){ + menu->errmes("Can't open file %s for writing !\nSettings were not saved.",tmp); + return; + } + fprintf(fptr,"res_default=%d\n",res_default); + fprintf(fptr,"save_logic_as_text=%d\n",save_logic_as_text); + fprintf(fptr,"show_elses_as_gotos=%d\n",show_elses_as_gotos); + fprintf(fptr,"show_all_messages=%d\n",show_all_messages); + fprintf(fptr,"show_special_syntax=%d\n",show_special_syntax); + fprintf(fptr,"reldir=%d\n",reldir); + fprintf(fptr,"command=%s\n",command.c_str()); + fprintf(fptr,"srcdirname=%s\n",srcdirname.c_str()); + fprintf(fptr,"template=%s\n",templatedir.c_str()); + fprintf(fptr,"help=%s\n",helpdir.c_str()); + fprintf(fptr,"picstyle=%d\n",picstyle); + fclose(fptr); + +} + +//************************************************ +int Game::RecompileAll() +{ + int i,ResNum,err; + FILE *fptr; + Logic logic; + char tmp1[16],*ptr; + extern TStringList InputLines; + + for(i=0;ifilename != ""){ + winlist[i].w.t->save(); + winlist[i].w.t->status->message(""); + } + } + else if(winlist[i].type==LOGIC){ + if(winlist[i].w.l->filename != ""){ + winlist[i].w.l->save_logic(); + winlist[i].w.l->status->message(""); + } + } + + } + + int step=0,steps=0; + for(ResNum=0;ResNum<256;ResNum++){ + if(game->ResourceInfo[LOGIC][ResNum].Exists){ + steps++; + } + } + + + Q3ProgressDialog progress( "Recompiling all logics...", "Cancel", steps,0, 0, TRUE ); + progress.setMinimumDuration(0); + + for(ResNum=0;ResNum<256;ResNum++){ + if(game->ResourceInfo[LOGIC][ResNum].Exists){ + //look for the source file first + sprintf(tmp,"%s/logic.%03d",game->srcdir.c_str(),ResNum); + fptr = fopen(tmp,"rb"); + if(fptr==NULL){ + sprintf(tmp,"%s/logic.%d",game->srcdir.c_str(),ResNum); + fptr = fopen(tmp,"rb"); + } + if(fptr==NULL){ + sprintf(tmp,"%s/logic%d.txt",game->srcdir.c_str(),ResNum); + fptr = fopen(tmp,"rb"); + } + if(fptr!=NULL){ + InputLines.lfree(); + while(fgets(tmp,MAX_TMP,fptr)!=NULL){ + if((ptr=strchr(tmp,0x0a)))*ptr=0; + if((ptr=strchr(tmp,0x0d)))*ptr=0; + //strcat(tmp,"\n"); + InputLines.add(tmp); + } + fclose(fptr); + } + else{ //source file not found - reading from the game + err=logic.decode(ResNum); + if(err){ + sprintf(tmp,"logic.%d",ResNum); + menu->errmes(tmp,"Errors:\n%s",logic.ErrorList.c_str()); + continue; + } + InputLines.lfree(); + string::size_type pos; + string str=logic.OutputText; + while((pos=str.find_first_of("\n"))!=string::npos){ + InputLines.add(str.substr(0,pos)); + str=str.substr(pos+1); + } + if(str!=""){ + InputLines.add(str); + } + } + err=logic.compile(); + if(!err){ + game->AddResource(LOGIC,ResNum); + } + else{ + if(logic.ErrorList != ""){ + sprintf(tmp1,"logic.%d",ResNum); + menu->errmes(tmp1,"Errors:\n%s",logic.ErrorList.c_str()); + } + } + progress.setProgress( step++ ); + if ( progress.wasCancelled() )return 1; + } + } + + progress.setProgress( steps ); + QMessageBox::information( menu, "AGI studio","Recompilation is complete !"); + + return 0; + +} diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..5c47b46 --- /dev/null +++ b/src/game.h @@ -0,0 +1,127 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef GAME_H +#define GAME_H +#include +#include +#include "global.h" + +using namespace std; + +typedef struct { + char Filename[12]; //[*]vol.* + long Loc; //location in vol file + bool Exists; +}TResourceInfo ; + +#define MaxResourceSize 65530 + +typedef struct { + byte *Data; + int Size; +}TResource; + + +class Game +{ + public: + Game(); + int open(string name); + int newgame(string name); + int from_template(string name); + int close(); + void save_settings(); + void read_settings(); + void defaults(); + void make_source_dir(); + int GetResourceSize(char ResType,int ResNum); + int ReadResource(char ResourceType, int ResourceID); + int AddResource(int ResType,int ResNum); + int DeleteResource(int ResType,int ResNum); + int RebuildVOLfiles(); + int RecompileAll(); + + TResourceInfo ResourceInfo[4][256]; //logic, picture, view, sound + string dir; //game directory + string ID; //game ID for V3 games (always 'V2' for V2 games) + string dirname; //name of the 'directory' file + //(e.g. picdir, snddir for V2, [ID]dir for V3) + + string srcdir; //dir for saving logic sources + bool isOpen,isV3; + + //defaults; some GUI defauts are part of GAME object because it is the + //only object which is guaranteed to exist at the beginning of the program + int res_default; //default resource type in resources window + int picstyle; //Picedit style + bool save_logic_as_text; //default for 'extract' function + bool show_all_messages; //logic decompile - show all messages at end + //or just unused ones + bool show_elses_as_gotos; + bool show_special_syntax; //v30=4 vs assignn(v30,4) + bool reldir; //if the source dir is relative to the game dir or absolute + string command; //interpreter command line + string srcdirname; //source dir as entered in options + //(i.e. either relative or absolute; srcdir is always absolute) + string templatedir; //template game directory + string helpdir; //help directory + private: + double AGIVersionNumber; + string FindAGIV3GameID(const char *name); + double GetAGIVersionNumber(void); + int ReadV3Resource(char ResourceType,int ResourceID); + FILE *OpenPatchVol(int PatchVol,int *filesize); + FILE *OpenDirUpdate(int *dirsize,int ResType); +}; + +extern Game *game; + +extern const char *ResTypeName[4]; +extern const char *ResTypeAbbrv[4]; + +extern TResource ResourceData; + +extern const char EncryptionKey[]; + +#define MAX_TMP 2048 +extern char tmp[]; + +//resource types +//(the numbers assigned to these defines are important !) +#define LOGIC 0 +#define PICTURE 1 +#define VIEW 2 +#define SOUND 3 + +//additional resource types +#define OBJECT 4 +#define WORDS 5 +#define TEXT 6 + +#define RESOURCES 7 +#define PREVIEW 8 +#define HELPWIN 9 + +//Picedit styles (tools and picture in one window or in separate windows (for small displays)) +#define P_ONE 0 +#define P_TWO 1 + +#endif //GAME_H diff --git a/src/global.h b/src/global.h new file mode 100644 index 0000000..892b615 --- /dev/null +++ b/src/global.h @@ -0,0 +1,28 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +typedef unsigned char byte; + +#ifndef __GNUC__ +using namespace std; +#endif + +namespace Qt {} +using namespace Qt; diff --git a/src/helpwindow.cpp b/src/helpwindow.cpp new file mode 100644 index 0000000..5e07cbe --- /dev/null +++ b/src/helpwindow.cpp @@ -0,0 +1,371 @@ +/**************************************************************************** +** +** This help window was modified from an example code by QT. +** Original license: +** +** Copyright (C) 1992-1999 Troll Tech AS. All rights reserved. +** +** This file is part of an example program for Qt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ +//my modifications of the original source: +//included .xpm in the source, removed 'about' buttons, added setSource, +//removed tr() (didn't compile with Mandrake 7.0) +//added hideEvent,showEvent + +#include "helpwindow.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include + +#include + +#include "home.xpm" +#include "forward.xpm" +#include "back.xpm" + +#include "menu.h" + +HelpWindow *helpwindow,*helpwindow1; + +HelpWindow::HelpWindow( const QString& home_, const QString& _path, QWidget* parent, const char *name ) + : Q3MainWindow( parent, name ), pathCombo( 0 ), selectedURL(), + path( QFileInfo( home_ ).dirPath( TRUE ), "*.htm*" ) +{ + + + Q3StyleSheetItem* style; + + // Modify the application-wide default style sheet to handle + // some extra HTML gracefully. + // + // Ignore any bodytext in ...: + style = new Q3StyleSheetItem( Q3StyleSheet::defaultSheet(), "head" ); + style->setDisplayMode(Q3StyleSheetItem::DisplayNone); + // + // Not in default style sheet, just fake it: + style = new Q3StyleSheetItem( Q3StyleSheet::defaultSheet(), "dl" ); + style->setDisplayMode(Q3StyleSheetItem::DisplayBlock); + style = new Q3StyleSheetItem( Q3StyleSheet::defaultSheet(), "dt" ); + style->setDisplayMode(Q3StyleSheetItem::DisplayBlock); + style->setContexts("dl"); + // + // Many HTML files omit the

    or
  • , so we add this for efficiency: + Q3StyleSheet::defaultSheet()->item("p")->setSelfNesting( FALSE ); + Q3StyleSheet::defaultSheet()->item("li")->setSelfNesting( FALSE ); + + + + readHistory(); + readBookmarks(); + + fileList = path.entryList(); + + browser = new Q3TextBrowser( this ); + browser->mimeSourceFactory()->setFilePath( _path ); + browser->setFrameStyle( Q3Frame::Panel | Q3Frame::Sunken ); + connect( browser, SIGNAL( textChanged() ), + this, SLOT( textChanged() ) ); + + setCentralWidget( browser ); + + if ( !home_.isEmpty() ) + browser->setSource( home_ ); + + connect( browser, SIGNAL( highlighted( const QString&) ), + statusBar(), SLOT( message( const QString&)) ); + + resize( 640,700 ); + + Q3PopupMenu* file = new Q3PopupMenu( this ); + file->insertItem( "&New Window", this, SLOT( newWindow() ), Qt::ALT | Qt::Key_N ); + file->insertItem( "&Open File", this, SLOT( openFile() ), Qt::ALT | Qt::Key_O ); + file->insertSeparator(); + file->insertItem( "&Close", this, SLOT( hide() ), Qt::ALT | Qt::Key_Q ); + + Q3PopupMenu* go = new Q3PopupMenu( this ); + backwardId = go->insertItem( QPixmap(back), + "&Backward", browser, SLOT( backward() ), + Qt::ALT | Qt::Key_Left ); + forwardId = go->insertItem( QPixmap(forward), + "&Forward", browser, SLOT( forward() ), + Qt::ALT | Qt::Key_Right ); + go->insertItem( QPixmap(home), "&Home", browser, SLOT( home() ) ); + + hist = new Q3PopupMenu( this ); + QStringList::Iterator it = history.begin(); + for ( ; it != history.end(); ++it ) + mHistory[ hist->insertItem( *it ) ] = *it; + connect( hist, SIGNAL( activated( int ) ), + this, SLOT( histChosen( int ) ) ); + + bookm = new Q3PopupMenu( this ); + bookm->insertItem( "Add Bookmark", this, SLOT( addBookmark() ) ); + bookm->insertSeparator(); + + QStringList::Iterator it2 = bookmarks.begin(); + for ( ; it2 != bookmarks.end(); ++it2 ) + mBookmarks[ bookm->insertItem( *it2 ) ] = *it2; + connect( bookm, SIGNAL( activated( int ) ), + this, SLOT( bookmChosen( int ) ) ); + + menuBar()->insertItem( "&File", file ); + menuBar()->insertItem( "&Go", go ); + menuBar()->insertItem( "History" , hist ); + menuBar()->insertItem( "Bookmarks" , bookm ); + + menuBar()->setItemEnabled( forwardId, FALSE); + menuBar()->setItemEnabled( backwardId, FALSE); + connect( browser, SIGNAL( backwardAvailable( bool ) ), + this, SLOT( setBackwardAvailable( bool ) ) ); + connect( browser, SIGNAL( forwardAvailable( bool ) ), + this, SLOT( setForwardAvailable( bool ) ) ); + + + Q3ToolBar* toolbar = new Q3ToolBar( this ); + addToolBar( toolbar, "Toolbar"); + QToolButton* button; + + button = new QToolButton( QPixmap(back), "Backward", "", browser, SLOT(backward()), toolbar ); + connect( browser, SIGNAL( backwardAvailable(bool) ), button, SLOT( setEnabled(bool) ) ); + button->setEnabled( FALSE ); + button = new QToolButton( QPixmap(forward), "Forward", "", browser, SLOT(forward()), toolbar ); + connect( browser, SIGNAL( forwardAvailable(bool) ), button, SLOT( setEnabled(bool) ) ); + button->setEnabled( FALSE ); + button = new QToolButton( QPixmap(home), "Home", "", browser, SLOT(home()), toolbar ); + + toolbar->addSeparator(); + + pathCombo = new QComboBox( TRUE, toolbar ); + connect( pathCombo, SIGNAL( activated( const QString & ) ), + this, SLOT( pathSelected( const QString & ) ) ); + toolbar->setStretchableWidget( pathCombo ); + setRightJustification( TRUE ); + + pathCombo->insertItem( home_ ); + pathCombo->installEventFilter( this ); + QObjectList l = queryList( "QLineEdit" ); + if ( l.size()>0 ) + ( (QLineEdit*)l.at(0) )->installEventFilter( this ); + + browser->setFocus(); +} + + +void HelpWindow::setBackwardAvailable( bool b) +{ + menuBar()->setItemEnabled( backwardId, b); +} + +void HelpWindow::setForwardAvailable( bool b) +{ + menuBar()->setItemEnabled( forwardId, b); +} + + +void HelpWindow::textChanged() +{ + if ( browser->documentTitle().isNull() ) + setCaption( browser->context() ); + else + setCaption( browser->documentTitle() ) ; + + selectedURL = caption(); + if ( !selectedURL.isEmpty() && pathCombo ) { + path = QDir( QFileInfo( selectedURL ).dirPath( TRUE ), "*.htm*" ); + fileList = path.entryList(); + bool exists = FALSE; + int i; + for ( i = 0; i < pathCombo->count(); ++i ) { + if ( pathCombo->text( i ) == selectedURL ) { + exists = TRUE; + break; + } + } + if ( !exists ) { + pathCombo->insertItem( selectedURL, 0 ); + pathCombo->setCurrentItem( 0 ); + mHistory[ hist->insertItem( selectedURL ) ] = selectedURL; + } else + pathCombo->setCurrentItem( i ); + selectedURL = QString::null; + } +} + +HelpWindow::~HelpWindow() +{ + history.clear(); + QMap::Iterator it = mHistory.begin(); + for ( ; it != mHistory.end(); ++it ) + history.append( *it ); + + QFile f( QDir::currentDirPath() + "/.history" ); + f.open( QIODevice::WriteOnly ); + QDataStream s( &f ); + s << history; + f.close(); + + bookmarks.clear(); + QMap::Iterator it2 = mBookmarks.begin(); + for ( ; it2 != mBookmarks.end(); ++it2 ) + bookmarks.append( *it2 ); + + QFile f2( QDir::currentDirPath() + "/.bookmarks" ); + f2.open( QIODevice::WriteOnly ); + QDataStream s2( &f2 ); + s2 << bookmarks; + f2.close(); +} + + +void HelpWindow::openFile() +{ + QString fn = Q3FileDialog::getOpenFileName( QString::null, QString::null, this ); + if ( !fn.isEmpty() ) + browser->setSource( fn ); +} + +void HelpWindow::setSource(char *filename) +{ + + browser->setSource( filename ); +} + +void HelpWindow::newWindow() +{ + ( new HelpWindow(browser->source(), "qbrowser") )->show(); +} + +void HelpWindow::pathSelected( const QString &_path ) +{ + browser->setSource( _path ); + path = QDir( QFileInfo( _path ).dirPath( TRUE ), "*.htm*" ); + fileList = path.entryList(); + QMap::Iterator it = mHistory.begin(); + bool exists = FALSE; + for ( ; it != mHistory.end(); ++it ) { + if ( *it == _path ) { + exists = TRUE; + break; + } + } + if ( !exists ) + mHistory[ hist->insertItem( _path ) ] = _path; +} + +bool HelpWindow::eventFilter( QObject * o, QEvent * e ) +{ + + QObjectList l = queryList( "QLineEdit" ); + if ( l.empty() ) + return FALSE; + + QLineEdit *lined = (QLineEdit*)l.at(0); + + if ( ( o == pathCombo || o == lined ) && + e->type() == QEvent::KeyPress ) { + + if ( isprint(((QKeyEvent *)e)->ascii()) ) { + if ( lined->hasMarkedText() ) + lined->del(); + QString nt( lined->text() ); + nt.remove( 0, nt.findRev( '/' ) + 1 ); + nt.truncate( lined->cursorPosition() ); + nt += (char)(((QKeyEvent *)e)->ascii()); + + QStringList::Iterator it = fileList.begin(); + while ( it != fileList.end() && (*it).left( nt.length() ) != nt ) + ++it; + + if ( !(*it).isEmpty() ) { + nt = *it; + int cp = lined->cursorPosition() + 1; + int l = path.canonicalPath().length() + 1; + lined->validateAndSet( path.canonicalPath() + "/" + nt, cp, cp, l + nt.length() ); + return TRUE; + } + } + } + + return FALSE; +} + +void HelpWindow::readHistory() +{ + if ( QFile::exists( QDir::currentDirPath() + "/.history" ) ) { + QFile f( QDir::currentDirPath() + "/.history" ); + f.open( QIODevice::ReadOnly ); + QDataStream s( &f ); + s >> history; + f.close(); + while ( history.count() > 20 ) + history.remove( history.begin() ); + } +} + +void HelpWindow::readBookmarks() +{ + if ( QFile::exists( QDir::currentDirPath() + "/.bookmarks" ) ) { + QFile f( QDir::currentDirPath() + "/.bookmarks" ); + f.open( QIODevice::ReadOnly ); + QDataStream s( &f ); + s >> bookmarks; + f.close(); + } +} + +void HelpWindow::histChosen( int i ) +{ + if ( mHistory.contains( i ) ) + browser->setSource( mHistory[ i ] ); +} + +void HelpWindow::bookmChosen( int i ) +{ + if ( mBookmarks.contains( i ) ) + browser->setSource( mBookmarks[ i ] ); +} + +void HelpWindow::addBookmark() +{ + mBookmarks[ bookm->insertItem( caption() ) ] = caption(); +} + +//********************************************* +void HelpWindow::hideEvent( QHideEvent * ) +{ + + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//********************************************* +void HelpWindow::showEvent( QShowEvent * ) +{ + + if(window_list && window_list->isVisible())window_list->draw(); + +} diff --git a/src/helpwindow.h b/src/helpwindow.h new file mode 100644 index 0000000..9d89217 --- /dev/null +++ b/src/helpwindow.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** $Id: helpwindow.h 44 2012-08-17 19:22:03Z elonen $ +** +** Copyright (C) 1992-1999 Troll Tech AS. All rights reserved. +** +** This file is part of an example program for Qt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ + +#ifndef HELPWINDOW_H +#define HELPWINDOW_H + +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include + +class QComboBox; +class Q3PopupMenu; + +class HelpWindow : public Q3MainWindow +{ + Q_OBJECT +public: + HelpWindow( const QString& home_, const QString& path, QWidget* parent = 0, const char *name=0 ); + ~HelpWindow(); + void setSource(char *filename); +private slots: + void setBackwardAvailable( bool ); + void setForwardAvailable( bool ); + + void textChanged(); + void openFile(); + void newWindow(); + + void pathSelected( const QString & ); + void histChosen( int ); + void bookmChosen( int ); + void addBookmark(); + void showEvent( QShowEvent * ); + void hideEvent( QHideEvent * ); + +private: + bool eventFilter( QObject * o, QEvent * e ); + void readHistory(); + void readBookmarks(); + + Q3TextBrowser* browser; + QComboBox *pathCombo; + int backwardId, forwardId; + QString selectedURL; + QDir path; + QStringList fileList, history, bookmarks; + QMap mHistory, mBookmarks; + Q3PopupMenu *hist, *bookm; +}; + + +extern HelpWindow *helpwindow,*helpwindow1; + + +#endif + diff --git a/src/home.xpm b/src/home.xpm new file mode 100644 index 0000000..15b69bc --- /dev/null +++ b/src/home.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static const char *home[] = { +/* columns rows colors chars-per-pixel */ +"16 16 4 1", +" c black", +". c #C0C0C0C0C0C0", +"X c gray100", +"o c None", +/* pixels */ +"oooooooooooooooo", +"ooooooo ooooooo", +"oo ooo oooooo", +"oo oo XX.. ooooo", +"oo o XXXX.. oooo", +"oo XXXXXX.. ooo", +"oo XXXXXXXX.. oo", +"o XXXXXXXXX... o", +" XXXXXXXX.. ", +"oo XXXXXXXX.. oo", +"oo XXX XX.. oo", +"oo XXX o XX.. oo", +"oo XXX o XX.. oo", +"oo XXX o XX.. oo", +"oo XXX o XX.. oo", +"oo o oo" +}; diff --git a/src/icon1.ico b/src/icon1.ico new file mode 100644 index 0000000000000000000000000000000000000000..607579b86eb1a381b7c644db7615df04cc37277c GIT binary patch literal 9710 zcmeHNy=oLu6h6x;7B<1oZi9`L2#R18A0dz7D+noO8^OW{u-e!OmUh}KY0`w`4T9KA zXCO8q8FD>m=6*A04)^ZO?9MVv*b8UR|M#6cGr1dI1xZ-`p{ImdQb zB>(;a(Z^k)=TgJ+jz!|-;+iLqE2#p_=OK|>r|j=L2WeOvYn|MJ4Q|m5Yh(4z-yq-3 z8k*lux#~O?ud6>azn!=1Jhp#Tf6L$Pd|LH-r~2*vNY(e9ADUmEr?E4&?>%e00r=&6 zqZZ3=eLZVWcFiqwSU&6b#HnGn{M-9qKLhr8OZoaiTGFn$xj*^*+j*Ac)NKp-i4Hlh zMYr~1Zxlc8C^1hjd)6Q=zD?t|^8|domu2jQ`w#Hh`eis5^;mrCFY4_hXZft(2gkj~ zm=is!WbEcNc7+!=AG?+md(LUG`P!#F24XS&WsKtm$3^_=`a8wFzaiTVZm+;*Ujcp2 z>PZnt3_kRtxYS^wUdNEL8a2?!$NW@0mItoZQj2+FG>4v^*1Kf(U;;25eC_gZKb*FymG5uwTn*X7t!gE7Q$ +#include + +#include "linklist.h" +#include "picture.h" + +void Picture::dldelete() +{ + struct picCodeNode *temp; + + if (picPos == NULL) return; + + if (picPos == picStart) picStart = picPos->next; + if (picPos == picLast) picLast = picPos->prior; + + if (picPos->prior != NULL) { + picPos->prior->next = picPos->next; + } + if (picPos->next != NULL) { + picPos->next->prior = picPos->prior; + } + + temp = picPos->next; + free(picPos); + picPos = temp; + + bufLen--; + /* bufPos should still be the same */ +} + +void Picture::removeAction() +{ + if (picPos != NULL) { + dldelete(); + while ((picPos != NULL) && (picPos->node < 0xF0)) dldelete(); + } +} + +void Picture::wipeAction() +{ + if (picPos != NULL) { + dldelete(); + while (picPos != NULL) dldelete(); + } +} + +void Picture::dlstore(struct picCodeNode *i) +{ + + + if ((picStart == NULL) && (picLast == NULL)) { + picStart = picLast = i; + i->next = NULL; + i->prior = NULL; + picPos = NULL; + } + else if (picPos == NULL) { // End Node + i->next = NULL; + i->prior = picLast; + picLast->next = i; + picLast = i; + picPos = NULL; + } + else { + switch (addMode) { + case INS_MODE: + i->prior = picPos->prior; // works for picStart as well + i->next = picPos; + if (picPos != picStart) picPos->prior->next = i; + if (picPos == picStart) picStart = i; + picPos->prior = i; + // picPos = i; + break; + + case OVR_MODE: + i->prior = picPos->prior; // link from i + i->next = picPos->next; + if (picPos != picStart) picPos->prior->next = i; + if (picPos == picStart) picStart = i; + if (picPos != picLast) picPos->next->prior = i; + if (picPos == picLast) picLast = i; + free(picPos); + picPos = i->next; + break; + } + } + + bufLen++; + bufPos++; +} + +void Picture::displayList() +{ + struct picCodeNode *temp; + + temp = picStart; + printf("%02X ", temp->node); + + do { + temp = temp->next; + printf("%X ", temp->node); + } while (temp->next != NULL); + + printf("\n"); +} + +void Picture::freeList() +{ + struct picCodeNode *temp, *store; + + if ((picStart != NULL) && (picLast != NULL)) { + + temp = picStart; + store = temp->next; + free(temp); + + do { + temp = store; + store = temp->next; + free(temp); + } while (store != NULL); + + picStart = picLast = picPos = NULL; + } + + bufPos = 0; + bufLen = 0; +} + +void Picture::moveBack() +{ + if (picPos == NULL) { + picPos = picLast; + if (bufPos > 0) bufPos--; + } + else { + if (picPos->prior != NULL) { + picPos = picPos->prior; + bufPos--; + } + } +} + +void Picture::moveForward() +{ + if (picPos !=NULL) { + picPos = picPos->next; + bufPos++; + } +} + +void Picture::moveToStart() +{ + picPos = picStart; + bufPos = 0; + +} + +void Picture::moveToEnd() +{ + picPos = NULL; + bufPos = bufLen; +} + +void Picture::moveBackAction() +{ + do { + moveBack(); + if (picPos == picStart) break; + } while (picPos->node < 0xF0); +} + +void Picture::moveForwardAction() +{ + do { + moveForward(); + if (picPos == NULL) break; + } while (picPos->node < 0xF0); +} + + +/* LIST TEST PROGRAM +void main() +{ + struct picCodeNode *trial, *trial2, *trial3, *temp; + int i; + + trial = (struct picCodeNode *)malloc(sizeof(picCodes)); + trial2 = (struct picCodeNode *)malloc(sizeof(picCodes)); + trial3 = (struct picCodeNode *)malloc(sizeof(picCodes)); + + trial->node = 0x64; + trial2->node = 0x50; + trial3->node = 0x40; + dlstore(trial); + dlstore(trial2); + dlstore(trial3); + + for (i=0; i<10; i++) { + temp = (struct picCodeNode *)malloc(sizeof(picCodes)); + temp->node = i; + dlstore(temp); + } + + clrscr(); + displayList(); + moveBack(); + temp = (struct picCodeNode *)malloc(sizeof(picCodes)); + temp->node = 0x3F; + dlstore(temp); + displayList(); + + moveBack(); + moveBack(); + moveBack(); + addMode = OVR_MODE; + temp = (struct picCodeNode *)malloc(sizeof(picCodes)); + temp->node = 0x4F; + dlstore(temp); + displayList(); + + moveToStart(); + temp = (struct picCodeNode *)malloc(sizeof(picCodes)); + temp->node = 0x8F; + dlstore(temp); + displayList(); + + moveToStart(); + addMode = INS_MODE; + temp = (struct picCodeNode *)malloc(sizeof(picCodes)); + temp->node = 0x7F; + dlstore(temp); + displayList(); + + moveForward(); + moveForward(); + moveForward(); + moveForward(); + temp = (struct picCodeNode *)malloc(sizeof(picCodes)); + temp->node = 0x6F; + dlstore(temp); + displayList(); + + moveToEnd(); + temp = (struct picCodeNode *)malloc(sizeof(picCodes)); + temp->node = 0x5F; + dlstore(temp); + displayList(); + + freeList(); +} +*/ diff --git a/src/linklist.h b/src/linklist.h new file mode 100644 index 0000000..037e8d8 --- /dev/null +++ b/src/linklist.h @@ -0,0 +1,37 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/************************************************************************** +** linklist.h (by Lance Ewing) +**************************************************************************/ + +#ifndef _LINKLIST_H_ +#define _LINKLIST_H_ + +#define INS_MODE 0 +#define OVR_MODE 1 + +struct picCodeNode { + unsigned char node; + struct picCodeNode *next; + struct picCodeNode *prior; +}; + +#endif /* _LINKLIST_H_ */ diff --git a/src/logcompile.cpp b/src/logcompile.cpp new file mode 100644 index 0000000..98d4469 --- /dev/null +++ b/src/logcompile.cpp @@ -0,0 +1,1508 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * Almost all of this code was adapted from the Windows AGI Studio + * developed by Peter Kelly. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "logic.h" +#include "game.h" +#include "logedit.h" +#include "menu.h" + +#include +#include +#include + +extern TStringList InputLines; //temporary - +//input text from the editor window or file + +static bool UseTypeChecking = true; +static int ResPos,LogicSize; +static TStringList EditLines,IncludeFilenames; +static string DefineNames[MaxDefines]; +static string DefineValues[MaxDefines]; +static int NumDefines; +static int RealLineNum[65535], LineFile[65535]; +static int DefineNameLength[MaxDefines]; +static string Messages[MaxMessages]; +static bool MessageExists[MaxMessages]; + +typedef struct{ + string Name; + int Loc; +}TLogicLabel; +static TLogicLabel Labels[MaxLabels+1]; +static int NumLabels; + +static bool ErrorOccured; +static int CurLine; +static string LowerCaseLine,ArgText,LowerCaseArgText; +static string::size_type LinePos,LineLength,ArgTextLength,ArgTextPos; +static bool FinishedReading; +static int CommandNameStartPos; +static string CommandName; +static int CommandNum; +static bool NOTOn; + +char empty_tmp[] = {0}; + +extern const char EncryptionKey[]; +static int EncryptionStart; +//************************************************* +static void WriteByte(byte b) +{ + + if(ResPos < ResourceData.Size){ + ResourceData.Data[ResPos++]=b; + if(ResPos > LogicSize)LogicSize=ResPos; + } +} + + +static void WriteByteAtLoc(byte b,int Loc) +{ + + if(Loc < ResourceData.Size){ + ResourceData.Data[Loc]=b; + if(Loc > LogicSize)LogicSize= Loc; + } + +} + +static void WriteLSMSWord(short word) +{ + + WriteByte(word % 256); + WriteByte(word / 256); + +} +//************************************************* +void Logic::ShowError(int Line, string ErrorMsg) +{ + + int LineNum = RealLineNum[Line]; + if(LineFile[Line] == 0 || Line > EditLines.num){ + // error is in logic in editor window + sprintf(tmp,"Line %d: %s\n",RealLineNum[Line],ErrorMsg.c_str()); + } + else{ //error in include file + if (LineFile[Line] > IncludeFilenames.num){ + sprintf(tmp,"[unknown include file] Line ???: %s\n",ErrorMsg.c_str()); + } + else{ + sprintf(tmp,"File %s Line %d: %s\n",IncludeFilenames.at(LineFile[Line]-1).c_str(),LineNum,ErrorMsg.c_str()); + } + } + + ErrorList.append(tmp); + ErrorOccured=true; + +} + +//*************************************************** +string Logic::ReadString(string::size_type *pos, string& str) + //returns string without quotes, starting from pos1 + //pos is set to the 1st char after string +{ + string::size_type pos1 = *pos; + string::size_type pos2 = pos1; + + // printf ("ReadString: str=%s pos=%d\n",str.c_str(),*pos); + + do{ + pos2 = str.find_first_of("\"",pos2+1); + if(pos2 == string::npos){ + ShowError(CurLine,"\" required at end of string."); + printf("string: *%s*\n",str.c_str()); + return ""; + } + }while(str[pos2-1]=='\\'); + + *pos = pos2+1; + if(pos2==pos1+1){ + return ""; + } + + return str.substr(pos1+1,pos2-pos1-1); +} +//*************************************************** +int Logic::RemoveComments(TStringList Lines) +{ + int CommentDepth = 0; + for(CurLine=0;CurLine0 && Line.substr(i,2) == "*/" ){ + --CommentDepth; + ++i; + continue; + } + } + if ( CommentDepth == 0 ){ + if(Line[i]=='\"' && (i==0 || Line[i-1] != '\\')) + InQuotes = !InQuotes; + NewLine += Line[i]; + } + } + Lines.replace(CurLine,NewLine); + } + return 0; +} +//*************************************************** +int Logic::AddIncludes() +{ + TStringList IncludeStrings,IncludeLines; + int CurInputLine,CurIncludeLine; + string filename; + int err=0; + string::size_type pos1,pos2; + int CurLine; + char *ptr; + + IncludeFilenames = TStringList(); + IncludeStrings = TStringList(); + EditLines = TStringList(); + IncludeLines = TStringList(); + CurLine = 0; + for(CurInputLine = 0;CurInputLinedir.c_str(),filename.c_str()); + FILE *fptr = fopen(tmp,"rb"); + if(fptr==NULL){ + sprintf(tmp,"Can't open include file: %s/src/%s",game->dir.c_str(),filename.c_str()); + ShowError(CurLine,tmp); + err=1; + continue; + } + IncludeLines.lfree(); + + while(fgets(tmp,MAX_TMP,fptr)!=NULL){ + if((ptr=strchr(tmp,0x0a)))*ptr=0; + if((ptr=strchr(tmp,0x0d)))*ptr=0; + IncludeLines.add(tmp); + } + fclose(fptr); + if(IncludeLines.num==0)continue; + IncludeFilenames.add(filename); + RemoveComments(IncludeLines); + EditLines.replace(CurLine,empty_tmp); + for(CurIncludeLine=0;CurIncludeLine= MaxDefines){ + ShowError(CurLine,"Too many defines (max " + IntToStr(MaxDefines) + ")"); + err=1; + continue; + } + pos1 = str.find_first_not_of(" ",1); + pos2 = str.find_first_of(" ",pos1); + if(pos1 == string::npos||pos2 == string::npos){ + ShowError(CurLine,"Missing define name !"); + err=1; + continue; + } + ThisDefineName = str.substr(pos1,pos2-1); + if(ThisDefineName.find_first_not_of("qwertyuiopasdfghjklzxcvbnm1234567890._") != string::npos){ + ShowError(CurLine,"Define name can contain only characters from [a-z],'.' and '_'."); + err=1; + continue; + } + for(i=0;i MaxLabels){ + ShowError(CurLine,"Too many labels (max "+IntToStr(MaxLabels)+")"); + err=1;continue; + } + if(LabelName == "if" || LabelName == "else" || LabelName == "goto"){ + ShowError(CurLine,"Invalid label name ("+LabelName+")"); + err=1;continue; + } + for(i=0;iNumLines){ + FinishedReading = true; + return; + } + do{ + LowerCaseLine = EditLines.at(CurLine); + if(LowerCaseLine == empty_tmp || (LinePos=LowerCaseLine.find_first_not_of(" ")) == string::npos){ + CurLine++; + continue; + } + //printf("Line %d: %s\n",CurLine,LowerCaseLine.c_str()); + toLower(&LowerCaseLine); + LineLength = LowerCaseLine.length(); + return; + }while(CurLine0 && (str[i-1]==' ' || str[i-1]=='\t')) + --i; + return str.substr(0,i); +} +//*************************************************** +string Logic::ReplaceDefine(string InText) +{ + string str=InText; + toLower(&str); + for(int i=0;i= LineLength || EditLines.at(CurLine)[LinePos] != '('){ + ShowError(CurLine,"'(' expected."); + return; + } + LinePos++; + if(CmdNum==14 && CommandIsIf){ //said test command + NumSaidArgs = -1; + FinishedReadingSaidArgs = false; + do{ + ReadArgText(); + NumSaidArgs++; + if(ArgText[0]=='"'){ + ArgValue=0; + ArgTextPos=0; + ThisWord=ReadString(&ArgTextPos,ArgText); + if(ErrorOccured) + ShowError(CurLine,"\" required at end of word."); + else{ + //find word group number + bool found=false; + for(int k=0;kNumGroups;k++){ + for(int i=0;iWordGroup[k].Words.num;i++){ + if( wordlist->WordGroup[k].Words.at(i) == ThisWord){ + ArgValue = wordlist->WordGroup[k].GroupNum; + found=true; + break; + } + } + if(found)break; + } + if(!found){ + ShowError(CurLine,"Unknown word "+ThisWord+"."); + return; + } + } + } + else ArgValue = ReadArgValue(); + SaidArgs[NumSaidArgs] = ArgValue; + if (SaidArgs[NumSaidArgs] < 0 || SaidArgs[NumSaidArgs] > 65535){ + ShowError(CurLine,"Invalid word number for argument " +IntToStr(NumSaidArgs)+ " (must be 0-65535)."); + SaidArgs[NumSaidArgs] = 0; + } + if ((LinePos < LineLength) & (LowerCaseLine[LinePos] == ',')){ + if (NumSaidArgs > MaxSaidArgs){ + ShowError(CurLine,"Too many arguments for said command."); + FinishedReadingSaidArgs = true; + } + } + else if(LinePos < LineLength && LowerCaseLine[LinePos] == ')'){ + FinishedReadingSaidArgs = true; + } + else + ShowError(CurLine,"',' or ')' expected after argument "+IntToStr(NumSaidArgs)+"."); + LinePos++; + }while(!FinishedReadingSaidArgs||ErrorOccured); + WriteByte(NumSaidArgs+1); + for (int i=0;i<=NumSaidArgs;i++){ + WriteByte(SaidArgs[i] % 256); + WriteByte(SaidArgs[i] / 256); + } + }//if said test command + else{ //other command + if (CommandIsIf) ThisCommand = TestCommand[CmdNum]; + else ThisCommand = AGICommand[CmdNum]; + for (CurArg = 0;CurArg=1 && ArgText[0]=='"'){ + // argument is message and given as string + ArgTextPos=0; + ThisMessage = ""; + //splitting the message into lines if it doesn't fit the screen + do{ + if(ThisMessage != "" && ThisMessage[ThisMessage.length()-1]!=' ')ThisMessage += " "; + ThisMessage += ReadString(&ArgTextPos,ArgText); + if(LinePos+1>=LineLength || LowerCaseLine.find_first_not_of(" ",LinePos+1)==string::npos){ + + NextLine(); + SkipSpaces(); + ReadArgText(); + } + else break; + }while(true); + ThisMessageNum = MessageNum(ThisMessage); + if (ThisMessageNum > 0){ + WriteByte(ThisMessageNum); + } + else{ + ThisMessageNum = AddMessage(ThisMessage); + if (ThisMessageNum == 0) + ShowError(CurLine,"Too many messages (max 255)."); + else + WriteByte(ThisMessageNum); + } + }//argument is message and given as string + else if (ThisCommand.argTypes[CurArg] == atIObj && ArgTextLength >= 1 && ArgText[0] == '"'){ + // argument is inventory object and given as string + ArgTextPos=0; + ThisInvObjectName= ReadString(&ArgTextPos,ArgText); + if(ThisInvObjectName == "")ShowError(CurLine,"Object name must be at least one character."); + else{ + for(i=0;iItemNames.num;i++){ + if(objlist->ItemNames.at(i)==ThisInvObjectName){ + ThisInvObjectNum = i; + WriteByte(i); + break; + } + } + if(i>=objlist->ItemNames.num){ + ShowError(CurLine,"Unknown inventory object "+ThisInvObjectName); + } + } + }// argument is inventory object and given as string + else{ //normal argument + ThisArgTypePrefix = (char *)ArgTypePrefix[(int)ThisCommand.argTypes[CurArg]]; + if(UseTypeChecking && (strcmp(LowerCaseArgText.substr(0,strlen(ThisArgTypePrefix)).c_str(),ThisArgTypePrefix))){ + ShowError(CurLine,"Invalid or unknown argument type for argument "+IntToStr(CurArg)+" (should be a "+ArgTypeName[(int)ThisCommand.argTypes[CurArg]]+")."); + } + else{ + if (UseTypeChecking)ArgTextPos+=strlen(ThisArgTypePrefix); + else + while (ArgTextPos < ArgTextLength && !(LowerCaseArgText[ArgTextPos] >= 'a' && LowerCaseArgText[ArgTextPos] <= 'z' )) ArgTextPos++; + ArgValue=ReadArgValue(); + if(ArgValue<0||ArgValue>255) + ShowError(CurLine,"Invalid or missing value for argument "+IntToStr(CurArg)+" (must be 0-255)"); + else + WriteByte(ArgValue); + } + }//normal argument + if (CurArg < ThisCommand.NumArgs-1){ + if (ArgTextPos < ArgTextLength) + ShowError(CurLine,"',' expected after argument "+IntToStr(CurArg)+"."); + else if(LinePos >= LineLength || LowerCaseLine[LinePos] != ',') + ShowError(CurLine,"',' expected after argument "+IntToStr(CurArg)+"."); + else + LinePos++; + } + else if (ArgTextPos < ArgTextLength){ + ShowError(CurLine,"(1) ')' expected after argument "+IntToStr(CurArg)+"."); + printf("Line %s argtextpos=%d arglen=%d\n",LowerCaseLine.c_str(),(int)ArgTextPos,(int)ArgTextLength); + } + } + SkipSpaces(); + if (LinePos >= LineLength || LowerCaseLine[LinePos] != ')'){ + + if (ThisCommand.NumArgs > 0){ + ShowError(CurLine,"(2) ')' expected after argument "+IntToStr(ThisCommand.NumArgs)+"."); + printf("Line %s argtextpos=%d arglen=%d\n",LowerCaseLine.c_str(),(int)ArgTextPos,(int)ArgTextLength); + } + else + ShowError(CurLine,"')' expected."); + } + else + LinePos++; + } + +} +//*************************************************** +string Logic::ReadText() +{ + int p = LinePos; + string::size_type pos = LowerCaseLine.find_first_of("( ,):",LinePos); + if(pos == string::npos){ + LinePos = LineLength; + return LowerCaseLine.substr(p); + } + else{ + LinePos = pos; + return LowerCaseLine.substr(p,pos-p); + } + +} +//*************************************************** +string Logic::ReadPlainText() +{ + int p = LinePos; + string::size_type pos = LowerCaseLine.find_first_not_of("qwertyuiopasdfghjklzxcvbnm1234567890._",LinePos); + + if(pos == string::npos){ + LinePos = LineLength; + return LowerCaseLine.substr(p); + } + else{ + LinePos = pos; + return LowerCaseLine.substr(p,pos-p); + } + +} +//*************************************************** +string Logic::ReadExprText() +{ + int p = LinePos; + string::size_type pos = LowerCaseLine.find_first_not_of("=+-*/>255) + ShowError(CurLine,"Invalid number given or error in expression syntax."); + else{ + SkipSpaces(); + expr = ReadExprText(); + SkipSpaces(); + ArgText = ReplaceDefine(ReadPlainText()); + arg2isvar = (ArgText[0]=='v'); + if(arg2isvar) + arg2=Val(ArgText.substr(1)); + else + arg2=Val(ArgText); + if(arg2<0||arg2>255) + ShowError(CurLine,"Invalid number given or error in expression syntax."); + else{ + CommandNum=0; + AddNOT = false; + if(expr == "==")CommandNum = 0x01; //equal + else if(expr == "<")CommandNum = 0x03; //less + else if(expr == ">")CommandNum = 0x05; //greater + else if(expr == "!="){ CommandNum = 0x01; AddNOT = true; } //!equal + else if(expr == ">="){ CommandNum = 0x03; AddNOT = true; } //!less + else if(expr == "<="){ CommandNum = 0x05; AddNOT = true; } //!greater + else ShowError(CurLine,"Expression syntax error"); + if(CommandNum>0){ + if (arg2isvar)CommandNum++; + if (AddNOT) WriteByte(0xFD); + WriteByte(CommandNum); + WriteByte(arg1); + WriteByte(arg2); + return true; + } + } + } + }//if(ArgText[0]=='v') + else if(ArgText[0]=='f'){ + arg1 = Val(ArgText.substr(1)); + if(arg1<0||arg1>255) + ShowError(CurLine,"Invalid number given or error in expression syntax.."); + else{ + WriteByte(0x07); // isset + WriteByte(arg1); + return true; + } + }//if(ArgText[0]=='f') + else LinePos = OldLinePos; + return false; + + +} +//*************************************************** +bool Logic::AddSpecialSyntax() +{ + int arg1,arg2,arg3; + bool arg2isvar=false,arg3isvar=false,arg2isstar=false; + string ArgText="",expr,expr2; + int OldLinePos; + + OldLinePos = LinePos; + LinePos -= CommandName.length(); + if(CommandName[0]=='*'){ + LinePos++; + ArgText = "*" + ReplaceDefine(ReadPlainText()); + } + else ArgText = ReplaceDefine(ReadPlainText()); + + if(ArgText[0]=='v'){ + + arg1 = Val(ArgText.substr(1)); + if(arg1<0 || arg1>255) + ShowError(CurLine,"Invalid number given or error in expression syntax."); + else{ + SkipSpaces(); + expr = ReadExprText(); + if(expr == "++"){ + WriteByte(0x01); // increment + WriteByte(arg1); + return true; + } + else if (expr == "--"){ + WriteByte(0x02); // decrement + WriteByte(arg1); + return true; + } + else{ + if(expr[0]=='*'){ + expr = expr.substr(1); + LinePos++; + } + SkipSpaces(); + arg2isstar = false; + ArgText = ReadPlainText(); + if(ReadPlainText() == "" && LowerCaseLine[LinePos-ArgText.length()]=='*'){ + LinePos++; + ArgText = "*" + ReplaceDefine(ReadPlainText()); + } + else ArgText = ReplaceDefine(ArgText); + + if(ArgText[0] == 'v' && !arg2isstar)arg2isvar=true; + else if (ArgText.substr(0,2) == "*v" && !arg2isstar) arg2isstar = true; + + if(arg2isvar)arg2 = Val(ArgText.substr(1)); + else if(arg2isstar)arg2 = Val(ArgText.substr(2)); + else arg2 = Val(ArgText); + + if(arg2 <0 || arg2 >255) + ShowError(CurLine,"Invalid number given or error in expression syntax."); + else{ + if(expr == "+=" && !arg2isstar){ + if(arg2isvar)WriteByte(0x06); //addv + else WriteByte(0x05); //addn + WriteByte(arg1); + WriteByte(arg2); + return true; + } + else if(expr == "-=" && !arg2isstar){ + if(arg2isvar)WriteByte(0x08); //subv + else WriteByte(0x07); //subn + WriteByte(arg1); + WriteByte(arg2); + return true; + } + else if(expr == "*=" && !arg2isstar){ + if(arg2isvar)WriteByte(0xa6); //mul.v + else WriteByte(0xa5); //mul.n + WriteByte(arg1); + WriteByte(arg2); + return true; + } + else if(expr == "/=" && !arg2isstar){ + if(arg2isvar)WriteByte(0xa8); //div.v + else WriteByte(0xa7); //div.n + WriteByte(arg1); + WriteByte(arg2); + return true; + } + else if(expr == "="){ + if(LinePos < LineLength && EditLines.at(CurLine)[LinePos] == ';'){ + //must be assignn, assignv or rindirect + if (arg2isvar) WriteByte(0x04); // assignv + else if (arg2isstar) WriteByte(0x0A); // rindirect + else WriteByte(0x03); // assignv + WriteByte(arg1); + WriteByte(arg2); + return true; + } + else if(arg2 != arg1) ShowError(CurLine,"Expression syntax error"); + else{ + SkipSpaces(); + expr2 = ReadExprText(); + SkipSpaces(); + ArgText = ReplaceDefine(ReadPlainText()); + arg3isvar = (ArgText[0]=='v'); + if(arg3isvar)arg3=Val(ArgText.substr(1)); + else arg3 = Val(ArgText); + if(arg3<0 || arg3>255) + ShowError(CurLine,"Invalid number given or error in expression syntax."); + else{ + if (expr2 == "+"){ + if (arg3isvar) WriteByte(0x06); //addv + else WriteByte(0x05); //addn + WriteByte(arg1); + WriteByte(arg3); + return true; + } + else if (expr2 == "-"){ + if (arg3isvar) WriteByte(0x08); //subv + else WriteByte(0x07); //subn + WriteByte(arg1); + WriteByte(arg3); + return true; + } + else if (expr2 == "*"){ + if (arg3isvar) WriteByte(0xa6); //mul.v + else WriteByte(0xa5); //mul.n + WriteByte(arg1); + WriteByte(arg3); + return true; + } + else if (expr2 == "/"){ + if (arg3isvar) WriteByte(0xa8); //div.v + else WriteByte(0xa7); //div.n + WriteByte(arg1); + WriteByte(arg3); + return true; + } + else ShowError(CurLine,"Expression syntax error"); + } + } + }//if(expr == "=") + else ShowError(CurLine,"Expression syntax error"); + } + }//if (expr != "--" && expr != "++") + }//if(arg1<0 || arg1>255) + }//if(ArgText[0]=='v') + else if(ArgText.substr(0,2)=="*v"){ + LinePos -= (CommandName.length() -1); + ArgText = ReplaceDefine(ReadPlainText()); + arg1 = Val(ArgText.substr(1)); + if(arg1<0 || arg1>255) + ShowError(CurLine,"Invalid number given or error in expression syntax."); + else{ + SkipSpaces(); + expr = ReadExprText(); + if(expr != "=")ShowError(CurLine,"Expression syntax error"); + else{ + SkipSpaces(); + ArgText = ReplaceDefine(ReadPlainText()); + arg2isvar = (ArgText[0]=='v'); + if(arg2isvar)arg2 = Val(ArgText.substr(1)); + else arg2 = Val(ArgText); + if(arg2 < 0 || arg2 > 255) ShowError(CurLine,"Invalid number given or error in expression syntax."); + else{ + if(arg2isvar)WriteByte(0x09); //lindirectv + else WriteByte(0x0b); //lindirectn + WriteByte(arg1); + WriteByte(arg2); + return true; + } + } + } + }//if(ArgText.substr(0,2)=="*v") + else LinePos = OldLinePos; + return false; +} +//*************************************************** +int Logic::LabelNum(string LabelName) +{ + + for(int i=1;i<=NumLabels;i++){ + if(Labels[i].Name == LabelName)return i; + } + return 0; + +} +//*************************************************** +bool Logic::LabelAtStartOfLine(string LabelName) +{ + string::size_type pos = LinePos - LabelName.length()-1; + if(LowerCaseLine.find_first_not_of(" ")=0;CurMessage--){ + if(MessageExists[CurMessage])break; + } + NumMessages = CurMessage; + WriteByte(NumMessages); + ResPos = MessageSectionStart + 3 + NumMessages*2; + EncryptionStart = ResPos; + for (CurMessage = 1;CurMessage<=NumMessages;CurMessage++){ + if(!MessageExists[CurMessage]){ + MessageLoc[CurMessage]=0; + continue; + } + ThisMessageLength = Messages[CurMessage].length(); + MessageLoc[CurMessage] = ResPos - MessageSectionStart - 1; + for(int i=0;i>8)&0xff,BlockStartDataLoc[BlockDepth]+1); + BlockDepth--; + SkipSpaces(); + if (LinePos >= LineLength && CurLine < EditLines.num-1)NextLine(); + if(LowerCaseLine.substr(LinePos,4) == "else"){ + LinePos+=4; + SkipSpaces(); + if(! BlockIsIf[BlockDepth+1]) + ShowError(CurLine,"'else' not allowed after command blocks that start with 'else'."); + + else if(LinePos >= LineLength || LowerCaseLine[LinePos] != '{') + ShowError(CurLine,"'{' expected after else."); + + else{ + LinePos++; + BlockDepth++; + BlockLength[BlockDepth] +=3; + WriteByteAtLoc(BlockLength[BlockDepth]&0xff,BlockStartDataLoc[BlockDepth]); + WriteByteAtLoc((BlockLength[BlockDepth]>>8)&0xff,BlockStartDataLoc[BlockDepth]+1); + BlockIsIf[BlockDepth] = true; + WriteByte(0xfe); + BlockStartDataLoc[BlockDepth] = ResPos; + WriteByte(0x00); // block length filled in later. + WriteByte(0x00); + } + }//if(LowerCaseLine.substr(LinePos,4) == "else" + }//if BlockDepth > 0 + }//if LowerCaseLine[LinePos] == '}' + else{ + ReadCommandName(); + if(CommandName == "if"){ + WriteByte(0xFF); + InIf = true; + SkipSpaces(); + if(LinePos >= LineLength || EditLines.at(CurLine)[LinePos] != '(') + ShowError(CurLine,"'(' expected at start of if statement."); + + LinePos++; + InIfBrackets = false; + NumCommandsInIfStatement = 0; + AwaitingNextTestCommand = true; + } + else if(CommandName == "else") + ShowError(CurLine,"'}' required before 'else'."); + + else if(CommandName == "goto"){ + if(LinePos >= LineLength || LowerCaseLine[LinePos] != '(') + ShowError(CurLine,"'(' expected."); + else{ + LinePos++; + ReadCommandName(); + CommandName = ReplaceDefine(CommandName); + if (LabelNum(CommandName) == 0) + ShowError(CurLine,"Unknown label "+CommandName+"."); + else if (NumGotos >= MaxGotos) + ShowError(CurLine,"Too many labels (max "+IntToStr(MaxLabels)+")."); + else{ + NumGotos++; + Gotos[NumGotos].LabelNum = LabelNum(CommandName); + WriteByte(0xFE); + Gotos[NumGotos].DataLoc = ResPos; + WriteByte(0x00); + WriteByte(0x00); + if(LinePos >= LineLength || LowerCaseLine[LinePos] != ')') + ShowError(CurLine,"')' expected after label name."); + + LinePos++; + if(LinePos >= LineLength || LowerCaseLine[LinePos] != ';') + ShowError(CurLine,"';' expected after goto command."); + LinePos++; + } + } + } + else{ + CommandNum = FindCommandNum(false,CommandName); + EncounteredLabel = (LabelNum(CommandName) > 0); + if (EncounteredLabel && LinePos < LineLength && LowerCaseLine[LinePos] == ':') + LinePos++; + else EncounteredLabel = false; + EncounteredLabel = (EncounteredLabel && LabelAtStartOfLine(CommandName)); + if(EncounteredLabel){ + Labels[LabelNum(CommandName)].Loc = ResPos; + } + else{ + if (CommandNum == 255){ // not found + if (!AddSpecialSyntax()) + ShowError(CurLine,"Unknown action command "+EditLines.at(CurLine).substr(CommandNameStartPos,CommandName.length())+"."); + } + else{ + WriteByte(CommandNum); + ReadArgs(false,CommandNum); + if (CommandNum == 0)LastCommandWasReturn = true; + } + if (LinePos >= LineLength || EditLines.at(CurLine)[LinePos] != ';') ShowError(CurLine,"';' expected after command."); + + LinePos++; + }//if we found a label + }//command + }//if LowerCaseLine[LinePos] != '}' + }//(!InIf) + if(InIf){ + LastCommandWasReturn = false; + if (AwaitingNextTestCommand){ + if (LowerCaseLine[LinePos] == '('){ + if (InIfBrackets)ShowError(CurLine,"Brackets too deep in if statement."); + InIfBrackets = true; + WriteByte(0xFC); + NumCommandsInIfBrackets = 0; + LinePos++; + }// if LowerCaseLine[LinePos] = '(' + else if (LowerCaseLine[LinePos] == ')'){ + if (NumCommandsInIfStatement == 0) + ShowError(CurLine,"If statement must contain at least one command."); + else if(InIfBrackets && (NumCommandsInIfBrackets==0)) + ShowError(CurLine,"Brackets must contain at least one command."); + else ShowError(CurLine,"Expected statement but found closing bracket."); + LinePos++; + } + else{ + NOTOn = false; + if (LowerCaseLine[LinePos] == '!'){ + NOTOn = true; + LinePos++; + } + SkipSpaces(); + ReadCommandName(); + CommandNum = FindCommandNum(true,CommandName); + if (NOTOn) WriteByte(0xFD); + if (CommandNum == 255){ // not found + if (!AddSpecialIFSyntax())ShowError(CurLine,"Unknown test command "+EditLines.at(CurLine).substr(CommandNameStartPos,CommandName.length())+"."); + } + else{ + WriteByte(CommandNum); + ReadArgs(true,CommandNum); + } + NumCommandsInIfStatement++; + if (InIfBrackets) NumCommandsInIfBrackets++; + AwaitingNextTestCommand = false; + } + } // if AwaitingNextTestCommand + else if(LinePos < LineLength){ + if(LowerCaseLine[LinePos] == ')'){ + LinePos++; + if(InIfBrackets){ + if (NumCommandsInIfBrackets == 0) + ShowError(CurLine,"Brackets must contain at least one command."); + else InIfBrackets = false; + WriteByte(0xFC); + } + else{ + if (NumCommandsInIfStatement == 0) + ShowError(CurLine,"If statement must contain at least one command."); + else{ + SkipSpaces(); + if (LinePos > LineLength || EditLines.at(CurLine)[LinePos] != '{') + ShowError(CurLine,"'{' expected after if statement."); + LinePos++; + WriteByte(0xFF); + if (BlockDepth > MaxBlockDepth) + ShowError(CurLine,"Too many nested blocks (max "+IntToStr(MaxBlockDepth)+")."); + else{ + BlockDepth++; + BlockStartDataLoc[BlockDepth] = ResPos; + BlockIsIf[BlockDepth] = true; + WriteByte(0x00); // block length filled in later. + WriteByte(0x00); + } + InIf = false; + } + } + } // else if LowerCaseLine[LinePos] == ')' + else if (LowerCaseLine[LinePos] == '!'){ + ShowError(CurLine,"'!' can only be placed directly in front of a command."); + LinePos++; + } + else if(LowerCaseLine.substr(LinePos,2) == "&&"){ + if (InIfBrackets)ShowError(CurLine,"'&&' not allowed within brackets."); + AwaitingNextTestCommand = true; + LinePos+=2; + } + else if(LowerCaseLine.substr(LinePos,2) == "||"){ + if (!InIfBrackets) + ShowError(CurLine,"Commands to be ORred together must be placed within brackets."); + AwaitingNextTestCommand = true; + LinePos+=2; + } + else{ + if (InIfBrackets) + ShowError(CurLine,"Expected '||' or end of if statement."); + else + ShowError(CurLine,"Expected '&&' or end of if statement."); + } + }// if (not AwaitingNextTestCommand) and (LinePos < LineLength) + }//if InIf + SkipSpaces(); + if (ErrorOccured)FinishedReading = true; + else if (LinePos >= LineLength)NextLine(); + }while(!FinishedReading); + if (!LastCommandWasReturn)ShowError(CurLine,"return command expected."); + if(InIf){ + if (AwaitingNextTestCommand){ + if (NumCommandsInIfStatement == 0)ShowError(CurLine,"Expected test command."); + else ShowError(CurLine,"Expected another test command or end of if statement."); + } + else{ + if(InIfBrackets)ShowError(CurLine,"Expected '||' or end of if statement."); + else ShowError(CurLine,"Expected '&&' or end of if statement."); + } + } + else if (BlockDepth > 0){ + ShowError(CurLine,"'}' expected."); + } + for( CurGoto =1;CurGoto<=NumGotos;CurGoto++){ + GotoData = Labels[Gotos[CurGoto].LabelNum].Loc - Gotos[CurGoto].DataLoc - 2; + WriteByteAtLoc((GotoData&0xff),Gotos[CurGoto].DataLoc); + WriteByteAtLoc((GotoData>>8)&0xff,Gotos[CurGoto].DataLoc+1); + } + + return err; +} +//*************************************************** +int Logic::compile() +{ + int ret,i,j; + + sprintf(tmp,"%s/words.tok",game->dir.c_str()); + ret = wordlist->read(tmp); + if(ret)return 1; + + sprintf(tmp,"%s/object",game->dir.c_str()); + ret = objlist->read(tmp,false); + if(ret)return 1; + + objlist->ItemNames.toLower(); + // words already in lower case in file so we don't need to convert them + for(i=0;iItemNames.num;i++){ + if(objlist->ItemNames.at(i).find_first_of("\"")==string::npos)continue; + //replace " with \" + char *ptr=(char *)objlist->ItemNames.at(i).c_str(); + for(j=0;*ptr;ptr++){ + if(*ptr=='"'){ + tmp[j++]='\\'; + tmp[j++]='"'; + } + else tmp[j++]=*ptr; + } + tmp[j]=0; + objlist->ItemNames.replace(i,tmp); + } + + ResourceData.Size = MaxResourceSize; + LogicSize = 0; + ResPos = 2; + ErrorOccured = false; + NumDefines = 0; + ErrorList=""; + + if(RemoveComments(InputLines))return 1; + if(AddIncludes())return 1; + if(ReadDefines())return 1; + if(ReadPredefinedMessages())return 1; + if(ReadLabels())return 1; + if(CompileCommands())return 1; + + WriteMessageSection(); + + EditLines.lfree(); + + if(ErrorOccured)return 1; + // printf("\n************* SUCCESS !!! ***********\n"); + ResourceData.Size = LogicSize; + return 0; + +} diff --git a/src/logdecode.cpp b/src/logdecode.cpp new file mode 100644 index 0000000..7cedc44 --- /dev/null +++ b/src/logdecode.cpp @@ -0,0 +1,685 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * Almost all of this code was adapted from the Windows AGI Studio + * developed by Peter Kelly. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "game.h" +#include "logedit.h" +#include "words.h" +#include "object.h" +#include "menu.h" +#include "agicommands.h" + +#include +#include + +static int EncryptionStart; +static int MessageSectionStart,MessageSectionEnd; +static bool MessageUsed[256],MessageExists[256]; +static int ResPos; +static byte CurByte; +static int NumMessages; + +static string Messages[MaxMessages]; + +static byte ThisCommand; +bool ShowArgTypes = true; +bool ShowNonExistingValues = true; // Uses the number of an object, word or message instead of the text if it does not exist +byte SpecialSyntaxType = 1; // 0 for v30 = v30 + 4;, 1 for v30 += 4; + +static byte BlockDepth; +static short BlockEnd[MaxBlockDepth+1]; +static short BlockLength[MaxBlockDepth+1]; +static bool BlockIsIf[MaxBlockDepth+1]; +static short TempBlockLength,CurBlock; +static byte CurArg; +static unsigned int ArgsStart; + +static TResource LabelIndex; +static int LabelLoc,NumLabels; +static bool DoGoto; +static string ThisLine; + +static bool ErrorOccured; + +static bool FirstCommand, OROn , NOTOn; +static byte NumSaidArgs; + +static byte IndentPos; +//*************************************************** +static byte ReadByte(void) +{ + if(ResPos < ResourceData.Size){ + return ResourceData.Data[ResPos++]; + } + return 0; +} +//*************************************************** +static short ReadLSMSWord(void) +{ + byte MSbyte,LSbyte; + + LSbyte = ReadByte(); + MSbyte = ReadByte(); + + return ((MSbyte<<8)|LSbyte); + +} +//*************************************************** +static byte ReadEncByte(void) +{ + return (ReadByte() ^ EncryptionKey[(ResPos-EncryptionStart+10)%11]) ; + +} +//*************************************************** +void Logic::ReadMessages(void) +{ + + int MessageStart[256]; + string ThisMessage; + int i; + + // NOTE: There is no message 0 (this is not supported by the file format). + + for(i=0;i 0){ + MessageSectionEnd = ReadLSMSWord() + MessageSectionStart; + for (i = 1;i <= NumMessages;i++){ + MessageStart[i] = ReadLSMSWord(); + } + EncryptionStart = ResPos; + for (i = 1;i <= NumMessages;i++){ + if (MessageStart[i] > 0){ + ThisMessage = ""; + ResPos = MessageSectionStart + MessageStart[i] + 1; + do{ + CurByte = ReadEncByte(); + if (CurByte == 0 || ResPos >= ResourceData.Size)break; + if(CurByte == 0x0a)ThisMessage += "\\n"; + else if (CurByte == 0x22)ThisMessage += "\\\""; + else if (CurByte == 0x5c)ThisMessage += "\\\\"; + else ThisMessage += CurByte; + }while(true); + Messages[i]=ThisMessage; + MessageExists[i] = true; + } + } + } + +} +//*************************************************** +void Logic::DisplayMessages(void) +{ + int i; + + if(game->show_all_messages){ + OutputText.append("// Messages\n"); + for(i=1;i<=255;i++){ + if (MessageExists[i]){ + OutputText.append("#message " + IntToStr(i) + " \""+Messages[i]+"\"\n"); + } + } + } + else{ //(only those not used elsewhere in the logic are here) + OutputText.append("// Messages\n"); + for(i=1;i<=255;i++){ + if (MessageExists[i] && !MessageUsed[i]){ + OutputText.append("#message " + IntToStr(i)+" \""+Messages[i]+"\"\n"); + } + } + } + +} +//*************************************************** +int Logic::FindLabels_ReadIfs(void) +{ + byte NumSaidArgs; + + do{ + CurByte = ReadByte(); + if(CurByte == 0xFC)CurByte = ReadByte(); + if(CurByte == 0xFC)CurByte = ReadByte(); // we may have 2 0xFCs in a row, e.g. (a || b) && (c || d) + if(CurByte == 0xFD)CurByte = ReadByte(); + + if (CurByte > 0 && CurByte <= NumTestCommands){ + ThisCommand = CurByte; + if (ThisCommand == 14){ // said command + NumSaidArgs = ReadByte(); + ResPos += NumSaidArgs*2; + } + else{ + ResPos += TestCommand[ThisCommand].NumArgs; + } + } + else if(CurByte == 0xFF){ + if (BlockDepth >= MaxBlockDepth - 1){ + sprintf(tmp,"Too many nested blocks (%d)\n",BlockDepth); + ErrorList.append(tmp); + ErrorOccured=true; + break; + } + BlockDepth++; + BlockIsIf[BlockDepth] = true; + BlockLength[BlockDepth] = ReadLSMSWord(); + BlockEnd[BlockDepth] = BlockLength[BlockDepth] + ResPos; + if (BlockEnd[BlockDepth] > BlockEnd[BlockDepth-1]){ + sprintf(tmp,"Block too long (%d bytes longer than rest of previous block)",BlockEnd[BlockDepth]-BlockEnd[BlockDepth-1]); + ErrorOccured=true; + ErrorList.append(string(tmp)+"\n"); + } + break; + } + else{ + sprintf(tmp,"Unknown test command (%d)",CurByte); + break; + } + }while(true); + + return 0; +} +//*************************************************** +void Logic::AddBlockEnds(void) +{ + for(int CurBlock = BlockDepth;CurBlock>=1;CurBlock--){ + if (BlockEnd[CurBlock] <= ResPos){ + OutputText.append(MultStr(" ",CurBlock-1)+"}\n"); + BlockDepth--; + } + } +} +//*************************************************** +int Logic::FindLabels(void) +{ + + LabelIndex.Size = ResourceData.Size; + LabelIndex.Data = (byte *)calloc(LabelIndex.Size,1); + BlockDepth = 0; + NumLabels = 0; + do{ + for( CurBlock = BlockDepth;CurBlock>=1;CurBlock--){ + if (BlockEnd[CurBlock] <= ResPos)BlockDepth--; + } + CurByte = ReadByte(); + + if (CurByte == 0xFF)FindLabels_ReadIfs(); + else if(CurByte <= NumAGICommands){ + ResPos += AGICommand[CurByte].NumArgs; + } + else if(CurByte == 0xFE){ + DoGoto = false; + TempBlockLength = ReadLSMSWord(); + if ((BlockEnd[BlockDepth] == ResPos) && (BlockIsIf[BlockDepth]) && (BlockDepth > 0) && (!game->show_elses_as_gotos)){ + BlockIsIf[BlockDepth] = false; + if (TempBlockLength + ResPos > BlockEnd[BlockDepth-1] || (TempBlockLength & 0x8000) || BlockLength[BlockDepth] <= 3){ + DoGoto = true; + } + else{ + BlockLength[BlockDepth] = TempBlockLength; + BlockEnd[BlockDepth] = BlockLength[BlockDepth] + ResPos; + } + } + else{ + DoGoto = true; + } + //goto + if (DoGoto){ + LabelLoc = TempBlockLength + ResPos; + if (LabelLoc > LabelIndex.Size - 1){ + sprintf(tmp,"Label past end of logic (%x %x)\n ",LabelLoc,LabelIndex.Size); + ErrorList.append(tmp); + ErrorOccured=true; + break; + } + if (LabelIndex.Data[LabelLoc] == 0){ + NumLabels++; + LabelIndex.Data[LabelLoc] = NumLabels; + } + } + } + else{ + sprintf(tmp,"Unknown command (%d)",CurByte); + break; + } + }while(ResPos < MessageSectionStart); + + return 0; +} +//*************************************************** +void Logic::AddArg(byte Arg, byte ArgType) +{ + int NumCharsToDisplay; + string ThisMessage; + if(ShowArgTypes){ + switch(ArgType){ + case atMsg: + if (MessageExists[Arg]){ + string ThisMessage = Messages[Arg]; + do{ + if(ThisMessage.length() + ThisLine.length() > maxcol){ + NumCharsToDisplay = maxcol - ThisLine.length(); + do{ + NumCharsToDisplay--; + }while(!(NumCharsToDisplay <= 0 || ThisMessage[NumCharsToDisplay]==' ')); + if (NumCharsToDisplay <= 0) + NumCharsToDisplay = maxcol-ThisLine.length(); + if (NumCharsToDisplay <= 0) + NumCharsToDisplay = ThisMessage.length(); + ThisLine += "\"" + ThisMessage.substr(0,NumCharsToDisplay) + "\""; + if(NumCharsToDisplay < (int)ThisMessage.length()){ + ThisMessage = ThisMessage.substr(NumCharsToDisplay+1); + OutputText.append(ThisLine+"\n"); + } + else{ + ThisMessage = ""; + OutputText.append(ThisLine); + } + if (ArgsStart >= maxcol - 20)ArgsStart = maxcol - 20; + ThisLine = MultStr(" ",ArgsStart); + } + else{ + ThisLine += "\"" + ThisMessage + "\"" ; + ThisMessage = ""; + } + }while(ThisMessage.length()>0); + } + else if(ShowNonExistingValues){ + ThisLine += ArgTypePrefix[atMsg] + IntToStr(Arg); + } + else{ + sprintf(tmp,"Unknown message (%d)\n",Arg); + ErrorList.append(tmp); + ErrorOccured=true; + } + MessageUsed[Arg] = true; + break; + case atIObj: + if (Arg <= objlist->ItemNames.num - 1){ + ThisLine += "\"" + objlist->ItemNames.at(Arg) + "\""; + } + else if(ShowNonExistingValues){ + ThisLine += ArgTypePrefix[atIObj] + IntToStr(Arg); + } + else{ + sprintf(tmp,"Unknown inventory item (%d)\n",Arg); + ErrorList.append(tmp); + ErrorOccured=true; + } + break; + default: + if(ArgType != 0){ + ThisLine += ArgTypePrefix[ArgType] + IntToStr(Arg); + } + else{ + ThisLine += IntToStr(Arg); + } + break; + } + } + else{ + ThisLine += IntToStr(Arg); + } + +} +//*************************************************** +void Logic::AddSpecialSyntaxCommand(void) +{ + int arg1; + + arg1 = ReadByte(); + switch(ThisCommand){ + // increment + case 0x01: ThisLine += "v"+IntToStr(arg1)+"++"; break; + // decrement + case 0x02: ThisLine += "v"+IntToStr(arg1)+"--"; break; + // assignn + case 0x03: ThisLine += "v"+IntToStr(arg1)+" = "+IntToStr(ReadByte()); break; + // assignv + case 0x04: ThisLine += "v"+IntToStr(arg1)+" = v"+IntToStr(ReadByte()); break; + // addn + case 0x05: if (SpecialSyntaxType == 0) + ThisLine += "v"+IntToStr(arg1)+" = v"+IntToStr(arg1)+" + "+IntToStr(ReadByte()); + else ThisLine += "v"+IntToStr(arg1)+" += "+IntToStr(ReadByte()); break; + // addv + case 0x06: if (SpecialSyntaxType == 0) + ThisLine += "v"+IntToStr(arg1)+" = v"+IntToStr(arg1)+" + v"+IntToStr(ReadByte()); + else ThisLine += "v"+IntToStr(arg1)+" += v"+IntToStr(ReadByte()); break; + // subn + case 0x07: if (SpecialSyntaxType == 0) + ThisLine += "v"+IntToStr(arg1)+" = v"+IntToStr(arg1)+" - "+IntToStr(ReadByte()); + else ThisLine += "v"+IntToStr(arg1)+" -= "+IntToStr(ReadByte()); break; + // subv + case 0x08: if (SpecialSyntaxType == 0) + ThisLine += "v"+IntToStr(arg1)+" = v"+IntToStr(arg1)+" - v"+IntToStr(ReadByte()); + else ThisLine += "v"+IntToStr(arg1)+" -= v"+IntToStr(ReadByte()); break; + // lindirectv + case 0x09: ThisLine += "*v"+IntToStr(arg1)+" = v"+IntToStr(ReadByte()); break; + // rindirect + case 0x0A: ThisLine += "v"+IntToStr(arg1)+" = *v"+IntToStr(ReadByte()); break; + // lindirectn + case 0x0B: ThisLine += "*v"+IntToStr(arg1)+" = "+IntToStr(ReadByte()); break; + // mul.n + case 0xA5: if (SpecialSyntaxType == 0) + ThisLine += "v"+IntToStr(arg1)+" = v"+IntToStr(arg1)+" * "+IntToStr(ReadByte()); + else ThisLine += "v"+IntToStr(arg1)+" *= "+IntToStr(ReadByte()); break; + // mul.v + case 0xA6: if (SpecialSyntaxType == 0) + ThisLine += "v"+IntToStr(arg1)+" = v"+IntToStr(arg1)+" * v"+IntToStr(ReadByte()); + else ThisLine += "v"+IntToStr(arg1)+" *= v"+IntToStr(ReadByte()); break; + // div.n + case 0xA7: if (SpecialSyntaxType == 0) + ThisLine += "v"+IntToStr(arg1)+" = v"+IntToStr(arg1)+" / "+IntToStr(ReadByte()); + else ThisLine += "v"+IntToStr(arg1)+" /= "+IntToStr(ReadByte()); break; + // div.v + case 0xA8: if (SpecialSyntaxType == 0) + ThisLine += "v"+IntToStr(arg1)+" = v"+IntToStr(arg1)+" / v"+IntToStr(ReadByte()); + else ThisLine += "v"+IntToStr(arg1)+" /= v"+IntToStr(ReadByte()); break; + } + +} +//*************************************************** +void Logic::AddSpecialIFSyntaxCommand(void) +{ + + switch(ThisCommand){ + case 1: // equaln + ThisLine += 'v' + IntToStr(ReadByte()); + if (NOTOn) ThisLine += " != "; + else ThisLine += " == "; + ThisLine += IntToStr(ReadByte()); + break; + case 2: // equalv + ThisLine += 'v' + IntToStr(ReadByte()); + if (NOTOn) ThisLine += " != v"; + else ThisLine += " == v"; + ThisLine += IntToStr(ReadByte()); + break; + case 3: // lessn + ThisLine += 'v' + IntToStr(ReadByte()); + if (NOTOn) ThisLine += " >= "; + else ThisLine += " < "; + ThisLine += IntToStr(ReadByte()); + break; + case 4: // lessv + ThisLine += 'v' + IntToStr(ReadByte()); + if (NOTOn) ThisLine += " >= v"; + else ThisLine += " < v"; + ThisLine += IntToStr(ReadByte()); + break; + case 5: // greatern + ThisLine += 'v' + IntToStr(ReadByte()); + if (NOTOn) ThisLine += " <= "; + else ThisLine += " > "; + ThisLine += IntToStr(ReadByte()); + break; + case 6: // greaterv + ThisLine += 'v' + IntToStr(ReadByte()); + if (NOTOn) ThisLine += " <= v"; + else ThisLine += " > v"; + ThisLine += IntToStr(ReadByte()); + break; + } + +} +//*************************************************** +void Logic::ReadIfs(void) +{ + int ThisWordGroupIndex, ThisWordGroupNum; + + FirstCommand = true; + OROn = false; + ThisLine = MultStr(" ",BlockDepth)+"if ("; + do{ + NOTOn = false; + CurByte = ReadByte(); + if (CurByte == 0xFC){ + OROn = !OROn; + if (OROn){ + if (!FirstCommand){ + ThisLine += " &&"; + OutputText.append(ThisLine+"\n"); + ThisLine = MultStr(" ",BlockDepth)+" "; + FirstCommand = true; + } + ThisLine += '('; + } + else ThisLine += ')'; + CurByte = ReadByte(); + } + if(CurByte == 0xFC && !OROn){ // we may have 2 0xFCs in a row, e.g. (a || b) && (c || d) + ThisLine += " &&"; + OutputText.append(ThisLine+"\n"); + ThisLine = MultStr(" ",BlockDepth)+" "; + FirstCommand = true; + ThisLine += "("; + OROn = true; + CurByte = ReadByte(); + } + if (CurByte == 0xFD){ // NOT + NOTOn = true; + CurByte = ReadByte(); + } + if (CurByte > 0 && CurByte <= NumTestCommands){ + if(!FirstCommand){ + if (OROn) ThisLine += " ||"; + else ThisLine += " &&"; + OutputText.append(ThisLine+"\n"); + ThisLine = MultStr(" ",BlockDepth)+" "; + } + ThisCommand = CurByte; + if (game->show_special_syntax && ThisCommand >=1 && ThisCommand <=6) + AddSpecialIFSyntaxCommand(); + else{ + if (NOTOn) ThisLine += '!'; + ThisLine += string(TestCommand[ThisCommand].Name) + '('; + ArgsStart = ThisLine.length(); + if (ThisCommand == 14){ // said command + NumSaidArgs = ReadByte(); + for (CurArg = 1;CurArg<=NumSaidArgs; CurArg++){ + ThisWordGroupNum = ReadLSMSWord(); + ThisWordGroupIndex = wordlist->GetWordGroupIndex(ThisWordGroupNum); + if (ThisWordGroupIndex < 0){ + if (ShowNonExistingValues){ + ThisLine += IntToStr(ThisWordGroupNum); + } + else{ + sprintf(tmp,"Unknown word group (%d)\n",ThisWordGroupNum); + ErrorList.append(tmp); + ErrorOccured=true; + break; + } + } + else{ + ThisLine += '"' + string(wordlist->WordGroup[ThisWordGroupIndex].Words.at(0)) + '"'; + if (CurArg < NumSaidArgs)ThisLine += ','; + } + } + } + else{ + for (CurArg = 0; CurArg < TestCommand[ThisCommand].NumArgs; CurArg++){ + CurByte = ReadByte(); + AddArg(CurByte,TestCommand[ThisCommand].argTypes[CurArg]); + if (CurArg < TestCommand[ThisCommand].NumArgs-1)ThisLine += ','; + } + } // if ThisCommand != 14 + ThisLine += ')'; + } + FirstCommand = false; + }//if (CurByte > 0) && (CurByte <= NumTestCommands) + else if (CurByte == 0xff){ + ThisLine += ") {"; + if (BlockDepth >= MaxBlockDepth - 1){ + sprintf(tmp,"Too many nested blocks (%d)\n",BlockDepth); + ErrorList.append(tmp); + ErrorOccured=true; + break; + } + else{ + BlockDepth++; + BlockIsIf[BlockDepth] = true; + BlockLength[BlockDepth] = ReadLSMSWord(); + BlockEnd[BlockDepth] = BlockLength[BlockDepth] + ResPos; + if (BlockEnd[BlockDepth] > BlockEnd[BlockDepth-1]){ + sprintf(tmp,"Block too long (%d bytes longer than rest of previous block)\n",BlockEnd[BlockDepth]-BlockEnd[BlockDepth-1]); + ErrorList.append(tmp); + ErrorOccured=true; + break; + } + } + OutputText.append(ThisLine+"\n"); + ThisLine = MultStr(" ",BlockDepth); + break; + }// if CurByte = 0xFF + else{ + sprintf(tmp,"Unknown test command (%d)\n",CurByte); + ErrorList.append(tmp); + ErrorOccured=true; + break; + } + }while(!ErrorOccured); +} +//*************************************************** +int Logic::decode(int ResNum) +{ + int ret=0,i,j; + + OutputText = ""; + sprintf(tmp,"%s/words.tok",game->dir.c_str()); + ret = wordlist->read(tmp); + if(ret)return 1; + + sprintf(tmp,"%s/object",game->dir.c_str()); + ret = objlist->read(tmp,false); + if(ret)return 1; + objlist->ItemNames.toLower(); + // words already in lower case in file so we don't need to convert them + for(i=0;iItemNames.num;i++){ + if(objlist->ItemNames.at(i).find_first_of("\"")==string::npos)continue; + //replace " with \" + char *ptr=(char *)objlist->ItemNames.at(i).c_str(); + for(j=0;*ptr;ptr++){ + if(*ptr=='"'){ + tmp[j++]='\\'; + tmp[j++]='"'; + } + else tmp[j++]=*ptr; + } + tmp[j]=0; + objlist->ItemNames.replace(i,tmp); + } + + ret = game->ReadResource(LOGIC,ResNum); + if(ret)return 1; + + ErrorList=""; + ResPos = 0; + MessageSectionStart = ReadLSMSWord() + 2; + + if (MessageSectionStart > ResourceData.Size - 1){ + sprintf(tmp,"Error: Message section start %x is beyond end of resource\n", + MessageSectionStart); + ErrorList.append(tmp); + return 1; + } + ErrorOccured=false; + ReadMessages(); + ResPos = 2; + BlockEnd[0] = MessageSectionStart; + BlockIsIf[0] = false; + memset(BlockIsIf,0,sizeof(BlockIsIf)); + FindLabels(); + BlockDepth = 0; + ResPos = 2; + do{ + AddBlockEnds(); + if (LabelIndex.Data[ResPos] > 0){ + OutputText.append("Label" + IntToStr(LabelIndex.Data[ResPos]) + ":\n"); + } + CurByte = ReadByte(); + if(CurByte == 0xFF)ReadIfs(); + else if(CurByte <= NumAGICommands){ + ThisCommand = CurByte; + ThisLine = MultStr(" ",BlockDepth); + if (game->show_special_syntax && (ThisCommand>=0x01 && ThisCommand<=0x0B)||(ThisCommand>=0xA5&&ThisCommand<=0xA8))AddSpecialSyntaxCommand(); + else{ + ThisLine+=(string(AGICommand[ThisCommand].Name) + "("); + ArgsStart = ThisLine.length(); + IndentPos = ThisLine.length(); + for(CurArg = 1;CurArg<=AGICommand[ThisCommand].NumArgs;CurArg++){ + CurByte = ReadByte(); + AddArg(CurByte,AGICommand[ThisCommand].argTypes[CurArg-1]); + if(CurArg < AGICommand[ThisCommand].NumArgs)ThisLine+=","; + } + ThisLine+=")"; + } + ThisLine+=";"; + OutputText.append(ThisLine+"\n"); + } + else if(CurByte == 0xfe){ + DoGoto = false; + TempBlockLength = ReadLSMSWord(); + if (BlockEnd[BlockDepth] == ResPos && (BlockIsIf[BlockDepth]) && BlockDepth > 0 && (!game->show_elses_as_gotos)){ + //else + BlockIsIf[BlockDepth] = false; + if (TempBlockLength + ResPos > BlockEnd[BlockDepth-1] || TempBlockLength & 0x8000 || BlockLength[BlockDepth] <= 3){ + DoGoto = true; + } + else{ + OutputText.append(MultStr(" ",BlockDepth-1) + "}\n"); + OutputText.append(MultStr(" ",BlockDepth-1) + "else {\n"); + BlockLength[BlockDepth] = TempBlockLength; + BlockEnd[BlockDepth] = BlockLength[BlockDepth] + ResPos; + } + } + else DoGoto = true; + // goto + if (DoGoto){ + LabelLoc = TempBlockLength + ResPos; + if (LabelLoc > LabelIndex.Size - 1){ + sprintf(tmp,"Label past end of logic (%x %x)\n ",LabelLoc,LabelIndex.Size); + ErrorList.append(tmp); + ErrorOccured=true; + break; + } + else{ + OutputText.append(MultStr(" ",BlockDepth) + "goto(Label"+IntToStr(LabelIndex.Data[LabelLoc])+");\n"); + } + } + } + else{ + sprintf(tmp,"Unknown action command (%d)\n",CurByte); + ErrorList.append(tmp); + ErrorOccured = true; + break; + } + }while(ResPos < MessageSectionStart); + if(!ErrorOccured)AddBlockEnds(); + free(LabelIndex.Data); + OutputText.append("\n"); + DisplayMessages(); + return (ErrorOccured)?1:0; + +} diff --git a/src/logedit.cpp b/src/logedit.cpp new file mode 100644 index 0000000..210d001 --- /dev/null +++ b/src/logedit.cpp @@ -0,0 +1,1436 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "logedit.h" +#include "game.h" +#include "menu.h" +#include "agicommands.h" + +#include +#include +#include +#ifndef _WIN32 +#include +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TStringList InputLines; //temporary buffer for reading the text from editor +//and sending to compilation + +//*********************************************** +// Syntax highlight + +static QString operators ="!-+=<>/*&|^%", + wordchars = "0123456789abcdefghijlkmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ._#"; + +static QColor normal_color = QColor("black"), + comment_color = QColor("#808080"), + string_color = QColor("red"), + number_color = QColor("darkCyan"), + command_color = QColor("darkBlue"), + test_color = QColor("brown"), + operator_color = QColor("blue"); + +class LogicSyntaxHL : public Q3SyntaxHighlighter +{ +public: + + LogicSyntaxHL( Q3TextEdit* te ) + : Q3SyntaxHighlighter( te ) {} + + void highlightWord( const QString& line, int start, int len ) + { + QColor* col = 0; + QString word( line.mid(start, len)); + + // Number? + if ( word.find(QRegExp("[^0-9]")) < 0 ) + col = &number_color; + else + { + // AGI command? + for ( CommandStruct* cmd = AGICommand; + cmd < AGICommand + (sizeof(AGICommand)/sizeof(CommandStruct)); + ++cmd ) + { + if ( word == cmd->Name ) + { + col = &command_color; + break; + } + } + // AGI test command? + for ( CommandStruct* cmd = TestCommand; + cmd < TestCommand + (sizeof(TestCommand)/sizeof(CommandStruct)); + ++cmd ) + { + if ( word == cmd->Name ) + col = &test_color; + } + // Control structure + if ( word[0]=='#' || word == "if" || word == "else" || word == "goto" ) + col = &operator_color; + } + + if ( col ) + setFormat( start, len, *col); + } + + int highlightParagraph ( const QString & text, int endStateOfLastPara ) + { + setFormat( 0, text.length(), normal_color); + + QString txt = text; + + int comment_depth = endStateOfLastPara; + bool in_quotes = (comment_depth==-1); + if ( comment_depth < 0 ) + comment_depth = 0; + + int curchar = 0, lastchar = 0; + while( !txt.isEmpty()) + { + // Get next line & shorten + int eol = txt.find( '\n' ); + if ( eol < 0 ) + eol = txt.length()-1; + QString line = txt.mid(0,eol); + txt = txt.mid(eol+1); + bool in_word = false; + + // Process the line + int i; + for ( i=0; i<(int)line.length(); ++i ) + { + // Single words + if ( in_word && wordchars.find(line[i]) < 0 ) + { + highlightWord( line, lastchar, curchar+i-lastchar ); + in_word = false; + } + + // Comments + if ( !in_quotes ) + { + if (comment_depth==0 && line.mid(i,1) == "[") + { + setFormat( (curchar+i), line.length()-i+1, comment_color); + break; + } + // More than two chars left? + if ( i<(int)line.length()-1 ) + { + if (comment_depth==0 && (line.mid(i,2) == "//" )) + { + setFormat( (curchar+i), line.length()-i+1, comment_color); + break; + } + else if ( line.mid(i,2) == "/*") + { + if ( comment_depth == 0 ) + lastchar = (curchar+i); + ++comment_depth; + ++i; + continue; + } + else if (comment_depth>0 && line.mid(i,2) == "*/" ) + { + --comment_depth; + if ( comment_depth == 0 ) + { + setFormat( lastchar, (curchar+i)-lastchar+2, comment_color); + lastchar = (curchar+i+2); + } + ++i; + continue; + } + } + } + + // Quotes + if ( comment_depth == 0 ) + { + if(line[i]=='\"' && (i==0 || line[i-1] != '\\')) + { + if ( in_quotes ) + setFormat( lastchar, (curchar+i)-lastchar+1, string_color); + lastchar = curchar+i; + in_quotes = !in_quotes; + } + + if ( !in_quotes ) + { + if( !in_word && wordchars.find(line[i]) >= 0 && + (i==0 || wordchars.find(line[i-1]) < 0 )) + { + in_word = true; + lastchar = curchar+i; + } + else if ( operators.find(line[i]) >= 0 ) + setFormat((curchar+i), 1, operator_color); + } + } + } + + // End of line, format word if still open + if ( in_word ) + highlightWord( line, lastchar, line.length()-lastchar ); + + curchar += i; + if ( in_quotes ) + setFormat( lastchar, curchar-lastchar+1, string_color); + } + + // End of paragraph, format comment block if still open + if ( comment_depth > 0 ) + setFormat( lastchar, curchar-lastchar+1, comment_color); + + return (in_quotes ? -1 : comment_depth); + } +}; + +//*********************************************** +LogEdit::LogEdit( QWidget *parent, const char *name, int win_num, ResourcesWin *res, bool readonly) + : QWidget( parent, name, Qt::WDestructiveClose ) + , findedit(NULL) + , roomgen(NULL) +{ + setCaption("Logic editor"); + + logic = new Logic(); + winnum = win_num; //my window number + resources_win = res; //resources window which called me + + editor = new Q3MultiLineEdit(this); + + QFont font("Monospace"); + font.setPointSize(readonly?8:9); + font.setStyleHint( QFont::TypeWriter ); + editor->setFont( font ); + + editor->setSizePolicy( QSizePolicy( + QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding )); + editor->setWordWrap( Q3TextEdit::NoWrap ); + syntax_hl = new LogicSyntaxHL( editor ); + + if ( readonly ) + { + editor->setReadOnly( readonly ); + } + else + { + editor->setMinimumSize(512,600); + setMinimumSize(450,400); + } + + setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding )); + + Q3BoxLayout *all = new Q3VBoxLayout(this,10); + all->addWidget(editor); + + if ( !readonly ) { + Q3PopupMenu *file = new Q3PopupMenu( this ); + Q_CHECK_PTR( file ); + + file->insertItem( "Read from file", this, SLOT(read_logic()) ); + file->insertItem( "Save", this, SLOT(save_logic()), Qt::CTRL + Qt::Key_S ); + file->insertItem( "Save as", this, SLOT(save_as()) ); + file->insertItem( "Compile", this, SLOT(compile_logic()) ,Qt::Key_F9 ); + file->insertItem( "Compile all", this, SLOT(compile_all_logic()) ); + file->insertItem( "Compile all and run", this, SLOT(compile_and_run()) ,Qt::Key_F10 ); + file->insertItem( "Change logic number", this, SLOT(change_logic_number()) ); + file->insertSeparator(); + file->insertItem( "Delete", this, SLOT(delete_logic()) ); + file->insertItem( "New room", this, SLOT(new_room()) ); + file->insertSeparator(); + file->insertItem( "Close", this, SLOT(close()) ); + + Q3PopupMenu *edit = new Q3PopupMenu( this ); + Q_CHECK_PTR( edit ); + edit->insertItem( "Cut", editor, SLOT(cut()) , Qt::CTRL + Qt::Key_X ); + edit->insertItem( "Copy", editor, SLOT(copy()) , Qt::CTRL + Qt::Key_C ); + edit->insertItem( "Paste", editor, SLOT(paste()) , Qt::CTRL + Qt::Key_V); + edit->insertSeparator(); + edit->insertItem( "Clear all", this, SLOT(clear_all()) ); + edit->insertSeparator(); + edit->insertItem( "Find", this, SLOT(find_cb()) ,Qt::CTRL + Qt::Key_F); + edit->insertItem( "Find again", this, SLOT(find_again()) ,Qt::Key_F3); + edit->insertSeparator(); + edit->insertItem( "Go to line", this, SLOT(goto_cb()) ,Qt::ALT + Qt::Key_G); + + Q3PopupMenu *help = new Q3PopupMenu( this ); + Q_CHECK_PTR( help ); + help->insertItem( "Context help", this, SLOT(context_help()), Qt::Key_F1); + help->insertItem( "All commands", this, SLOT(command_help())); + + QMenuBar *menu = new QMenuBar(this); + Q_CHECK_PTR( menu ); + menu->insertItem( "File", file ); + menu->insertItem( "Edit", edit ); + menu->insertItem( "Help", help ); + menu->setSeparator( QMenuBar::InWindowsStyle ); + + all->setMenuBar(menu); + + status = new QStatusBar(this); + QLabel *msg = new QLabel( status, "message" ); + status->addWidget( msg, 4 ); + all->addWidget(status); + + connect( editor, SIGNAL(cursorPositionChanged(int,int)), + this, SLOT(update_line_num(int,int))); + } + + getmaxcol(); + changed=false; + filename=""; + hide(); +} + +//*********************************************** +void LogEdit::deinit() +{ + + if(findedit){ + findedit->close(true); + findedit=NULL; + } + if(roomgen){ + roomgen->close(true); + roomgen=NULL; + } + delete logic; + logic = 0; + delete syntax_hl; + syntax_hl = 0; + + winlist[winnum].type=-1; + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//********************************************* +void LogEdit::hideEvent( QHideEvent * ) +{ + + if(findedit){ + findedit->close(true); + findedit=NULL; + } + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//********************************************* +void LogEdit::showEvent( QShowEvent * ) +{ + + if(window_list && window_list->isVisible())window_list->draw(); + +} +//*********************************************** +void LogEdit::closeEvent( QCloseEvent *e ) +{ + + if(changed){ + QString str = editor->text(); + if(!strcmp(str.latin1(),logic->OutputText.c_str())){ //not changed + deinit(); + e->accept(); + return; + } + + if(LogicNum != -1){ + sprintf(tmp,"Save changes to logic.%d ?",LogicNum); + } + else{ + sprintf(tmp,"Save changes to logic ?"); + } + switch ( QMessageBox::warning( this, "Logic editor", + tmp, + "Yes", + "No", + "Cancel", + 0, 2) ) { + case 0: // yes + save_logic(); + deinit(); + e->accept(); + break; + case 1: // no + deinit(); + e->accept(); + break; + default: // cancel + e->ignore(); + break; + } + + } + else{ + deinit(); + e->accept(); + } + +} + +//*********************************************** +int LogEdit::open() +{ + + getmaxcol(); + LogicNum = -1; + show(); + changed=true; + return 0; +} + +//*********************************************** +int LogEdit::open(char *filenam) +{ + getmaxcol(); + + FILE *fptr = fopen(filenam,"rb"); + if(fptr!=NULL){ + filename = string(filenam); + editor->clear(); + char *ptr; + QString filecont; + while(fgets(tmp,MAX_TMP,fptr)!=NULL){ + if((ptr=(char*)strchr(tmp,0x0a))) *ptr=0; + if((ptr=(char*)strchr(tmp,0x0d))) *ptr=0; + filecont += QString(tmp) + "\n"; + } + editor->setText( filecont ); + fclose(fptr); + logic->OutputText=editor->text().latin1(); + if((ptr=(char*)strrchr(filename.c_str(),'/')))ptr++; + else ptr=(char *)filename.c_str(); + if(LogicNum!=-1) + sprintf(tmp,"logic.%d (file %s)",LogicNum,ptr); + else + sprintf(tmp,"logic (file %s)",ptr); + setCaption(tmp); + show(); + changed=true; + + return 0; + } + else{ + menu->errmes("Can't open file %s !",filenam); + //QMessageBox::critical( this, "Agistudio", + // QString( "Can't open file '" ) + filenam + "'"); + return 1; + } +} + +//*********************************************** +int LogEdit::open(int ResNum) +{ + int err=0; + QString str; + FILE *fptr; + getmaxcol(); + + logic->maxcol=maxcol; + + //look for the source file first + sprintf(tmp,"%s/logic.%03d",game->srcdir.c_str(),ResNum); + fptr = fopen(tmp,"rb"); + if(fptr==NULL){ + sprintf(tmp,"%s/logic.%d",game->srcdir.c_str(),ResNum); + fptr = fopen(tmp,"rb"); + } + if(fptr==NULL){ + sprintf(tmp,"%s/logic%d.txt",game->srcdir.c_str(),ResNum); + fptr = fopen(tmp,"rb"); + } + if(fptr!=NULL){ + LogicNum = ResNum; + err=open(tmp); + } + else{ //source file not found - reading from the game + err=logic->decode(ResNum); + if(!err)editor->setText(logic->OutputText.c_str()); + else { + sprintf(tmp,"logic.%d",ResNum); + menu->errmes(tmp,"Errors:\n%s",logic->ErrorList.c_str()); + } + str.sprintf("logic.%d",ResNum); + setCaption(str); + LogicNum = ResNum; + show(); + changed=true; + } + + return err; +} + +//*********************************************** +void LogEdit::save(char *filename) +{ + + QString str; + byte *s; + FILE *fptr; + + if((fptr=fopen(filename,"wb"))==NULL){ + menu->errmes("Can't open file %s !\n",filename); + return; + } + for(int i=0;inumLines();i++){ + str = editor->textLine(i); + if(!str.isNull()){ + s = (byte *)str.latin1(); + fprintf(fptr,"%s\n",s); + } + } + fclose(fptr); + changed=false; +} + +//*********************************************** +void LogEdit::save_logic() +{ + + if(LogicNum==-1){ + save_as(); + } + else if(filename != ""){ + save((char *)filename.c_str()); + char *ptr; + if((ptr=(char*)strrchr(filename.c_str(),'/')))ptr++; + else ptr=(char *)filename.c_str(); + sprintf(tmp,"File %s",ptr); + setCaption(tmp); + } + else{ + sprintf(tmp,"%s/logic.%03d",game->srcdir.c_str(),LogicNum); + save(tmp); + sprintf(tmp,"Logic %d (file)",LogicNum); + setCaption(tmp); + } + +} +//*********************************************** +void LogEdit::save_as() +{ + + Q3FileDialog *f = new Q3FileDialog(0,"Save",true); + const char *filters[] = {"logic*.*","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Save"); + f->setMode(Q3FileDialog::AnyFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ) + save((char *)f->selectedFile().latin1()); + } +} + +//*********************************************** +void LogEdit::read_logic() +{ + + Q3FileDialog *f = new Q3FileDialog(0,"Read",true); + const char *filters[] = {"logic*.*","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Read"); + f->setMode(Q3FileDialog::ExistingFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ) + open((char *)f->selectedFile().latin1()); + } +} + +//*********************************************** +int LogEdit::compile_all_logic() +{ + int ret,err=0; + for(int i=0;icompile_logic(); + if(ret)err=1; + } + } + return err; +} + +//*********************************************** +int LogEdit::compile_logic() +{ + QString str; + byte *s; + int err,i; + string filename; + char name[128]; + char tmp1[16],*ptr,*ptr1; + + InputLines.lfree(); + for(i=0;inumLines();i++){ + str = editor->textLine(i); + if(!str.isNull() && str.length()>0){ + s = (byte *)str.latin1(); + if(s[0]<0x80) //i'm getting \221\005 at the last line... + InputLines.add((char *)str.latin1()); + } + else{ + InputLines.add(""); + } + } + + for(i=0;ifilename != ""){ + winlist[i].w.t->save(); + winlist[i].w.t->status->message(""); + } + } + } + + err=logic->compile(); + + if(!err){ + status->message("Compiled OK !", 2000); + if(LogicNum!=-1){ + game->AddResource(LOGIC,LogicNum); + save_logic(); + changed=false; + } + } + else{ + if(logic->ErrorList != ""){ + if(LogicNum!=-1) + sprintf(tmp1,"logic.%d",LogicNum); + else + sprintf(tmp1,"logic"); + strcpy(tmp,logic->ErrorList.c_str()); + + if(!strncmp(tmp,"File ",5)){ + ptr=strstr(tmp,"Line "); + strncpy(name,tmp+5,(int)(ptr-tmp-6)); + name[(int)(ptr-tmp-6)]=0; + for(i=0;ifilename; + char *ptr2; + if((ptr2=(char*)strrchr(filename.c_str(),'/')))ptr2++; + else ptr2=(char *)filename.c_str(); + if(!strcmp(ptr2,name)){ + int num=atoi(ptr+5); + winlist[i].w.t->editor->setCursorPosition(num,0,false); + ptr1=strchr(ptr,'\n'); + *ptr1=0; + winlist[i].w.t->status->message(ptr); + break; + } + } + } + if(i>=MAXWIN){ + char fullname[256]; + string tmp1=tmp; + sprintf(fullname,"%s/%s",game->srcdir.c_str(),name); + for(i=0;iopen(fullname); + ptr=(char*)strstr(tmp1.c_str(),"Line "); + int num=atoi(ptr+5); + winlist[i].w.t->editor->setCursorPosition(num,0,false); + ptr1=strchr(ptr,'\n'); + *ptr1=0; + winlist[i].w.t->status->message(ptr); + break; + } + } + } + } + else{ + ptr=strstr(tmp,"Line "); + int num=atoi(ptr+5); + editor->setCursorPosition(num,0,false); + ptr1=strchr(ptr,'\n'); + *ptr1=0; + status->message(tmp); + } + menu->errmes(tmp1,"Errors:\n%s",logic->ErrorList.c_str()); + } + } + return err; +} + +//*********************************************** +void LogEdit::compile_and_run() +{ + if(!compile_all_logic()) + menu->run_game(); +} + +//*********************************************** +void LogEdit::change_logic_number() +{ + + AskNumber *changelogic = new AskNumber(0,0,"Logic number","Enter logic number: [0-255]"); + + if(!changelogic->exec())return; + QString str = changelogic->num->text(); + int num = atoi((char *)str.latin1()); + if(num<0||num>255){ + menu->errmes("Logic number must be between 0 and 255 !"); + return ; + } + if(game->ResourceInfo[LOGIC][num].Exists){ + sprintf(tmp,"Resource logic.%d already exists. Replace it ?",num); + switch( QMessageBox::warning( this, "Logic", tmp, + "Replace", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + break; + case 1: + return; + } + } + + LogicNum = num; + compile_logic(); + filename=""; + save_logic(); + if(resources_win){ + resources_win->select_resource_type(LOGIC); + resources_win->set_current(num); + } + open(num); + +} + +//*********************************************** +void LogEdit::delete_logic() +{ + int k; + + if(LogicNum==-1)return; + + sprintf(tmp,"Really delete logic %d ?",LogicNum); + switch( QMessageBox::warning( this, "Logic", tmp, + "Delete", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + game->DeleteResource(LOGIC,LogicNum); + delete_file(LogicNum); + if(resources_win){ + k = resources_win->list->currentItem(); + resources_win->select_resource_type(LOGIC); + resources_win->list->setCurrentItem(k); + } + changed=false; + close(); + break; + case 1: + break; + } +} + +//*********************************************** +void LogEdit::delete_file(int ResNum) +{ + struct stat buf; + + sprintf(tmp,"%s/logic.%03d",game->srcdir.c_str(),ResNum); + if(stat(tmp,&buf)==0){ + unlink(tmp); + } + sprintf(tmp,"%s/logic.%d",game->srcdir.c_str(),ResNum); + if(stat(tmp,&buf)==0){ + unlink(tmp); + } + sprintf(tmp,"%s/logic%d.txt",game->srcdir.c_str(),ResNum); + if(stat(tmp,&buf)==0){ + unlink(tmp); + } + +} + +//*********************************************** +void LogEdit::clear_all() +{ + + switch( QMessageBox::warning( this, "Logic", "Really clear all ?", + "Clear", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + editor->clear(); + logic->OutputText = ""; + break; + case 1: + break; + } + +} + +//*********************************************** +void LogEdit::new_room() +{ + // FILE *fptr; + + switch( QMessageBox::warning( this, "Logic", "Replace the editor contents\nwith the new room template ?", + "Replace", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + /* + sprintf(tmp,"%s/src/newroom.txt",game->templatedir.c_str()); + fptr = fopen(tmp,"rb"); + if(fptr==NULL){ + menu->errmes("Can't open "+string(tmp)+"!"); + return; + } + editor->clear(); + char *ptr; + while(fgets(tmp,MAX_TMP,fptr)!=NULL){ + if((ptr=strchr(tmp,0x0a)))*ptr=0; + if((ptr=strchr(tmp,0x0d)))*ptr=0; + editor->insertLine(tmp,-1); + } + fclose(fptr); + */ + if(roomgen==NULL)roomgen=new RoomGen(); + if(roomgen->exec()){ + editor->setText(roomgen->text.c_str()); + logic->OutputText=editor->text().latin1(); + changed=true; + } + break; + case 1: + break; + } + +} +//*********************************************** +void LogEdit::goto_cb() +{ + + AskNumber *ask_number = new AskNumber(0,0,"Go to line", + "Go to line: "); + + if(!ask_number->exec())return; + + QString str = ask_number->num->text(); + int linenum = atoi((char *)str.latin1()); + editor->setCursorPosition(linenum,0,false); + +} +//*********************************************** +void LogEdit::find_cb() +{ + + if(findedit==NULL)findedit = new FindEdit(NULL,NULL,editor,status); + findedit->show(); + findedit->find_field->setFocus(); + +} + +//*********************************************** +void LogEdit::find_again() +{ + + if(findedit==NULL)find_cb(); + else findedit->find_next_cb(); + +} + +//*********************************************** +void LogEdit::getmaxcol() + //get maximum number of columns on screen (approx.) + //(for formatting the 'print' messages) +{ + // QFontMetrics f = fontMetrics(); + // maxcol = editor->width()/f.width('a'); + maxcol = 50; +} + +//*********************************************** +void LogEdit::resizeEvent( QResizeEvent * ) +{ + + QString str = editor->text(); + getmaxcol(); + editor->setText(str); +} + +//*********************************************** +void LogEdit::context_help() +{ + int para, index; + editor->getCursorPosition( ¶, &index ); + if ( para<0 || index<0 ) + return; + QString paratxt = editor->text( para ); + int start = index, end = index; + + if (wordchars.find(paratxt[start]) < 0) + return; + + // Find the bounds of the whole word + while( start > 0 && wordchars.find(paratxt[start-1]) >= 0 ) + --start; + while( end < (int)paratxt.length() && wordchars.find(paratxt[end]) >= 0 ) + ++end; + + QString word = paratxt.mid( start, end-start ).lower(); + if (!menu->help_topic( word )) + status->message("No help found for '" + word + "'", 2000); +} + +//*********************************************** +void LogEdit::command_help() +{ + menu->help_topic("commands_by_category"); +} + +//*********************************************** +void LogEdit::update_line_num( int para, int pos ) +{ + QString str; + QTextOStream( &str ) << pos << ", " << para; + status->message(str); +} + + +//******************************************************* +TextEdit::TextEdit( QWidget *parent, const char *name,int win_num) + : QWidget( parent, name ,Qt::WDestructiveClose ) +{ + + setCaption("Text editor"); + + winnum = win_num; + editor = new Q3MultiLineEdit(this); + editor->setMinimumSize(380,380); + + QFont font; + font.setPointSize(10); + font.setStyleHint( QFont::TypeWriter ); + editor->setFont( font ); + editor->setWordWrap( Q3TextEdit::NoWrap ); + + Q3PopupMenu *file = new Q3PopupMenu( this ); + Q_CHECK_PTR( file ); + + file->insertItem( "New", this, SLOT(new_text())); + file->insertItem( "Open", this, SLOT(open()) ); + file->insertItem( "Save", this, SLOT(save()), Qt::CTRL + Qt::Key_S ); + file->insertItem( "Save as", this, SLOT(save_as()) ); + file->insertSeparator(); + file->insertItem( "Close", this, SLOT(close()) ); + + Q3PopupMenu *edit = new Q3PopupMenu( this ); + Q_CHECK_PTR( edit ); + edit->insertItem( "Cut", editor, SLOT(cut()) , Qt::CTRL + Qt::Key_X ); + edit->insertItem( "Copy", editor, SLOT(copy()) , Qt::CTRL + Qt::Key_C ); + edit->insertItem( "Paste", editor, SLOT(paste()) , Qt::CTRL + Qt::Key_V); + edit->insertSeparator(); + edit->insertItem( "Clear all", this, SLOT(clear_all()) ); + edit->insertSeparator(); + edit->insertItem( "Find", this, SLOT(find_cb()) ,Qt::CTRL + Qt::Key_F); + edit->insertItem( "Find again", this, SLOT(find_again()) ,Qt::Key_F3); + + QMenuBar *menu = new QMenuBar(this); + Q_CHECK_PTR( menu ); + menu->insertItem( "File", file ); + menu->insertItem( "Edit", edit ); + menu->setSeparator( QMenuBar::InWindowsStyle ); + setMinimumSize(400,400); + + Q3BoxLayout *all = new Q3VBoxLayout(this,10); + all->setMenuBar(menu); + + all->addWidget(editor); + + status = new QStatusBar(this); + QLabel *msg = new QLabel( status, "message" ); + status->addWidget( msg, 4 ); + all->addWidget(status); + + changed=false; + filename = ""; + findedit=NULL; + OutputText = ""; +} + +//*********************************************** +void TextEdit::deinit() +{ + if(findedit){ + findedit->close(true); + findedit=NULL; + } + winlist[winnum].type=-1; + if(window_list && window_list->isVisible())window_list->draw(); +} + +//********************************************* +void TextEdit::hideEvent( QHideEvent * ) +{ + + if(findedit){ + findedit->close(true); + findedit=NULL; + } + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//********************************************* +void TextEdit::showEvent( QShowEvent * ) +{ + + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//*********************************************** +void TextEdit::closeEvent( QCloseEvent *e ) +{ + + if(changed){ + QString str = editor->text(); + if(!strcmp(str.latin1(),OutputText.c_str())){ //not changed + deinit(); + e->accept(); + return; + } + + if(filename != "") + sprintf(tmp,"Do you want to save changes to\n%s ?",filename.c_str()); + else + strcpy(tmp,"Do you want to save changes ?"); + switch ( QMessageBox::warning( this, "Text editor", + tmp, + "Yes", + "No", + "Cancel", + 0, 2) ) { + case 0: // yes + save(); + deinit(); + e->accept(); + break; + case 1: // no + deinit(); + e->accept(); + break; + default: // cancel + e->ignore(); + break; + } + } + else{ + deinit(); + e->accept(); + } + +} + +//*********************************************** +void TextEdit::new_text() +{ + + if(filename.length()>0){ + //if (changed) + sprintf(tmp,"Do you want to save changes to\n%s ?",filename.c_str()); + switch ( QMessageBox::warning( this, "Text editor", + tmp, + "Yes", + "No", + "Cancel", + 0, 2) ) { + case 0: // yes + save(); //??????????????? + break; + case 1: // no + break; + default: // cancel + break; + } + } + + filename=""; + setCaption("New text"); + editor->clear(); + show(); + changed=true; + OutputText = ""; +} + +//*********************************************** +void TextEdit::open() +{ + + Q3FileDialog *f = new Q3FileDialog(0,"Open",true); + const char *filters[] = {"All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Open"); + f->setMode(Q3FileDialog::ExistingFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ){ + open((char *)f->selectedFile().latin1()); + show(); + changed=true; + } + } +} + +//*********************************************** +int TextEdit::open(char *filenam) +{ + FILE *fptr = fopen(filenam,"rb"); + + if(fptr!=NULL){ + struct stat buf; + fstat(fileno(fptr),&buf); + editor->clear(); + char *ptr; + QString filecont; + while(fgets(tmp,MAX_TMP,fptr)!=NULL){ + if((ptr=strchr(tmp,0x0a)))*ptr=0; + if((ptr=strchr(tmp,0x0d)))*ptr=0; + filecont += QString(tmp) + "\n"; + } + editor->setText( filecont ); + fclose(fptr); + OutputText=editor->text().latin1(); + filename = string(filenam); + char *name = strrchr(filenam,'/'); + if(name==NULL)name=filenam; + else name++; + QString str; + str.sprintf("file %s",name); + setCaption(str); + show(); + changed=true; + return 0; + } + else{ + menu->errmes("Can't open file %s !",filenam); + return 1; + } +} + +//*********************************************** +void TextEdit::save() +{ + if(filename == ""){ + save_as(); + } + else{ + save(filename.c_str()); + } +} + +//*********************************************** +void TextEdit::save_as() +{ + + Q3FileDialog *f = new Q3FileDialog(0,"Save",true); + const char *filters[] = {"All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Save"); + f->setMode(Q3FileDialog::AnyFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ) + save((const char *)f->selectedFile().latin1()); + } +} + +//*********************************************** +void TextEdit::save(const char *filename) +{ + + QString str; + byte *s; + FILE *fptr; + + if((fptr=fopen(filename,"wb"))==NULL){ + menu->errmes("Can't open file %s !\n",filename); + return; + } + for(int i=0;inumLines();i++){ + str = editor->textLine(i); + if(!str.isNull()){ + s = (byte *)str.latin1(); + fprintf(fptr,"%s\n",s); + } + } + fclose(fptr); + changed=false; + char *ptr; + if((ptr=(char*)strrchr(filename,'/')))ptr++; + else ptr=(char *)filename; + sprintf(tmp,"File %s",ptr); + setCaption(tmp); +} + +//*********************************************** +void TextEdit::clear_all() +{ + + switch( QMessageBox::warning( this, "Text", "Really clear all ?", + "Clear", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + editor->clear(); + break; + case 1: + break; + } + } + +//*********************************************** +void TextEdit::find_cb() +{ + + if(findedit==NULL)findedit = new FindEdit(NULL,NULL,editor,status); + findedit->show(); + findedit->find_field->setFocus(); + +} + +//*********************************************** +void TextEdit::find_again() +{ + + if(findedit==NULL)find_cb(); + else findedit->find_next_cb(); + +} + +//*********************************************** +FindEdit::FindEdit( QWidget *parent, const char *name, Q3MultiLineEdit *edit ,QStatusBar *s) + : QWidget( parent, name ,Qt::WDestructiveClose) +{ + setCaption("Find"); + // setMinimumSize(340,140); + + status = s; + editor = edit; + + Q3BoxLayout *all = new Q3VBoxLayout(this,10); + + Q3BoxLayout *txt = new Q3HBoxLayout(all,4); + + QLabel *label = new QLabel("Find what:",this); + txt->addWidget(label); + + find_field = new QLineEdit(this); + find_field->setMinimumWidth(200); + connect( find_field, SIGNAL(returnPressed()), SLOT(find_first_cb()) ); + txt->addWidget(find_field); + + Q3BoxLayout *left1 = new Q3HBoxLayout(all,10); + + Q3ButtonGroup *direction = new Q3ButtonGroup(2,Qt::Vertical,"Dir",this); + up = new QRadioButton("Up",direction); + up->setChecked(false); + down = new QRadioButton("Down",direction); + down->setChecked(true); + left1->addWidget(direction); + + Q3ButtonGroup *from = new Q3ButtonGroup(2,Qt::Vertical,"From",this); + start = new QRadioButton("Start",from); + start->setChecked(true); + current = new QRadioButton("Current",from); + current->setChecked(false); + left1->addWidget(from); + + + Q3GroupBox *type = new Q3GroupBox(2,Qt::Vertical,"Match",this); + match_whole = new QCheckBox("Match exact",type); + // box->addWidget(match_whole); + match_case = new QCheckBox("Match case",type); + // box->addWidget(match_case); + left1->addWidget(type); + + + Q3BoxLayout *right = new Q3VBoxLayout(left1,5); + find_first = new QPushButton("Find",this); + right->addWidget(find_first); + connect( find_first, SIGNAL(clicked()), SLOT(find_first_cb()) ); + find_next = new QPushButton("Find next",this); + connect( find_next, SIGNAL(clicked()), SLOT(find_next_cb()) ); + right->addWidget(find_next); + cancel = new QPushButton("Cancel",this); + connect( cancel, SIGNAL(clicked()), SLOT(cancel_cb()) ); + right->addWidget(cancel); + + + adjustSize(); + curline=0; + +} + +//*********************************************** +void FindEdit::find_first_cb() +{ + + if(current->isChecked()){ + int line,col; + editor->getCursorPosition(&line,&col); + curline=line; + } + else if(down->isChecked()){ + curline=0; + } + else{ + curline=editor->numLines()-1; + } + + find_next_cb(); + +} + +//*********************************************** +void FindEdit::find_next_cb() +{ + + int k; + QString str; + QString w = find_field->text(); + char *word = (char *)w.latin1(); + int len = strlen(word); + if(len==0)return; + char *ptr,*ptr0,*ww,*ww0; + int num=editor->numLines(); + bool mwhole=match_whole->isChecked(); + bool mcase=!(match_case->isChecked()); + bool found; + + if(mcase)toLower(word); + + if(down->isChecked()){ + if(curline<0)curline=0; + for(;curlinetextLine(curline); + ww = (char *)str.latin1(); + ww0=ww; + if(mcase)toLower(ww); + if(mwhole){ + ptr0=ww; + found=false; + do{ + ptr=strstr(ptr0,word); + if(!ptr)break; + ptr0=ptr+len; + if(ptr>ww && isalnum(*(ptr-1)))continue; + if(isalnum(*ptr0))continue; + found=true; + }while(!found); + if(!found)continue; + } + else{ + if((ptr=strstr(ww,word))==NULL)continue; + } + k=int(ptr-ww); + editor->setCursorPosition(curline,k,false); + editor->setSelection(curline,k,curline,k+len); + sprintf(tmp,"%d: %s",curline,ww0); + status->message(tmp); + curline++; + return; + } + } + else{ + if(curline>=num)curline=num-1; + for(;curline>=0;curline--){ + str = editor->textLine(curline); + ww = (char *)str.latin1(); + ww0=ww; + if(mcase)toLower(ww); + if((ptr=strstr(ww,word))==NULL)continue; + if(mwhole){ + ptr0=ww; + found=false; + do{ + ptr=strstr(ptr0,word); + if(!ptr)break; + ptr0=ptr+len; + if(ptr>ww && isalnum(*(ptr-1)))continue; + if(isalnum(*ptr0))continue; + found=true; + }while(!found); + if(!found)continue; + } + else{ + if((ptr=strstr(ww,word))==NULL)continue; + } + k=int(ptr-ww); + editor->setCursorPosition(curline,k,false); + editor->setSelection(curline,k,curline,k+len); + sprintf(tmp,"%d: %s",curline,ww0); + status->message(tmp); + curline--; + return; + } + } + menu->errmes("Find","'%s' not found !",word); + status->clear(); + +} + +//*********************************************** +void FindEdit::cancel_cb() +{ + + hide(); + status->clear(); +} +//*********************************************** + diff --git a/src/logedit.h b/src/logedit.h new file mode 100644 index 0000000..ad4e86b --- /dev/null +++ b/src/logedit.h @@ -0,0 +1,147 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef LOGEDIT_H +#define LOGEDIT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include + +#include "util.h" +#include "wutil.h" +#include "logic.h" +#include "roomgen.h" +#include "resources.h" + +//find string in the editor window +class FindEdit : public QWidget +{ + Q_OBJECT +public: + FindEdit( QWidget *parent=0, const char *name=0, Q3MultiLineEdit *edit=0,QStatusBar *s=0); + QStatusBar *status; + QPushButton *find_first,*find_next,*cancel; + QRadioButton *up,*down,*start,*current; + QCheckBox *match_whole,*match_case; + QLineEdit *find_field; + Q3MultiLineEdit *editor; + int curline; +public slots: + void find_first_cb(); + void find_next_cb(); + void cancel_cb(); +}; + +class LogicSyntaxHL; + +//Logic editor +class LogEdit : public QWidget +{ + Q_OBJECT +public: + LogEdit( QWidget *parent=0, const char *name=0,int winnum=0,ResourcesWin *res=0, bool readonly=false ); + Q3MultiLineEdit *editor; + FindEdit *findedit; + ResourcesWin *resources_win; + QStatusBar *status; + RoomGen *roomgen; + Logic *logic; + LogicSyntaxHL *syntax_hl; + string filename; + unsigned int maxcol; + int open(); + int open(int ResNum); +public slots: + void new_room(); + void read_logic(); + void save_logic(); + void save_as(); + int compile_logic(); + int compile_all_logic(); + void compile_and_run(); + void change_logic_number(); + void delete_logic(); + void clear_all(); + void find_cb(); + void find_again(); + void goto_cb(); + void context_help(); + void command_help(); + void update_line_num( int para, int pos ); + protected: + int LogicNum; + int winnum; + bool changed; + int open(char *filename); + void save(char *filename); + void deinit(); + void delete_file(int num); + void getmaxcol(); + void resizeEvent( QResizeEvent * ); + void closeEvent( QCloseEvent *e ); + void showEvent( QShowEvent * ); + void hideEvent( QHideEvent * ); +}; + +//a simple text editor +class TextEdit : public QWidget +{ + Q_OBJECT +public: + TextEdit( QWidget *parent=0, const char *name=0,int winnum=0); + Q3MultiLineEdit *editor; + FindEdit *findedit; + QStatusBar *status; + string filename; + int open(char *filename); + void save(const char *filename); +public slots: + void new_text(); + void clear_all(); + void open(); + void save(); + void save_as(); + void find_cb(); + void find_again(); + protected: + string OutputText; + int winnum; + bool changed; + void closeEvent( QCloseEvent *e ); + void showEvent( QShowEvent * ); + void hideEvent( QHideEvent * ); + void deinit(); +}; + + +#endif diff --git a/src/logic.cpp b/src/logic.cpp new file mode 100644 index 0000000..702233a --- /dev/null +++ b/src/logic.cpp @@ -0,0 +1,37 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "logic.h" + +#include +#include + +Logic::Logic() +{ + + wordlist = new WordList(); + objlist = new ObjList(); + maxcol=80; + OutputText = ""; +} + + + + diff --git a/src/logic.h b/src/logic.h new file mode 100644 index 0000000..1ddde28 --- /dev/null +++ b/src/logic.h @@ -0,0 +1,91 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef LOGIC_H +#define LOGIC_H + +#include "words.h" +#include "object.h" +#include "agicommands.h" +#include "game.h" + +#define MaxBlockDepth 12 +#define MaxLabels 255 +#define MaxDefines 255 +#define MaxMessages 256 +#define MaxGotos 255 + +//Logic class used both for decode and compile +class Logic +{ + public: + Logic(); + WordList *wordlist; + ObjList *objlist; + string OutputText; //result of the decoding + string ErrorList; //compilation error messages + unsigned int maxcol; //max number of columns in window - used in formatting 'print' strings + int compile(); + int decode(int resnum); + + private: + void ShowError(int Line, string ErrorMsg); + void DisplayMessages(); + void ReadMessages(); + int FindLabels_ReadIfs(); + void AddBlockEnds(); + int FindLabels(); + void AddArg(byte Arg, byte ArgType); + void AddSpecialSyntaxCommand(); + void AddSpecialIFSyntaxCommand(); + void ReadIfs(); + + string ReadString(string::size_type *pos, string& str); + int RemoveComments(TStringList Lines); + int AddIncludes(); + int ReadDefines(); + int ReadPredefinedMessages(); + int ReadLabels(); + void NextLine(); + void SkipSpaces(); + byte MessageNum(string TheMessage); + byte AddMessage(string TheMessage); + string ReplaceDefine(string InText); + void ReadArgText(); + int ReadArgValue(); + int Val(string str); + void ReadArgs(bool CommandIsIf, byte CmdNum); + string ReadText(); + string ReadPlainText(); + string ReadExprText(); + void ReadCommandName(); + byte FindCommandNum(bool CommandIsIf,string CmdName); + bool AddSpecialIFSyntax(); + bool AddSpecialSyntax(); + int LabelNum(string LabelName); + bool LabelAtStartOfLine(string LabelName); + void WriteMessageSection(); + int CompileCommands(); + +}; + +extern char tmp[]; + +#endif diff --git a/src/logo.xpm b/src/logo.xpm new file mode 100644 index 0000000..6cebe06 --- /dev/null +++ b/src/logo.xpm @@ -0,0 +1,168 @@ +/* XPM */ +static const char *logo[] = { +/* columns rows colors chars-per-pixel */ +"320 148 14 1", +" c black", +". c #505050", +"X c #0000A0", +"o c #5050FF", +"O c #00A000", +"+ c #50FF50", +"@ c #00A0A0", +"# c #50FFFF", +"$ c #A00000", +"% c #A05000", +"& c #FF5050", +"* c #FFFF50", +"= c #A0A0A0", +"- c gray100", +/* pixels */ +"--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"------------------------ OOOOOO ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------------------- OOOOOOOOOOOOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"-------------------- OOOOOOOOOOOOOOOOOO --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"-------------------- OOOOOOOOOOOOOOOOOOOO ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"------------------ OOOOOOOOOOOOOOOOOOOOOOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------------- OOOOOOOOOOOOOOOOOOOOOOOOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------------- OOOOOOOOOO OOOOOOOOOO --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"-------------- OOOOOOOOOO -------- OOOOOOOO --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"-------------- OOOOOOOO ---------- OOOOOOOO --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"-------------- OOOOOO -------------- OOOOOO --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"------------ OOOOOOOO -------------- OOOOOOOO ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"------------ OOOOOO ------------------ OOOOOO ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"------------ OOOOOO ------------ ---- OOOOOO ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"------------ OOOO ------------ ------ OOOO ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"------------ OOOO ------------ OO ---- OOOO ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOOOO ---------- OOOO ---- OOOOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOO ------------ OOOOOO -- OOOOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOO ---------- OOOOOOOO -- OOOOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOO ---------- OOOOOOOO ---- OOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOO -------- OOOOOOOO ------ OOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOO -------- OOOOOOOO ------ OOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOO ------ OOOOOOOOOO ------ OOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOO ------ OOOOOOOOOO ------ OOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOO ---- OOOOOOOOOOOOOO ---- OOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOO ---- OOOOOOOOOOOOOO ---- OOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOOOO -- OOOOOOOOOOOOOOOO -- OOOO ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"---------- OOOOOO ---- OOOO OOOOOOOO OOOOOO ---------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"------------ OOOO ---- OO -- OOOOOOOO OOOO ------------ ---------------------------------------- XXXXXXXXXX ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"------------ OOOOOO ---- -- OOOOOOOO OOOO ------------ XXXXXXXXXXXXXXXX@@ -------------------------------------- XXXXXXXXXXXXXX@@@@@@@@ ------------------------ --------------------------------------------------------------------------------------------------------------------------------", +"------------ OOOOOO ---- ------ OOOOOOOOOOOO ------------ XXXXXXXXXXXXXXXX@@ ---------------------------------- XXXXXXXXXXXXXXXXXXXXXXXX@@ ---------------------- XXXXXXXXXXXXXX@@ --------------------------------------------------------------------------------------------------------------------------------", +"------------ OOOOOOOO ---------- OOOOOOOOOO -------------- XXXXXXXXXXXXXXXX@@XX ------------------------------ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ -------------------- XXXXXXXXXXXXXX@@ --------------------------------------------------------------------------------------------------------------------------------", +"------------ OOOOOOOO ------------ OOOOOOOO ------------ XXXXXXXXXXXXXXXXXXXX@@ ---------------------------- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ -------------------- XXXXXXXXXXXXXX@@ --------------------------------------------------------------------------------------------------------------------------------", +"-------------- OOOOOOOO ---------- OOOOOOOO ------------ XXXXXXXXXXXXXXXXXXXX@@ -------------------------- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ------------------ XXXXXXXXXXXXXX@@ ------------------------------------------------------------------------------------------&&------------------------------------", +"-------------- OOOOOOOOOO ---- OOOOOOOOOOOO ---------- XXXXXXXXXXXXXXXXXXXX@@ -------------------------- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ---------------- XXXXXXXXXXXXXX@@ ----------------------------------------------------------------------------------------&&----------------$$--------------------", +"---------------- OOOOOOOOOOOO OOOOOOOOOOOO ---------- XXXXXXXXXXXXXXXXXXXX@@ ------------------------ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ---------------- XXXXXXXXXXXXXX@@ ----------------------------------------------------------------------------------------&&----------------$$--------------------", +"---------------- OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO -------- XXXXXXXXXXXXXXXXXXXX@@ ------------------------ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ -------------- XXXXXXXXXXXXXX@@ --------------------------------------------------------------------------------------&&$$----------------$$$$------------------", +"------------------ OOOOOOOOOOOOOOOOOOOOOO OOOOOO -------- XXXXXXXXXXXXXXXXXXXXXX@@ -------------------- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ -------------- XXXXXXXXXXXXXX@@ -------------------------------- ----------------------------------------------&&$$$$--$$ ----------$$------------------", +"-------------------- OOOOOOOOOOOOOOOOOO OOOO -------- XXXXXXXXXXXXXXXXXXXXXXXX@@ -------------------- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ -------------- XXXXXXXXXXXXXX@@ ------------------------------ --------------------------------------------&&$$$$$$$$$$ --------$$------------------", +"-------------------- OOOOOOOOOOOOOOOOOO -- OO -------- XXXXXXXXXXXXXXXXXXXXXXXX@@ ------------------ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ -------------- XXXXXXXXXXXXXX@@ ------------------------------ --------------------------------------------&&$$$$$$$$$$$$ ------$$ ----------------", +"---------------------- OOOOOOOOOOOO ---- ---------- XXXXXXXXXXXXXXXXXXXXXXXX@@ ------------------ XXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXX@@ ---------------------------- ------------------------------------------&&$$$$$$$$$$$$$$ ----&&$$ ----------------", +"------------------------ ---------- ---------- XXXXXXXXXXXXXXXXXXXXXXXX@@ ------------------ XXXXXXXXXXXXXXXX@@XX -- XXXXXXXXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXX@@ ---------------------------- ------------------------------------------&&$$$$$$$$$$$$$$ &&$$$$ ----------------", +"---------------------------------------------------------- XXXXXXXXXXXXXXXXXXXXXXXXXX@@ ---------------- XXXXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXX@@ -------------------------- ------------------------------------------&&$$==$$$$$$$$$$$$&&$$$$$$ ----------------", +"---------------------------------------------------------- XXXXXXXXXXXXXXXXXXXXXXXXXX@@ -------------- XXXXXXXXXXXXXXXX@@ -------------- XXXXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXX@@ -------------------------- ----------------------------------------$$$$==$$==$$$$$$$$$$$$$$$$ ----------------", +"-------------------------------------------------------- XXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ -------------- XXXXXXXXXXXXXX@@ ---------------- XXXXXXXXXX@@@@ ------------ XXXXXXXXXXXXXX@@ -------------------------- ----------------------------------------$$----======$$$$$$$$$$$$$$ ----------------", +"-------------------------------------------------------- XXXXXXXXXXXX@@ XXXXXXXXXXXX@@ -------------- XXXXXXXXXXXXXX@@ ------------------ XXXX@@@@ ---------------- XXXXXXXXXXXXXX@@ -------------------------- -- -- ----------------------------------------$$--==----==&&$$$$$$$$$$ ------------------", +"-------------------------------------------------------- XXXXXXXXXXXX@@ XXXXXXXXXXXX@@ -------------- XXXXXXXXXXXX@@ -------------------- @@@@ -------------------- XXXXXXXXXXXXXX@@ -------------------------- ---- ------ ----------------------------------------==--==----==&&$$$$$$$$$$ ------------------", +"-------------------------------------------------------- XXXXXXXXXXXX@@ XXXXXXXXXXXXXX@@ ------------ XXXXXXXXXXXX@@ ---------------------- ------------------------ XXXXXXXXXXXXXX@@ -------------------------- -- --..-- ----------------------------------------== == --==&&$$$$$$$$ --------------------", +"-------------------------------------------------------- XXXXXXXXXXXX@@ XXXXXXXXXXXXXX@@ ------------ XXXXXXXXXXXX@@ -------------------------------------------------- XXXXXXXXXXXXXX@@ -------------------------- -- ---- -- ----------------------------------------== -- --==&&$$$$$$ ----------------------", +"-------------------------------------------------------- XXXXXXXXXX@@ -- XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXX@@ -------------------------------------------------- XXXXXXXXXXXXXX@@ -------------------------- --..%%%%..-- ----------------------------------------$$ --==&&$$$$$$ ----------------------", +"------------------------------------------------------ XXXXXXXXXXXX@@ -- XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXX@@ -------------------------------------------------- XXXXXXXXXXXXXX@@ -------------------------- --%%****%%-- --------------------------------------&&&&== --==$$$$$$ ----------------------", +"------------------------------------------------------ XXXXXXXXXXXX@@ -- XXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ -------------------------------------------------- XXXXXXXXXXXXXX@@ --------------------------..%%********%% --------------------------------------&&$$$$.. --==$$$$$$ ----------------------", +"------------------------------------------------------ XXXXXXXXXXXX@@ -- XXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ -------------------------------------------------- XXXXXXXXXXXXXX@@ -------------------------- **********%% --------------------------------------&&$$$$&&..==$$$$$$$$ ----------------------", +"------------------------------------------------------ XXXXXXXXXXXX@@ -- XXXXXXXXXXXXXX@@ -------- XXXXXXXXXXXXXX@@ -------------------------------------------------- XXXXXXXXXXXXXX@@ -------------------------- %%%%****%%%% ----------------------------------**--&&$$&&$$..$$$$$$$$$$ ----------------------", +"------------------------------------------------------ XXXXXXXXXXXX@@ -- XXXXXXXXXXXXXX@@ -------- XXXXXXXXXXXX@@ ---------------------------------------------------- XXXXXXXXXXXXXX@@ -------------------------- %%%%%%%%%%%% ----------------------------------**-- $$$$$$..$$$$$$$$ ------------------------", +"------------------------------------------------------ XXXXXXXXXXXX@@ -- XXXXXXXXXXXXXX@@ -------- XXXXXXXXXXXX@@ ------------ ---------- XXXXXXXXXXXXXX@@ -------------------------- ==%%%%%%%%-- ------------------------------**--%%---- $$$$$$$$$$$$$$ ------------------------", +"---------------------------------------------------- XXXXXXXXXXXX@@ ------ XXXXXXXXXXXX@@ -------- XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ -------------------------- ====%%%%==-- ----------------------------%%****%%-- $$$$$$$$ $$$$ --------------------------", +"---------------------------------------------------- XXXXXXXXXXXX@@ ------ XXXXXXXXXXXX@@ -------- XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ -------------------------- --======---- ----------------------------%%****%%---- $$$$.. $$$$ --------------------------", +"---------------------------------------------------- XXXXXXXXXXXX@@ ------ XXXXXXXXXXXXXX@@ ------ XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ------------------------== ----==-------- ----------------------------%%**%%------$$.. $$$$----------------------------", +"---------------------------------------------------- XXXXXXXXXXXX@@ ------ XXXXXXXXXXXXXX@@ ------ XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ------------------------== -------------- ------------------------%%********$$$$---- $$$$$$$$----------------------------", +"---------------------------------------------------- XXXXXXXXXXXX@@ ------ XXXXXXXXXXXXXX@@ ------ XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ------------------------.. -------------- ------------------------%%%%****$$$$----$$$$$$$$$$----------------------------", +"---------------------------------------------------- XXXXXXXXXXXX@@ ------ XXXXXXXXXXXXXX@@ ------ XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ------------------------.. ------------== ----------------------------%%$$$$$$ --$$$$$$$$$$----------------------------", +"-------------------------------------------------- XXXXXXXXXXXXXX@@ ------ XXXXXXXXXXXXXX@@ ------ XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ------------------------ ..----------====.. ------------------------------$$$$$$ $$$$$$$$&&$$$$--------------------------", +"-------------------------------------------------- XXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ---- XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ------------------------ ..==----------==.. ----------------------------$$$$ $$$$$$&&$$$$$$--------------------------", +"-------------------------------------------------- XXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ---- XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ------------------------ ====----------==.. ------------------------------$$ ....&&$$$$$$..--------------------------", +"-------------------------------------------------- XXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ---- XXXXXXXXXXXX@@ ------------ XXXXXXXXXXXXXXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ---------------------- ==--------------.. ------------------------------$$$$..&&$$..$$$$$$..--------------------------", +"-------------------------------------------------- XXXXXXXXXXXX@@ XXXXXXXXXXXXXX@@ ---- XXXXXXXXXXXXXX@@ ---------- @@@@@@@@@@@@XXXXXXXXXXXX@@ ---------- XXXXXXXXXXXXXX@@ ---------------------- ----------------== --------------------------------$$&&$$$$$$$$$$....--------------------------", +"-------------------------------------------------- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ---- XXXXXXXXXXXXXX@@ OO-------- XXXXXXXXXXXX@@ OO-------- XXXXXXXXXXXXXX@@ ---------------------- -------------------- ----------------------------------&&$$$$$$$$.... --------------------------", +"----------------------------------------OO------ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ---- XXXXXXXXXXXXXX@@ OOOO----------OO++++++ XXXXXXXXXXXX@@ OOOO------ XXXXXXXXXXXXXX@@ ---------------------- -------------------- ----------------------------------&&$$$$$$.... --------------------------", +"--------------------------------------OOOOOO---- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ -- XXXXXXXXXXXXXX@@ OOOOOO----OOOO++++++++ XXXXXXXXXXXX@@ OOOOOO---- XXXXXXXXXXXXXX@@ --OOOOOO------------ ==-------------------- ----------------------------------.......... --------------------------", +"------------------------------------OO++OOOOOO-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ -- XXXXXXXXXXXXXX@@ OOOOOOOOOO++++++++++++ XXXXXXXXXXXX@@ OOOOOOOO-- XXXXXXXXXXXXXX@@ OO++OOOOOOOOOOOO---- ..-------------------- ----------------------------------&&...... $$ --------------------------", +"----------------------------------OO++++OOOOOOOO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ --OO XXXXXXXXXXXX@@ OOOOOOOOOO++++++++++++ XXXXXXXXXXXX@@ OOOOOOOO-- XXXXXXXXXXXXXX@@ ++++OOOOOOOOOOOOOOOO -------------------- ----------------------------------&&$$ **$$$$--------------------------", +"--------------------------------OO++++++OOOOOOOO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ OO++ XXXXXXXXXXXXXX@@ OOOOOOOO++++++++++++ XXXXXXXXXXXX@@ OOOOOOOOOO XXXXXXXXXXXXXX@@ ++++++OOOOOOOOOOOOOO -------------------- ----------------------------------$$$$ **$$$$--------------------------", +"------------------------------OO++++++++OOOOOOOO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@++++ XXXXXXXXXXXXXX@@ OOOOOOOOOO++++++++++ XXXXXXXXXXXX@@ OOOOOOOOOO XXXXXXXXXXXXXX@@ ++++++OOOOOOOOOOOOOO -------------------- ----------------++----------------$$$$$$ $$%%**$$--------------------------", +"------------------------------OO++++OO++++OOOO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++ XXXXXXXXXXXXXXXX@@ OOOOOOOO++++++++++ XXXXXXXXXXXX@@ OOOOOOOOOO XXXXXXXXXXXXXX@@ ++++++OOOOOOOOOOOOOO -------------------- OO------------++--++OO--------------$$$$$$$$$$**$$--------------------------", +"----------------------------OO++++++++++++OOOO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++ XXXXXXXXXXXXXXXX@@ ++++OOOO++++++++ XXXXXXXXXXXXXX@@ ++OOOOOOOO XXXXXXXXXXXXXX@@ ++++++++OOOOOOOOOOOO%% -------------------- ++OO--------++--OOOO++OO------------$$$$$$$$$$$$ --------------OO----------", +"--------------------OOOO----OO++++++OO++++OOOO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++++ XXXXXXXXXXXXXXXX@@ ++++++++++++ XXXXXXXXXXXXXX@@ ++++OOOOOO XXXXXXXXXXXXXX@@ ++++++++++OOOOOOOO%%** --------------**** ++++OO----++--OOOOOOOOOO--------------$$$$$$++ --------OOOOOOOOOO------", +"----------------OOOOOOOO--OO++++++OO++++++++OO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++++ XXXXXXXXXXXXXXXXXX ++++++ XXXXXXXXXXXXXXXXXX@@ ++++OOOOOO XXXXXXXXXXXXXX@@ ++++++++OO++OOOOOO%%**** --------------** ++++++OO++OOOO++OOOOOOOOOO------------++OOOO++OO ------OO++OOOOOOOO----", +"------------OOOOOOOOOOOOOOOO++++++++++++++++++ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++++ XXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXX@@ ++++OOOOOO XXXXXXXXXXXXXX@@ ++++++++++++OOOO%%****** --------------** %%++++++OOOO++++++++OOOOOOOOOO----------++OOOOOOOO.... --OO++++OOOOOOOO----", +"----------OOOOOOOOOOOOOOOO++++++++++++++++++++ XXXXXXXXXXXXXX@@@@@@@@@@@@@@@@@@@@@@@@XXXXXXXXXXXXXX@@ ++++ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++++OOOOOO XXXXXXXXXXXXXX@@ ++++++++++++OOOO%%******** ------------** ****%%++++OOOOOO++++OOOOOOOOOOOO--======OOOOOO++OOOOOO--.... OO++++++OOOOOO----", +"----------OO++++OOOOOOOOOOOO++++++++++++++++ XXXXXXXXXXXXXXXX@@ XXXXXXXXXXXXXX@@ ++++ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++++OOOOOO XXXXXXXXXXXXXX@@ ++++++OO++OOOOOO%%******** ----------%% ******%%++++OOOOOO++++++OOOOOOOO====OO..OOOO++++OOOOOOOO------ ++OOOOOOOO--", +"--------OO++++++++++OOOOOOOO++++++++++++++++ XXXXXXXXXXXXXXXX@@ OO++++++++++++++++ XXXXXXXXXXXXXX@@ ++++++ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++++++OOOOOO XXXXXXXXXXXXXX@@ ++++++++++OOOOOO%%********** --------==%% ********%%++OOOOOO++++++OOOOOOOO==OOOO..OOOO++OOOOOOOOOO....--OO.... OOOOOO--", +"--------OO++++++++++OOOOOOOOOO++++++++++++++ XXXXXXXXXXXXXXXX@@ OO++++++++++++++++ XXXXXXXXXXXXXX@@ ++++++ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++++++++OOOOOO XXXXXXXXXXXXXX@@ ++++++++++OOOOOO%%********** ------====%%**********%%++OOOOOOOO++++++++OO==--OO..====OOOOOOOOOOOO........OO++++....$$$$OOOO--", +"------OO++++++++++++++OOOOOOOO++++++++++++++ XXXXXXXXXXXXXX@@ OOOOOO++++++++++++++++ XXXXXXXXXXXX@@ ++++++++ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++++++++OOOOOO XXXXXXXXXXXXXX@@ ++++++++++OOOOOO%%**********%%--------==..%%**********%%++OOOOOOOO++OO++++++==........--==OOOOOO................++++++....$$OO--", +"----OO++++++++++++++++++++OOOO++++++++++++++ XXXXXXXXXXXXXX@@ OOOOOO++++OO++++++++++ XXXXXXXXXXXX@@ ++++++++ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++++++++OOOOOOOO XXXXXXXXXXXXXX@@ ++++++++OOOOOO%%************%%------==.. %%**********%%++OOOOOOOO++++++++++..====................................&&++++..$$OOOO", +"----OO++++++++++++++++++++++++++++++++++++++ XXXXXXXXXXXXXX@@ OOOOOO++++OO++++++++++ XXXXXXXXXXXXXX@@ ++++++++ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++++++++++OOOOOOOO XXXXXXXXXXXXXX@@ ++++++++OOOOOO%%%%**********%%--======.. %%**********%%++++OOOOOO++++++....====................................&&$$++..$$OOOOOO", +"--OO++++++++++++++++++++++++++++++++++++++ XXXXXXXXXXXXXXXX@@++++++OOOOOO++++OO++++++ XXXXXXXXXXXXXX@@ ++++++++++ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX@@ ++++++++++++OOOOOOOO XXXXXXXXXXXXXX@@ ++++++OOOOOOOO%%%%**********%%====.... %%********%%++++++OOOOOO++....================........................&&$$$$..OOOOOOOO", +"--OO++++++++++OO++++OO++++++++++++++++++++ XXXXXXXXXXXXXX@@ ++OO++++++++++++++++++++++ XXXXXXXXXXXX@@ ++++OO++++++ XXXXXXXXXXXXXXXXXXXXXXXX@@@@ ++++OO++++++++OOOOOOOO XXXXXXXXXXXXXX@@ ++++++++++OOOO%%%%%%********%% %%******%%%%++++++OOOOOO..========================..................&&$$$$.. OOOOOO", +"--OO++++++++++++++++++++++++++++++OOOO++++ @@@@@@@@@@@@@@@@ ++++++++++++OO++++++++++++ @@@@@@@@@@@@@@ ++++OO++++++++ @@@@@@@@@@@@@@@@@@@@@@ ++++++++++++++++++OO++++ XXXXXXXXXXXXXX@@ ++++++OO++OOOOOO%%%%******%%%% %%******%%....++++OOOO..==============================............&&$$$$$$ OOOOOO", +"--OO++++++++++OO++OO++++++++++++OOOOOO++++ ++++++++++++++++++++++++++ ++++++OO++++++++ ++++++OO++++OO++++OOOO++++++ @@@@@@@@@@@@@@@@ ++++++++OO++OOOO..%%%%****%%%%==..........%%%%**%%.... ++++....====....============....========.................... OOOOOO", +"--OO++++++++++++++++++++++++++++OOOOOOOO++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++OO++++++++++++++++++++++++++++++++++++++++++++OO++++++++OO++++++ ++++OO++++++OO..====%%%%%%%%====..........%%%%%%%%.... ..==......==..================....======.................... OOOO", +"OO++++++++++++++OO++++++++++++++OOOOOOOO++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++OO++++++++++++++++++++++++++++++++++++++++++OO++++++++++++++++++++OOOOOOOOOOOO++++++OO++++++++..======%%%%%%==========......%%%%........ ========..========================..====.................... OOOO", +"OO++++++++++++++++++++++++++++OOOOOOOO++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++OOOOOOOOOO++++++++OO++++++..========================................ ======....========================..====.................. OOOO", +"OO++++++++++++++++++++++++++++OOOOOOOO++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++OOOO++++++++++++++++..========================................ ========..========================......==.................. OOOO", +"OO++++++++++++++++++++++++++++OOOOOO++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++..============================................ ============================....======.................... OOOO", +"++++++++++++++++++++++%%%%%%%%%%%%%%++++++++++ &&&&&& ++++++++ ++ ++++++++ ++++ ++++++++++++ ++++++++++++ ++++++++++++++++..==============================.............. ==========================================................ OOOO", +"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% &&&&&&&&&&&& %%++++ &&&&&&&&&&&&&&&&&&&&&& ++ &&&&&& ++++++++ &&&&&& ++++ &&&&&&&&&&&&&& ++++++++++ &&&&&& ++++++++++ &&&&&&&&&&&& ++++++++++++++..================================............ ========================================................ OO", +"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% &&&&&&&&&&&&&& %%%%%% &&&&&&&&&&&&&&&&&&&&&& ++ &&&&&& ++++++++ &&&&&& ++++ &&&&&&&&&&&&&&&& ++++++++ &&&&&& ++++++++ &&&&&&&&&&&&&&&& ++++++%%%%%%..================================............ ==========================================................ OO", +"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% &&&&&&&&&&&&&&&& %%%% &&&&&&&&&&&&&&&&&&&&&& %% &&&&&& %%%%++++ &&&&&& ++++ &&&&&&&&&&&&&&&&&& ++++++ &&&&&& ++++++++ &&&&&&&&&&&&&&&& %%%%%%%%%%%%..======================....====..====.......... ==========================================................ OO", +"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% &&&&&& &&&&&& %%%% &&&&&&&&&&&&&&&&&&&&&& %% &&&&&& %%%%%%%% &&&&&& %%++ &&&&&&&&&&&&&&&&&&&& ++++ &&&&&& ++%%%% &&&&&&&&&&&&&&&&&&&& %%%%%%%%%%..==========================....======.......... ============================================.............. OO", +"%%%%%%%%%%%%%%%%%%%%%%%%%%********%%%%%% &&&& %%%%%% &&&& %%%% &&&&&&&&&&&&&&&&&&&&&& %% &&&&&& %%%%%%%% &&&&&& %%%% &&&&&& &&&&&&&& %%%% &&&&&& %%%%%% &&&&&& &&&&&& %%%%%%%%%%..============================..========........ ==========================================.............. OO", +"%%%%%%%%%%****************************** &&&& %%%%%% %%%% &&&&&& %% &&&&&& %%%%%%%% &&&&&& %%%% &&&&&& %%%% &&&&&& %%%% &&&&&& %%%%%% &&&& %%%%%%%% &&&& %%%%%%%%..============================..==========.......... ============================================............ oo", +"**************************************** &&&&&& %%%%%%%%%%%%%%%%%%%%%%%% &&&&&& %%%%%%%%%% &&&&&& %%%%%%%% &&&&&& **%% &&&&&& %%%% &&&&&& %%%% &&&&&& %%**** &&&& %%%%%%%% &&&& %%%%****..============================..============........ ============================================............ oo", +"**************************************** &&&&&& %%%%%%******%%%% &&&&&& %%%%%%%%%% &&&&&& %%%%**** &&&&&& **** &&&&&& %%%% &&&&&& %%** &&&&&& ****** &&&& ******** &&&& ********..============================..============........ ============================================............ oo", +"****************************************** &&&&&&&&&&&&&& ************** &&&&&& ********** &&&&&& ******** &&&&&& **** &&&&&& **** &&&&&& **** &&&&&& ****** &&&& ******** &&&& ********..==========================================........ ============================================.............. oo", +"****************************************** &&&&&&&&&&&&&&&& ************ &&&&&& ********** &&&&&& ******** &&&&&& **** &&&&&& **** &&&&&& **** &&&&&& ****** &&&& ******** &&&& ********..============================================...... ==============================================............ oo", +"******************************************** &&&&&&&&&&&& ************ &&&&&& ********** &&&&&& ******** &&&&&& **** &&&&&& **** &&&&&& **** &&&&&& ****** &&&& ******** &&&& ********..============================================........ ==============================================............ oo", +"oooooooooooooooooooooooooooooooooooooooooooooooo &&&&&&&&&& oooooooooo &&&&&& oooooooooo &&&&&& oooooooo &&&&&& oooo &&&&&& oooo &&&&&& oooo &&&&&& oooooo &&&& oooooooo &&&& oooooooooo============================================........ ==============================================............ oo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooo &&&&&&&& oooooooooo &&&&&& oooooooooo &&&&&& oooooooo &&&&&& oooo &&&&&& oooo &&&&&& oooo &&&&&& oooooo &&&& oooooooo &&&& oooooooooooo==========================================........ ==============================================............ oo", +"oooooooooooooooooooooooooooooooooooooo oooooo &&&&&& oooooooooo &&&&&& oooooooooo &&&&&& oooooooo &&&&&& oooo &&&&&& oooo &&&&&& oooo &&&&&& oooooo &&&& oooooooo &&&& oooooooooooooooo======================================........ ==============================================............ oo", +"oooooooooooooooooooooooooooooooooooooo &&&&&& oooooo &&&&&& oooooooooo &&&&&& oooooooooo &&&&&& oooooooo &&&&&& oooo &&&&&& oooo &&&&&& oooo &&&&&& oooooo &&&& oooooooo &&&& oooooooo##oooooooo====================================........ ==============================================............ oo", +"oooooooooooooooooooooooooooooooooooooo &&&&&& oooooo &&&&&& oooooooooo &&&&&& oooooooooo &&&&&&&& &&&&&&&& oooo &&&&&& &&&&&&&& oooo &&&&&& oooooo &&&&&& &&&&&& oooooooooo##oooooooo====================================...... ==============================================............ oo", +"oooooooooooooooooooooooooooooooooooooo &&&&&&&& oooo &&&&&& oooooooooo &&&&&& oooooooooo &&&&&&&&&&&&&&&&&&&&&& oooooo &&&&&&&&&&&&&&&&&&&& oooo &&&&&& oooooo &&&&&&&&&&&&&&&&&&&& oooooooooooo##oooooooooo====================oooo========oooooooooooooo========================================.......... oooo", +"oooooooooooooooooooooooooooooooooooooooo &&&&&&&& &&&&&& oooooooooooo &&&&&& oooooooooooo &&&&&&&&&&&&&&&&&&&& oooooo &&&&&&&&&&&&&&&&&& oooooo &&&&&& oooooooo &&&&&&&&&&&&&&&& oooooooooooooooo##oooooooooo================oooooooooooooooooooooooooooooooooooooooo==============================........ oooo", +"oooooooooooooooooooooooooooooooooooooooo &&&&&&&&&&&&&&&&&& oooooooooooo &&&&&& oooooooooooo &&&&&&&&&&&&&&&&&& oooooooo &&&&&&&&&&&&&&&&&& oooooo &&&&&& oooooooo &&&&&&&&&&&&&&&& oooooooooooooooooo##oooooooooooo============oooooooooooooooooooooooooooooooooooooooooooo==========================........ oooo", +"oooooooooooooooooooooooooooooooooooooooooo &&&&&&&&&&&&&& oooooooooooooo &&&&&& oooooooooooooo &&&&&&&&&&&&&&&& oooooooo &&&&&&&&&&&&&& oooooooo &&&&&& oooooooooo &&&&&&&&&&&& oooooooooooooooooooooo####oooooooooooooooooooooooooooo##########oooooooooooooooooooooo##oooooo======================........ oooo", +"oooooooooooooooooooooooooooooooooooooo##oooo oooooooooooooooo oooooooooooooooo oooooooooo oooooooooooo oooooooooooo oooooooooooooooooooooooooooo####oooooooooooooooooooo####oooooooooooooooooooooooooooooooooo##oooooooo==================........ oo##", +"oooooooooooooooooooooooooooooooooooooooo##oooooooooooooooooooooooo##oooooooooooooooooo##oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo##oooo########oooooooooooo####oooooooooooooo##oooooooooooooooooooooooo########oooooooo##oooooooooooooooooooooooooooooooooo##oo", +"oooooooooooooooooooooooooooooooooooooooooo##oooooooooooooooooooo##oooooooooooooooooo##oooooo##oooooooooooooooooooooooooooooooooooooooooooooooooooooo########oooooooooooooooooooooooooooooooooooo##oooo##oooooooooooooooooooooooooooooooooo####oooooooooooooooo##########oooooooo######oooo##oooooooooooooooooooooooooooooo##oooo", +"oooooooooooooooooooooooooooooooooooooooooooo##############oooooo##oooo##oooooo######oooooooooo####oooooooooooooooooooo##########oooooooooooooo######oooooooo######oooooooo######oooooooooooooo##oooooo##oooooooooooooooo######oooooooo####oooooooooooooo######oooooooooooooooooooooooo####oo####oooooooooooooooooooooooo##oooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo##oooooooo######oooooooooooooooooooo########oooooooo####oooooooooooooooo########oooooooooooooooooooooooo####oooooooooooooooooooo##oooo##oooooooooooooooooooooooo########oooooooooooooooooooooooooooooooooooooooooooooooooooooooooo########oooooooooo######oooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo##oooooooooooooooooooooooooooooooooooooooooo########oooooooooooooo######oooooooooooooooooooooooooooo####oooooooooooooooooooooo##oooo##oooooooooooooooooooooooooooooooooooooooooooooo####oooooooooooooooooo######oooooooooooooooooooooooooo##########oooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooo####oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo####oooooooooooooooooooooooooooooooo##oooooooooooooooooooooo####oooooooooooooooooooooooooooooooooooooooooooooooo######oooo####oooooooooo####oooooo####oooooooooooooooooooooooooooooooooooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooo##############oooooooooooooooooooooooooooo########oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo############oooooooooooooooooooooooooooooooooooooooooooooooo####oooooooooooooo##oooooooooooooooooooooo####oooooooooooooooooooooooooooooooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo####oooooo####oooooooo####oooooooooooooooooooooooooooooooooooooooooooooooooo##########oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo##oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo######oooooooooooooooooooooooooo##########oooooooooo######oooooooooooooooooooo####oooooooooo########oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo####oooooooooooooooooooooooooooooooooooooooooooooo######oooooo####oooooooooooooo##oooooooooooooooooooooo##oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo####oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"--oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo--", +"------oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo------", +"--------oooooooooo------------oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo--------------------------oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo----------------------oooooooooooooooooooooooo----------------", +"------------------------------------oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo------------------------------------------------------------------oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo--------------------------------------------------------------------------", +"----------------------------------------------------oooooooooooooooooooooooooooooooooooooooooooooooo------------------------------------------------------------------------------------------oooooooooooooooooooooooooooooo----------------------------------------------------------------------------------------------------", +"--------------------------------------------------------------------------oooooooooooooooo--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------", +"--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------" +}; diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..0ae19bf --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,80 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include + +#include +#include + +#include "menu.h" +#include "game.h" + +QApplication *app; +char tmp[MAX_TMP]; //global temporary buffer + +static char help[]= +"QT AGI Studio v1.1.\n\ +A Sierra On-Line(tm) adventure game creator and editor.\n\ +\n\ +Usage: agistudio [switches] \n\ +\n\ +where [switches] are optionally:\n\ +\n\ +-dir GAMEDIR : open an existing game in GAMEDIR\n\ +-help : this message\n\ +\n"; + +//*************************************************** +int main( int argc, char **argv ) +{ + char *gamedir=NULL; + + tmp[0]=0; + + for(int i=1;isetMainWidget( menu ); + + game = new Game(); + + menu->show(); + + if(gamedir){ + int err = game->open(gamedir); + if(!err)menu->show_resources(); + } + return app->exec(); +} diff --git a/src/menu.cpp b/src/menu.cpp new file mode 100644 index 0000000..75eae3e --- /dev/null +++ b/src/menu.cpp @@ -0,0 +1,1173 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "menu.h" +#include "game.h" +#include "wordsedit.h" +#include "objedit.h" +#include "viewedit.h" +#include "logedit.h" +#include "resources.h" +#include "wutil.h" +#include "preview.h" +#include "picedit.h" +#include "dir.h" +#include "options.h" +#include "helpwindow.h" + +#include +#ifdef _WIN32 + #include + #include + #include + #define TEXT 6 +#else + #include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include +#ifdef IMGEXT + #include +#endif +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include + +#include "toolbar_open.xpm" +#include "toolbar_close.xpm" +#include "toolbar_run.xpm" +#include "toolbar_viewedit.xpm" +#include "toolbar_logedit.xpm" +#include "toolbar_picedit.xpm" +#include "toolbar_wordsedit.xpm" +#include "toolbar_objedit.xpm" +#include "toolbar_textedit.xpm" +#include "logo.xpm" +#include "app_icon.xpm" + +extern char tmp[]; +Menu *menu; +WindowList *window_list; +static About *about; +WinList winlist[MAXWIN]; //list of all open resource editor windows + +//************************************************* +Menu::Menu( QWidget *parent, const char *name ) + : Q3MainWindow( parent, name ) +{ + int n=0; + + setCaption("AGI Studio"); + setIcon((const char**)app_icon); + + Q3PopupMenu *new_game = new Q3PopupMenu( this ); + Q_CHECK_PTR( new_game ); + + new_game->insertItem ( "From &Template", this, SLOT(from_template()) ); + new_game->insertItem ( "&Blank", this, SLOT(blank()) ); + + Q3PopupMenu *game = new Q3PopupMenu( this ); + Q_CHECK_PTR( game ); + + game->insertItem ( "&New", new_game ); + game->insertItem ( "&Open", this, SLOT(open_game()) ); + id[n++] = game->insertItem ( "&Close", this, SLOT(close_game()) ); + id[n++] = game->insertItem ( "&Run", this, SLOT(run_game()), Qt::CTRL+Qt::Key_R ); + game->insertSeparator(); + game->insertItem ( "&Settings", this, SLOT(settings()) ); + game->insertSeparator(); + game->insertItem( "E&xit", this, SLOT(quit_cb()), Qt::CTRL+Qt::Key_Q ); + + Q3PopupMenu *resource = new Q3PopupMenu( this ); + Q_CHECK_PTR( resource ); + + id[n++] = resource->insertItem ("New window", this, SLOT(new_resource_window())); + resource->insertSeparator(); + n_res=n; + id[n++] = resource->insertItem ( "&Add", this, SLOT(add_resource()) ); + id[n++] = resource->insertItem ( "&Extract", this, SLOT(extract_resource()) ); + id[n++] = resource->insertItem ( "&Delete", this, SLOT(delete_resource()) ); + id[n++] = resource->insertItem ( "&Renumber", this, SLOT(renumber_resource()) ); + resource->insertSeparator(); + id[n++] = resource->insertItem ( "Re&build VOL files", this, SLOT(rebuild_vol()) ); + id[n++] = resource->insertItem ( "Recompile all", this, SLOT(recompile_all()) ); + + + Q3PopupMenu *tools = new Q3PopupMenu( this ); + Q_CHECK_PTR( tools ); + + id[n++] = tools->insertItem ( "&View Editor", this, SLOT(view_editor()) ); + id[n++] = tools->insertItem ( "&Logic Editor", this, SLOT(logic_editor()) ); + id[n++] = tools->insertItem ( "&Text Editor", this, SLOT(text_editor()) ); + id[n++] = tools->insertItem ( "&Object Editor", this, SLOT(object_editor()) ); + id[n++] = tools->insertItem ( "&Words.tok Editor", this, SLOT(words_editor()) ); + id[n++] = tools->insertItem ( "&Picture Editor", this, SLOT(picture_editor()) ); + id[n++] = tools->insertItem ( "&Sound Player", this, SLOT(sound_player()) ); + + Q3PopupMenu *help = new Q3PopupMenu( this ); + Q_CHECK_PTR( help ); + + help->insertItem ( "&Contents", this, SLOT(help_contents()) ); + help->insertItem ( "&Index", this, SLOT(help_index()), Qt::Key_F1); + help->insertSeparator(); + help->insertItem ( "About", this, SLOT(about_it()) ); + help->insertItem ( "About QT", this, SLOT(about_qt()) ); + + Q3PopupMenu *window = new Q3PopupMenu( this ); + Q_CHECK_PTR( window ); + + window->insertItem ( "Save all", this, SLOT(save_all()) ); + window->insertItem ( "Save all and run", this, SLOT(save_and_run()) ); + window->insertItem ( "Window list", this, SLOT(window_list_cb()) ); + + menubar = new QMenuBar(this); + Q_CHECK_PTR( menubar ); + menubar->insertItem( "&Game", game ); + menubar->insertItem( "&Resource", resource ); + menubar->insertItem( "&Tools", tools ); + menubar->insertItem( "Window", window ); + menubar->insertSeparator(); + menubar->insertItem( "&Help", help ); + menubar->setSeparator( QMenuBar::InWindowsStyle ); + + + Q3ToolBar *toolbar = new Q3ToolBar(this); + open = new QPushButton(toolbar); + open->setPixmap((const char**)toolbar_open); + connect( open, SIGNAL(clicked()), SLOT(open_game()) ); + QToolTip::add( open, "Open game" ); + + close_ = new QPushButton(toolbar); + close_->setPixmap((const char**)toolbar_close); + connect( close_, SIGNAL(clicked()), SLOT(close_game()) ); + QToolTip::add( close_, "Close game" ); + + run = new QPushButton(toolbar); + run->setPixmap((const char**)toolbar_run); + connect( run, SIGNAL(clicked()), SLOT(run_game()) ); + QToolTip::add( run, "Run game" ); + + view = new QPushButton(toolbar); + view->setPixmap((const char**)toolbar_viewedit); + connect( view, SIGNAL(clicked()), SLOT(view_editor()) ); + QToolTip::add( view, "View editor" ); + + logic = new QPushButton(toolbar); + logic->setPixmap((const char**)toolbar_logedit); + connect( logic, SIGNAL(clicked()), SLOT(logic_editor()) ); + QToolTip::add( logic, "Logic editor" ); + + text = new QPushButton(toolbar); + text->setPixmap((const char**)toolbar_textedit); + connect( text, SIGNAL(clicked()), SLOT(text_editor()) ); + QToolTip::add( text, "Text editor" ); + + obj = new QPushButton(toolbar); + obj->setPixmap((const char**)toolbar_objedit); + connect( obj, SIGNAL(clicked()), SLOT(object_editor()) ); + QToolTip::add( obj, "Object editor" ); + + words = new QPushButton(toolbar); + words->setPixmap((const char**)toolbar_wordsedit); + connect( words, SIGNAL(clicked()), SLOT(words_editor()) ); + QToolTip::add( words, "WORDS.TOK editor" ); + + pic = new QPushButton(toolbar); + pic->setPixmap((const char**)toolbar_picedit); + connect( pic, SIGNAL(clicked()), SLOT(picture_editor()) ); + QToolTip::add( pic, "Picture editor" ); + + toolbar->setMovingEnabled(false); + toolbar->setResizeEnabled(false); + toolbar->show(); + + status = new QStatusBar(this); + QLabel *msg = new QLabel( status, "message" ); + status->addWidget( msg, 4 ); + status->setSizeGripEnabled(false); + + err = new QMessageBox(NULL, "AGI Studio"); + err->setIcon(QMessageBox::Critical); + err->hide(); + + warn = new QMessageBox(NULL, "AGI Studio"); + warn->setIcon(QMessageBox::Warning); + warn->hide(); + + max_disabled = n; + disable(); + + adjustSize(); + setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed )); + setFixedSize( toolbar->sizeHint()); + + for(int i=0;ierrmes("Too many open windows !"); + return -1; + } + return n; +} + +//********************************************** +void Menu::disable() +{ + + for(int i=0;isetItemEnabled( id[i], FALSE ); + } + close_->setEnabled(false); + run->setEnabled(false); + view->setEnabled(false); + logic->setEnabled(false); + obj->setEnabled(false); + words->setEnabled(false); + pic->setEnabled(false); +} + +//********************************************** +void Menu::enable() +{ + + for(int i=0;isetItemEnabled( id[i], TRUE ); + } + close_->setEnabled(true); + run->setEnabled(true); + view->setEnabled(true); + logic->setEnabled(true); + obj->setEnabled(true); + words->setEnabled(true); + pic->setEnabled(true); +} + +//********************************************** +void Menu::open_game() +{ + OpenGameDir( 0, false ); +} + +//********************************************** +void Menu::show_resources() +{ + + if(resources_win==NULL){ + int n; + if((n=get_win())==-1)return; + resources_win = new ResourcesWin(NULL,"Resources",n); + winlist[n].type=RESOURCES; + winlist[n].w.r=resources_win; + inc_res(resources_win); + } + resources_win->select_resource_type(game->res_default); + resources_win->show(); + enable(); + + +} +//********************************************** +void Menu::inc_res(ResourcesWin *res) +{ + + num_res++; + if(num_res==1){ + resources_win=res; + enable_resources(); + } + else{ + resources_win=NULL; + disable_resources(); + } + +} +//********************************************** +void Menu::dec_res() +{ + + num_res--; + if(num_res==1){ + for(int i=0;isetItemEnabled( id[i], TRUE ); + } + + +} +//********************************************** +void Menu::disable_resources() +{ + + for(int i=n_res;isetItemEnabled( id[i], FALSE ); + } + +} + +//********************************************** +void Menu::quit_cb() +{ + + close(); + +} + +//********************************************** +void Menu::closeEvent( QCloseEvent *e ) +{ + + if(game->isOpen){ + close_game(); + if(game->isOpen){ + e->ignore(); + return; + } + } + e->accept(); + +} + +//********************************************** +void Menu::close_game() +{ + int i; + + //close all open windows (they will ask to save if something was changed) + for(i=0;iclose(); + break; + case PICTURE: + winlist[i].w.p->close(); + break; + case VIEW: + winlist[i].w.v->close(); + break; + case OBJECT: + winlist[i].w.o->close(); + break; + case WORDS: + winlist[i].w.w->close(); + break; + case TEXT: + winlist[i].w.t->close(); + break; + } + } + } + + int n; + for(i=0;i=LOGIC&&n<=TEXT) + return ; //some window was not closed + } + + + //ok to close + for(i=0;iclose(); + } + } + + if(window_list) + window_list->hide(); + disable(); + game->isOpen=false; + +} + +//********************************************** +void Menu::run_game() +{ + +#ifdef _WIN32 + int i; + _chdir(game->dir.c_str()); +#else + int i=fork(); + if(i==0){ + chdir(game->dir.c_str()); +#endif +#define MAX_ARG 32 + char *argv[MAX_ARG]; + strcpy(tmp,game->command.c_str()); + argv[0]=strtok(tmp," "); + for(i=1;icommand.c_str()); + } +#ifdef _WIN32 + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); +#else + exit(0); + } +#endif + +} +//********************************************** +int Menu::save_all() +{ + + int ret,err=0; + for(int i=0;icompile_logic(); + if(ret)err=1; + break; + case PICTURE: + winlist[i].w.p->save_to_game(); + break; + case VIEW: + winlist[i].w.v->save_to_game(); + break; + } + } + return err; + +} +//********************************************** +void Menu::save_and_run() +{ + if(!save_all()) + run_game(); + +} +//********************************************** +void Menu::window_list_cb() +{ + + if(window_list==NULL)window_list=new WindowList(); + window_list->draw(); + +} +//********************************************** +void Menu::settings() +{ + + if(options==NULL)options = new Options(); + options->show(); + +} + +//********************************************** +void Menu::from_template() +{ + menu->templ=true; + OpenGameDir( 0, true ); +} + +//********************************************** +void Menu::blank() +{ + menu->templ=false; + OpenGameDir( 0, true ); +} + +//********************************************** +void Menu::new_resource_window() +{ + + int i,n; + int sel[4]={0,0,0,0}; + + for(i=0;iselected]=1; + } + } + + if((n=get_win())==-1)return; + ResourcesWin *resources_win = new ResourcesWin(NULL,"Resources",n); + winlist[n].type=RESOURCES; + winlist[n].w.r=resources_win; + int res=game->res_default; + for(i=0;i<4;i++){ + if(sel[i]==0){ + res=i; + break; + } + } + resources_win->select_resource_type(res); + resources_win->show(); + num_res++; + if(num_res>1)disable_resources(); + +} + +//********************************************** +void Menu::add_resource() +{ + + resources_win->add_resource(); + +} + +//********************************************** +void Menu::extract_resource() +{ + + resources_win->extract_resource(); + +} + +//********************************************** +void Menu::delete_resource() +{ + + resources_win->delete_resource(); + +} + +//********************************************** +void Menu::renumber_resource() +{ + + resources_win->renumber_resource(); + +} + +//********************************************** +void Menu::rebuild_vol() +{ + + switch( QMessageBox::warning( this, "Rebuild VOL files", "Are you sure ?", + "Yes", "No", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + game->RebuildVOLfiles(); + break; + case 1: + break; + } +} + +//********************************************** +void Menu::recompile_all() +{ + + switch( QMessageBox::warning( this, "Recompile all", "Do you really want to recompile all logics ?", + "Yes", "No", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + game->RecompileAll(); + break; + case 1: + break; + } +} + +//********************************************** +void Menu::view_editor() +{ + int n; + if((n=get_win())==-1)return; + winlist[n].w.v = new ViewEdit(NULL,NULL,n,resources_win); + winlist[n].type=VIEW; + winlist[n].w.v->open(); + +} + +//********************************************** +void Menu::logic_editor() +{ + + int n; + if((n=get_win())==-1)return; + winlist[n].w.l = new LogEdit(NULL,NULL,n,resources_win); + winlist[n].type=LOGIC; + winlist[n].w.l->open(); + +} + +//********************************************** +void Menu::text_editor() +{ + + int n; + if((n=get_win())==-1)return; + winlist[n].w.t = new TextEdit(NULL,NULL,n); + winlist[n].type=TEXT; + winlist[n].w.t->new_text(); + +} + +//********************************************** +void Menu::object_editor() +{ + + int n; + if((n=get_win())==-1)return; + winlist[n].w.o = new ObjEdit(NULL,NULL,n); + winlist[n].type=OBJECT; + winlist[n].w.o->open(); + +} + +//********************************************** +void Menu::words_editor() +{ + + int n; + if((n=get_win())==-1)return; + winlist[n].w.w = new WordsEdit(NULL,NULL,n,resources_win); + winlist[n].type=WORDS; + winlist[n].w.w->open(); + +} + +//********************************************** +void Menu::picture_editor() +{ + + int n; + if((n=get_win())==-1)return; + winlist[n].w.p = new PicEdit(NULL,NULL,n,resources_win); + winlist[n].type=PICTURE; + winlist[n].w.p->open(); + +} + +//********************************************** +void Menu::sound_player() +{ + extern void play_sound (char *); + + Q3FileDialog *f = new Q3FileDialog(0,"Play sound",true); + const char *filters[] = {"sound*.*","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Play sound"); + f->setMode(Q3FileDialog::ExistingFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ){ + play_sound((char *)f->selectedFile().latin1()); + } + } + +} + +//********************************************** +void Menu::help_contents() + //from QT examples (qbrowser) +{ + sprintf(tmp,"%s/index.html",game->helpdir.c_str()); + if(helpwindow==NULL){ + int n; + if((n=get_win())==-1)return; + helpwindow = new HelpWindow(tmp,"."); + winlist[n].type=HELPWIN; + winlist[n].w.h=helpwindow; + } + else helpwindow->setSource(tmp); + helpwindow->show(); +} + +//********************************************** +bool Menu::help_topic( const QString& topic ) +{ + sprintf(tmp,"%s/%s.html",game->helpdir.c_str(), + QString(topic).replace(".", "_").latin1()); + + if ( QFile( tmp ).exists()) + { + if(helpwindow1==NULL){ + int n; + if((n=get_win())==-1) return true; + helpwindow1 = new HelpWindow(tmp,"."); + winlist[n].type=HELPWIN; + winlist[n].w.h=helpwindow1; + } + else helpwindow1->setSource(tmp); + helpwindow1->show(); + helpwindow1->raise(); + return true; + } + else + return false; +} + +//********************************************** +void Menu::help_index() +{ + sprintf(tmp,"%s/indexabc.html",game->helpdir.c_str()); + if(helpwindow1==NULL){ + int n; + if((n=get_win())==-1)return; + helpwindow1 = new HelpWindow(tmp,"."); + winlist[n].type=HELPWIN; + winlist[n].w.h=helpwindow1; + } + else helpwindow1->setSource(tmp); + helpwindow1->show(); +} + +//********************************************** +void Menu::about_it() +{ + if(about==NULL)about=new About(); + about->show(); +} + +//********************************************** +void Menu::about_qt() +{ + + QMessageBox::aboutQt( this, "AGI studio" ); + +} + +//********************************************** +void Menu::errmes(const char *caption, const char *fmt, ...) +{ + char tmp[512]; + va_list argp; + + va_start(argp, fmt); + vsprintf(tmp,fmt,argp); + va_end(argp); + + err->setText(QString(tmp)); + err->setCaption(caption); + err->adjustSize(); + err->show(); + + +} + +//************************************************* +void Menu::errmes(const char *fmt, ...) +{ + char tmp[512]; + va_list argp; + + va_start(argp, fmt); + vsprintf(tmp,fmt,argp); + va_end(argp); + + err->setText(QString(tmp)); + err->setCaption("AGI studio"); + err->adjustSize(); + err->show(); + +} + + +//********************************************** +void Menu::warnmes(const char *fmt, ...) +{ + char tmp[512]; + va_list argp; + + va_start(argp, fmt); + vsprintf(tmp,fmt,argp); + va_end(argp); + + warn->setText(QString(tmp)); + warn->setCaption("AGI studio"); + warn->adjustSize(); + warn->show(); + +} + + +//********************************************** +#ifdef IMGEXT +void Menu::load_imgext() + //QT image extensions - to handle more image formats + //currently it is only jpg and it doesn't work well anyway +{ + + qInitImageIO() ; + imgext = true; + +} +#endif + +//********************************************** + +About::About(QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + setCaption("About QT AGI Studio"); + + Q3BoxLayout *all = new Q3VBoxLayout(this,2); + + QLabel *alogo = new QLabel(this); + alogo->setPixmap(QPixmap(logo)); + alogo->setAlignment( Qt::AlignHCenter ); + alogo->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum )); + all->addWidget(alogo); + + Q3TextEdit* about = new Q3TextEdit(this); + about->setTextFormat(Qt::RichText); + about->setReadOnly(true); + about->setText( + "
    QT AGI studio v. 1.3.0
    " + "http://agistudio.sourceforge.net/
    " + "
    " + "Authors:
    " + "Helen Zommer (helen@cc.huji.ac.il)
    " + "Jarno Elonen (elonen@iki.fi)
    " + "
    " + "and also:
    " + "Peter Kelly (pmk@post.com)
    " + "Lance Ewing (lance.e@ihug.co.nz)
    " + "Claudio Matsuoka (claudio@helllabs.org)
    " + "
    " + "Windows port by:
    " + "Nat Budin (natb@brandeis.edu)" + "

    " + "This program is free software; you can " + "redistribute it and/or modify it under " + "the terms of the GNU General Public " + "License, version 2 or later, as published " + "by the Free Software Foundation."); + all->addWidget(about); + + QPushButton *ok = new QPushButton(this); + ok->setText("OK"); + ok->setMaximumSize(80,40); + connect(ok, SIGNAL(clicked()), SLOT(hide())); + all->addWidget(ok); + + +} + +//********************************************** + +WindowList::WindowList(QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + + setCaption("Window list"); + Q3BoxLayout *l = new Q3VBoxLayout(this,10); + + win = new Q3ListBox(this); + win->setColumnMode (1); + win->setMinimumSize(100,200); + connect( win, SIGNAL(selected(int)), SLOT(select_cb(int)) ); + l->add(win); + + Q3BoxLayout *l1 = new Q3HBoxLayout(l,10); + + QPushButton *select = new QPushButton(this); + select->setText("Select"); + connect( select, SIGNAL(clicked()), SLOT(select_ok()) ); + l1->addWidget(select); + QPushButton *del = new QPushButton(this); + del->setText("Delete"); + connect( del, SIGNAL(clicked()), SLOT(del_cb()) ); + l1->addWidget(del); + QPushButton *close = new QPushButton(this); + close->setText("Close list"); + connect( close, SIGNAL(clicked()), SLOT(hide()) ); + l1->addWidget(close); + + adjustSize(); + +} + +//********************************************** + +void WindowList::draw() +{ + QString caption; + + win->clear(); + for(int i=0;icaption()); + if(winlist[i].w.l->isMinimized())caption.insert(0,"(.) "); + break; + case PICTURE: + caption = winlist[i].w.p->caption(); + if(winlist[i].w.p->isMinimized())caption.insert(0,"(.) "); + break; + case VIEW: + caption = winlist[i].w.v->caption(); + if(winlist[i].w.v->isMinimized())caption.insert(0,"(.) "); + break; + case OBJECT: + caption = winlist[i].w.o->caption(); + if(winlist[i].w.o->isMinimized())caption.insert(0,"(.) "); + break; + case WORDS: + caption = winlist[i].w.w->caption(); + if(winlist[i].w.w->isMinimized())caption.insert(0,"(.) "); + break; + case TEXT: + caption = winlist[i].w.t->caption(); + if(winlist[i].w.t->isMinimized())caption.insert(0,"(.) "); + break; + case RESOURCES: + caption = winlist[i].w.r->caption(); + if(winlist[i].w.r->isMinimized())caption.insert(0,"(.) "); + break; + case HELPWIN: + caption = QString("Help"); + if(winlist[i].w.h->isMinimized())caption.insert(0,"(.) "); + else if(!winlist[i].w.h->isVisible())caption.insert(0,"(~) "); + break; + case PREVIEW: + caption = winlist[i].w.pr->caption(); + if(winlist[i].w.pr->isMinimized())caption.insert(0,"(.) "); + break; + } + win->insertItem(caption); + } + + show(); +} + +//********************************************** + +void WindowList::select_cb(int sel) +{ + QString caption; + + int n=0; + for(int i=0;iisMinimized()){ + winlist[i].w.l->showNormal(); + caption = QString("Logic editor: ").append(winlist[i].w.l->caption()); + win->changeItem(caption,sel); + } + winlist[i].w.l->setActiveWindow(); + winlist[i].w.l->raise(); + break; + case PICTURE: + if(winlist[i].w.p->isMinimized()){ + winlist[i].w.p->showNormal(); + caption = winlist[i].w.p->caption(); + win->changeItem(caption,sel); + } + winlist[i].w.p->setActiveWindow(); + winlist[i].w.p->raise(); + break; + case VIEW: + if(winlist[i].w.v->isMinimized()){ + winlist[i].w.v->showNormal(); + caption = winlist[i].w.v->caption(); + win->changeItem(caption,sel); + } + winlist[i].w.v->setActiveWindow(); + winlist[i].w.v->raise(); + break; + case TEXT: + if(winlist[i].w.t->isMinimized()){ + winlist[i].w.t->showNormal(); + caption = winlist[i].w.t->caption(); + win->changeItem(caption,sel); + } + winlist[i].w.t->setActiveWindow(); + winlist[i].w.t->raise(); + break; + case WORDS: + if(winlist[i].w.w->isMinimized()){ + winlist[i].w.w->showNormal(); + caption = winlist[i].w.w->caption(); + win->changeItem(caption,sel); + } + winlist[i].w.w->setActiveWindow(); + winlist[i].w.w->raise(); + break; + case OBJECT: + if(winlist[i].w.o->isMinimized()){ + winlist[i].w.o->showNormal(); + caption = winlist[i].w.o->caption(); + win->changeItem(caption,sel); + } + winlist[i].w.o->setActiveWindow(); + winlist[i].w.o->raise(); + break; + case RESOURCES: + if(winlist[i].w.r->isMinimized()){ + winlist[i].w.r->showNormal(); + caption = winlist[i].w.r->caption(); + win->changeItem(caption,sel); + } + winlist[i].w.r->setActiveWindow(); + winlist[i].w.r->raise(); + break; + case HELPWIN: + if(winlist[i].w.h->isMinimized()){ + winlist[i].w.h->showNormal(); + caption = QString("Help"); + win->changeItem(caption,sel); + } + else if(!winlist[i].w.h->isVisible()){ + winlist[i].w.h->show(); + caption = winlist[i].w.h->caption(); + win->changeItem(caption,sel); + } + winlist[i].w.h->setActiveWindow(); + winlist[i].w.h->raise(); + break; + case PREVIEW: + if(winlist[i].w.pr->isMinimized()){ + winlist[i].w.pr->showNormal(); + caption = winlist[i].w.pr->caption(); + win->changeItem(caption,sel); + } + winlist[i].w.pr->setActiveWindow(); + winlist[i].w.pr->raise(); + break; + } + break; + } + n++; + } + +} + +//********************************************** + +void WindowList::select_ok() +{ + if(win->currentItem()!=-1) + select_cb(win->currentItem()); + +} + +//********************************************** + +void WindowList::del_cb() +{ + + int sel = win->currentItem(); + if(sel==-1)return; + + int n=0; + for(int i=0;iclose(); + break; + case VIEW: + winlist[i].w.v->close(); + break; + case PICTURE: + winlist[i].w.p->close(); + break; + case TEXT: + winlist[i].w.t->close(); + break; + case WORDS: + winlist[i].w.w->close(); + break; + case OBJECT: + winlist[i].w.o->close(); + break; + case RESOURCES: + winlist[i].w.r->close(); + break; + case HELPWIN: + winlist[i].w.h->hide(); + break; + case PREVIEW: + winlist[i].w.pr->close(); + break; + } + break; + } + n++; + } + draw(); + +} diff --git a/src/menu.h b/src/menu.h new file mode 100644 index 0000000..cc49add --- /dev/null +++ b/src/menu.h @@ -0,0 +1,170 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef MENU_H +#define MENU_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include + +#include "wordsedit.h" +#include "objedit.h" +#include "viewedit.h" +#include "logedit.h" +#include "picedit.h" +#include "dir.h" +#include "resources.h" +#include "helpwindow.h" + +class WindowList : public QWidget +{ + + Q_OBJECT +public: + WindowList( QWidget *parent=0, const char *name=0 ); + Q3ListBox *win; +public slots: + void draw(); + void select_cb(int); + void select_ok(); + void del_cb(); +}; + + +class About: public QWidget +{ + Q_OBJECT +public: + About( QWidget *parent=0, const char *name=0); +}; + + +class Menu : public Q3MainWindow +{ + Q_OBJECT +public: + Menu( QWidget *parent=0, const char *name=0); + QStatusBar *status; + ResourcesWin *resources_win; + void errmes(const char *, const char *,...); + void errmes(const char *,...); + void warnmes(const char *,...); + + void enable(void); + void disable(void); + void show_resources(); + void enable_resources(); + void disable_resources(); + void inc_res(ResourcesWin *res); + void dec_res(); + bool templ; +#ifdef IMGEXT + bool imgext; + void load_imgext(); +#endif + public slots: + void open_game(void); + void close_game(void); + void quit_cb(void); + void run_game(void); + void settings(void); + + void from_template(void); + void blank(void); + + void add_resource(void); + void extract_resource(void); + void delete_resource(void); + void renumber_resource(void); + void rebuild_vol(void); + void recompile_all(void); + void new_resource_window(); + + void view_editor(void); + void logic_editor(void); + void text_editor(void); + void object_editor(void); + void words_editor(void); + void picture_editor(void); + void sound_player(void); + + void help_contents(void); + void help_index(void); + bool help_topic( const QString& topic ); + void about_it(void); + void about_qt(void); + void closeEvent( QCloseEvent *e ); + + int save_all(void); + void save_and_run(void); + void window_list_cb(void); +protected: + QMenuBar *menubar; + QMessageBox *err,*warn; + QPushButton *create; + Q3FileDialog *f; + QPushButton *open,*close_,*run,*view,*logic,*text,*obj,*words,*pic; + int num_res; + int n_res; + int id[24]; + int max_disabled; + +}; + +extern Menu *menu; + +typedef struct { + union { + LogEdit *l; + ViewEdit *v; + WordsEdit *w; + ObjEdit *o; + PicEdit *p; + TextEdit *t; + ResourcesWin *r; + Preview *pr; + HelpWindow *h; + }w; + int type; +}WinList; + +#define MAXWIN 64 +extern WinList winlist[MAXWIN]; +extern int get_win(); +extern WindowList *window_list; + +#endif //MENU_H + diff --git a/src/midi.cpp b/src/midi.cpp new file mode 100644 index 0000000..e5cc751 --- /dev/null +++ b/src/midi.cpp @@ -0,0 +1,306 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * Midi support, written by Jarno Elonen , 2003 + * Based on SND2MIDI 1.2 by Jens Restemeier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + #include "global.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static const char* g_gm_instrument_names[] = +{ + "1. Acoustic Grand Piano", + "2. Bright Acoustic Piano", + "3. Electric Grand Piano", + "4. Honky-tonk Piano", + "5. Electric Piano 1", + "6. Electric Piano 2", + "7. Harpsichord", + "8. Clavi", + "9. Celesta", + "10. Glockenspiel", + "11. Music Box", + "12. Vibraphone", + "13. Marimba", + "14. Xylophone", + "15. Tubular Bells", + "16. Dulcimer", + "17. Drawbar Organ", + "18. Percussive Organ", + "19. Rock Organ", + "20. Church Organ", + "21. Reed Organ", + "22. Accordion", + "23. Harmonica", + "24. Tango Accordion", + "25. Acoustic Guitar (nylon)", + "26. Acoustic Guitar (steel)", + "27. Electric Guitar (jazz)", + "28. Electric Guitar (clean)", + "29. Electric Guitar (muted)", + "30. Overdriven Guitar", + "31. Distortion Guitar", + "32. Guitar harmonics", + "33. Acoustic Bass", + "34. Electric Bass (finger)", + "35. Electric Bass (pick)", + "36. Fretless Bass", + "37. Slap Bass 1", + "38. Slap Bass 2", + "39. Synth Bass 1", + "40. Synth Bass 2", + "41. Violin", + "42. Viola", + "43. Cello", + "44. Contrabass", + "45. Tremolo Strings", + "46. Pizzicato Strings", + "47. Orchestral Harp", + "48. Timpani", + "49. String Ensemble 1", + "50. String Ensemble 2", + "51. SynthStrings 1", + "52. SynthStrings 2", + "53. Choir Aahs", + "54. Voice Oohs", + "55. Synth Voice", + "56. Orchestra Hit", + "57. Trumpet", + "58. Trombone", + "59. Tuba", + "60. Muted Trumpet", + "61. French Horn", + "62. Brass Section", + "63. SynthBrass 1", + "64. SynthBrass 2", + "65. Soprano Sax", + "66. Alto Sax", + "67. Tenor Sax", + "68. Baritone Sax", + "69. Oboe", + "70. English Horn", + "71. Bassoon", + "72. Clarinet", + "73. Piccolo", + "74. Flute", + "75. Recorder", + "76. Pan Flute", + "77. Blown Bottle", + "78. Shakuhachi", + "79. Whistle", + "80. Ocarina", + "81. Lead 1 (square)", + "82. Lead 2 (sawtooth)", + "83. Lead 3 (calliope)", + "84. Lead 4 (chiff)", + "85. Lead 5 (charang)", + "86. Lead 6 (voice)", + "87. Lead 7 (fifths)", + "88. Lead 8 (bass + lead)", + "89. Pad 1 (new age)", + "90. Pad 2 (warm)", + "91. Pad 3 (polysynth)", + "92. Pad 4 (choir)", + "93. Pad 5 (bowed)", + "94. Pad 6 (metallic)", + "95. Pad 7 (halo)", + "96. Pad 8 (sweep)", + "97. FX 1 (rain)", + "98. FX 2 (soundtrack)", + "99. FX 3 (crystal)", + "100. FX 4 (atmosphere)", + "101. FX 5 (brightness)", + "102. FX 6 (goblins)", + "103. FX 7 (echoes)", + "104. FX 8 (sci-fi)", + "105. Sitar", + "106. Banjo", + "107. Shamisen", + "108. Koto", + "109. Kalimba", + "110. Bag pipe", + "111. Fiddle", + "112. Shanai", + "113. Tinkle Bell", + "114. Agogo", + "115. Steel Drums", + "116. Woodblock", + "117. Taiko Drum", + "118. Melodic Tom", + "119. Synth Drum", + "120. Reverse Cymbal", + "121. Guitar Fret Noise", + "122. Breath Noise", + "123. Seashore", + "124. Bird Tweet", + "125. Telephone Ring", + "126. Helicopter", + "127. Applause", + "128. Gunshot", + NULL +}; + +// Write given AGI Sound resource to given QIODevice +void writeMidi(const byte* snd, QIODevice& write_to, const unsigned char instr[]) +{ + long delta_tmp; + #define WRITE_DELTA(X) \ + delta_tmp=X>>21; if (delta_tmp>0) out << Q_UINT8((delta_tmp&127)|128); \ + delta_tmp=X>>14; if (delta_tmp>0) out << Q_UINT8((delta_tmp&127)|128); \ + delta_tmp=X>>7; if (delta_tmp>0) out << Q_UINT8((delta_tmp&127)|128); \ + out << Q_UINT8(X&127) + + double ll=log10(pow(2.0,1.0/12.0)); + + if ( write_to.isSequentialAccess() || !write_to.isWritable()) + qFatal("writeMidi() requires a writable random access IODevice"); + + QDataStream out( &write_to ); + + // Header + out.writeRawBytes("MThd",4); + out << Q_UINT32(6) + << Q_UINT16(1) // mode + << Q_UINT16(3) // # of tracks + << Q_UINT16(96); // ticks / quarter + + for (int n=0;n<3;n++) + { + out.writeRawBytes("MTrk",4); + qlonglong lp = write_to.at(); + out << Q_UINT32(0); // chunklength + WRITE_DELTA(0); // set instrument + out << Q_UINT8(0xc0+n) + << Q_UINT8(instr[n]); + + unsigned short start=snd[n*2+0] | (snd[n*2+1]<<8); + unsigned short end=((snd[n*2+2] | (snd[n*2+3]<<8)))-5; + + for (unsigned short pos=start; pos0) + { + double fr; + int note; + // I don't know, what frequency equals midi note 0 ... + // This moves the song 3 octaves down: + fr=(log10(111860.0 / (double)freq) / ll)-36; + note=(int)floor(fr); + if (note<0) note=0; + if (note>127) note=127; + // note on + WRITE_DELTA(0); + out << Q_UINT8(0x90+n) + << Q_UINT8(note) + << Q_UINT8(100); + // note off + WRITE_DELTA(dur); + out << Q_UINT8(0x80+n) + << Q_UINT8(note) + << Q_UINT8(0); + } + else + { + // note on + WRITE_DELTA(0); + out << Q_UINT8(0x90+n) + << Q_UINT8(0) + << Q_UINT8(0); + // note off + WRITE_DELTA(dur); + out << Q_UINT8(0x80+n) + << Q_UINT8(0) + << Q_UINT8(0); + } + } + + WRITE_DELTA(0); + out << Q_UINT8(0xff) + << Q_UINT8(0x2f) + << Q_UINT8(0x0); + + qlonglong ep=write_to.at(); + write_to.at(lp); + out << Q_UINT32((ep-lp)-4); + write_to.at(ep); + } + + #undef WRITE_DELTA +} + +static unsigned char s_selected_instr[3] = {0,0,0}; + +// Show a "Save as" file dialog and call the Midi export function +void showSaveAsMidi( QWidget* parent, const byte* snd ) +{ + class MyFileDialog : public Q3FileDialog + { + public: + MyFileDialog( QWidget* parent, const char* name ) : + Q3FileDialog( parent, name ) + { + QLabel* label = new QLabel( "Channel instruments", this ); + label->setAlignment( AlignAuto | AlignTop | ExpandTabs ); + Q3VBox* butts = new Q3VBox(this); + butts->setSpacing ( 2 ); + for (int i=0; i<3; ++i ) + { + instr[i] = new Q3ComboBox( butts ); + instr[i]->insertStrList( g_gm_instrument_names ); + instr[i]->setCurrentItem( s_selected_instr[i] ); + } + addWidgets( label, butts, 0 ); + } + Q3ComboBox* instr[3]; + } fd( parent, NULL ); + + fd.setMode( Q3FileDialog::AnyFile ); + fd.setFilter( "MIDI files (*.mid *.midi)" ); + + if ( fd.exec() == QDialog::Accepted ) + { + QString fname = fd.selectedFile(); + if ( fname.find( '.' ) < 0 ) + fname += ".mid"; + + QFile f( fname ); + f.open( QIODevice::WriteOnly ); + + for (int i=0; i<3; ++i ) + s_selected_instr[i] = (unsigned char)fd.instr[i]->currentItem(); + + writeMidi(snd, f, s_selected_instr); + f.close(); + } +} diff --git a/src/midi.h b/src/midi.h new file mode 100644 index 0000000..297e746 --- /dev/null +++ b/src/midi.h @@ -0,0 +1,27 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef MIDI_H +#define MIDI_H + +class QWidget; +void showSaveAsMidi( QWidget* parent, const byte* snd ); + +#endif diff --git a/src/object.cpp b/src/object.cpp new file mode 100644 index 0000000..1d62588 --- /dev/null +++ b/src/object.cpp @@ -0,0 +1,194 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * Almost all of this code was adapted from the Windows AGI Studio + * developed by Peter Kelly. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "game.h" +#include "words.h" +#include "object.h" +#include "menu.h" + +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#include + +//**************************************************** +//list of inventory objects +ObjList::ObjList() +{ + +} +//**************************************************** +bool ObjList::GetItems() +{ + string ThisItemName; + int NamePos; + int CurrentItem,ItemNamesStart,ThisNameStart; + byte lsbyte,msbyte; + + CurrentItem = 0; + lsbyte = ResourceData.Data[0]; + msbyte = ResourceData.Data[1]; + ItemNamesStart = msbyte * 256 + lsbyte + 3; + MaxScreenObjects = ResourceData.Data[2]; + do{ + lsbyte = ResourceData.Data[3+CurrentItem*3]; + msbyte = ResourceData.Data[3+CurrentItem*3+1]; + ThisNameStart = (msbyte<<8)|lsbyte + 3; + RoomNum[CurrentItem] = ResourceData.Data[3+CurrentItem*3+2]; + NamePos = ThisNameStart; + if (NamePos > ResourceData.Size)return false; //object name past end of file + ThisItemName = ""; + do{ + if(ResourceData.Data[NamePos] > 0){ + ThisItemName += ResourceData.Data[NamePos]; + NamePos++; + } + }while(ResourceData.Data[NamePos] != 0 && NamePos < ResourceData.Size); + ItemNames.add(ThisItemName); + CurrentItem++; + + }while((CurrentItem+1)*3 < ItemNamesStart && CurrentItem < MaxItems); + return true; +} +//**************************************************** +void ObjList::XORData () +{ + + for(int i=0;ierrmes("Error opening file %s",filename); + return 1; + } + + struct stat buf; + fstat(fileno(fptr),&buf); + int size=buf.st_size; + if(size > MaxResourceSize){ + menu->errmes("Error: File %s is too big (>%d bytes)",filename,MaxResourceSize); + return 1; + } + + ItemNames.lfree(); + ResourceData.Size = size; + fread( ResourceData.Data, ResourceData.Size, 1, fptr); + fclose(fptr); + if (FileIsEncrypted) { + XORData(); + } + if(!GetItems()){ + XORData(); + FileIsEncrypted = !FileIsEncrypted; + if(!GetItems()){ + menu->errmes("Error! Invalid OBJECT file."); + return 1; + } + } + if (ItemNames.num == 0){ + menu->errmes("Error! 0 objects in file."); + return 1; + } + + return 0; +} + +//******************************************** +int ObjList::save(char *filename,bool FileIsEncrypted) +{ + byte lsbyte,msbyte; + int ItemNamesStart,ObjectFilePos; + int CurrentItem,CurrentChar; + FILE *fptr; + + ResourceData.Size = ItemNames.num*3 + 5; + //3 bytes for each index entry, 3 bytes for header, 2 for '?' object + for (CurrentItem = 1;CurrentItem<=ItemNames.num;CurrentItem++){ + if(ItemNames.at(CurrentItem-1) != "?") + ResourceData.Size+=ItemNames.at(CurrentItem-1).length()+1; + } + + //create data + ItemNamesStart = ItemNames.num*3 + 3; + msbyte = (ItemNamesStart-3) / 256; + lsbyte = (ItemNamesStart-3) % 256; + ResourceData.Data[0] = lsbyte; + ResourceData.Data[1] = msbyte; + ResourceData.Data[2] = MaxScreenObjects; + ResourceData.Data[3] = lsbyte; + ResourceData.Data[4] = msbyte; + ResourceData.Data[5] = 0; + ResourceData.Data[ItemNamesStart] = '?'; + ResourceData.Data[ItemNamesStart + 1] = 0; + ObjectFilePos = ItemNamesStart + 2; + for (CurrentItem = 1;CurrentItem<=ItemNames.num;CurrentItem++){ + if (ItemNames.at(CurrentItem-1) == "?"){ + ResourceData.Data[CurrentItem*3] = ResourceData.Data[0]; + ResourceData.Data[CurrentItem*3+1] = ResourceData.Data[1]; + ResourceData.Data[CurrentItem*3+2] = RoomNum[CurrentItem-1]; + } + else{ + msbyte = (ObjectFilePos-3) / 256; + lsbyte = (ObjectFilePos-3) % 256; + ResourceData.Data[CurrentItem*3] = lsbyte;; + ResourceData.Data[CurrentItem*3+1] = msbyte; + ResourceData.Data[CurrentItem*3+2] = RoomNum[CurrentItem-1]; + for (CurrentChar = 0; CurrentChar<(int)ItemNames.at(CurrentItem-1).length();CurrentChar++){ + ResourceData.Data[ObjectFilePos] = ItemNames.at(CurrentItem-1)[CurrentChar]; + ObjectFilePos++; + } + ResourceData.Data[ObjectFilePos] = 0; + ObjectFilePos++; + } + }//end create data + fptr = fopen(filename,"wb"); + if(fptr==NULL){ + menu->errmes("Error opening file %s !",filename); + return 1; + } + if(FileIsEncrypted)XORData(); + + fwrite(ResourceData.Data,ResourceData.Size,1,fptr); + fclose(fptr); + return 0; + +} + +//***************************************** +void ObjList::clear() +{ + + ItemNames.lfree(); + ItemNames.add("?"); + memset(RoomNum,0,sizeof(RoomNum)); + +} diff --git a/src/object.h b/src/object.h new file mode 100644 index 0000000..a8ebcc0 --- /dev/null +++ b/src/object.h @@ -0,0 +1,44 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef OBJECT_H +#define OBJECT_H + +#include "util.h" + +#define MaxItems 256 + +//the list of inventory objects +class ObjList +{ + public: + ObjList(); + TStringList ItemNames; + byte RoomNum[MaxItems]; + byte MaxScreenObjects; //what this is for ? + void XORData(); + int read(char *filename,bool FileIsEncrypted); + int save(char *filename,bool FileIsEncrypted); + bool GetItems(); + void clear(); +}; + + +#endif diff --git a/src/objedit.cpp b/src/objedit.cpp new file mode 100644 index 0000000..a3dd00e --- /dev/null +++ b/src/objedit.cpp @@ -0,0 +1,363 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "game.h" +#include "object.h" +#include "objedit.h" +#include "menu.h" + +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include +#include + + +//***************************************** +//Inventory object editor +ObjEdit::ObjEdit( QWidget *parent, const char *nam, int win_num) + : QWidget( parent, nam, Qt::WDestructiveClose ) +{ + + setCaption("Object Editor"); + setMinimumSize(400,400); + + winnum = win_num; + objlist = new ObjList(); + + Q3PopupMenu *file = new Q3PopupMenu( this ); + Q_CHECK_PTR( file ); + + file->insertItem( "New", this, SLOT(new_file()) ); + file->insertItem( "Open", this, SLOT(open_file()) ); + file->insertItem( "Save", this, SLOT(save_file()) ); + file->insertItem( "Save As", this, SLOT(save_as_file()) ); + file->insertSeparator(); + file->insertItem( "Close", this, SLOT(close()) ); + + options = new Q3PopupMenu( this ); + Q_CHECK_PTR( options ); + encrypted = options->insertItem( "Encrypted", this, SLOT(encrypted_cb()) ); + options->setItemChecked(encrypted,true); + + QMenuBar *menu = new QMenuBar(this); + Q_CHECK_PTR( menu ); + menu->insertItem( "File", file ); + menu->insertItem( "Options", options ); + menu->setSeparator( QMenuBar::InWindowsStyle ); + + Q3BoxLayout *all = new Q3VBoxLayout(this,14); + all->setMenuBar(menu); + + list = new Q3ListBox(this); + list->setMinimumSize(400,400); + list->setColumnMode (1); + + connect( list, SIGNAL(highlighted(int)), SLOT(select_object(int)) ); + connect( list, SIGNAL(selected(int)), SLOT(select_object(int)) ); + all->addWidget(list); + + name = new QLineEdit(this); + connect( name, SIGNAL(returnPressed()), SLOT(name_cb()) ); + all->addWidget(name); + + Q3BoxLayout *down = new Q3HBoxLayout(all,4); + + add = new QPushButton("&Add",this); + connect( add, SIGNAL(clicked()), SLOT(add_cb()) ); + down->addWidget(add); + del = new QPushButton("&Delete",this); + connect( del, SIGNAL(clicked()), SLOT(del_cb()) ); + down->addWidget(del); + + QLabel *label = new QLabel("Room no:",this); + down->addWidget(label); + + num = new QLineEdit(this); + connect( num, SIGNAL(returnPressed()), SLOT(num_cb()) ); + down->addWidget(num); + + left = new QPushButton("<",this); + connect( left, SIGNAL(clicked()), SLOT(left_cb()) ); + down->addWidget(left); + right = new QPushButton(">",this); + connect( right, SIGNAL(clicked()), SLOT(right_cb()) ); + down->addWidget(right); + + adjustSize(); + + filename = ""; + changed=false; +} + +//***************************************** +void ObjEdit::open() +{ + + sprintf(tmp,"%s/object",game->dir.c_str()); + open(tmp); + show(); + +} + +//***************************************** +void ObjEdit::deinit() +{ + delete objlist; + winlist[winnum].type=-1; + if(window_list && window_list->isVisible())window_list->draw(); +} + + +//********************************************* +void ObjEdit::hideEvent( QHideEvent * ) +{ + + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//********************************************* +void ObjEdit::showEvent( QShowEvent * ) +{ + + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//***************************************** +void ObjEdit::closeEvent( QCloseEvent *e ) +{ + + if(changed){ + switch ( QMessageBox::warning( this, "ObjEdit", + "Save changes to OBJECT file ?", + "Yes", + "No", + "Cancel", + 0, 2) ) { + case 0: // yes + save_file(); + deinit(); + e->accept(); + break; + case 1: // no + deinit(); + e->accept(); + break; + default: // cancel + e->ignore(); + break; + } + } + else{ + deinit(); + e->accept(); + } + +} + +//***************************************** +void ObjEdit::open(char *name) +{ + int ret = objlist->read(name,false); + if(ret)return; + + filename = name; + + list->clear(); + for(int i=0;iItemNames.num;i++){ + sprintf(tmp,"%d. %s",i,objlist->ItemNames.at(i).c_str()); + list->insertItem(tmp); + } + list->show(); + list->setCurrentItem(0); + changed=false; + +} + +//***************************************** +void ObjEdit::open_file() +{ + + Q3FileDialog *f = new Q3FileDialog(0,"Open",true); + const char *filters[] = {"object","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Open"); + f->setMode(Q3FileDialog::ExistingFile); + f->setDir(game->dir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ) + open((char *)f->selectedFile().latin1()); + } +} + +//***************************************** +void ObjEdit::save_file() +{ + if(filename==""){ + save_as_file(); + } + else{ + objlist->save((char *)filename.c_str(),options->isItemChecked(encrypted)); + changed=false; + } +} + +//***************************************** +void ObjEdit::save_as_file() +{ + + Q3FileDialog *f = new Q3FileDialog(0,"Save",true); + const char *filters[] = {"object","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Save"); + f->setMode(Q3FileDialog::AnyFile); + f->setDir(game->dir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ){ + objlist->save((char *)f->selectedFile().latin1(),options->isItemChecked(encrypted)); + changed=false; + } + } +} + +//***************************************** +void ObjEdit::new_file() +{ + + objlist->clear(); + CurObject = 0; + list->clear(); + list->insertItem("0. ?"); + list->setCurrentItem(CurObject); + changed=false; +} + +//***************************************** +void ObjEdit::select_object(int n) +{ + name->setText(objlist->ItemNames.at(n).c_str()); + sprintf(tmp,"%d",objlist->RoomNum[n]); + num->setText(tmp); + CurObject = n; +} + +//***************************************** +void ObjEdit::add_cb() +{ + + objlist->ItemNames.add("?"); + CurObject = objlist->ItemNames.num-1; + objlist->RoomNum[CurObject]=0; + sprintf(tmp,"%d. ?",CurObject); + list->insertItem(tmp); + list->setCurrentItem(CurObject); + changed=true; + +} + +//***************************************** +void ObjEdit::del_cb() +{ + + objlist->ItemNames.replace(CurObject,"?"); + sprintf(tmp,"%d. ?",CurObject); + list->changeItem(tmp,CurObject); + changed=true; +} + +//***************************************** +void ObjEdit::left_cb() +{ + + if(objlist->RoomNum[CurObject]>0){ + objlist->RoomNum[CurObject]--; + sprintf(tmp,"%d",objlist->RoomNum[CurObject]); + num->setText(tmp); + changed=true; + } + +} + +//***************************************** +void ObjEdit::right_cb() +{ + + if(objlist->RoomNum[CurObject]<255){ + objlist->RoomNum[CurObject]++; + sprintf(tmp,"%d",objlist->RoomNum[CurObject]); + num->setText(tmp); + changed=true; + } + +} + +//***************************************** +void ObjEdit::num_cb() +{ + + char *str = (char *)num->text().latin1(); + int k = atoi(str); + if(!strcmp(str,"0") || (k>0&&k<256) ){ + objlist->RoomNum[CurObject] = k; + changed=true; + } + else{ + sprintf(tmp,"%d",objlist->RoomNum[CurObject]); + num->setText(tmp); + } +} + +//***************************************** +void ObjEdit::name_cb() +{ + + char *str = (char *)name->text().latin1(); + objlist->ItemNames.replace(CurObject,str); + sprintf(tmp,"%d. %s",CurObject,str); + list->changeItem(tmp,CurObject); + changed=true; +} + +//***************************************** +void ObjEdit::encrypted_cb() +{ + + options->setItemChecked(encrypted,!options->isItemChecked(encrypted)); + +} +//***************************************** diff --git a/src/objedit.h b/src/objedit.h new file mode 100644 index 0000000..2647bb1 --- /dev/null +++ b/src/objedit.h @@ -0,0 +1,81 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef OBJEDIT_H +#define OBJEDIT_H + +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include + +#include "util.h" +#include "object.h" + +//inventory objects editor +class ObjEdit : public QWidget +{ + Q_OBJECT +public: + ObjEdit( QWidget *parent=0, const char *name=0, int winnum=0); + void open(); +public slots: + void open_file(); + void save_file(); + void save_as_file(); + void new_file(); + void select_object(int); + void add_cb(); + void del_cb(); + void left_cb(); + void right_cb(); + void num_cb(); + void name_cb(); + void encrypted_cb(); + protected: + int winnum; + Q3ListBox *list; + QLineEdit *name,*num; + QPushButton *add,*del,*left,*right; + Q3PopupMenu *options; + int encrypted; + int CurObject; + bool changed; + string filename; + ObjList *objlist; + + void open(char *); + void save(char *); + void deinit(); + void closeEvent( QCloseEvent *e ); + void showEvent( QShowEvent * ); + void hideEvent( QHideEvent * ); +}; + +#endif diff --git a/src/options.cpp b/src/options.cpp new file mode 100644 index 0000000..81b36f8 --- /dev/null +++ b/src/options.cpp @@ -0,0 +1,297 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "options.h" +#include "game.h" + +#include + +#include +#include +//Added by qt3to4: +#include +#include +#include +#include + +Options *options; + +//*********************************************** +Options::Options( QWidget *parent, const char *name) + : Q3TabDialog( parent, name) +{ + + setCaption("Settings"); + + set_general(); + set_directories(); + set_logedit(); + set_interpreter(); + + connect( this, SIGNAL( applyButtonPressed() ), SLOT( apply() ) ); + setDefaultButton(); + connect( this, SIGNAL( defaultButtonPressed() ), SLOT( defaults() ) ); + setCancelButton(); + set_settings(); + +} + +//*********************************************** +void Options::set_general() +{ + + QWidget *general = new QWidget(this); + Q3BoxLayout *all = new Q3VBoxLayout(general,10); + + Q3GroupBox *b1 = new Q3GroupBox(2,Horizontal,"",general); + + QLabel *l = new QLabel("Default resource type",b1); + l->setText("Default resource type"); //to avoid compilation warning + + type = new QComboBox(false,b1,"type"); + type->insertItem( "LOGIC" ); + type->insertItem( "PICTURE" ); + type->insertItem( "VIEW" ); + type->insertItem( "SOUND" ); + + QLabel *l2 = new QLabel("Picedit style",b1); + l2->setText("Picedit style"); //to avoid compilation warning + + picstyle = new QComboBox(false,b1,"picstyle"); + picstyle->insertItem( "One window" ); + picstyle->insertItem( "Two windows" ); + + all->addWidget(b1); + + Q3ButtonGroup *extract = new Q3ButtonGroup(2,Horizontal,"Extract logic as",general); + extract->setMaximumSize(200,100); + extract->setExclusive(true); + text = new QRadioButton("Text",extract); + binary = new QRadioButton("Binary",extract); + + all->addWidget(extract); + + + addTab(general,"General"); + +} + +//*********************************************** +void Options::set_logedit() +{ + + QWidget *logedit = new QWidget(this); + + Q3BoxLayout *all = new Q3VBoxLayout(logedit,10); + messages = new QCheckBox("Show all messages at end (not just unused ones)",logedit); + all->addWidget(messages); + elses = new QCheckBox("Show all elses as gotos",logedit); + all->addWidget(elses); + special = new QCheckBox("Show special syntax (e.g. v30=4)",logedit); + all->addWidget(special); + addTab(logedit,"Logic editor"); + +} + +//*********************************************** +void Options::set_directories() +{ + + QWidget *dirs = new QWidget(this); + Q3BoxLayout *all = new Q3VBoxLayout(dirs,10); + Q3GroupBox *src = new Q3GroupBox(3,Horizontal,"Logic source directory",dirs); + reldir = new QRadioButton("[Game_dir/]",src); + connect(reldir,SIGNAL(clicked()),SLOT(set_reldir())); + relname = new QLineEdit(src); + + QLabel *l = new QLabel(" ",src); //dummy label to keep table alignment + l->setText(" "); //to avoid compilation warning + + absdir = new QRadioButton("Full path",src); + connect(absdir,SIGNAL(clicked()),SLOT(set_absdir())); + absname = new QLineEdit(src); + QPushButton *browse = new QPushButton("Browse",src); + connect(browse,SIGNAL(clicked()),SLOT(browse_abs())); + + all->addWidget(src); + + Q3BoxLayout *b1 = new Q3HBoxLayout(all); + + QLabel *lt = new QLabel("Template:",dirs); + b1->addWidget(lt); + + templatedir = new QLineEdit(dirs); + b1->addWidget(templatedir); + + QPushButton *browse1 = new QPushButton("Browse",dirs); + b1->addWidget(browse1); + connect(browse1,SIGNAL(clicked()),SLOT(browse_template())); + + Q3BoxLayout *b2 = new Q3HBoxLayout(all); + + QLabel *lh = new QLabel("Help:",dirs); + b2->addWidget(lh); + + helpdir = new QLineEdit(dirs); + b2->addWidget(helpdir); + + QPushButton *browse2 = new QPushButton("Browse",dirs); + b2->addWidget(browse2); + connect(browse2,SIGNAL(clicked()),SLOT(browse_help())); + + addTab(dirs,"Directories"); +} + +//*********************************************** +void Options::set_interpreter() +{ + + QWidget *interp = new QWidget(this); + Q3BoxLayout *all = new Q3VBoxLayout(interp,10); + QLabel *l = new QLabel("Interpreter command line:\n(will be invoked with the\ncurrent directory == game_directory)",interp); + all->addWidget(l); + + Q3BoxLayout *b1 = new Q3HBoxLayout(all); + command = new QLineEdit(interp); + b1->addWidget(command); + + QPushButton *browse = new QPushButton("Browse",interp); + browse->setMaximumSize(80,60); + connect(browse,SIGNAL(clicked()),SLOT(browse_interpreter())); + b1->addWidget(browse); + + addTab(interp,"Interpreter"); + +} + +//*********************************************** +void Options::apply() +{ + + game->res_default=type->currentItem(); + game->save_logic_as_text=text->isChecked(); + game->show_all_messages=messages->isChecked(); + game->show_elses_as_gotos=elses->isChecked(); + game->show_special_syntax=special->isChecked(); + game->reldir=reldir->isChecked(); + game->command=string((char *)command->text().latin1()); + if(game->reldir){ + game->srcdirname=string((char *)relname->text().latin1()); + } + else{ + game->srcdirname=string((char *)absname->text().latin1()); + } + game->templatedir=string((char *)templatedir->text().latin1()); + game->helpdir=string((char *)helpdir->text().latin1()); + game->picstyle=picstyle->currentItem(); + game->save_settings(); + hide(); + +} + +//*********************************************** +void Options::defaults() +{ + + game->defaults(); + set_settings(); + +} + +//*********************************************** +void Options::set_settings() +{ + + type->setCurrentItem(game->res_default); + text->setChecked(game->save_logic_as_text); + messages->setChecked(game->show_all_messages); + elses->setChecked(game->show_elses_as_gotos); + special->setChecked(game->show_special_syntax); + reldir->setChecked(game->reldir); + absdir->setChecked(!(game->reldir)); + command->setText(game->command.c_str()); + if(game->reldir){ + relname->setText(game->srcdirname.c_str()); + absname->clear(); + } + else{ + absname->setText(game->srcdirname.c_str()); + relname->clear(); + } + templatedir->setText(game->templatedir.c_str()); + helpdir->setText(game->helpdir.c_str()); + picstyle->setCurrentItem(game->picstyle); +} + +//*********************************************** +void Options::browse_abs() +{ + + QString s (Q3FileDialog::getExistingDirectory ()); + if(s.isNull())return; + absname->setText(s); + +} + +//*********************************************** +void Options::browse_template() +{ + + QString s (Q3FileDialog::getExistingDirectory ()); + if(s.isNull())return; + templatedir->setText(s); + +} + +//*********************************************** +void Options::browse_help() +{ + + QString s (Q3FileDialog::getExistingDirectory ()); + if(s.isNull())return; + helpdir->setText(s); + +} + +//*********************************************** +void Options::browse_interpreter() +{ + + QString s (Q3FileDialog::getOpenFileName ()); + if(s.isNull())return; + command->setText(s); + +} + +//*********************************************** +void Options::set_reldir() +{ + absdir->setChecked(false); + +} + +//*********************************************** +void Options::set_absdir() +{ + reldir->setChecked(false); + +} + +//*********************************************** diff --git a/src/options.h b/src/options.h new file mode 100644 index 0000000..dbe4f56 --- /dev/null +++ b/src/options.h @@ -0,0 +1,83 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef OPTIONS_H +#define OPTIONS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "wutil.h" +#include "view.h" + + + + +class Options : public Q3TabDialog +{ + Q_OBJECT +public: + Options( QWidget *parent=0, const char *name=0); + QComboBox *type,/* *style,*/ *picstyle; + QCheckBox *messages,*elses,*special; + QRadioButton *text,*binary; + QLineEdit *relname,*absname; + QRadioButton *reldir,*absdir; + QLineEdit *command,*templatedir,*helpdir; + +public slots: + void set_general(); + void set_logedit(); + void set_directories(); + void set_interpreter(); + void set_settings(); + + void apply(); + void defaults(); + + void browse_abs(); + void browse_template(); + void browse_help(); + void browse_interpreter(); + + void set_reldir(); + void set_absdir(); +}; + + +extern Options *options; +extern char tmp[]; + +#endif diff --git a/src/picedit.cpp b/src/picedit.cpp new file mode 100644 index 0000000..78b29e8 --- /dev/null +++ b/src/picedit.cpp @@ -0,0 +1,1490 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "game.h" +#include "menu.h" +#include "wutil.h" +#include "picture.h" +#include "preview.h" + +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "left1_x.xpm" +#include "left2_x.xpm" +#include "right1_x.xpm" +#include "right2_x.xpm" +#include "zoom_minus_x.xpm" +#include "zoom_plus_x.xpm" + +static const char *comment[]={ + "pic colour", //0xf0 + "pic off", //0xf1 + "pri colour",//0xf2 + "pri off", //0xf3, + "Y corner", //0xf4, + "X corner", //0xf5, + "abs line", //0xf6, + "rel line", //0xf7, + "fill", //0xf8, + "pattern", //0xf9, + "brush", //0xfa, + " ", //0xfb, + " ", //0xfc, + " ", //0xfd, + " ", //0xfe, + "end", //0xff + }; + +static const char *colname[]={ + "black", + "blue", + "green", + "cyan", + "red", + "magenta", + "brown", + "white", + "gray", + "lightblue", + "lightgreen", + "lightcyan", + "lightred", + "lightmagenta", + "yellow", + "brightwhite" +}; + + +//*************************************** +PicEdit::PicEdit( QWidget *parent, const char *name,int win_num,ResourcesWin *res ) + : QWidget( parent, name, Qt::WDestructiveClose) +{ + setCaption("Picture Editor"); + + winnum = win_num; + resources_win = res; + picture = new Picture(); + + Q3PopupMenu *file = new Q3PopupMenu( this ); + Q_CHECK_PTR( file ); + file->insertItem( "New", this, SLOT(open()) ); + file->insertItem( "Load from file", this, SLOT(open_file()) ); + file->insertItem( "Save to game", this, SLOT(save_to_game()) ); + file->insertItem( "Save to game as...", this, SLOT(save_to_game_as()) ); + file->insertItem( "Save to file", this, SLOT(save_file()) ); + file->insertSeparator(); + file->insertItem( "Delete", this, SLOT(delete_picture()) ); + file->insertSeparator(); + file->insertItem( "Close", this, SLOT(close()) ); + + Q3PopupMenu *util = new Q3PopupMenu( this ); + Q_CHECK_PTR( util ); + util->insertItem("View data", this, SLOT(view_data()) ); + util->insertItem("Background", this, SLOT(background()) ); + + Q3PopupMenu *help = new Q3PopupMenu( this ); + Q_CHECK_PTR( help ); + help->insertItem( "Help on picture editor", this, SLOT(editor_help()) ); + + QMenuBar *menu = new QMenuBar(this); + Q_CHECK_PTR( menu ); + menu->insertItem( "File", file ); + menu->insertItem( "Utilities", util ); + menu->insertItem( "Help", help ); + menu->setSeparator( QMenuBar::InWindowsStyle ); + + Q3BoxLayout *all = new Q3HBoxLayout(this,10); + all->setMenuBar(menu); + + Q3BoxLayout *leftb = new Q3VBoxLayout(all,10); + + tool = new Q3ButtonGroup(5,Qt::Horizontal,0,this); + line = new QRadioButton("Line",tool); + line->setChecked(false); + // line->setFocusPolicy(ClickFocus); + pen = new QRadioButton("Pen",tool); + pen->setChecked(false); + // pen->setFocusPolicy(ClickFocus); + step = new QRadioButton("Step",tool); + step->setChecked(false); + // step->setFocusPolicy(ClickFocus); + fill = new QRadioButton("Fill",tool); + fill->setChecked(false); + // fill->setFocusPolicy(ClickFocus); + brush = new QRadioButton("Brush",tool); + brush->setChecked(false); + // brush->setFocusPolicy(ClickFocus); + connect(tool, SIGNAL(clicked(int)), SLOT(change_tool(int)) ); + + + leftb->addWidget(tool); + + Q3BoxLayout *b1 = new Q3HBoxLayout(leftb,10); + + palette = new Palette1(this,0,this); + palette->setMinimumSize(250,40); + palette->setMaximumSize(350,80); + b1->addWidget(palette); + + Q3BoxLayout *b2 = new Q3HBoxLayout(leftb,10); + + Q3ButtonGroup *shape = new Q3ButtonGroup(2,Qt::Vertical,"Shape",this); + QRadioButton *circle = new QRadioButton("Circle",shape); + circle->setChecked(true); + // circle->setFocusPolicy(ClickFocus); + QRadioButton *square = new QRadioButton("Square",shape); + square->setChecked(false); + // square->setFocusPolicy(ClickFocus); + b2->addWidget(shape); + connect(shape, SIGNAL(clicked(int)), SLOT(change_shape(int)) ); + + Q3ButtonGroup *type = new Q3ButtonGroup(2,Qt::Vertical,"Type",this); + QRadioButton *spray = new QRadioButton("Spray",type); + spray->setChecked(true); + // spray->setFocusPolicy(ClickFocus); + QRadioButton *solid = new QRadioButton("Solid",type); + solid->setChecked(false); + // solid->setFocusPolicy(ClickFocus); + b2->addWidget(type); + connect(type, SIGNAL(clicked(int)), SLOT(change_type(int)) ); + + Q3GroupBox *lsize = new Q3GroupBox(1,Qt::Vertical,this); + lsize->setTitle("Size"); + lsize->setMargin(4); + b2->addWidget(lsize); + + QSpinBox *size = new QSpinBox(1,7,1,lsize); + size->setValue(1); + // size->setFocusPolicy(ClickFocus); + connect(size, SIGNAL(valueChanged(int)), SLOT(change_size(int)) ); + + Q3BoxLayout *b3 = new Q3HBoxLayout(leftb,1); + + QPushButton *home = new QPushButton(this); + home->setPixmap(QPixmap(left2_x)); + // home->setFocusPolicy(ClickFocus); + connect(home, SIGNAL(clicked()), SLOT(home_cb()) ); + b3->addWidget(home); + QPushButton *left = new QPushButton(this); + //left->setFocusPolicy(ClickFocus); + left->setPixmap(QPixmap(left1_x)); + connect(left, SIGNAL(clicked()), SLOT(left_cb()) ); + b3->addWidget(left); + pos = new QLineEdit(this); + pos->setMinimumWidth(64); + //pos->setFocusPolicy(ClickFocus); + connect( pos, SIGNAL(returnPressed()), SLOT(set_pos()) ); + b3->addWidget(pos); + QPushButton *right = new QPushButton(this); + //right->setFocusPolicy(ClickFocus); + connect(right, SIGNAL(clicked()), SLOT(right_cb()) ); + right->setPixmap(QPixmap(right1_x)); + b3->addWidget(right); + QPushButton *end = new QPushButton(this); + //end->setFocusPolicy(ClickFocus); + connect(end, SIGNAL(clicked()), SLOT(end_cb()) ); + end->setPixmap(QPixmap(right2_x)); + b3->addWidget(end); + QPushButton *del = new QPushButton("Del",this); + //del->setFocusPolicy(ClickFocus); + connect(del, SIGNAL(clicked()), SLOT(del_cb()) ); + b3->addWidget(del); + QPushButton *wipe = new QPushButton("Wipe",this); + //wipe->setFocusPolicy(ClickFocus); + connect(wipe, SIGNAL(clicked()), SLOT(wipe_cb()) ); + b3->addWidget(wipe); + + Q3BoxLayout *b31 = new Q3HBoxLayout(leftb,4); + + codeline = new QLineEdit(this); + codeline->setFocusPolicy(Qt::NoFocus); + b31->addWidget(codeline); + + comments = new QLineEdit(this); + comments->setFocusPolicy(Qt::NoFocus); + b31->addWidget(comments); + + Q3BoxLayout *b4 = new Q3HBoxLayout(leftb,2); + + QPushButton *zoom_minus = new QPushButton(this); + zoom_minus->setPixmap(QPixmap(zoom_minus_x)); + zoom_minus->setFixedSize(32,32); + //zoom_minus->setFocusPolicy(ClickFocus); + connect( zoom_minus, SIGNAL(clicked()), SLOT(zoom_minus()) ); + b4->addWidget(zoom_minus); + + QPushButton *zoom_plus = new QPushButton(this); + zoom_plus->setPixmap(QPixmap(zoom_plus_x)); + zoom_plus->setFixedSize(32,32); + //zoom_plus->setFocusPolicy(ClickFocus); + connect( zoom_plus, SIGNAL(clicked()), SLOT(zoom_plus()) ); + b4->addWidget(zoom_plus); + + Q3ButtonGroup *drawmode = new Q3ButtonGroup(2,Qt::Vertical,"Show",this); + pic = new QRadioButton("Visual",drawmode); + pic->setChecked(true); + pri_mode=false; + picture->set_mode(0); + pri = new QRadioButton("Priority",drawmode); + bg = new QCheckBox("Background",drawmode); + prilines = new QCheckBox("PriorityLines",drawmode); + connect( drawmode, SIGNAL(clicked(int)), SLOT(change_drawmode(int)) ); + drawmode->setExclusive(false); + b4->addWidget(drawmode); + + status = new QStatusBar(this); + QLabel *msg = new QLabel( status, "message" ); + status->addWidget( msg, 4 ); + pricolor = new Q3Frame( status ); + pricolor->setMinimumSize( 8,8 ); + pricolor->setMaximumSize( 8,8 ); + QToolTip::add( pricolor, "Priority 'color' required to mask an EGO on this priority level" ); + status->addWidget( pricolor, 0, true ); + status->setSizeGripEnabled( false ); + leftb->addWidget(status); + + if(game->picstyle==P_TWO){ + canvas = new PCanvas(0,0,this); + canvas->setMinimumSize(canvas->pixsize*MAX_W+canvas->x0+10,canvas->pixsize*MAX_HH+canvas->x0+10); + canvas->resizeContents(canvas->pixsize*MAX_W+canvas->x0,canvas->pixsize*MAX_HH+canvas->x0); + canvas->resize(canvas->pixsize*MAX_W+canvas->x0,canvas->pixsize*MAX_HH+canvas->x0); + //canvas->setFocusPolicy(ClickFocus); + + } + else{ + canvas = new PCanvas(this,0,this); + canvas->setMinimumSize(canvas->pixsize*MAX_W+canvas->x0+10,canvas->pixsize*MAX_HH+canvas->x0+10); + canvas->resizeContents(canvas->pixsize*MAX_W+canvas->x0,canvas->pixsize*MAX_HH+canvas->x0); + all->addWidget(canvas,1); + //canvas->setFocusPolicy(ClickFocus); + setFocusProxy(canvas); + } + + + changed = false; + adjustSize(); + viewdata = NULL; + closing = false; + +} +//********************************************* +void PicEdit::save(char *filename) +{ + picture->save(filename); + changed = false; + +} + +//********************************************* +void PicEdit::open_file() +{ + Q3FileDialog *f = new Q3FileDialog(0,"Open",true); + const char *filters[] = {"picture*.*","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Open picture"); + f->setMode(Q3FileDialog::ExistingFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ) + open((char *)f->selectedFile().latin1()); + } + +} + +//********************************************* +void PicEdit::open(int ResNum) +{ + if(picture->open(ResNum))return; + PicNum = ResNum; + sprintf(tmp,"Picture editor: picture.%d",PicNum); + setCaption(tmp); + if(canvas->isTopLevel()) + canvas->setCaption(tmp); + canvas->update(); + show_pos(); + changed=false; + show(); + canvas->show(); + update_palette(); + update_tools(); +} + +//********************************************* +void PicEdit::open(char *filename) +{ + if(picture->open(filename))return; + PicNum = -1; + sprintf(tmp,"Picture editor"); + setCaption(tmp); + if(canvas->isTopLevel()) + canvas->setCaption(tmp); + canvas->update(); + show_pos(); + changed=false; + show(); + canvas->show(); + update_palette(); + update_tools(); +} + +//********************************************* +void PicEdit::save_file() +{ + Q3FileDialog *f = new Q3FileDialog(0,"Save",true); + const char *filters[] = {"picture*.*","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Save picture"); + f->setMode(Q3FileDialog::AnyFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ) + save((char *)f->selectedFile().latin1()); + } +} + +//********************************************* +void PicEdit::deinit() +{ + if(viewdata){ + viewdata->close(true); + viewdata=NULL; + } + if(canvas->isTopLevel()){ + closing=true; + canvas->close(true); + } + delete picture; + winlist[winnum].type=-1; + if(window_list && window_list->isVisible())window_list->draw(); + +} +//********************************************* +void PicEdit::showEvent( QShowEvent * ) +{ + showing=true; + if(canvas->isTopLevel() && !canvas->isVisible()){ + canvas->showNormal(); + } + showing=false; + if(window_list && window_list->isVisible())window_list->draw(); + + +} +//********************************************* +void PicEdit::hideEvent( QHideEvent * ) +{ + hiding=true; + if(isMinimized() && canvas->isTopLevel() && canvas->isVisible()){ + canvas->showMinimized(); + } + hiding=false; + if(viewdata){ + viewdata->close(true); + viewdata=NULL; + } + if(window_list && window_list->isVisible())window_list->draw(); + + +} +//********************************************* +void PicEdit::closeEvent( QCloseEvent *e ) +{ + if(changed){ + if(PicNum != -1){ + sprintf(tmp,"Save changes to picture.%d ?",PicNum); + } + else{ + sprintf(tmp,"Save changes to picture ?"); + } + strcat(tmp,"\n(picture will be saved to game)"); + + switch ( QMessageBox::warning( this, "Picture editor", + tmp, + "Yes", + "No", + "Cancel", + 0, 2) ) { + case 0: // yes + save_to_game(); + deinit(); + e->accept(); + break; + case 1: // no + deinit(); + e->accept(); + break; + default: // cancel + e->ignore(); + break; + } + } + else{ + deinit(); + e->accept(); + } + +} + +//********************************************* +void PicEdit::save_to_game() +{ + if(PicNum != -1){ + picture->save(PicNum); + if(resources_win){ + if(resources_win->preview==NULL)resources_win->preview=new Preview(); + resources_win->preview->open(PicNum,PICTURE); + } + changed=false; + } + else + save_to_game_as(); + +} + +//********************************************* +void PicEdit::save_to_game_as() +{ + AskNumber *picture_number = new AskNumber(0,0,"Picture number","Enter picture number: [0-255]"); + + if(!picture_number->exec())return; + + QString str = picture_number->num->text(); + int num = atoi((char *)str.latin1()); + + if(num<0||num>255){ + menu->errmes("Picture number must be between 0 and 255 !"); + return ; + } + if(game->ResourceInfo[PICTURE][num].Exists){ + sprintf(tmp,"Resource picture.%d already exists. Replace it ?",num); + + switch( QMessageBox::warning( this, "Picture", tmp, + "Replace", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + picture->save(num); + PicNum = num; + if(resources_win){ + if(resources_win->preview==NULL)resources_win->preview=new Preview(); + resources_win->preview->open(PicNum,PICTURE); + } + changed=false; + break; + case 1: + break; + } + } + else{ + picture->save(num); + changed=false; + PicNum = num; + if(resources_win){ + resources_win->select_resource_type(PICTURE); + resources_win->set_current(num); + } + open(num); + } + +} + +//********************************************* +void PicEdit::delete_picture() +{ + int k; + if(PicNum==-1)return; + sprintf(tmp,"Really delete picture %d ?",PicNum); + switch( QMessageBox::warning( this, "Picture", tmp, + "Delete", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + game->DeleteResource(PICTURE,PicNum); + if(resources_win){ + k = resources_win->list->currentItem(); + resources_win->select_resource_type(PICTURE); + resources_win->list->setCurrentItem(k); + } + break; + case 1: + break; + } + +} + +//********************************************* +void PicEdit::open() +{ + picture->newpic(); + show_pos(); + if(canvas->isTopLevel()) + canvas->setCaption("picture"); + canvas->update(); + show(); + canvas->show(); + update_palette(); + update_tools(); +} + +//********************************************* +void PicEdit::view_data() +{ + if(viewdata==NULL)viewdata=new ViewData(0,0,picture); + if(PicNum!=-1){ + sprintf(tmp,"View data: picture %d",PicNum); + viewdata->setCaption(tmp); + } + else viewdata->setCaption("View data: picture"); + viewdata->read(); + +} + +//********************************************* +void PicEdit::background() +{ + + Q3FileDialog *f = new Q3FileDialog(0,"Load background image",true); + const char *filters[] = {"All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Load background image"); + f->setMode(Q3FileDialog::ExistingFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ) + canvas->load_bg((char *)f->selectedFile().latin1()); + } + +} + +//********************************************* +void PicEdit::zoom_minus() +{ + + if(canvas->pixsize>1){ + canvas->setPixsize(canvas->pixsize-1); + int w,h; + w = canvas->cur_w+4; + h = canvas->cur_h+4; + canvas->resizeContents(w,h); + } + +} + +//********************************************* +void PicEdit::zoom_plus() +{ + + if(canvas->pixsize<4){ + canvas->setPixsize(canvas->pixsize+1); + int w,h; + w = canvas->cur_w+4; + h = canvas->cur_h+4; + canvas->resizeContents(w,h); + } + +} + +//********************************************* +void PicEdit::change_drawmode(int mode) +{ + + switch(mode){ + case 0: //draw visual + pri_mode=false; + picture->set_mode(0); + pri->setChecked(false); + pic->setChecked(true); + break; + case 1: //draw priority + pri_mode=true; + picture->set_mode(1); + pic->setChecked(false); + pri->setChecked(true); + break; + case 2: //draw (also) background + canvas->bg_on=bg->isChecked(); + if(canvas->bg_on && canvas->bg_loaded) + picture->bg_on=true; + else + picture->bg_on=false; + break; + case 3: //priority lines + canvas->pri_lines=prilines->isChecked(); + break; + } + canvas->linedraw=false; + canvas->update(); + +} + +//********************************************* +void PicEdit::change_tool(int k) +{ + if(canvas->linedraw)canvas->line(false); + picture->tool_proc(k); +} + +//********************************************* +void PicEdit::change_size(int k) +{ + picture->set_brush(0,k); + +} + +//********************************************* +void PicEdit::change_shape(int k) +{ + picture->set_brush(1,k); + +} + +//********************************************* +void PicEdit::change_type(int k) +{ + picture->set_brush(2,k); + +} + +//********************************************* +void PicEdit::show_pos() + //show current picture buffer position +{ + char *t; + int code=0,val=-1; + sprintf(tmp,"%5d",picture->bufPos); + pos->setText(tmp); + t=picture->showPos(&code,&val); + codeline->setText(t); + if(code>=0xf0&&code<=0xff){ //action: can add comments + if(code==0xf0||code==0xf2){ //add color name + sprintf(tmp,"%s %s",comment[code-0xf0],colname[val]); + comments->setText(tmp); + } + else{ + comments->setText(comment[code-0xf0]); + } + } + else comments->clear(); + +} + +//********************************************* +void PicEdit::home_cb() + //set picture buffer position to start +{ + picture->home_proc(); + canvas->update(); + show_pos(); + update_palette(); + update_tools(); +} + +//********************************************* +void PicEdit::end_cb() + //set picture buffer position to end +{ + picture->end_proc(); + canvas->update(); + show_pos(); + update_palette(); + update_tools(); +} + +//********************************************* +void PicEdit::left_cb() + //set picture buffer position to the previous action +{ + picture->left_proc(); + canvas->update(); + show_pos(); + update_palette(); + update_tools(); +} + +//********************************************* +void PicEdit::right_cb() + //set picture buffer position to the next action +{ + + picture->right_proc(); + canvas->update(); + show_pos(); + update_palette(); + update_tools(); +} + +//********************************************* +void PicEdit::del_cb() + //delete action from the picture buffer position +{ + + picture->del_proc(); + canvas->update(); + show_pos(); + update_palette(); + update_tools(); +} + +//********************************************* +void PicEdit::wipe_cb() + //delete all action from the picture buffer position to the end +{ + + picture->wipe_proc(); + canvas->update(); + show_pos(); + update_palette(); + update_tools(); +} + +//********************************************* +void PicEdit::set_pos() + //set picture buffer position +{ + QString str=pos->text(); + char *s = (char *)str.latin1(); + int num = atoi(s); + if(num!=0 || s[0]=='0'){ + if(!picture->setBufPos(num)){ + canvas->update(); + } + } + show_pos(); + update_palette(); + update_tools(); + pos->clearFocus(); + setFocus(); + return; + +} +//********************************************* +void PicEdit::update_tools() +{ + + switch(picture->tool){ + case T_LINE: + if(!line->isChecked())line->setChecked(true); + break; + case T_STEP: + if(!step->isChecked())step->setChecked(true); + break; + case T_PEN: + if(!pen->isChecked())pen->setChecked(true); + break; + case T_FILL: + if(!fill->isChecked())fill->setChecked(true); + break; + case T_BRUSH: + if(!brush->isChecked())brush->setChecked(true); + break; + default: + QRadioButton *b = (QRadioButton *)tool->selected(); + if(b)b->setChecked(false); + } + +} +//********************************************* +void PicEdit::update_palette() +{ + bool ch=false; + if(!picture->picDrawEnabled && palette->left!=-1){ + palette->left=-1; + ch=true; + } + if(picture->picDrawEnabled && palette->left!=picture->picColour){ + palette->left=picture->picColour; + ch=true; + } + if(!picture->priDrawEnabled && palette->right!=-1){ + palette->right=-1; + ch=true; + } + if(picture->priDrawEnabled && palette->right!=picture->priColour){ + palette->right=picture->priColour; + ch=true; + } + + if(ch)palette->update(); + + +} +//********************************************* +bool PicEdit::focusNextPrevChild ( bool ) +{ + canvas->setFocus(); + return true; + +} + +//************************************************ +void PicEdit::editor_help() +{ + menu->help_topic("picture_editor_main"); +} + +//************************************************ + +PCanvas::PCanvas ( QWidget *parent, const char *name, PicEdit *w) + : Q3ScrollView( parent, name ) + //the area to draw picture +{ + + picedit = w; + picture = picedit->picture; + pixsize=2; + x0=5;y0=5; + cur_w=MAX_W*pixsize; + cur_h=MAX_HH*pixsize; + pixmap = QPixmap(cur_w,cur_h); + viewport()->setMouseTracking(true); + bg_loaded=false; + bg_on=false; + pri_lines=false; + bgpix = QImage(); +} + +//********************************************* +void PCanvas::setSize(int w,int h) +{ + if(cur_w != w || cur_h != h){ + pixmap.resize(w*pixsize*2,h*pixsize); + cur_w=w; + cur_h=h; + } +} + +//********************************************* +void PCanvas::setPixsize(int s) +{ + + pixsize=s; + cur_w=MAX_W*pixsize; + cur_h=MAX_HH*pixsize; + pixmap.resize(cur_w,cur_h); + QPainter p(&pixmap); + p.eraseRect(0,0,cur_w,cur_h); + update(); + +} +//********************************************* +void PCanvas::viewportMousePressEvent(QMouseEvent* event) +{ + int x,y,xx,yy; + + viewportToContents( event->x(), event->y(), x, y ); + xx=x; + yy=y; + x-=x0; + y-=y0; + + x/=pixsize; + y/=pixsize; + + if(x<0)x=0; + else if(x>=MAX_W)x=MAX_W-1; + if(y<0)y=0; + else if(y>=MAX_HH)y=MAX_HH-1; + + if (event->button() & Qt::LeftButton){ + if(picture->button_action(x,y)) + picedit->show_pos(); + } + else if (event->button() & Qt::RightButton){ + /* + QRadioButton *b = (QRadioButton *)picedit->tool->selected(); + if(b!=0)b->setChecked(false); + picture->clear_tools(); + picture->tool = -1; + */ + picture->init_tool(); + } + update(); + picedit->changed=true; +} + +//********************************************* +void PCanvas::viewportMouseMoveEvent(QMouseEvent* event) +{ + int x,y,xx,yy; + + viewportToContents( event->x(), event->y(), x, y ); + xx=x; + yy=y; + + x-=x0; + y-=y0; + + x/=pixsize; + y/=pixsize; + + if(x<0)x=0; + else if(x>=MAX_W)x=MAX_W-1; + if(y<0)y=0; + else if(y>=MAX_HH)y=MAX_HH-1; + + x1=x; + y1=y; + + // printf("mouse move: %d %d (%d %d)\n",x,y,xx,yy); + + if(picture->move_action(x,y)) + line(true); + + if(x>=0&&y>=0){ + int pri = y/12+1; + sprintf(tmp,"X=%d Y=%d Pri=%d",x/2,y,pri); + picedit->status->message(tmp); + picedit->pricolor->setPaletteBackgroundColor( egacolor[pri+1] ); + } + +} + +//********************************************* +void PCanvas::drawContents(QPainter* p,int ,int ,int ,int ) +{ + + if(cur_w==0 ||cur_h==0)return; + + p->drawPixmap( x0, y0, pixmap ); + +} + +//********************************************* +void PCanvas::update() +{ + + QPainter p(&pixmap); + int x,y; + byte c; + byte *data; + + data = (picedit->pri_mode)?picture->priority:picture->picture; + if(bg_loaded && bg_on){ //if must draw background + bool pic = !picedit->pri_mode; + for(y=0;ycurp; + + if(picture->bg_on){ + //with background - must redraw the line containing background pixels + //(x-pixels are not doubled !) + for(i=0;in;i++){ + p.fillRect(curp->p[i].x*pixsize,curp->p[i].y*pixsize, + pixsize,pixsize,curp->p[i].cc); + + } + } + else{ + //no background - just restore the agi image + for(i=0;in;i++){ + c=curp->p[i].c; + p.fillRect(curp->p[i].x*2*pixsize,curp->p[i].y*pixsize, + pixsize*2,pixsize,egacolor[c]); + + } + } + + if(mode==true){ + linedraw=true; + newp = picture->newp; + //draw the 'new' line + for(int i=0;in;i++){ + c=newp->p[i].c; + p.fillRect(newp->p[i].x*2*pixsize,newp->p[i].y*pixsize, + pixsize*2,pixsize,egacolor[c]); + + } + } + else{ + linedraw=false; + } + +#if 0 + //find the max rectangle to repaint + if(curp->n){ + if(picture->bg_on){ + x00=curp->p[0].x; + y00=curp->p[0].y; + x11=curp->p[curp->n-1].x; + y11=curp->p[curp->n-1].y; + } + else{ + x00=curp->p[0].x*2; + y00=curp->p[0].y; + x11=curp->p[curp->n-1].x*2; + y11=curp->p[curp->n-1].y; + } + if(newp){ + x0_=newp->p[0].x*2; + y0_=newp->p[0].y; + x1=newp->p[newp->n-1].x*2; + y1=newp->p[newp->n-1].y; + + X0=(MIN(MIN(x00,x0_),MIN(x11,x1)))*pixsize; + Y0=(MIN(MIN(y00,y0_),MIN(y11,y1)))*pixsize; + X1=(MAX(MAX(x00,x0_),MAX(x11,x1)))*pixsize; + Y1=(MAX(MAX(y00,y0_),MAX(y11,y1)))*pixsize; + } + else{ + X0=(MIN(x00,x11))*pixsize; + Y0=(MIN(y00,y11))*pixsize; + X1=(MAX(x00,x11))*pixsize; + Y1=(MAX(y00,y11))*pixsize; + } + } + else{ + + x0_=newp->p[0].x*2*pixsize; + y0_=newp->p[0].y*pixsize; + x1=newp->p[newp->n-1].x*2*pixsize; + y1=newp->p[newp->n-1].y*pixsize; + X0=MIN(x0_,x1); + Y0=MIN(y0_,y1); + X1=MAX(x0_,x1); + Y1=MAX(y0_,y1); + + } +#endif + repaintContents(x0,y0,x0+MAX_W*pixsize,y0+MAX_HH*pixsize,false); + +} +//********************************************* +void PCanvas::keyPressEvent( QKeyEvent *k ) +{ + switch(k->key()){ + case Qt::Key_L: + case Qt::Key_F1: + picedit->line->setChecked(true); + picedit->change_tool(T_LINE); + break; + case Qt::Key_P: + case Qt::Key_F2: + picedit->pen->setChecked(true); + picedit->change_tool(T_PEN); + break; + case Qt::Key_S: + case Qt::Key_F3: + picedit->step->setChecked(true); + picedit->change_tool(T_STEP); + break; + case Qt::Key_F: + case Qt::Key_F4: + picedit->fill->setChecked(true); + picedit->change_tool(T_FILL); + break; + case Qt::Key_B: + case Qt::Key_F5: + picedit->brush->setChecked(true); + picedit->change_tool(T_BRUSH); + break; + case Qt::Key_Tab: + picedit->pri_mode=!picedit->pri_mode; + picedit->change_drawmode(picedit->pri_mode?1:0); + break; + case Qt::Key_Home: + picedit->home_cb(); + break; + case Qt::Key_End: + picedit->end_cb(); + break; + case Qt::Key_Right: + picedit->right_cb(); + break; + case Qt::Key_Left: + picedit->left_cb(); + break; + case Qt::Key_Delete: + picedit->del_cb(); + break; + case Qt::Key_F10: + if(picedit->bg->isChecked())picedit->bg->setChecked(false); + else picedit->bg->setChecked(true); + picedit->change_drawmode(2); + break; + + default: + k->ignore(); + break; + } + +} +//********************************************* +bool PCanvas::focusNextPrevChild ( bool ) +{ + + setFocus(); + return false; + +} +//***************************************** +void PCanvas::load_bg(char *filename) +{ + + if(!bgpix.load(filename)){ //loads all formats supported by QT +#ifdef IMGEXT + //if can't load - try image extensions + //(currently only jpeg; loads with colors all wrong) + if(!menu->imgext){ + menu->load_imgext(); + if(!bgpix.load(filename)){ + menu->errmes("Can't open file %s !",filename); + return; + } + } + else{ + menu->errmes("Can't open file %s !",filename); + return; + } +#else + menu->errmes("Can't open file %s !",filename); + return; +#endif + } + bg_loaded=true; + + picture->bgpix=&bgpix; + picedit->bg->setChecked(true); + bg_on=true; + picture->bg_on=true; + update(); + +} + +//********************************************* +void PCanvas::showEvent( QShowEvent * ) +{ + + if(isTopLevel() && !picedit->isVisible() && !picedit->showing){ + picedit->showNormal(); + } + if(window_list && window_list->isVisible())window_list->draw(); + +} +//********************************************* +void PCanvas::hideEvent( QHideEvent * ) +{ + + if(isTopLevel() && picedit->isVisible() && !picedit->hiding){ + picedit->showMinimized(); + } + +} +//********************************************* +void PCanvas::closeEvent( QCloseEvent *e ) +{ + + if(picedit->closing){ + e->accept(); + return; + } + picedit->closing=true; + if(isTopLevel()){ + picedit->close(); + e->ignore(); + } + +} +/*******************************************************/ +Palette1::Palette1( QWidget *parent, const char *name , PicEdit *p) + : QWidget( parent, name ) +{ + + left=right=-1; + picedit = p; + +} + +//***************************************** +void Palette1::paintEvent( QPaintEvent * ) + //draw palette with the currently selected colors marked 'V' (visual) and 'P' (priority) +{ + QPainter p(this); + int w,h,x,y,dx,dy,i; + + w = this->width(); + h = this->height(); + dx=w/9; + dy=h/2; + w=dx*9; + h=dy*2; + + for(y=0,i=0;ywidth(); + h = this->height(); + dx=w/9; + dy=h/2; + w=dx*9; + h=dy*2; + + x=event->x()/dx; + y=event->y()/dy; + + if(x>=8){ //choose "off" + i=-1; + } + else{ //choose color + i=y*8+x; + } + + if (event->button() & Qt::LeftButton){ + if(left != i){ + left = i; + picedit->picture->choose_color(M_LEFT,i); + repaint(); + } + } + else if (event->button() & Qt::RightButton){ + if(right != i){ + right = i; + picedit->picture->choose_color(M_RIGHT,i); + repaint(); + } + } + +} + +//************************************************ +ViewData::ViewData( QWidget *parent, const char *name,Picture *p ) + : QWidget( parent, name) + //view picture codes +{ + + picture = p; + Q3BoxLayout *all = new Q3VBoxLayout(this,20); + codes = new Q3MultiLineEdit(this); + codes->setMinimumSize(300,200); + codes->setReadOnly(true); + all->addWidget(codes); + + Q3BoxLayout *b = new Q3HBoxLayout(all,20); + Q3BoxLayout *left = new Q3VBoxLayout(b,20); + comments = new QCheckBox("Show comments",this); + connect(comments, SIGNAL(clicked()), SLOT(read())); + left->addWidget(comments); + wrap = new QCheckBox("Line wrap",this); + connect(wrap, SIGNAL(clicked()), SLOT(read())); + left->addWidget(wrap); + + Q3BoxLayout *right = new Q3VBoxLayout(b,20); + QPushButton *close = new QPushButton("Close",this); + close->setMaximumSize(80,60); + connect(close, SIGNAL(clicked()), SLOT(close())); + right->addWidget(close); + QLabel *dummy = new QLabel(" ",this); + right->addWidget(dummy); + + data.lfree(); + +} + +//************************************************ +void ViewData::resizeEvent( QResizeEvent * ) +{ + + QString str = codes->text(); + getmaxcol(); + codes->setText(str); +} + +//************************************************ +void ViewData::getmaxcol() +{ + + QFontMetrics f = fontMetrics(); + maxcol = codes->width()/f.width('a'); + +} + +//************************************************ +void ViewData::read() +{ + char *str; + bool comm = comments->isChecked(); + bool wr = wrap->isChecked(); + int c,cc,i,k,len; + char *ptr,*ptr0; + bool first; + + codes->setUpdatesEnabled(false); //to speed up repaint + + picture->viewData(&data); + getmaxcol(); + + codes->clear(); + for(i=0;i=maxcol)||k+6>=maxcol){ + len=(int)(ptr-ptr0); + strncat(tmp,ptr0,len); + tmp[len]=0; + codes->insertLine(tmp,-1); + strcpy(tmp," "); + first=false; + ptr0=ptr; + k=0; + } + else k+=3; + } + strcat(tmp,ptr0); + if(comm){ //add comments (action and color when applicable) + sscanf(str,"%x %x",&c,&cc); + strcat(tmp," //"); + strcat(tmp,comment[c-0xf0]); + if(c==0xf0||c==0xf2){ + strcat(tmp," "); + strcat(tmp,colname[cc]); + } + } + codes->insertLine(tmp,-1); + } + else{ + if(comm){ //add comments (action and color when applicable) + sscanf(str,"%x %x",&c,&cc); + sprintf(tmp,"%s //%s",str,comment[c-0xf0]); + if(c==0xf0||c==0xf2){ + strcat(tmp," "); + strcat(tmp,colname[cc]); + } + codes->insertLine(tmp,-1); + } + else codes->insertLine(str,-1); + } + } + codes->setUpdatesEnabled(true); + codes->update(); + show(); +} + +//************************************************ + diff --git a/src/picedit.h b/src/picedit.h new file mode 100644 index 0000000..18b0714 --- /dev/null +++ b/src/picedit.h @@ -0,0 +1,192 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef PICEDIT_H +#define PICEDIT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "wutil.h" +#include "picture.h" +#include "resources.h" + +class PicEdit; + +class Palette1 : public QWidget +{ + Q_OBJECT +public: + Palette1( QWidget *parent=0, const char *name=0, PicEdit *w=0); + int left,right; + protected: + PicEdit *picedit; + + void paintEvent(class QPaintEvent *); + void mousePressEvent(QMouseEvent* event); +}; + +//************************************************ +class PCanvas : public Q3ScrollView +{ + Q_OBJECT +public: + PCanvas( QWidget *parent=0, const char *name=0, PicEdit *w=0); + int pixsize; + int cur_w,cur_h; + bool bg_loaded,bg_on; + bool linedraw; + bool pri_lines; + int x0,y0,x1,y1; + void line(bool mode); + void load_bg(char *filename); + void draw(int ResNum); + void update(); + void setSize(int w,int h); + void setPixsize(int pixsize); + protected: + int CurColor; + Picture *picture; + QPixmap pixmap; + QImage bgpix; + PicEdit *picedit; + void closeEvent( QCloseEvent *e ); + void showEvent( QShowEvent *); + void hideEvent( QHideEvent *); + void keyPressEvent( QKeyEvent * ); + void viewportMousePressEvent(QMouseEvent* e); + void viewportMouseMoveEvent(QMouseEvent* e); + void drawContents ( QPainter * p, int clipx, int clipy, int clipw, int cliph ) ; + bool focusNextPrevChild ( bool next ) ; +}; + +//************************************************ +class ViewData: public QWidget +{ + Q_OBJECT +public: + ViewData( QWidget *parent=0, const char *name=0,Picture *p=0); +public slots: + void read(); + protected: + QCheckBox *comments,*wrap; + Q3MultiLineEdit *codes; + TStringList data; + Picture *picture; + int maxcol; + + void getmaxcol(); + void resizeEvent( QResizeEvent * ); + void KeyPressEvent( QKeyEvent * ); +}; + +//************************************************ +class PicEdit : public QWidget +{ + Q_OBJECT +public: + PicEdit( QWidget *parent=0, const char *name=0,int winnum=0,ResourcesWin *res=0); + void open(int ResNum); + Picture *picture; + Q3ButtonGroup *tool; + QRadioButton *line,*step,*pen,*fill,*brush; + QRadioButton *pic,*pri; + QStatusBar *status; + QWidget *pricolor; + QCheckBox *bg,*prilines; + ResourcesWin *resources_win; + bool changed; + bool closing,hiding,showing; + int pri_mode; +public slots: + void open(); + void open_file(); + void save_file(); + void save_to_game(); + void save_to_game_as(); + void delete_picture(); + + void view_data(); + void background(); + + void zoom_minus(); + void zoom_plus(); + + void change_drawmode(int); + void change_tool(int); + void change_size(int); + void change_shape(int); + void change_type(int); + + void home_cb(); + void end_cb(); + void left_cb(); + void right_cb(); + void del_cb(); + void wipe_cb(); + + void set_pos(); + void show_pos(); + + void editor_help(); + + protected: + int PicNum; + int winnum; + PCanvas *canvas; + Palette1 *palette; + QLineEdit *pos,*codeline,*comments; + ViewData *viewdata; + void open(char *filename); + void save(char *filename); + void deinit(); + void closeEvent( QCloseEvent *e ); + void showEvent( QShowEvent *); + void hideEvent( QHideEvent *); + void update_palette(); + void update_tools(); + bool focusNextPrevChild ( bool next ) ; +}; + + +#endif + + diff --git a/src/picture.cpp b/src/picture.cpp new file mode 100644 index 0000000..18bfee2 --- /dev/null +++ b/src/picture.cpp @@ -0,0 +1,1562 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * A big part of this code is adapted from the original (MSDOS) + * Picedit developed by Lance Ewing. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#ifndef _WIN32 +#include +#endif +#include + +#include "linklist.h" +#include "picture.h" +#include "menu.h" + + +static bool picDrawEnabled0,priDrawEnabled0; +static int picColour0,priColour0; + +//********************************************************* +Picture::Picture() +{ + picPos=picStart=picLast=NULL; + this->freeList(); + bg_on = false; +} + +//********************************************************* +char *Picture::showPos(int *code,int *val) + //show current picture buffer position +{ + char tmp1[6]; + tmp[0]=0; + struct picCodeNode *temp; + int count; + + if(picPos){ + *code=picPos->node; + if(picPos->next){ + *val=picPos->next->node; + } + } + for (temp=picPos, count=0; ((count<6)&&(temp!=NULL)); count++, temp=temp->next) { + sprintf(tmp1, "%02X", temp->node); + strcat(tmp,tmp1); + } + return tmp; +} + +//********************************************************* +int Picture::setBufPos(int inputValue) + //set current picture buffer position to inputValue +{ + + if ((inputValue < 0) || (inputValue > bufLen)) return 1; + + if (inputValue == bufLen) { + picPos = NULL; + bufPos = inputValue; + } + else{ + /* Find given location */ + while (bufPos != inputValue) { + if (inputValue < bufPos) { + if (picPos == NULL) + picPos = picLast; + else + picPos = picPos->prior; + bufPos--; + } + else { + picPos = picPos->next; + bufPos++; + } + } + + /* Find current action position */ + while (picPos->node < 0xF0) { + picPos = picPos->prior; + bufPos--; + } + } + draw(); + init_tool(); + return 0; + +} + +//********************************************************* +void Picture::qstore(byte q) +{ + if (spos+1==rpos || (spos+1==QUMAX && !rpos)) { + return; + } + buf[spos] = q; + spos++; + if (spos==QUMAX) spos = 0; /* loop back */ +} +//********************************************************* +byte Picture::qretrieve() +{ + if (rpos==QUMAX) rpos=0; /* loop back */ + if (rpos==spos) { + return EMPTY; + } + rpos++; + return buf[rpos-1]; +} + +/************************************************************************** +** getCode +** +** Gets the next picture code from the linked list. +**************************************************************************/ +byte Picture::getCode(struct picCodeNode **temp) +{ + byte retVal; + + if (*temp == NULL) return 0xFF; + + retVal = (*temp)->node; + *temp = (*temp)->next; + + return retVal; +} + + +byte Picture::testCode(struct picCodeNode **temp) +{ + byte retVal; + + if (*temp == NULL) return 0xFF; + + retVal = (*temp)->node; + + return retVal; +} + + +/************************************************************************** +** picPSet +** +** Draws a pixel in the picture screen. +**************************************************************************/ +void Picture::picPSet(word x, word y) +{ + + x<<=1; + if (x >= MAX_W) return; + if (y >= MAX_H) return; + + picture[y*MAX_W+x] = picColour; + picture[y*MAX_W+x+1] = picColour; + +} + +/************************************************************************** +** priPSet +** +** Draws a pixel in the priority screen. +**************************************************************************/ +void Picture::priPSet(word x, word y) +{ + + x<<=1; + if (x >= MAX_W) return; + if (y >= MAX_H) return; + priority[y*MAX_W+x] = priColour; + priority[y*MAX_W+x+1] = priColour; + +} + +/************************************************************************** +** pset +** +** Draws a pixel in each screen depending on whether drawing in that +** screen is enabled or not. +**************************************************************************/ +void Picture::pset(word x, word y) +{ + if (picDrawEnabled) picPSet(x, y); + if (priDrawEnabled) priPSet(x, y); +} + +/************************************************************************** +** picGetPixel +** +** Get colour at x,y on the picture page. +**************************************************************************/ +byte Picture::picGetPixel(word x, word y) +{ + + x <<= 1; + if (x >= MAX_W) return 4; + if (y >= MAX_H) return 4; + + return (picture[y*MAX_W+x]); +} + +/************************************************************************** +** priGetPixel +** +** Get colour at x,y on the priority page. +**************************************************************************/ +byte Picture::priGetPixel(word x, word y) +{ + + x <<= 1; + if (x >= MAX_W) return 4; + if (y >= MAX_H) return 4; + + return (priority[y*MAX_W+x]); + +} + +/************************************************************************** +** round +** +** Rounds a float to the closest int. Takes into actions which direction +** the current line is being drawn when it has a 50:50 decision about +** where to put a pixel. +**************************************************************************/ +int Picture::round(float aNumber, float dirn) +{ + if (dirn < 0) + return ((aNumber - floor(aNumber) <= 0.501)? (int)floor(aNumber) : (int)ceil(aNumber)); + return ((aNumber - floor(aNumber) < 0.499)? (int)floor(aNumber) : (int)ceil(aNumber)); +} + +/************************************************************************** +** drawline +** +** Draws an AGI line. +**************************************************************************/ +void Picture::drawline(word x1, word y1, word x2, word y2) +{ + int height, width; + float x, y, addX, addY; + + height = (y2 - y1); + width = (x2 - x1); + addX = (height==0?height:(float)width/abs(height)); + addY = (width==0?width:(float)height/abs(width)); + + if (abs(width) > abs(height)) { + y = y1; + addX = (width == 0? 0 : (width/abs(width))); + for (x=x1; x!=x2; x+=addX) { + pset(round(x, addX), round(y, addY)); + y+=addY; + } + pset(x2,y2); + } + else { + x = x1; + addY = (height == 0? 0 : (height/abs(height))); + for (y=y1; y!=y2; y+=addY) { + pset(round(x, addX), round(y, addY)); + x+=addX; + } + pset(x2,y2); + } + +} + +/************************************************************************** +** okToFill +**************************************************************************/ +bool Picture::okToFill(byte x, byte y) +{ + if (!picDrawEnabled && !priDrawEnabled) return false; + if (picColour == 15) return false; + if (!priDrawEnabled) return (picGetPixel(x, y) == 15); + if (priDrawEnabled && !picDrawEnabled) return (priGetPixel(x, y) == 4); + return (picGetPixel(x, y) == 15); +} + +/************************************************************************** +** agiFill +**************************************************************************/ +void Picture::agiFill(word x, word y) +{ + byte x1, y1; + rpos = spos = 0; + + qstore(x); + qstore(y); + + for (;;) { + + x1 = qretrieve(); + y1 = qretrieve(); + + if ((x1 == EMPTY) || (y1 == EMPTY)) + break; + else { + + if (okToFill(x1,y1)) { + + pset(x1, y1); + + if (okToFill(x1, y1-1) && (y1!=0)) { + qstore(x1); + qstore(y1-1); + } + if (okToFill(x1-1, y1) && (x1!=0)) { + qstore(x1-1); + qstore(y1); + } + if (okToFill(x1+1, y1) && (x1!=159)) { + qstore(x1+1); + qstore(y1); + } + if (okToFill(x1, y1+1) && (y1!=167)) { + qstore(x1); + qstore(y1+1); + } + + } + + } + + } + +} + +/************************************************************************** +** xCorner +** +** Draws an xCorner (drawing action 0xF5) +**************************************************************************/ +void Picture::xCorner(struct picCodeNode **temp) +{ + byte x1, x2, y1, y2; + + x1 = getCode(temp); + y1 = getCode(temp); + + pset(x1,y1); + + for (;;) { + x2 = getCode(temp); + if (x2 >= 0xF0) break; + drawline(x1, y1, x2, y1); + x1 = x2; + y2 = getCode(temp); + if (y2 >= 0xF0) break; + drawline(x1, y1, x1, y2); + y1 = y2; + } + + if (*temp == NULL) *temp = NULL; + else *temp = (*temp)->prior; +} + +/************************************************************************** +** yCorner +** +** Draws an yCorner (drawing action 0xF4) +**************************************************************************/ +void Picture::yCorner(struct picCodeNode **temp) +{ + byte x1, x2, y1, y2; + + x1 = getCode(temp); + y1 = getCode(temp); + + pset(x1, y1); + + for (;;) { + y2 = getCode(temp); + if (y2 >= 0xF0) break; + drawline(x1, y1, x1, y2); + y1 = y2; + x2 = getCode(temp); + if (x2 >= 0xF0) break; + drawline(x1, y1, x2, y1); + x1 = x2; + } + + if (*temp == NULL) *temp = NULL; + else *temp = (*temp)->prior; +} + +/************************************************************************** +** relativeDraw +** +** Draws short lines relative to last position. (drawing action 0xF7) +**************************************************************************/ +void Picture::relativeDraw(struct picCodeNode **temp) +{ + byte x1, y1, disp; + char dx, dy; + + x1 = getCode(temp); + y1 = getCode(temp); + + pset(x1, y1); + + for (;;) { + disp = getCode(temp); + if (disp >= 0xF0) break; + dx = ((disp & 0xF0) >> 4) & 0x0F; + dy = (disp & 0x0F); + if (dx & 0x08) dx = (-1)*(dx & 0x07); + if (dy & 0x08) dy = (-1)*(dy & 0x07); + drawline(x1, y1, x1 + dx, y1 + dy); + x1 += dx; + y1 += dy; + } + + if (*temp == NULL) *temp = NULL; + else *temp = (*temp)->prior; +} + +/************************************************************************** +** fill +** +** Agi flood fill. (drawing action 0xF8) +**************************************************************************/ +void Picture::fill(struct picCodeNode **temp) +{ + byte x1, y1; + + for (;;) { + if ((x1 = getCode(temp)) >= 0xF0) break; + if ((y1 = getCode(temp)) >= 0xF0) break; + agiFill(x1, y1); + } + + if (*temp == NULL) *temp = NULL; + else *temp = (*temp)->prior; +} + +/************************************************************************** +** absoluteLine +** +** Draws long lines to actual locations (cf. relative) (drawing action 0xF6) +**************************************************************************/ +void Picture::absoluteLine(struct picCodeNode **temp) +{ + byte x1, y1, x2, y2; + + x1 = getCode(temp); + y1 = getCode(temp); + + pset(x1, y1); + + for (;;) { + if ((x2 = getCode(temp)) >= 0xF0) break; + if ((y2 = getCode(temp)) >= 0xF0) break; + drawline(x1, y1, x2, y2); + x1 = x2; + y1 = y2; + } + + if (*temp == NULL) *temp = NULL; + else *temp = (*temp)->prior; +} + + +#define plotPatternPoint() \ + if (patCode & 0x20) { \ + if ((splatterMap[bitPos>>3] >> (7-(bitPos&7))) & 1) pset(x1, y1); \ + bitPos++; \ + if (bitPos == 0xff) bitPos=0; \ + } else pset(x1, y1) + +/************************************************************************** +** plotPattern +** +** Draws pixels, circles, squares, or splatter brush patterns depending +** on the pattern code. +**************************************************************************/ +void Picture::plotPattern(byte x, byte y) +{ + static char circles[][15] = { /* agi circle bitmaps */ + {0x80}, + {0xfc}, + {0x5f, 0xf4}, + {0x66, 0xff, 0xf6, 0x60}, + {0x23, 0xbf, 0xff, 0xff, 0xee, 0x20}, + {0x31, 0xe7, 0x9e, 0xff, 0xff, 0xde, 0x79, 0xe3, 0x00}, + {0x38, 0xf9, 0xf3, 0xef, 0xff, 0xff, 0xff, 0xfe, 0xf9, 0xf3, 0xe3, 0x80}, + {0x18, 0x3c, 0x7e, 0x7e, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7e, 0x7e, + 0x7e, 0x3c, 0x18} + }; + + static byte splatterMap[32] = { /* splatter brush bitmaps */ + 0x20, 0x94, 0x02, 0x24, 0x90, 0x82, 0xa4, 0xa2, + 0x82, 0x09, 0x0a, 0x22, 0x12, 0x10, 0x42, 0x14, + 0x91, 0x4a, 0x91, 0x11, 0x08, 0x12, 0x25, 0x10, + 0x22, 0xa8, 0x14, 0x24, 0x00, 0x50, 0x24, 0x04 + }; + + static byte splatterStart[128] = { /* starting bit position */ + 0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48, + 0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d, + 0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf, + 0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1, + 0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce, + 0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed, + 0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6, + 0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51, + 0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7, + 0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf, + 0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0, + 0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49, + 0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2, + 0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3, + 0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1 + }; + + int circlePos = 0; + byte x1, y1, penSize, bitPos = splatterStart[patNum]; + + penSize = (patCode&7); + + if (x<((penSize/2)+1)) x=((penSize/2)+1); + else if (x>160-((penSize/2)+1)) x=160-((penSize/2)+1); + if (y=168-penSize) y=167-penSize; + + for (y1=y-penSize; y1<=y+penSize; y1++) { + for (x1=x-((int)ceil((float)penSize/2)); x1<=x+((int)floor((float)penSize/2)); x1++) { + if (patCode & 0x10) { /* Square */ + plotPatternPoint(); + } + else { /* Circle */ + if ((circles[patCode&7][circlePos>>3] >> (7-(circlePos&7)))&1) { + plotPatternPoint(); + } + circlePos++; + } + } + } + +} + + +/************************************************************************** +** plotBrush +** +** Plots points and various brush patterns. +**************************************************************************/ +void Picture::plotBrush(struct picCodeNode **temp) +{ + byte x1, y1; + + for (;;) { + if (patCode & 0x20) { + if ((patNum = getCode(temp)) >= 0xF0) break; + patNum = (patNum >> 1 & 0x7f); + } + if ((x1 = getCode(temp)) >= 0xF0) break; + if ((y1 = getCode(temp)) >= 0xF0) break; + plotPattern(x1, y1); + } + + if (*temp == NULL) *temp = NULL; + else *temp = (*temp)->prior; +} + +//******************************************************************** +void Picture::load(byte *picdata,int picsize) +{ + byte nodeData; + struct picCodeNode *temp=NULL; + bool stillLoading=true; + + //init link list + picPos = picStart = picLast = NULL; + addMode = INS_MODE; + bufPos = bufLen = 0; + + do { + nodeData = *picdata++; + picsize--; + if (nodeData != 0xFF) { + temp = (struct picCodeNode *)malloc(sizeof(picCodes)); + if (temp == NULL) { + printf("Error allocating memory while loading picture.\n"); + exit(1); + } + /* was in the original code but doesn't work + if (isFirst) { + picStart = temp; + isFirst = false; + } + */ + temp->node = nodeData; + dlstore(temp); + } + else + stillLoading = false; + + } while(picsize && stillLoading); + + picLast = temp; + picPos = NULL; + +} + +//************************************************* +int Picture::open(char *filename) +{ + + FILE *fptr = fopen(filename,"rb"); + + if(fptr==NULL){ + menu->errmes("Can't open file %s ! ",filename); + return 1; + } + + struct stat buf; + fstat(fileno(fptr),&buf); + ResourceData.Size=buf.st_size; + fread(ResourceData.Data,ResourceData.Size,1,fptr); + fclose(fptr); + + load(ResourceData.Data,ResourceData.Size); + refill_pic = refill_pri = false; + draw(); + init(); + return 0; + +} + +//************************************************* +int Picture::open(int ResNum) +{ + + int err = game->ReadResource(PICTURE,ResNum); + if(!err){ + load(ResourceData.Data,ResourceData.Size); + refill_pic = refill_pri = false; + draw(); + init(); + } + return err; +} + +//************************************************* +int Picture::save(int ResNum) +{ + + save(); + return(game->AddResource(PICTURE,ResNum)); + +} + +//************************************************* +int Picture::save(char *filename) +{ + FILE *fptr = fopen(filename,"wb"); + + if(fptr==NULL){ + menu->errmes("Can't open file %s ! ",filename); + return 1; + } + save(); + fwrite(ResourceData.Data,ResourceData.Size,1,fptr); + fclose(fptr); + return 0; + +} + +//************************************************* +void Picture::save() +{ + byte *ptr=ResourceData.Data; + struct picCodeNode *temp; + + if (picStart == NULL) { /* Black picture */ + *ptr = 0xFF; /* End of picture marker */ + ResourceData.Size=1; + return ; + } + + temp = picStart; + *ptr++ = temp->node; + + do { + temp = temp->next; + *ptr++ = temp->node; + } while (temp->next != NULL); + + *ptr++ = 0xFF; /* End of picture marker */ + ResourceData.Size = (int)(ptr-ResourceData.Data); + +} + +//************************************************* +void Picture::refill( struct picCodeNode *temp_fill_start, struct picCodeNode *temp_fill_end,int refmode) +{ + struct picCodeNode *temp,*picPos0,*temp_pic=0,*temp_pri=0; + int col_pic_orig,col_pri_orig,col_pic_new,col_pri_new; + bool picDrawEnabled_orig,priDrawEnabled_orig; + bool picDrawEnabled_new,priDrawEnabled_new; + bool draw_pic_orig,draw_pri_orig,draw_pic_new,draw_pri_new; + + picDrawEnabled_orig=priDrawEnabled_orig=false; + col_pic_orig = col_pri_orig = -1; + temp=temp_fill_start; + draw_pic_orig=draw_pri_orig=false; + + do{ + temp = temp->prior; + if(temp==NULL)break; + switch(temp->node){ + case 0xf0: + if(col_pic_orig==-1){ + col_pic_orig = (temp->next)->node; + picDrawEnabled_orig=true; + temp_pic=temp; + } + break; + case 0xf1: + if(col_pic_orig==-1){ + col_pic_orig=-2; + temp_pic=temp; + } + break; + case 0xf2: + if(col_pri_orig==-1){ + col_pri_orig = (temp->next)->node; + priDrawEnabled_orig=true; + temp_pri=temp; + } + break; + case 0xf3: + if(col_pri_orig==-1){ + col_pri_orig=-2; + temp_pri=temp; + } + break; + default: + if(temp->node >= 0xf4 && temp->node < 0xff){ + if(col_pic_orig==-1)draw_pic_orig=true; + if(col_pri_orig==-1)draw_pri_orig=true; + } + break; + } + }while(col_pic_orig==-1 || col_pri_orig==-1); //find the fill original color + + picPos0= picPos; + picPos = temp_fill_start; + + if((refmode|1) && picDrawEnabled0){ + if(picDrawEnabled_orig){ + if(col_pic!=col_pic_orig){ + if(col_pic==15){ + if(draw_pic_orig){ + addCode(0xf1); + } + else{ + temp_pic->node=0xf1; + picPos=temp_pic->next; + dldelete(); + } + } + else{//col_pic != 15 + if(draw_pic_orig){ + addCode(0xf0); + addCode(col_pic); + } + else{ + (temp_pic->next)->node=col_pic; + } + } + } + } + else{//!picDrawEnabled_orig + if(col_pic!=15){ + addCode(0xf0); + addCode(col_pic); + } + } + } + + if((refmode|2) && priDrawEnabled0){ + if(priDrawEnabled_orig){ + if(col_pri!=col_pri_orig){ + if(col_pri==4){ + if(draw_pri_orig){ + addCode(0xf3); + } + else{ + temp_pri->node=0xf3; + picPos=temp_pri->next; + dldelete(); + } + } + else{//col_pri != 4 + if(draw_pri_orig){ + addCode(0xf2); + addCode(col_pri); + } + else{ + (temp_pri->next)->node=col_pri; + } + } + } + } + else{//!priDrawEnabled_orig + if(col_pri!=4){ + addCode(0xf2); + addCode(col_pri); + } + } + } + + + temp = temp_fill_end; + picDrawEnabled_new=priDrawEnabled_new=false; + col_pic_new=col_pri_new=-1; + draw_pic_new=draw_pri_new = false; + if(temp){ + do{ + switch(temp->node){ + case 0xf0: + col_pic_new = (temp->next)->node; + picDrawEnabled_new=true; + break; + case 0xf1: + col_pic_new = -2; + break; + case 0xf2: + col_pri_new = (temp->next)->node; + priDrawEnabled_new=true; + break; + case 0xf3: + col_pri_new = -2; + break; + default: + if(temp->node >= 0xf4 && temp->node < 0xff){ + if(col_pic_new==-1)draw_pic_new=true; + if(col_pri_new==-1)draw_pri_new=true; + } + break; + } + temp = temp->next; + }while(temp && (col_pic_orig==-1 || col_pri_orig==-1)); + + + picPos = temp_fill_end; + if((refmode|1) && picDrawEnabled0){ + if(col_pic != col_pic_orig){ + if(draw_pic_new){ + if(picDrawEnabled_orig){ + addCode(0xf0); + addCode(col_pic_orig); + } + else{ + if(col_pic!=0x15){ + addCode(0xf1); + } + } + } + } + } + + if((refmode|2) && priDrawEnabled0){ + if(col_pri != col_pri_orig){ + if(draw_pri_new){ + if(priDrawEnabled_orig){ + addCode(0xf2); + addCode(col_pri_orig); + } + else{ + if(col_pri!=0x4){ + addCode(0xf3); + } + } + } + } + } + + } + picPos = picPos0; + draw(); +} + +//************************************************* +void Picture::draw() +{ + byte action; + struct picCodeNode *temp,*temp_fill_start,*temp_fill_end; + int refmode; + bool finishedPic=false; + int pC, pN; + + memset(picture, 15, MAX_W*MAX_H); /* Visual screen default, white */ + memset(priority, 4, MAX_W*MAX_H); /* Priority screen default, red */ + rpos = QUMAX; + spos = 0; + picDrawEnabled = false; + priDrawEnabled = false; + picColour = priColour = 0; + tool=-1; + + if ((picStart != NULL) && (picLast != NULL)) { + + pC = patCode; + pN = patNum; + patCode = patNum = 0; + + temp = picStart; + + if (picPos != picStart) do { + action = getCode(&temp); + + switch (action) { + + case 0xF0: picColour = getCode(&temp); + picDrawEnabled = true; + break; + case 0xF1: picDrawEnabled = false; break; + case 0xF2: priColour = getCode(&temp); + priDrawEnabled = true; + break; + case 0xF3: priDrawEnabled = false; break; + case 0xF4: tool=T_STEP; yCorner(&temp); break; + case 0xF5: tool=T_STEP; xCorner(&temp); break; + case 0xF6: tool=T_LINE; absoluteLine(&temp); break; + case 0xF7: tool=T_PEN; relativeDraw(&temp); break; + case 0xF8: tool=T_FILL; + temp_fill_start = temp->prior; + fill(&temp); + temp_fill_end = temp; + if(refill_pic || refill_pri){ + //find which FILL filled the selected area + refmode=0; + if(refill_pic && picGetPixel(refill_x,refill_y)!=15){ + refmode |= 1; + refill_pic=false; + } + if(refill_pri && priGetPixel(refill_x,refill_y)!=4){ + refill_pri=false; + refmode |= 2; + } + if(refmode){ + refill(temp_fill_start,temp_fill_end,refmode); + } + if(!refill_pic && !refill_pri)return; + } + break; + case 0xF9: patCode = getCode(&temp); break; + case 0xFA: tool=T_BRUSH; plotBrush(&temp); break; + case 0xFF: finishedPic=true; break; + default: + printf("Unknown picture code : %X\n", action); + printf("%p %p %p\n", picLast, picPos, temp); + break; + } + + } while((temp != picPos) && !finishedPic); + + patCode = pC; + patNum = pN; + } + +} + +//************************************************** +void Picture::init() +{ + clear_tools(); + + priDrawEnabled = picDrawEnabled = false; + addMode = INS_MODE; + curp = &points0; + points0.n=points1.n=0; + newp=&points; + add_pic=add_pri=false; +} + +//************************************************** +void Picture::newpic() +{ + + freeList(); + draw(); + init(); +} + +//************************************************** +void Picture::addCode(byte code) /* To the list */ +{ + struct picCodeNode *temp; + + temp = (struct picCodeNode *)malloc(sizeof(picCodes)); + if (temp == 0) { + printf("Memory allocation problem."); + exit(0); + } + temp->node = code; + dlstore(temp); +} +//************************************************** +void Picture::replaceCode(byte code) +{ + struct picCodeNode *temp; + + + temp = (struct picCodeNode *)malloc(sizeof(picCodes)); + if (temp == 0) { + printf("Memory allocation problem."); + exit(0); + } + temp->node = code; + addMode = OVR_MODE; + dlstore(temp); + addMode = INS_MODE; +} + +//************************************************** +void Picture::addPatCode() +{ + int pat=0; + + pat = (brushSize & 0x07); + if (brushShape == SQUARE) pat |= 0x10; + if (brushTexture == SPRAY) pat |= 0x20; + + addCode(pat); +} + +//************************************************** +void Picture::adjustDisp(int *dX, int *dY) + //for pen +{ + if (*dX > 6) *dX = 6; + if (*dX < -6) *dX = -6; + if (*dY > 7) *dY = 7; + if (*dY < -7) *dY = -7; +} + +//************************************************** +void Picture::clear_tools() +{ + numClicks=0; + stepClicks=0; + firstClick=true; + tool=-1; +} + +//************************************************** +void Picture::init_tool() +{ + numClicks=0; + stepClicks=0; + firstClick=true; +} +//************************************************** +void Picture::home_proc() +{ + moveToStart(); + draw(); + init_tool(); +} +//************************************************** +void Picture::left_proc() +{ + moveBackAction(); + draw(); + init_tool(); + +} +//************************************************** +void Picture::right_proc() +{ + moveForwardAction(); + draw(); + init_tool(); + +} +//************************************************** +void Picture::end_proc() +{ + moveToEnd(); + draw(); + init_tool(); +} +//************************************************** +void Picture::del_proc() +{ + + removeAction(); + draw(); + init_tool(); +} +//************************************************** +void Picture::wipe_proc() +{ + + wipeAction(); + draw(); + init_tool(); +} +//************************************************** +void Picture::tool_proc(int k) +{ + tool=k; + numClicks=0; + stepClicks=0; + firstClick=true; + +} +//************************************************** +void Picture::set_brush(int mode,int val) +{ + switch(mode){ + case 0: + brushSize = val; + break; + case 1: + brushShape = val; + break; + case 2: + brushTexture = val; + break; + } + numClicks=0; + +} +//************************************************** +void Picture::choose_color(int button,int color) +{ + + if(button == M_LEFT){ + add_pic=true; + if(color==-1){ //off + // addCode(0xF1); + code_pic=0xF1; + picDrawEnabled = false; + } + else{ + picColour = color; + // addCode(0xF0); + //addCode(picColour); + code_pic=0xF0; + col_pic=picColour; + picDrawEnabled = true; + } + } + else{ + add_pri=true; + if(color==-1){ //off + // addCode(0xF3); + code_pri=0xF3; + priDrawEnabled = false; + } + else{ + priColour = color; + //addCode(0xF2); + //addCode(priColour); + code_pri=0xF2; + col_pri=priColour; + priDrawEnabled = true; + } + } + init_tool(); + curcol=(drawing_mode)?priColour:picColour; +} + +//************************************************** +int Picture::move_action(int newX, int newY) +{ + int ret=0; //1 - draw "temporary" line on screen + + switch(tool){ + case T_LINE: + if(numClicks==0)break; + normline2(clickX>>1, clickY, newX>>1, newY); + ret=1; + break; + case T_PEN: + if(numClicks==0)break; + dX = ((newX>>1) - (clickX>>1)); + dY = ((newY) - (clickY)); + adjustDisp(&dX, &dY); + normline2(clickX>>1, clickY,(clickX>>1)+dX, clickY+dY); + ret=1; + break; + case T_STEP: + if(stepClicks==0)break; + switch (stepClicks) { + case 1: + dX = ((newX>>1) - (clickX>>1)); + dY = ((newY) - (clickY)); + if (abs(dX) > abs(dY)) dY = 0; + else dX = 0; + normline2(clickX>>1, clickY, (clickX>>1)+dX, clickY+dY); + ret=1; + break; + + default: + dX = ((newX>>1) - (clickX>>1)); + dY = ((newY) - (clickY)); + if (stepClicks % 2) dX = 0; + else dY = 0; + normline2(clickX>>1, clickY, (clickX>>1)+dX, clickY+dY); + ret=1; + break; + } + break; + } + + return ret; +} + +//************************************************** +int Picture::button_action(int newX, int newY) +{ + int disp; + int ret=0; + + if(!(tool == T_FILL && !okToFill(newX>>1, newY))){ + if(add_pic){ + addCode(code_pic); + if(code_pic==0xf0){ + addCode(col_pic); + } + add_pic=false; + } + if(add_pri){ + addCode(code_pri); + if(code_pri==0xf2){ + addCode(col_pri); + } + add_pri=false; + } + } + + switch(tool){ + case T_LINE: + switch (numClicks++) { + case 0: break; + case 1: + addCode(0xF6); + addCode(clickX>>1); + addCode(clickY); + ret=1; + default: + addCode(newX>>1); + addCode(newY); + ret=1; + drawline(clickX>>1, clickY, newX>>1, newY); + break; + } + clickX = newX; + clickY = newY; + curp = &points0; + points0.n=points1.n=0; + break; + case T_PEN: + dX = ((newX>>1) - (clickX>>1)); + dY = ((newY) - (clickY)); + adjustDisp(&dX, &dY); + switch (numClicks++) { + case 0: + clickX = newX; + clickY = newY; + break; + case 1: + addCode(0xF7); + addCode(clickX>>1); + addCode(clickY); + default: + if (dX < 0) disp = (0x80 | ((((-1)*dX)-0) << 4)); + else disp = (dX << 4); + if (dY < 0) disp |= (0x08 | (((-1)*dY)-0)); + else disp |= dY; + addCode(disp); + ret=1; + drawline(clickX>>1, clickY, + (clickX>>1)+dX, (clickY)+dY); + clickX = clickX + (dX<<1); + clickY = clickY + dY; + break; + } + curp = &points0; + points0.n=points1.n=0; + break; + case T_STEP: + switch (stepClicks) { + case 0: + clickX = newX; + clickY = newY; + break; + + case 1: + dX = ((newX>>1) - (clickX>>1)); + dY = ((newY) - (clickY)); + if (abs(dX) > abs(dY)) { /* X or Y corner */ + dY = 0; + stepClicks++; + addCode(0xF5); + addCode(clickX>>1); + addCode(clickY); + addCode((clickX>>1)+dX); + } + else { + dX = 0; + addCode(0xF4); + addCode(clickX>>1); + addCode(clickY); + addCode((clickY)+dY); + } + ret=1; + drawline(clickX>>1, clickY, + (clickX>>1)+dX, (clickY)+dY); + clickX = clickX + (dX<<1); + clickY = clickY + dY; + break; + + default: + dX = ((newX>>1) - (clickX>>1)); + dY = ((newY) - (clickY)); + if (stepClicks % 2) { + dX = 0; + addCode((clickY)+dY); + } + else { + dY = 0; + addCode((clickX>>1)+dX); + } + ret=1; + drawline(clickX>>1, clickY, + (clickX>>1)+dX, (clickY)+dY); + clickX = clickX + (dX<<1); + clickY = clickY + dY; + break; + } + stepClicks++; + curp = &points0; + points0.n=points1.n=0; + break; + case T_FILL: + if(!(okToFill(newX>>1, newY))){ + status(0); + refill_x = newX>>1; + refill_y = newY; + refill_pic = refill_pri = true; + draw(); + ret=1; + init(); + status(1); + tool = T_FILL; + init_tool(); + break; + } + + agiFill(newX>>1, newY); + if (firstClick) { + addCode(0xF8); + firstClick = false; + } + addCode(newX>>1); + addCode(newY); + ret=1; + break; + case T_BRUSH: + if (numClicks == 0) { + addCode(0xF9); + addPatCode(); + addCode(0xFA); + } + numClicks++; + + patCode = brushSize; + if (brushShape == SQUARE) patCode |= 0x10; + if (brushTexture == SPRAY) patCode |= 0x20; + patNum = ((rand() % 0xEE) >> 1) & 0x7F; + plotPattern(newX>>1, newY); + if (brushTexture == SPRAY) addCode(patNum<<1); + addCode(newX>>1); + addCode(newY); + ret=1; + } + + return ret; + +} +//*************************************************** +void Picture::set_mode(int mode) +{ + + drawing_mode=mode; + if(mode==0){ + pptr = picture; + curcol = picColour; + } + else{ + pptr = priority; + curcol = priColour; + } + +} + +//*************************************************** +void Picture::putpix2(int x,int y) +{ + byte c; + QColor cc; + + if(x<0||y<0||x>=MAX_W||y>=MAX_HH){ + return; + } + + //save the pixels under the line to be drawn + //so it can be restored when the line is moved + if(bg_on){ //if background is on - must save the contents of the background image + x<<=1; + curp->p[curp->n].x=x; + curp->p[curp->n].y=y; + c=pptr[y*MAX_W+x]; + if((c==15&&pptr==picture)||(c==4&&pptr==priority)){ + curp->p[curp->n].cc=QColor(bgpix->pixel(x,y)); + curp->n++; + curp->p[curp->n].x=x+1; + curp->p[curp->n].y=y; + curp->p[curp->n].cc=QColor(bgpix->pixel(x+1,y)); + curp->n++; + } + else{ + cc=egacolor[c]; + curp->p[curp->n].cc=cc; + curp->n++; + curp->p[curp->n].x=x+1; + curp->p[curp->n].y=y; + curp->p[curp->n].cc=cc; + curp->n++; + } + x>>=1; + } + else{ //save the pixels + curp->p[curp->n].x=x; + curp->p[curp->n].y=y; + curp->p[curp->n].c=pptr[y*MAX_W+(x<<1)]; + curp->n++; + } + newp->p[newp->n].x=x; + newp->p[newp->n].y=y; + newp->p[newp->n].c=curcol; + newp->n++; + +} + +//*************************************************** +void Picture::normline2(int x1, int y1, int x2, int y2) +{ + int height, width; + float x, y, addX, addY; + + height = (y2 - y1); + width = (x2 - x1); + addX = (height==0?height:(float)width/abs(height)); + addY = (width==0?width:(float)height/abs(width)); + + points.n=0; + curp->n=0; + + if (abs(width) > abs(height)) { + y = y1; + addX = (width == 0? 0 : (width/abs(width))); + for (x=x1; x!=x2; x+=addX) { + putpix2(round(x, addX), round(y, addY)); + y+=addY; + } + putpix2(x2,y2); + } + else { + x = x1; + addY = (height == 0? 0 : (height/abs(height))); + for (y=y1; y!=y2; y+=addY) { + putpix2(round(x, addX), round(y, addY)); + x+=addX; + } + putpix2(x2,y2); + } + + if(curp==&points0)curp= (&points1); + else curp= (&points0); + +} + +//*************************************************** +void Picture::viewData(TStringList *data) +{ + struct picCodeNode *temp; + byte c; + char tmp1[6]; + + data->lfree(); + + if (picStart == NULL) { /* Black picture */ + data->add("ff"); + return ; + } + + temp = picStart; + tmp[0]=0; + for(temp=picStart;temp!=NULL;temp=temp->next){ + c = temp->node; + if(c>=0xf0 && tmp[0]){ + data->add(tmp); + sprintf(tmp,"%02x ",c); + } + else{ + sprintf(tmp1,"%02x ",c); + strcat(tmp,tmp1); + } + } + if(tmp1[0]!=0){ + strcat(tmp,tmp1); + data->add(tmp); + } + data->add("ff"); + +} +//*************************************************** + +void Picture::status(int mode) +{ + + if(mode==0){ + picDrawEnabled0 = picDrawEnabled; + priDrawEnabled0 = priDrawEnabled; + picColour0=picColour; + priColour0=priColour; + } + else{ + picDrawEnabled = picDrawEnabled0; + priDrawEnabled = priDrawEnabled0; + picColour=picColour0; + priColour=priColour0; + } + +} diff --git a/src/picture.h b/src/picture.h new file mode 100644 index 0000000..94ef999 --- /dev/null +++ b/src/picture.h @@ -0,0 +1,218 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef PICTURE_H +#define PICTURE_H + +#ifndef __GNUCPP__ +#include +#endif + +#include +#include + +#include "linklist.h" +#include "util.h" + + +#define MAX_W 320 +#define MAX_H 200 +#define MAX_HH 168 +//the actual height of the picture is 168 (to leave space for menu and text input) + +typedef unsigned short int word; +typedef uint8_t byte; + +#define M_LEFT 0 +#define M_RIGHT 2 + +#define CIRCLE 0 +#define SQUARE 1 +#define SPRAY 0 +#define SOLID 1 + +#define T_LINE 0 +#define T_PEN 1 +#define T_STEP 2 +#define T_FILL 3 +#define T_BRUSH 4 + +#define QUMAX 4000 +#define EMPTY 0xFF + + +typedef struct { + short x,y; + byte c; + QColor cc; +}Point; + + +typedef struct { + int n; + Point p[370]; +}Points; + + +//bitmap picture - for preview +class BPicture { + public: + BPicture(); + byte **picture; + byte **priority; + void show(byte *, int); + protected: + + byte buf[QUMAX+1]; + word rpos, spos; + bool picDrawEnabled,priDrawEnabled; + byte picColour, priColour, patCode, patNum; + + void qstore(byte q); + byte qretrieve(); + void picPSet(word x, word y); + void priPSet(word x, word y); + void pset(word x, word y); + byte picGetPixel(word x, word y); + byte priGetPixel(word x, word y); + int round(float aNumber, float dirn); + void drawline(word x1, word y1, word x2, word y2); + bool okToFill(byte x, byte y); + void agiFill(word x, word y); + void xCorner(byte **data); + void yCorner(byte **data); + void relativeDraw(byte **data); + void fill(byte **data); + void absoluteLine(byte **data); + void plotPattern(byte x, byte y); + void plotBrush(byte **data); + +}; + + +//'list' format picture - for edit +class Picture { + public: + Picture(); + byte picture[MAX_W*MAX_H]; + byte priority[MAX_W*MAX_H]; + byte *pptr; + bool bg_on; + QImage *bgpix; + Points points,points0,points1; + Points *curp,*newp; + void load(byte *, int); + int open(char *filename); + int open(int ResNum); + void save(); + int save(char *filename); + int save(int ResNum); + void newpic(); + void draw(); + void init(); + void set_mode(int); + void clear_tools(); + void init_tool(); + void home_proc(); + void end_proc(); + void left_proc(); + void right_proc(); + void del_proc(); + void wipe_proc(); + void tool_proc(int); + void choose_color(int button, int color); + void set_brush(int mode,int val); + int button_action(int newX, int newY); + int move_action(int newX, int newY); + char *showPos(int *code,int *val); + int setBufPos(int); + void viewData(TStringList *data); + void status(int mode); + void refill( struct picCodeNode *temp_fill_start, struct picCodeNode *temp_fill_end,int mode); + int drawing_mode; + int tool; + int brushSize,brushShape,brushTexture; + byte picColour, priColour, patCode, patNum, curcol; + bool picDrawEnabled,priDrawEnabled; + int bufPos; /* This variable holds current offset into buffer */ + int bufLen; + bool refill_pic,refill_pri; + int refill_x,refill_y; + protected: + + struct picCodeNode picCodes; + struct picCodeNode *picPos; + struct picCodeNode *picStart; + struct picCodeNode *picLast; + + byte buf[QUMAX+1]; + word rpos, spos; + int addMode; + bool add_pic,add_pri; + int code_pic,col_pic,code_pri,col_pri; + + void dldelete(); + void removeAction(); + void wipeAction(); + void dlstore(struct picCodeNode *i); + void displayList(); + void freeList(); + void moveBack(); + void moveForward(); + void moveToStart(); + void moveToEnd(); + void moveBackAction(); + void moveForwardAction(); + + byte getCode(struct picCodeNode **temp); + byte testCode(struct picCodeNode **temp); + + void qstore(byte q); + byte qretrieve(); + void picPSet(word x, word y); + void priPSet(word x, word y); + void pset(word x, word y); + byte picGetPixel(word x, word y); + byte priGetPixel(word x, word y); + int round(float aNumber, float dirn); + void drawline(word x1, word y1, word x2, word y2); + bool okToFill(byte x, byte y); + void agiFill(word x, word y); + void xCorner(struct picCodeNode **temp); + void yCorner(struct picCodeNode **temp); + void relativeDraw(struct picCodeNode **temp); + void fill(struct picCodeNode **temp); + void absoluteLine(struct picCodeNode **temp); + void plotPattern(byte x, byte y); + void plotBrush(struct picCodeNode **temp); + void addCode(byte code); + void replaceCode(byte code); + void addPatCode(); + void adjustDisp(int *dX, int *dY); + int clickX, clickY, dX, dY; + int stepClicks, numClicks; + bool firstClick; + void normline2(int x1, int y1, int x2, int y2); + void putpix2(int x,int y); +}; + +extern char tmp[]; + +#endif diff --git a/src/preview.cpp b/src/preview.cpp new file mode 100644 index 0000000..26924be --- /dev/null +++ b/src/preview.cpp @@ -0,0 +1,650 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "resources.h" +#include "game.h" +#include "preview.h" +#include "picture.h" +#include "wutil.h" +#include "menu.h" + +#include "logedit.h" + +#include + +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "right_x.xpm" +#include "left_x.xpm" + + +//***************************************** +Preview::Preview( QWidget* parent, const char* name ,ResourcesWin *res ): + Q3WidgetStack(parent,name) +{ + + setCaption("Preview"); + make_egacolors(); + + resources_win = res; + + // Logic + + w_logic = new QWidget (this); + w_logic->setMinimumSize(340,280); + + Q3BoxLayout *d = new Q3VBoxLayout(w_logic,5); + p_logic = new LogEdit( w_logic,0,0,res,true ); + d->addWidget(p_logic); + QPushButton *edit = new QPushButton("Edit",w_logic); + edit->setMaximumSize(80,60); + connect(edit,SIGNAL(clicked()),SLOT(double_click())); + d->addWidget(edit); + + // Sound + + w_sound = new QWidget (this); + w_sound->setMinimumSize(340,280); + + Q3BoxLayout *d1 = new Q3VBoxLayout(w_sound, 5); + QLabel *l1 = new QLabel("Preview is not available !\nDouble-click to listen.\nOr click the 'Listen' button.",w_sound,0); + d1->addWidget(l1); + + QPushButton *listen = new QPushButton("Listen",w_sound); + listen->setMaximumSize(120,60); + connect(listen,SIGNAL(clicked()),SLOT(double_click())); + d1->addWidget(listen); + + QPushButton *save_as_midi = new QPushButton("Save as MIDI",w_sound); + save_as_midi->setMaximumSize(120,60); + connect(save_as_midi,SIGNAL(clicked()),SLOT(export_resource())); + d1->addWidget(save_as_midi); + + d1->addStretch(); + + // Picture + + w_picture = new QWidget (this,0); + w_picture->setMinimumSize(340,280); + + Q3BoxLayout *pbox = new Q3VBoxLayout(w_picture,10); + + p_picture = new PreviewPicture(w_picture,0,this); + p_picture->setFixedSize(MAX_W,MAX_HH); + pbox->addWidget(p_picture); + + Q3BoxLayout *pbox1 = new Q3HBoxLayout(pbox,10); + + visual = new QRadioButton("Visual",w_picture); + visual->setChecked(true); + pbox1->addWidget(visual); + + priority = new QRadioButton("Priority",w_picture); + priority->setChecked(false); + pbox1->addWidget(priority); + + p_picture->drawing_mode=0; + + Q3ButtonGroup *bg = new Q3ButtonGroup(w_picture); + bg->hide(); + bg->insert(visual,0); + bg->insert(priority,1); + connect( bg, SIGNAL(clicked(int)), SLOT(change_mode(int)) ); + + + Q3BoxLayout *pbox2 = new Q3HBoxLayout(pbox,10); + QPushButton *pedit = new QPushButton("Edit",w_picture); + pedit->setMaximumWidth(100); + connect(pedit,SIGNAL(clicked()),SLOT(double_click())); + pbox2->addWidget(pedit,Qt::AlignCenter); + + save_pic_butt = new QPushButton("Save as...",w_picture); + save_pic_butt->setMaximumWidth(100); + connect(save_pic_butt,SIGNAL(clicked()),SLOT(save_pic())); + pbox2->addWidget(save_pic_butt,Qt::AlignCenter); + + formats_pic = new QComboBox(w_picture); + for (int i = 0; i < QImageWriter::supportedImageFormats().size(); ++i) { + formats_pic->insertItem(QImageWriter::supportedImageFormats().at(i).constData()); + } + + pbox2->addWidget(formats_pic); + pbox->addStretch(); + + // View + + w_view = new QWidget (this,0); + w_view->setMinimumSize(340,240); + + Q3BoxLayout *vbox = new Q3VBoxLayout(w_view,10); + + int maxrow1=3,maxcol1=5; + Q3GridLayout *grid1 = new Q3GridLayout( vbox, maxrow1,maxcol1, 1 ); + + int i; + for(i=0;isetColStretch(i,1); + grid1->addColSpacing(i,1); + } + + for(i=0;isetRowStretch(i,1); + grid1->addRowSpacing(i,2); + } + + + int row=0;int col=0; + QPixmap pright=QPixmap(right_x); + QPixmap pleft=QPixmap(left_x); + + QLabel *looplabel = new QLabel("Loop:",w_view); + grid1->addWidget(looplabel,row,col,Qt::AlignRight); col++; + + loopnum = new QLabel("0/0",w_view); + grid1->addWidget(loopnum,row,col,Qt::AlignLeft); col++; + + QPushButton *loopleft = new QPushButton(w_view); + loopleft->setPixmap(pleft); + connect( loopleft, SIGNAL(clicked()), SLOT(previous_loop()) ); + grid1->addWidget(loopleft,row,col,Qt::AlignRight); col++; + + QPushButton *loopright = new QPushButton(w_view); + loopright->setPixmap(pright); + connect( loopright, SIGNAL(clicked()), SLOT(next_loop()) ); + grid1->addWidget(loopright,row,col,Qt::AlignLeft); col++; + + QPushButton *vedit = new QPushButton("Edit",w_view); + vedit->setMaximumWidth(100); + connect(vedit,SIGNAL(clicked()),SLOT(double_click())); + grid1->addWidget(vedit,row,col,Qt::AlignCenter); col++; + + row++;col=0; + + QLabel *cellabel = new QLabel("Cel:",w_view); + grid1->addWidget(cellabel,row,col,Qt::AlignRight); col++; + + celnum = new QLabel("0/0",w_view); + grid1->addWidget(celnum,row,col,Qt::AlignLeft); col++; + + QPushButton *celleft = new QPushButton(w_view); + celleft->setPixmap(pleft); + connect( celleft, SIGNAL(clicked()), SLOT(previous_cel()) ); + grid1->addWidget(celleft,row,col,Qt::AlignRight); col++; + + QPushButton *celright = new QPushButton(w_view); + celright->setPixmap(pright); + connect( celright, SIGNAL(clicked()), SLOT(next_cel()) ); + grid1->addWidget(celright,row,col,Qt::AlignLeft); col++; + + QPushButton *anim = new QPushButton("Animate",w_view); + connect(anim,SIGNAL(clicked()),SLOT(animate_cb())); + grid1->addWidget(anim,row,col,Qt::AlignCenter); col++; + + row++;col=0; + + save_view_butt = new QPushButton("Save as...",w_view); + save_view_butt->setMaximumWidth(100); + connect(save_view_butt,SIGNAL(clicked()),SLOT(save_view())); + grid1->addWidget(save_view_butt,row,col,Qt::AlignCenter); col++; + + formats_view = new QComboBox(w_view); + // QStrList out = QImageIO::outputFormats (); + for (int i = 0; i < QImageWriter::supportedImageFormats().size(); ++i) { + formats_view->insertItem(QImageWriter::supportedImageFormats().at(i).constData()); + } + grid1->addWidget(formats_view,row,col,Qt::AlignCenter); // Reference to the same widget used in picture + + + p_view = new PreviewView(w_view,0,this); + p_view->setMinimumSize(64,64); + p_view->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum )); + vbox->addWidget(p_view); + + description = new Q3MultiLineEdit(w_view); + description->setReadOnly(true); + description->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding )); + vbox->addWidget(description); + vbox->addStretch(); + + // Build the widget stack + + addWidget( w_picture ); + addWidget( w_view ); + addWidget( w_sound ); + addWidget( w_logic ); + + setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding )); + adjustSize(); + animate=NULL; +} + +//***************************************** +void Preview::open(int ResNum,int type) +{ + switch(type){ + case LOGIC: + if(animate){ animate->closeall(); animate=NULL; } + raiseWidget( w_logic ); + p_logic->open(ResNum); + break; + case VIEW: + raiseWidget( w_view ); + p_view->draw(ResNum); + break; + case PICTURE: + if(animate){ animate->closeall(); animate=NULL; } + raiseWidget( w_picture ); + p_picture->draw(ResNum); + break; + case SOUND: + if(animate){ animate->closeall(); animate=NULL; } + raiseWidget( w_sound ); + break; + } + + show(); +} + +//***************************************** +void Preview::change_mode(int mode) +{ + + p_picture->drawing_mode=mode; + p_picture->update(); + +} + +//****************************************************** +void Preview::double_click() +{ + + resources_win->select_resource(resources_win->list->currentItem()); + +} +//****************************************************** +void Preview::previous_loop() +{ + + if(p_view->view->CurLoop>0){ + p_view->view->CurLoop--; + p_view->view->CurCel=0; + showlooppar(); + showcelpar(); + p_view->update(); + } +} +//****************************************************** +void Preview::next_loop() +{ + if(p_view->view->CurLoopview->NumLoops-1){ + p_view->view->CurLoop++; + p_view->view->CurCel=0; + showlooppar(); + showcelpar(); + p_view->update(); + } + +} +//****************************************************** +void Preview::previous_cel() +{ + if(p_view->view->CurCel>0){ + p_view->view->CurCel--; + showcelpar(); + p_view->update(); + } + +} +//****************************************************** +void Preview::prev_cel_cycle() +{ + + if(p_view->view->loops[p_view->view->CurLoop].NumCels<=1)return; + if(p_view->view->CurCel>0){ + p_view->view->CurCel--; + } + else{ + p_view->view->CurCel=p_view->view->loops[p_view->view->CurLoop].NumCels-1; + } + showcelpar(); + p_view->update(); + +} +//****************************************************** +void Preview::next_cel() +{ + + if(p_view->view->CurCelview->loops[p_view->view->CurLoop].NumCels-1){ + p_view->view->CurCel++; + showcelpar(); + p_view->update(); + } + +} +//****************************************************** +void Preview::next_cel_cycle() +{ + if(p_view->view->loops[p_view->view->CurLoop].NumCels<=1)return; + if(p_view->view->CurCelview->loops[p_view->view->CurLoop].NumCels-1){ + p_view->view->CurCel++; + } + else{ + p_view->view->CurCel=0; + } + showcelpar(); + p_view->update(); + +} +//****************************************************** +void Preview::showlooppar() +{ + + sprintf(tmp,"%d/%d",p_view->view->CurLoop,p_view->view->NumLoops-1); + loopnum->setText(tmp); + +} +//****************************************************** +void Preview::animate_cb() +{ + + if(animate==NULL)animate=new Animate(0,0,this,0); + animate->show(); + +} +//****************************************************** +void Preview::showcelpar() +{ + + sprintf(tmp,"%d/%d",p_view->view->CurCel,p_view->view->loops[p_view->view->CurLoop].NumCels-1); + celnum->setText(tmp); + +} + +//****************************************************** + +void Preview::save_pic() +{ + save_image( p_picture->pixmap, formats_pic->currentText().latin1() ); +} + +//****************************************************** + +void Preview::save_view() +{ + save_image( p_view->pixmap, formats_view->currentText().latin1() ); +} + +//****************************************************** +void Preview::save_image( QPixmap& pixmap, const char* format ) +{ + Q3FileDialog *f = new Q3FileDialog(0,"Save",true); + sprintf(tmp,"*.%s",format); + toLower(tmp); + const char *filters[] = {tmp,"All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Save as image"); + f->setMode(Q3FileDialog::AnyFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ){ + if(!pixmap.save((char *)f->selectedFile().latin1(),format)) + menu->errmes("Couldn't save picture !"); + } + } + +} +//****************************************************** +void Preview::export_resource() +{ + resources_win->export_resource(); +} +//***************************************** +void Preview::deinit() +{ + + if(animate){ + animate->closeall(); + animate=NULL; + } + resources_win->preview=NULL; + if(window_list && window_list->isVisible())window_list->draw(); +} + + +//********************************************* +void Preview::closeEvent( QCloseEvent *e ) +{ + + deinit(); + e->accept(); + +} +//********************************************* +void Preview::hideEvent( QHideEvent * ) +{ + + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//********************************************* +void Preview::showEvent( QShowEvent * ) +{ + + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//****************************************************** + +PreviewPicture::PreviewPicture( QWidget* parent, const char* name, Preview *p ): + QWidget(parent,name) +{ + + preview = p; + pixmap = QPixmap(MAX_W,MAX_HH); + ppicture = new BPicture(); + +} + +//***************************************** +void PreviewPicture::draw(int ResNum) +{ + + int err = game->ReadResource(PICTURE,ResNum); + if(!err){ + ppicture->show(ResourceData.Data,ResourceData.Size); + update(); + } + +} + +//***************************************** +void PreviewPicture::update() +{ + QPainter p(&pixmap); + byte **data; + int x,y; + byte c0=255,c; + + data = (drawing_mode)?ppicture->priority:ppicture->picture; + for(y=0;ywidth(); + int x = (W-pixsize*cur_w*2)/2; + p.drawPixmap( x, 0, pixmap ); +} + +//***************************************** +void PreviewView::update() +{ + int x,y; + + if(!view->opened)return; + + int w = view->loops[view->CurLoop].cels[view->CurCel].width; + int h = view->loops[view->CurLoop].cels[view->CurCel].height; + bool mirror = (view->loops[view->CurLoop].mirror!=-1); + byte *data = view->loops[view->CurLoop].cels[view->CurCel].data; + + if(cur_w != w || cur_h != h){ + pixmap.resize(w*pixsize*2,h*pixsize); + cur_w=w; + cur_h=h; + } + + QPainter p(&pixmap); + + if(mirror){ + for(y=0;yopen(ResNum); + if(!err){ + preview->showlooppar(); + preview->showcelpar(); + } + update(); + if(!err && view->Description != ""){ + show_description(); + preview->description->show(); + } + else{ + preview->description->hide(); + } + +} + +//***************************************** +void PreviewView::show_description() +{ + int x,y,w,h,W,H,n; + unsigned int maxcol; + + preview->description->hide(); + w = (view->loops[view->CurLoop].cels[view->CurCel].width)*2*pixsize; + h = (view->loops[view->CurLoop].cels[view->CurCel].height)*pixsize; + resize(w,h); + + W=preview->width(); + H=preview->height(); + x=this->x(); + y=this->y(); + preview->description->setGeometry(10,y+h+10,W-20,H-(y+h+20)); + + QFontMetrics f = fontMetrics(); + maxcol = (W-20)/f.width('a'); + + preview->description->clear(); + string ThisLine = ""; + string ThisMessage = view->Description; + + do{ + if(ThisMessage.length() + ThisLine.length() > maxcol){ + n = maxcol - ThisLine.length(); + do{ n--; }while(!(n == 0 || ThisMessage[n]==' ')); + if (n <= 0)n = maxcol-ThisLine.length(); + ThisLine += ThisMessage.substr(0,n); + ThisMessage = (n < (int)ThisMessage.length())?ThisMessage.substr(n+1):""; + preview->description->insertLine(ThisLine.c_str(),-1); + ThisLine = ""; + } + else{ + ThisLine += ThisMessage; + ThisMessage = ""; + } + + }while(ThisMessage != ""); + + if(ThisLine != ""){ + preview->description->insertLine(ThisLine.c_str(),-1); + } + +} +//***************************************** diff --git a/src/preview.h b/src/preview.h new file mode 100644 index 0000000..625b2f4 --- /dev/null +++ b/src/preview.h @@ -0,0 +1,131 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef PREVIEW_H +#define PREVIEW_H + +#include "picture.h" +#include "view.h" +#include "resources.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include + +class Animate; +class Preview; + +//**************************************************** +class PreviewView : public QWidget +{ + Q_OBJECT +public: + PreviewView( QWidget *parent=0, const char *name=0, Preview *p=0); + Preview *preview; + View *view; + QPixmap pixmap; + int cur_w,cur_h; + int pixsize; + void draw(int ResNum); + void update(); + void show_description(); + protected: + void paintEvent(QPaintEvent *); +}; + +//**************************************************** +class PreviewPicture : public QWidget +{ + Q_OBJECT +public: + PreviewPicture( QWidget *parent=0, const char *name=0, Preview *p=0); + Preview *preview; + BPicture *ppicture; + QPixmap pixmap; + int drawing_mode; + void draw(int ResNum); + void update(); + protected: + void paintEvent(QPaintEvent *); + +}; + +class ResourcesWin; +class LogEdit; + +//**************************************************** +class Preview : public Q3WidgetStack +{ + Q_OBJECT +public: + Preview( QWidget* parent = 0, const char* name=0, ResourcesWin *res=0); + Q3MultiLineEdit *description; + ResourcesWin *resources_win; + void open(int i,int type); +public slots: + void double_click(); + void change_mode(int); + void previous_loop(void); + void next_loop(void); + void previous_cel(void); + void next_cel(void); + void prev_cel_cycle(void); + void next_cel_cycle(void); + void showlooppar(); + void showcelpar(); + void save_image( QPixmap& img, const char* format ); + void save_pic(); + void save_view(); + void export_resource(); + void animate_cb(); + protected: + QComboBox *formats_pic, *formats_view; + QWidget *w_logic,*w_sound; + QWidget *w_picture; + + LogEdit *p_logic; + PreviewPicture *p_picture; + QRadioButton *visual,*priority; + QPushButton *save_pic_butt, *save_view_butt; + QWidget *w_view; + PreviewView *p_view; + QPushButton *loopleft,*loopright,*celleft,*celright; + QLabel *loopnum,*celnum; + Animate *animate; + void deinit(); + void closeEvent( QCloseEvent * ); + void showEvent( QShowEvent * ); + void hideEvent( QHideEvent * ); +}; + + +#endif diff --git a/src/resource.h b/src/resource.h new file mode 100644 index 0000000..78475a1 --- /dev/null +++ b/src/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by agistudio.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/resources.cpp b/src/resources.cpp new file mode 100644 index 0000000..7bd4d6c --- /dev/null +++ b/src/resources.cpp @@ -0,0 +1,779 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "resources.h" +#include "game.h" +#include "logedit.h" +#include "viewedit.h" +#include "preview.h" +#include "menu.h" +#include "midi.h" +#include "bmp2agipic.h" + +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef _WIN32 +#define strncasecmp(a, b, l) _stricmp(a, b) +#else +#include +#endif +#include +#include + + +//********************************************************** +ResourcesWin::ResourcesWin( QWidget* parent, const char* name, int win_num ): + QWidget(parent,name,Qt::WDestructiveClose) +{ + setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed )); + setCaption("resources"); + winnum = win_num; + + Q3PopupMenu *window = new Q3PopupMenu( this ); + Q_CHECK_PTR( window ); + window->insertItem ( "New", this, SLOT(new_resource_window()) ); + window->insertSeparator(); + window->insertItem ( "Close", this, SLOT(close()) ); + + + resourceMenu = new Q3PopupMenu( this ); + Q_CHECK_PTR( resourceMenu ); + resourceMenu->insertItem ( "&Add", this, SLOT(add_resource()) ); + resourceMenu->insertItem ( "&Extract", this, SLOT(extract_resource()) ); + resourceMenu->insertItem ( "&Delete", this, SLOT(delete_resource()) ); + resourceMenu->insertItem ( "&Renumber", this, SLOT(renumber_resource()) ); + importMenuItemID = resourceMenu->insertItem ( "Import &bitmap", this, SLOT(import_resource()) ); + resourceMenu->setItemEnabled(importMenuItemID, false); + resourceMenu->insertItem ( "Extract all", this, SLOT(extract_all_resource()) ); + + QMenuBar* resourceMenubar = new QMenuBar(this); + Q_CHECK_PTR( resourceMenubar ); + resourceMenubar->insertItem ("Window", window ); + resourceMenubar->insertItem( "&Resource", resourceMenu ); + resourceMenubar->setSeparator( QMenuBar::InWindowsStyle ); + + Q3BoxLayout *hbox = new Q3HBoxLayout( this, 10 ); + hbox->setMenuBar(resourceMenubar); + + Q3BoxLayout *resbox = new Q3VBoxLayout( hbox, 10 ); + + type = new QComboBox(FALSE, this, "type"); + + type->insertItem( "LOGIC" ); + type->insertItem( "PICTURE" ); + type->insertItem( "VIEW" ); + type->insertItem( "SOUND" ); + connect( type, SIGNAL(activated(int)), SLOT(select_resource_type(int)) ); + type->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed )); + resbox->addWidget(type); + + list = new Q3ListBox(this,"list"); + list->setColumnMode (1); + list->setMinimumSize(200,300); + connect( list, SIGNAL(highlighted(int)), SLOT(highlight_resource(int)) ); + connect( list, SIGNAL(selected(int)), SLOT(select_resource(int)) ); + list->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::MinimumExpanding )); + + selected = game->res_default; + resbox->addWidget(list); + + msg = new QLabel( this, "message" ); + msg->setAlignment( Qt::AlignLeft ); + resbox->addWidget(msg); + + addmenu = NULL; + preview = NULL; + closing = false; + + Q3BoxLayout *prevbox = new Q3VBoxLayout(hbox,10); + Q3GroupBox* group = new Q3GroupBox( 1, Qt::Vertical, "Preview", this ); + group->setMinimumSize(340+10*2,280+10*2); + group->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding )); + previewPane = group; + prevbox->addWidget(previewPane); + + adjustSize(); +} + +//******************************************************** +void ResourcesWin::select_resource_type( int ResType ) +{ + QString str; + int i,k; + + type->setCurrentItem(ResType); + selected = ResType; + + // enable import item if resource type supports it + resourceMenu->setItemEnabled(importMenuItemID, selected == PICTURE ); + + // Show a resource list + list->hide(); + list->clear(); + for(i=0,k=0;i<256;i++){ + if(game->ResourceInfo[ResType][i].Exists){ + str.sprintf( "%s.%3d", ResTypeName[ResType],i); + list->insertItem( str ); + ResourceIndex[k++]=i; + } + } + ResourceNum = k; + list->show(); + first=true; +} + +//******************************************************** +void ResourcesWin::highlight_resource( int k ) +{ + int i = ResourceIndex[k]; + int size = game->GetResourceSize(selected,i); + + QString str; + str.sprintf("%d bytes",size); + msg->setText(str); + + if(preview==NULL) + preview = new Preview(previewPane,0,this); + + preview->open(i,selected); + preview->show(); +} +//******************************************************** +void ResourcesWin::select_resource( int k ) +{ + int i = ResourceIndex[k]; + int size = game->GetResourceSize(selected,i); + int n; + extern void play_sound(int ResNum); + + QString str; + str.sprintf("%d bytes",size); + msg->setText(str); + + if((n=get_win())==-1)return; + switch(selected){ + case LOGIC: + winlist[n].w.l=new LogEdit(NULL,NULL,n); + winlist[n].type=LOGIC; + winlist[n].w.l->open(i); + break; + case PICTURE: + winlist[n].w.p=new PicEdit(NULL,NULL,n); + winlist[n].type=PICTURE; + winlist[n].w.p->open(i); + break; + case VIEW: + winlist[n].w.v = new ViewEdit(NULL,NULL,n); + winlist[n].type=VIEW; + winlist[n].w.v->open(i); + break; + case SOUND: + play_sound(i); + break; + } +} + +//******************************************************** +void ResourcesWin::set_current( int n ) +{ + + for(int i=0;isetCurrentItem(i); + break; + } + } + +} +//********************************************* +void ResourcesWin::deinit( ) +{ + closing = true; + if(preview){ + preview->close(); + preview=NULL; + } + for(int i=0;iresources_win==this)winlist[i].w.l->resources_win=NULL; + break; + case VIEW: + if(winlist[i].w.v->resources_win==this)winlist[i].w.v->resources_win=NULL; + break; + case PICTURE: + if(winlist[i].w.p->resources_win==this)winlist[i].w.p->resources_win=NULL; + break; + } + } + + winlist[winnum].type=-1; + menu->dec_res(); + if(window_list && window_list->isVisible())window_list->draw(); + +} +//********************************************* +void ResourcesWin::closeEvent( QCloseEvent *e ) +{ + + deinit(); + e->accept(); + +} +//********************************************* +void ResourcesWin::hideEvent( QHideEvent * ) +{ + + if(preview && preview->isVisible())preview->showMinimized(); + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//********************************************* +void ResourcesWin::showEvent( QShowEvent * ) +{ + + if(preview && !preview->isVisible())preview->showNormal(); + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//********************************************** +void ResourcesWin::new_resource_window() +{ + + menu->new_resource_window(); +} + +//********************************************** +void ResourcesWin::delete_resource() +{ + + int restype = selected; + int k = list->currentItem(); + int resnum = ResourceIndex[k]; + + sprintf(tmp,"Really delete %s.%d ?",ResTypeName[restype],resnum); + switch( QMessageBox::warning( this, "Delete resource", tmp, + "Delete", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + game->DeleteResource(restype,resnum); + select_resource_type(restype); + if(k>0) + list->setCurrentItem(k-1); + else + list->setCurrentItem(0); + break; + case 1: + break; + } + +} + +//********************************************** +void ResourcesWin::renumber_resource() +{ + + int k = list->currentItem(); + if(k==-1)return; + + AskNumber *ask_number = new AskNumber(0,0,"Resource number", + "Enter new resource number [0-255]: "); + + if(!ask_number->exec())return; + + QString str = ask_number->num->text(); + int newnum = atoi((char *)str.latin1()); + int restype = selected; + int resnum = ResourceIndex[k]; + if(game->ResourceInfo[restype][newnum].Exists){ + sprintf(tmp,"Resource %s.%d already exists. Replace it ?",ResTypeName[restype],newnum); + } + switch( QMessageBox::warning( this, "Renumber resource", tmp, + "Replace", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + game->ReadResource(restype,resnum); + game->DeleteResource(restype,resnum); + game->AddResource(restype,newnum); + select_resource_type(restype); + break; + case 1: + break; + } +} + +static QImage openBitmap( const char* title ) +{ + Q3FileDialog *f = new Q3FileDialog(0,"Load visible bitmap",true); + const char *filters[] = {"All files (*)",NULL}; + f->setFilters(filters); + + QImage pic; + + f->setCaption(title); + f->setMode(Q3FileDialog::ExistingFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) + if ( !f->selectedFile().isEmpty() ) + { + pic = QImage( f->selectedFile()); + if ( pic.isNull()) + menu->errmes("Error loading bitmap."); + } + + if (!pic.isNull()) + if ( (pic.width() != 320 && pic.width() != 160) || pic.height()<168 ) + { + menu->errmes("Bitmap size must be 320x168 or 160x168.\nHeight can be more but will be cropped to 168."); + } + return pic; +} + +//********************************************** +void ResourcesWin::import_resource() +{ + QImage vis, pri; + + vis = openBitmap("Open visible bitmap"); + if ( vis.isNull()) + return; + pri = openBitmap("Open PRIORITY bitmap (or press cancel)"); + + AskNumber *ask_number = new AskNumber(0,0,"Resource number", + "Enter new resource number [0-255]: "); + if(!ask_number->exec()) return; + + QString str = ask_number->num->text(); + int newnum = atoi((char *)str.latin1()); + int restype = selected; + + int replace = 0; + if(game->ResourceInfo[restype][newnum].Exists) + { + sprintf(tmp,"Resource %s.%d already exists. Replace it ?",ResTypeName[restype],newnum); + replace = QMessageBox::warning( this, "Overwrite resource", tmp, "Replace", "Cancel", 0, 1 ); + } + switch( replace ) + { + case 0: + { + if(game->ResourceInfo[restype][newnum].Exists) + game->DeleteResource(restype, newnum); + + QByteArray res; + const char* err = bitmapToAGIPicture( vis, pri, &res ); + if ( err ) + { + menu->errmes(err); + return; + } + ResourceData.Size = res.size(); + memcpy( ResourceData.Data, res.data(), res.size()); + + game->AddResource(restype, newnum); // uses data from ResourceData + select_resource_type(restype); + + for ( int k=0; k<255; ++k ) + if ( ResourceIndex[k] == newnum ) + list->setSelected(k, true); + } + break; + case 1: + break; + } +} + +//********************************************** +static void extract(char *filename,int restype,int resnum) +{ + if(game->ReadResource(restype,resnum))return ; + + FILE *fptr=fopen(filename,"wb"); + if(fptr==NULL){ + menu->errmes("Can't open file %s ! ",filename); + return ; + } + if(restype==LOGIC && game->save_logic_as_text){ + Logic *logic = new Logic(); + int err=logic->decode(resnum); + if(!err)fprintf(fptr,"%s",logic->OutputText.c_str()); + delete logic; + } + else{ + fwrite(ResourceData.Data,ResourceData.Size,1,fptr); + } + fclose(fptr); +} + +//********************************************** +void ResourcesWin::extract_resource() +{ + + int restype = selected; + int k = list->currentItem(); + int resnum = ResourceIndex[k]; + + Q3FileDialog *f = new Q3FileDialog(0,"Extract resource",true); + f->setCaption("Extract resource"); + f->setMode(Q3FileDialog::AnyFile); + f->setDir(game->srcdir.c_str()); + sprintf(tmp,"%s.%03d",ResTypeName[restype],resnum); + f->setSelection(tmp); + + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ){ + extract((char *)f->selectedFile().latin1(),restype,resnum); + } + } +} + +//********************************************** +void ResourcesWin::extract_all_resource() +{ + char filename[256]; + + int restype = selected; + sprintf(tmp,"Do you really want to extract all %s resources ?",ResTypeName[restype]); + switch( QMessageBox::warning( this, "Extract all", tmp, + "Yes", "No", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + break; + case 1: + return; + } + + + for(int resnum=0;resnum<256;resnum++){ + if(game->ResourceInfo[restype][resnum].Exists){ + sprintf(filename,"%s/%s.%03d",game->srcdir.c_str(),ResTypeName[restype],resnum); + extract(filename,restype,resnum); + } + } + +} + +//********************************************** +void ResourcesWin::add_resource() +{ + + Q3FileDialog *f = new Q3FileDialog(0,"Add resource",true); + + static const char *types[6] = {"logic*.*","picture*.*","view*.*","sound*.*","All files (*)",NULL}; + + const char *filters[6]; + + switch(selected){ + case LOGIC: + filters[0]=types[LOGIC]; + filters[1]=types[PICTURE]; + filters[2]=types[VIEW]; + filters[3]=types[SOUND]; + break; + case PICTURE: + filters[1]=types[LOGIC]; + filters[0]=types[PICTURE]; + filters[2]=types[VIEW]; + filters[3]=types[SOUND]; + break; + case VIEW: + filters[1]=types[LOGIC]; + filters[2]=types[PICTURE]; + filters[0]=types[VIEW]; + filters[3]=types[SOUND]; + break; + case SOUND: + filters[1]=types[LOGIC]; + filters[2]=types[PICTURE]; + filters[3]=types[VIEW]; + filters[0]=types[SOUND]; + break; + } + filters[4]=types[4]; + filters[5]=NULL; + + f->setFilters((const char **)filters); + f->setCaption("Add resource"); + f->setMode(Q3FileDialog::ExistingFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ){ + if(addmenu==NULL)addmenu = new AddResource(0,0,this); + addmenu->open((char *)f->selectedFile().latin1()); + } + } + + +} + +//********************************************** +void ResourcesWin::export_resource() +{ + int k = list->currentItem(); + if(k<0) return; + int i = ResourceIndex[k]; + + switch(selected) { + case SOUND: + if(game->ReadResource(SOUND,i)) + menu->errmes("Couldn't read sound resource ! "); + else + showSaveAsMidi( this, ResourceData.Data ); + break; + default: + qWarning("BUG in code. Export not supported for this resource type!"); + break; + } +} + +//********************************************** +AddResource::AddResource( QWidget *parent, const char *nam ,ResourcesWin *res ) + : QWidget( parent, nam ) +{ + + resources_win = res; + setCaption("Add resource"); + Q3BoxLayout *box = new Q3VBoxLayout(this,10); + + filename = new QLabel("Filename:",this); + // filename->setAutoResize(true); // TODO: REPLACE WITH A LAYOUT! + box->addWidget(filename); + + Q3BoxLayout *box0 = new Q3HBoxLayout(box,4); + + QLabel *lname = new QLabel("Name of resource:",this); + box0->addWidget(lname); + + name = new QLabel("",this); + // name->setAutoResize(true); // TODO: REPLACE WITH A LAYOUT! + box0->addWidget(name); + + type = new Q3ButtonGroup(4,Qt::Horizontal,"Type",this); + type->setExclusive(true); + QRadioButton *logic = new QRadioButton(type); + logic->setText("LOGIC"); + logic->setChecked(true); + restype=0; + QRadioButton *picture = new QRadioButton(type); + picture->setText("PICTURE"); + QRadioButton *view = new QRadioButton(type); + view->setText("VIEW"); + QRadioButton *sound = new QRadioButton(type); + sound->setText("SOUND"); + + connect( type, SIGNAL(clicked(int)), SLOT(select_type(int)) ); + + box->addWidget(type); + + Q3BoxLayout *box1 = new Q3HBoxLayout(box,10); + + QLabel *lnumber = new QLabel("Number: [0-255]",this); + box1->addWidget(lnumber); + + number = new QLineEdit(this); + number->setMinimumWidth(60); + connect( number, SIGNAL(textChanged(const QString &)), SLOT(edit_cb(const QString &)) ); + box1->addWidget(number); + + Q3BoxLayout *box2 = new Q3HBoxLayout(box,40); + + QPushButton *ok = new QPushButton("OK",this); + connect( ok, SIGNAL(clicked()), SLOT(ok_cb()) ); + box2->addWidget(ok); + + QPushButton *cancel = new QPushButton("Cancel",this); + connect( cancel, SIGNAL(clicked()), SLOT(cancel_cb()) ); + box2->addWidget(cancel); + +} + +//********************************************** +void AddResource::open(char *file_name) +{ + char *ptr; + + file = string(file_name); + if((ptr = strrchr(file_name,'/'))==NULL)ptr=file_name; + else ptr++; + sprintf(tmp,"Filename: %s",ptr); + filename->setText(tmp); + if(!strncasecmp(ptr,"logic",5)){ + restype=LOGIC; + type->setButton(restype); + } + else if(!strncasecmp(ptr,"picture",7)){ + restype=PICTURE; + type->setButton(restype); + } + else if(!strncasecmp(ptr,"view",4)){ + restype=VIEW; + type->setButton(VIEW); + } + else if(!strncasecmp(ptr,"sound",5)){ + restype=SOUND; + type->setButton(SOUND); + } + + select_type(restype); + show(); + +} + +//********************************************** +void AddResource::edit_cb(const QString &str) +{ + + int num = atoi((char *)str.latin1()); + sprintf(tmp,"%s.%d",ResTypeName[restype],num); + name->setText(tmp); + +} + +//********************************************** +static int load_resource(const char *filename,int restype) +{ + extern TStringList InputLines; + char *ptr; + byte b; + FILE *fptr = fopen(filename,"rb"); + if(fptr==NULL){ + menu->errmes("Can't open file %s ! ",filename); + return 1; + } + struct stat buf; + fstat(fileno(fptr),&buf); + int size=buf.st_size; + if(size >= MaxResourceSize){ + menu->errmes("File %s is too big ! ",filename); + fclose(fptr); + return 1; + } + + if(restype==LOGIC){ + //check if file is binary or ascii + fread(ResourceData.Data,MIN(size,64),1,fptr); + for(int i=0;i0x80||(b<0x20&&b!=0x0a&&b!=0x0d&&b!=0x09)){ //file is binary + fseek(fptr,0,SEEK_SET); + ResourceData.Size = size; + fread(ResourceData.Data,ResourceData.Size,1,fptr); + fclose(fptr); + return 0; + } + } + //file is ascii - trying to compile + fseek(fptr,0,SEEK_SET); + Logic *logic = new Logic(); + InputLines.lfree(); + while(fgets(tmp,1024,fptr)!=NULL){ + if((ptr=strchr(tmp,0x0a)))*ptr=0; + if((ptr=strchr(tmp,0x0d)))*ptr=0; + InputLines.add(tmp); + } + fclose(fptr); + int err = logic->compile(); + delete logic; + if(err)return 1; + } + else{ + ResourceData.Size = size; + fread(ResourceData.Data,ResourceData.Size,1,fptr); + fclose(fptr); + } + return 0; + +} + +//********************************************** +void AddResource::ok_cb() +{ + + QString str = number->text(); + int num = atoi((char *)str.latin1()); + + if(num<0||num>255){ + menu->errmes("Resource number must be between 0 and 255 !"); + return ; + } + + if(game->ResourceInfo[restype][num].Exists){ + sprintf(tmp,"Resource %s.%d already exists. Replace it ?",ResTypeName[restype],num); + + switch( QMessageBox::warning( this, "Add resource", tmp, + "Replace", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + if(!load_resource(file.c_str(),restype)) + game->AddResource(restype,num); + break; + case 1: + break; + } + } + else{ + if(!load_resource(file.c_str(),restype)){ + game->AddResource(restype,num); + if( resources_win->selected == restype) + resources_win->select_resource_type(restype); + } + } + hide(); + +} + +//********************************************** +void AddResource::cancel_cb() +{ + + hide(); + +} + +//********************************************** +void AddResource::select_type(int type) +{ + restype = type; + + QString str = number->text(); + int num = atoi((char *)str.latin1()); + + sprintf(tmp,"%s.%d",ResTypeName[restype],num); + name->setText(tmp); + +} + diff --git a/src/resources.h b/src/resources.h new file mode 100644 index 0000000..4f20656 --- /dev/null +++ b/src/resources.h @@ -0,0 +1,110 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef RESOURCES_H +#define RESOURCES_H + +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include + + +#include "preview.h" + +class ResourcesWin; +class Preview; + +class AddResource : public QWidget +{ + Q_OBJECT +public: + AddResource( QWidget *parent=0, const char *name=0 , ResourcesWin *res=0); + + QLabel *filename; + QLabel *name; + QLineEdit *number; + Q3ButtonGroup *type; + ResourcesWin *resources_win; + Preview *preview; + int restype; + string file; + void open(char *filename); +public slots: + void ok_cb(); + void cancel_cb(); + void select_type(int); + void edit_cb(const QString &); +}; + + + +class ResourcesWin : public QWidget +{ + Q_OBJECT +public: + ResourcesWin( QWidget* parent = 0, const char* name=0, int winnum=0); + Q3ListBox *list; + int selected; + int ResourceNum; + Preview *preview; + unsigned char ResourceIndex[256]; + bool closing; +public slots: + void select_resource_type( int i); + void highlight_resource( int i); + void select_resource( int i); + void set_current(int i); + void add_resource(void); + void extract_resource(void); + void extract_all_resource(void); + void delete_resource(void); + void renumber_resource(void); + void new_resource_window(void); + void export_resource(void); + void import_resource(void); + + protected: + bool first; + QLabel *msg; + QComboBox *type; + QWidget *previewPane; + AddResource *addmenu; + + Q3PopupMenu *resourceMenu; + int importMenuItemID; + + int winnum; + void closeEvent( QCloseEvent *e ); + void showEvent( QShowEvent * ); + void hideEvent( QHideEvent * ); + void deinit(); +}; + +#endif diff --git a/src/right.xpm b/src/right.xpm new file mode 100644 index 0000000..7b93ad9 --- /dev/null +++ b/src/right.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *right[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +" c black", +". c gray100", +/* pixels */ +"................", +"................", +".... ..........", +".... .........", +".... ........", +".... .......", +".... ......", +".... .....", +".... .....", +".... ......", +".... .......", +".... ........", +".... .........", +".... ..........", +"................", +"................" +}; diff --git a/src/right1.xpm b/src/right1.xpm new file mode 100644 index 0000000..c592402 --- /dev/null +++ b/src/right1.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *right1[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +" c black", +". c gray100", +/* pixels */ +"................", +"................", +".... ........", +"..... .......", +"...... ......", +"....... .....", +"........ ....", +"......... ...", +"......... ...", +"........ ....", +"....... .....", +"...... ......", +"..... .......", +".... ........", +"................", +"................" +}; diff --git a/src/right1_x.xpm b/src/right1_x.xpm new file mode 100644 index 0000000..8a59df6 --- /dev/null +++ b/src/right1_x.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *right1_x[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +" c black", +". c None", +/* pixels */ +"................", +"................", +".... ........", +"..... .......", +"...... ......", +"....... .....", +"........ ....", +"......... ...", +"......... ...", +"........ ....", +"....... .....", +"...... ......", +"..... .......", +".... ........", +"................", +"................" +}; diff --git a/src/right2.xpm b/src/right2.xpm new file mode 100644 index 0000000..0aca320 --- /dev/null +++ b/src/right2.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *right2[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +" c black", +". c gray100", +/* pixels */ +"................", +"................", +". ... ......", +".. ... .....", +"... ... ....", +".... ... ...", +"..... ... ..", +"...... ... .", +"...... ... .", +"..... ... ..", +".... ... ...", +"... ... ....", +".. ... .....", +". ... ......", +"................", +"................" +}; diff --git a/src/right2_x.xpm b/src/right2_x.xpm new file mode 100644 index 0000000..087077c --- /dev/null +++ b/src/right2_x.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *right2_x[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +" c black", +". c None", +/* pixels */ +"................", +"................", +". ... ......", +".. ... .....", +"... ... ....", +".... ... ...", +"..... ... ..", +"...... ... .", +"...... ... .", +"..... ... ..", +".... ... ...", +"... ... ....", +".. ... .....", +". ... ......", +"................", +"................" +}; diff --git a/src/right_x.xpm b/src/right_x.xpm new file mode 100644 index 0000000..ece32d4 --- /dev/null +++ b/src/right_x.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *right_x[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +" c black", +". c None", +/* pixels */ +"................", +"................", +".... ..........", +".... .........", +".... ........", +".... .......", +".... ......", +".... .....", +".... .....", +".... ......", +".... .......", +".... ........", +".... .........", +".... ..........", +"................", +"................" +}; diff --git a/src/rightarrow_x.xpm b/src/rightarrow_x.xpm new file mode 100644 index 0000000..f8985d1 --- /dev/null +++ b/src/rightarrow_x.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *rightarrow_x[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +" c black", +". c None", +/* pixels */ +"....... .......", +"....... ......", +"....... .....", +"....... ....", +"....... ...", +"....... ..", +". .", +". ", +". ", +". .", +"....... ..", +"....... ...", +"....... ....", +"....... .....", +"....... ......", +"....... ......." +}; diff --git a/src/roomgen.cpp b/src/roomgen.cpp new file mode 100644 index 0000000..123fd06 --- /dev/null +++ b/src/roomgen.cpp @@ -0,0 +1,916 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * The idea and most of the design of RoomGen module are copied from the + * "AGI Base Logic Generator" utility by Joel McCormick. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "logedit.h" +#include "game.h" +#include "menu.h" +#include "roomgen.h" + +#include +#include +#include +#ifndef _WIN32 +#include +#include +#endif +#include +#include +#include + +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include + +static const char *dirs[4] = {"left","right","bottom","horizon"}; + +//*********************************************** +RoomGen::RoomGen( QWidget *parent, const char *name) + : QDialog( parent, name, true ) +{ + int i; + setCaption("AGI Base Logic Generator"); + + Q3BoxLayout *all = new Q3VBoxLayout(this,5); + + Q3HBoxLayout *upper = new Q3HBoxLayout(all,10); + + Q3Grid *gtxt = new Q3Grid( 2, this); + gtxt->setSpacing(4); + upper->addWidget(gtxt); + + QLabel *llog = new QLabel("Logic Number:",gtxt); + llog=llog; //avoid compilation warning + lnum = new QLineEdit(gtxt); + lnum->setFixedWidth(40); + lnum->setText("0"); + //lnum->selectAll(); + connect(lnum,SIGNAL(textChanged(const QString &)),SLOT(lnum_cb())); + + QLabel *lpic = new QLabel("Picture Number:",gtxt); + lpic=lpic; + pnum = new QLineEdit(gtxt); + pnum->setFixedWidth(40); + pnum->setText("0"); + //pnum->selectAll(); + + QLabel *lhor = new QLabel("Horizon at Y:",gtxt); + lhor=lhor; + hnum = new QLineEdit(gtxt); + hnum->setFixedWidth(40); + hnum->setText("36"); + //hnum->selectAll(); + + Q3VBoxLayout *check = new Q3VBoxLayout(upper,2); + draw_ego = new QCheckBox("Draw Ego initially",this); + draw_ego->setChecked(true); + check->addWidget(draw_ego); + first_room = new QCheckBox("First room",this); + connect(first_room,SIGNAL(clicked()),SLOT(first_room_cb())); + check->addWidget(first_room); + inc_def = new QCheckBox("Include defines.txt",this); + check->addWidget(inc_def); + inc_def->setChecked(true); + gen_comm = new QCheckBox("Generate comments",this); + gen_comm->setChecked(true); + check->addWidget(gen_comm); + + Q3VBoxLayout *but = new Q3VBoxLayout(upper,2); + QPushButton *entry = new QPushButton("Entry and looking",this); + connect(entry,SIGNAL(clicked()),SLOT(entry_cb())); + but->addWidget(entry); + QPushButton *first = new QPushButton("First room controls",this); + connect(first,SIGNAL(clicked()),SLOT(first_cb())); + but->addWidget(first); + + Q3BoxLayout *ledge = new Q3HBoxLayout(all,1); + + // QGroupBox *ego_pos_b = new QGroupBox(1,Horizontal,"Ego Positioning (-1 = ignore)",this); + Q3Frame *ego_pos_b = new Q3Frame(this); + ego_pos_b->setFrameStyle( Q3Frame::Box | Q3Frame::Sunken ); + ego_pos_b->setLineWidth(1); + ego_pos_b->setMargin(2); + + Q3GridLayout *ego_pos = new Q3GridLayout(ego_pos_b,6,6,10,4); + + QLabel *ll = new QLabel("Ego Positioning (-1 = ignore)",ego_pos_b); + ego_pos->addMultiCellWidget(ll,0,0,0,5,AlignCenter); + + + int row=1,col; + + QLabel *l_from = new QLabel("Coming from",ego_pos_b); + ego_pos->addMultiCellWidget(l_from,row,row,0,1,AlignLeft); + + QLabel *l_pos = new QLabel("Position Ego at",ego_pos_b); + ego_pos->addMultiCellWidget(l_pos,row,row,2,5,AlignCenter); + + QLabel *l_lroom[4],*l_x[4],*l_y[4]; + row++; + + for(i=0;i<4;i++,row++){ + col=0; + l_lroom[i] = new QLabel("room:",ego_pos_b); + ego_pos->addWidget(l_lroom[i],row,col,AlignRight); col++; + from[i] = new QLineEdit(ego_pos_b); + from[i]->setFixedWidth(40); + from[i]->setText("-1"); + // from[i]->selectAll(); + ego_pos->addWidget(from[i],row,col,AlignLeft); col++; + + + l_x[i] = new QLabel("X:",ego_pos_b); + ego_pos->addWidget(l_x[i],row,col,AlignRight); col++; + x[i] = new QLineEdit(ego_pos_b); + x[i]->setText("-1"); + // x[i]->selectAll(); + x[i]->setFixedWidth(40); + ego_pos->addWidget(x[i],row,col,AlignLeft); col++; + + l_y[i] = new QLabel("Y:",ego_pos_b); + ego_pos->addWidget(l_y[i],row,col,AlignRight); col++; + y[i] = new QLineEdit(ego_pos_b); + y[i]->setText("-1"); + // y[i]->selectAll(); + y[i]->setFixedWidth(40); + ego_pos->addWidget(y[i],row,col,AlignLeft); col++; + } + + + QPushButton *ego_adv = new QPushButton("Advanced",ego_pos_b); + connect(ego_adv,SIGNAL(clicked()),SLOT(ego_advanced_cb())); + ego_pos->addMultiCellWidget(ego_adv,row,row,0,5,AlignCenter); + + ledge->addWidget(ego_pos_b,1); + + + Q3Frame *edge_control_b = new Q3Frame(this); + edge_control_b->setFrameStyle( Q3Frame::Box | Q3Frame::Sunken ); + edge_control_b->setLineWidth(1); + edge_control_b->setMargin(4); + + Q3GridLayout *edge_control = new Q3GridLayout(edge_control_b,6,2,10,1); + + QLabel *ll1 = new QLabel("Edge Controls (-1 = ignore)",edge_control_b); + edge_control->addMultiCellWidget(ll1,0,0,0,1,AlignCenter); + + row=1; + col=0; + + QLabel *l_if = new QLabel("If Ego touches:",edge_control_b); + edge_control->addWidget(l_if,row,col,AlignLeft); col++; + QLabel *l_goto = new QLabel("Goto Room:",edge_control_b); + edge_control->addWidget(l_goto,row,col,AlignCenter); col++; + row++; + + QLabel *l_e[4]; + const char *dirs[4] = {"Left Edge:","Right Edge:","Bottom Edge:","Horizon Edge:"}; + + for(i=0;i<4;i++,row++){ + col=0; + l_e[i] = new QLabel(dirs[i],edge_control_b); + edge_control->addWidget(l_e[i],row,col,AlignLeft); col++; + edge[i] = new QLineEdit(edge_control_b); + edge[i]->setFixedWidth(40); + edge[i]->setText("-1"); + // edge[i]->selectAll(); + edge_control->addWidget(edge[i],row,col,AlignCenter); col++; + } + + col=0; + QPushButton *edge_adv = new QPushButton("Advanced",edge_control_b); + connect(edge_adv,SIGNAL(clicked()),SLOT(edge_advanced_cb())); + edge_control->addMultiCellWidget(edge_adv,row,row,0,1,AlignCenter); + + ledge->addWidget(edge_control_b,0); + + Q3HBoxLayout *ltitle = new Q3HBoxLayout(all,4); + + QLabel *lcom = new QLabel("Logic Title (for comments):",this); + ltitle->addWidget(lcom); + title = new QLineEdit(this); + ltitle->addWidget(title); + + Q3HBoxLayout *last = new Q3HBoxLayout(all,20); + + QPushButton *ok = new QPushButton("OK",this); + ok->setMaximumSize(80,40); + connect(ok,SIGNAL(clicked()),SLOT(ok_cb())); + last->addWidget(ok,AlignRight); + + QPushButton *cancel = new QPushButton("Cancel",this); + cancel->setMaximumSize(80,40); + connect(cancel,SIGNAL(clicked()),SLOT(reject())); + last->addWidget(cancel,AlignLeft); + + adjustSize(); + + room_entry = NULL; + room_first = NULL; + ego_advanced = NULL; + edge_advanced = NULL; + xa=ya=-1; + for(i=0;i<4;i++){ + empty_e[i]=false; + display_e[i]=false; + e_mes[i]="You can't go that way."; + } + entry_mes=""; + look_mes=""; + status=input=true; + x1=y1=-1; +} +//************************************************ +bool RoomGen::bad_int(QLineEdit *w,int *res,int nmin,int nmax,bool ignore,const char *text) +{ + + *res=-1; + QString str=w->text(); + + if(!str.isEmpty()) + *res=atoi((char *)str.latin1()); + if((*res==-1) && ignore)return false; + if((*resnmax)){ + menu->errmes("%s must be between %d and %d !",text,nmin,nmax); + return true; + } + return false; + +} +//************************************************ +bool RoomGen::bad_int(int res,int nmin,int nmax,bool ignore,const char *text) +{ + + if(res==-1 && ignore)return false; + if(resnmax){ + menu->errmes("%s must be between %d and %d !",text,nmin,nmax); + return true; + } + return false; + +} + +//************************************************ +bool RoomGen::bad_input() +{ + + QString str; + int i; + + if(bad_int(lnum,&ln,0,255,false,"Logic number"))return true; + if(bad_int(pnum,&pn,0,255,false,"Picture number"))return true; + if(bad_int(hnum,&hn,0,167,false,"Horizon value"))return true; + + + for(i=0;i<4;i++){ + rn[i]=xn[i]=yn[i]=-1; + str=from[i]->text(); + if(!str.isEmpty())rn[i]=atoi((char *)str.latin1()); + str=x[i]->text(); + if(!str.isEmpty())xn[i]=atoi((char *)str.latin1()); + str=y[i]->text(); + if(!str.isEmpty())yn[i]=atoi((char *)str.latin1()); + if(rn[i]==-1||xn[i]==-1||yn[i]==-1){ + if(!(rn[i]==-1&&xn[i]==-1&&yn[i]==-1)){ + menu->errmes("Ego positioning: incomplete input !"); + return true; + } + } + else{ + if(bad_int(rn[i],0,255,false,"Ego positioning:\nRoom number"))return true; + if(bad_int(xn[i],0,319,false,"Ego positioning:\nX"))return true; + if(bad_int(yn[i],0,167,false,"Ego positioning:\nY"))return true; + } + } + + for(i=0;i<4;i++){ + if(bad_int(edge[i],&en[i],0,255,true,"Edge controls:\nroom number"))return true; + } + + if(!(xa==-1&&ya==-1)){ + if(bad_int(xa,0,319,false,"Unconditional Ego positioning:\nX"))return true; + if(bad_int(ya,0,167,false,"Unconditional Ego positioning:\nY"))return true; + } + + if(!(x1==-1&&y1==-1)){ + if(bad_int(x1,0,319,false,"First room Ego positioning:\nX"))return true; + if(bad_int(y1,0,167,false,"First room Ego positioning:\nY"))return true; + } + + return false; + +} +//************************************************ +void RoomGen::ok_cb() +{ + int i,k; + int level=0; + + if(bad_input())return; + + bool com=gen_comm->isChecked(); + + text="// ****************************************************************\n\ +//\n"; + QString str=title->text(); + if(str.isEmpty()){ + sprintf(tmp,"// Logic %d\n",ln); + } + else{ + sprintf(tmp,"// Logic %d: %s\n",ln,str.latin1()); + } + text+=tmp; + text+="// \n// ****************************************************************\n"; + + if(inc_def->isChecked()){ + text+="#include \"defines.txt\"\n"; + } + + text+="if (new_room) {\n"; + + if(ln==pn){ + text+=" load.pic(room_no);\n\ + draw.pic(room_no);\n\ + discard.pic(room_no);\n"; + } + else{ + sprintf(tmp," v255=%d;\n",pn); + text+=tmp; + text+=" load.pic(v255);\n\ + draw.pic(v255);\n\ + discard.pic(v255);\n"; + } + if(com)text+=" //ADD ADDITIONAL INITIALIZATION CODE HERE\n"; + + + if(hn!=36){ + sprintf(tmp," set.horizon(%d);\n",hn); + text+=tmp; + } + + if(first_room->isChecked()){ + text+=" if ((prev_room_no == 0 || prev_room_no == 1)){\n"; + if(com)text+=" //THIS IS THE FIRST ROOM, ADD ANY ONE-TIME INITIALIZATION HERE\n"; + if(x1!=-1){ + sprintf(tmp," position(ego, %d, %d);\n",x1,y1); + text+=tmp; + } + if(status)text+=" status.line.on();\n"; + if(input)text+=" accept.input();\n"; + text+=" }\n"; + level++; + } + + for(i=0;i<4;i++){ + if(rn[i]==-1)continue; + if(level){ + for(k=0;k0;i--){ + for(k=0;kisChecked()){ + text+=" draw(ego);\n"; + } + text+=" show.pic();\n"; + + if(entry_mes.length()>0){ + sprintf(tmp," print(\"%s\");\n",entry_mes.c_str()); + text+=tmp; + } + text+="}\n"; + + for(i=0;i<4;i++){ + if(en[i]==-1){ + if(display_e[i]){ + sprintf(tmp,"if (ego_edge_code == %s_edge){\n",dirs[i]); + text+=tmp; + sprintf(tmp," print(\"%s\");\n",e_mes[i].c_str()); + text+=tmp; + text+=" ego_dir = 0;\n}\n"; + } + else if(empty_e[i]){ + sprintf(tmp,"if (ego_edge_code == %s_edge){\n",dirs[i]); + text+=tmp; + if(com){ + sprintf(tmp," //ADD EGO-TOUCHING-%s CODE HERE\n",dirs[i]); + text+=tmp; + } + sprintf(tmp,"}\n"); + text+=tmp; + } + } + else{ + sprintf(tmp,"if (ego_edge_code == %s_edge){\n",dirs[i]); + text+=tmp; + if(com){ + sprintf(tmp," //ADD ADDITIONAL %s EXIT CODE HERE\n",dirs[i]); + text+=tmp; + } + sprintf(tmp," new.room(%d);\n}\n",en[i]); + text+=tmp; + } + } + + text+="if (input_recieved && unknown_word_no == 0 && !input_parsed) {\n"; + if(look_mes.length()>0){ + text += " if (said(\"look\")){\n"; + sprintf(tmp," print(\"%s\");\n }\n",look_mes.c_str()); + text+=tmp; + } + text +="}\n\nreturn();\n"; + + + done(Accepted); + +} +//************************************************ +void RoomGen::ego_advanced_cb() +{ + + if(ego_advanced==NULL)ego_advanced = new RoomGenPos(); + sprintf(tmp,"%d",xa); + ego_advanced->x->setText(tmp); + sprintf(tmp,"%d",ya); + ego_advanced->y->setText(tmp); + if(ego_advanced->exec()){ + xa=atoi((char *)ego_advanced->x->text().latin1()); + ya=atoi((char *)ego_advanced->y->text().latin1()); + } + +} +//************************************************ + +void RoomGen::edge_advanced_cb() +{ + int i; + + if(edge_advanced==NULL)edge_advanced = new RoomGenEdge(); + for(i=0;i<4;i++){ + edge_advanced->c_edge[i]->setChecked(empty_e[i]); + edge_advanced->m_edge[i]->setChecked(display_e[i]); + edge_advanced->e_mes[i]=e_mes[i]; + } + if(edge_advanced->exec()){ + for(i=0;i<4;i++){ + empty_e[i]=edge_advanced->c_edge[i]->isChecked(); + display_e[i]=edge_advanced->m_edge[i]->isChecked(); + if(display_e[i]){ + e_mes[i]=edge_advanced->e_mes[i]; + } + } + } + +} + +//************************************************ + +void RoomGen::entry_cb() +{ + + if(room_entry==NULL)room_entry = new RoomGenEntry(); + room_entry->entry_text->setText(entry_mes.c_str()); + room_entry->look_text->setText(look_mes.c_str()); + if(room_entry->exec()){ + entry_mes=room_entry->entry_text->text().latin1(); + look_mes=room_entry->look_text->text().latin1(); + } + + +} +//************************************************ + +void RoomGen::first_room_cb() +{ + + if(first_room->isChecked()){ + first_cb(); + } + +} +//************************************************ + + +void RoomGen::first_cb() +{ + + if(room_first==NULL)room_first = new RoomGenFirst(); + room_first->status->setChecked(status); + room_first->input->setChecked(input); + sprintf(tmp,"%d",x1); + room_first->x->setText(tmp); + sprintf(tmp,"%d",y1); + room_first->y->setText(tmp); + if(room_first->exec()){ + status=room_first->status->isChecked(); + input=room_first->input->isChecked(); + x1=atoi((char *)room_first->x->text().latin1()); + y1=atoi((char *)room_first->y->text().latin1()); + } + + +} +//************************************************ +void RoomGen::lnum_cb() +{ + + pnum->setText(lnum->text()); + +} +//************************************************ +RoomGenEntry::RoomGenEntry( QWidget *parent, const char *name) + : QDialog( parent, name, true ) +{ + + setCaption("Room Entry and Looking"); + + Q3BoxLayout *all = new Q3VBoxLayout(this,5); + + QLabel *entry = new QLabel("On room entry:",this); + all->addWidget(entry); + + + Q3BoxLayout *l1 = new Q3HBoxLayout(all,1); + QLabel *print1 = new QLabel("print(\"",this); + l1->addWidget(print1); + entry_text = new QLineEdit(this); + entry_text->setMinimumWidth(300); + l1->addWidget(entry_text); + QLabel *print11 = new QLabel("\");",this); + l1->addWidget(print11); + + + QLabel *ifsaid = new QLabel("if said(\"look\")){",this); + all->addWidget(ifsaid); + + QWidget *place = new QWidget(this); + + Q3BoxLayout *l2 = new Q3HBoxLayout(place,1); + QLabel *print2 = new QLabel("print(\"",place); + l2->addWidget(print2); + look_text = new QLineEdit(place); + look_text->setMinimumWidth(300); + l2->addWidget(look_text); + QLabel *print22 = new QLabel("\");",place); + l2->addWidget(print22); + + all->addWidget(place); + + QLabel *p = new QLabel("}",this); + all->addWidget(p); + + + Q3BoxLayout *last = new Q3HBoxLayout(all,10); + + QPushButton *ok = new QPushButton("OK",this); + ok->setMaximumSize(80,40); + connect(ok,SIGNAL(clicked()),SLOT(accept())); + last->addWidget(ok,AlignRight); + + QPushButton *cancel = new QPushButton("Cancel",this); + cancel->setMaximumSize(80,40); + connect(cancel,SIGNAL(clicked()),SLOT(reject())); + last->addWidget(cancel,AlignLeft); + + adjustSize(); + +} + + +//************************************************ +RoomGenFirst::RoomGenFirst( QWidget *parent, const char *name) + : QDialog( parent, name, true ) +{ + + setCaption("Controls for First Room"); + + Q3BoxLayout *all = new Q3VBoxLayout(this,5); + + QLabel *egopos = new QLabel("Ego positioning (-1 = ignore)",this); + all->addWidget(egopos); + + + Q3GridLayout *l1 = new Q3GridLayout(all,6,1,5); + QLabel *lx = new QLabel("X:",this); + l1->addWidget(lx,0,0,AlignRight); + x = new QLineEdit(this); + x->setFixedWidth(40); + x->setText("-1"); + x->selectAll(); + l1->addWidget(x,0,1,AlignLeft); + + QLabel *ly = new QLabel("Y:",this); + l1->addWidget(ly,0,2,AlignRight); + y = new QLineEdit(this); + y->setFixedWidth(40); + y->setText("-1"); + y->selectAll(); + l1->addWidget(y,0,3,AlignLeft); + + QLabel *place = new QLabel(" ",this); + l1->addWidget(place,0,4,AlignCenter); + l1->setColStretch(4,1); + + status = new QCheckBox("Turn on the status bar",this); + status->setChecked(true); + all->addWidget(status); + + input = new QCheckBox("Accept player input",this); + input->setChecked(true); + all->addWidget(input); + + Q3BoxLayout *last = new Q3HBoxLayout(all,10); + + QPushButton *ok = new QPushButton("OK",this); + ok->setMaximumSize(80,40); + connect(ok,SIGNAL(clicked()),SLOT(accept())); + last->addWidget(ok,AlignRight); + + QPushButton *cancel = new QPushButton("Cancel",this); + cancel->setMaximumSize(80,40); + connect(cancel,SIGNAL(clicked()),SLOT(reject())); + last->addWidget(cancel,AlignLeft); + + adjustSize(); + + +} + +//************************************************ +RoomGenPos::RoomGenPos( QWidget *parent, const char *name) + : QDialog( parent, name, true ) +{ + + setCaption("Controls for First Room"); + + Q3BoxLayout *all = new Q3VBoxLayout(this,5); + + QLabel *l = new QLabel("Absolute (Unconditional) Position:",this); + all->addWidget(l); + + Q3GridLayout *l1 = new Q3GridLayout(all,6,1,5); + QLabel *lx = new QLabel("X:",this); + l1->addWidget(lx,0,0,AlignRight); + x = new QLineEdit(this); + x->setFixedWidth(40); + x->setText("-1"); + x->selectAll(); + l1->addWidget(x,0,1,AlignLeft); + + QLabel *ly = new QLabel("Y:",this); + l1->addWidget(ly,0,2,AlignRight); + y = new QLineEdit(this); + y->setFixedWidth(40); + y->setText("-1"); + y->selectAll(); + l1->addWidget(y,0,3,AlignLeft); + + QLabel *place = new QLabel(" ",this); + l1->addWidget(place,0,4,AlignCenter); + l1->setColStretch(4,1); + + + QLabel *com = new QLabel( +"Unconditional positioning is useful for positioning ego\n\ +in the same place no matter what room it comes from.\n\ +It can be used in conjunction with conditional positioning\n\ +and the tp command in debug mode to position ego in a place\n\ +where you won't get stuck behind control lines, etc." +,this); + all->addWidget(com); + + Q3BoxLayout *last = new Q3HBoxLayout(all,10); + + QPushButton *ok = new QPushButton("OK",this); + ok->setMaximumSize(80,40); + connect(ok,SIGNAL(clicked()),SLOT(accept())); + last->addWidget(ok,AlignRight); + + QPushButton *cancel = new QPushButton("Cancel",this); + cancel->setMaximumSize(80,40); + connect(cancel,SIGNAL(clicked()),SLOT(reject())); + last->addWidget(cancel,AlignLeft); + + adjustSize(); + + +} + +//************************************************ +RoomGenEdge::RoomGenEdge( QWidget *parent, const char *name) + : QDialog( parent, name, true ) +{ + int i; + + setCaption("Edge Code Advanced Controls"); + + Q3BoxLayout *all = new Q3VBoxLayout(this,5); + + QLabel *com = new QLabel( +"It may be desirable to have an edge code that does not lead to different room.\n\ +For example, you may wish to have the game print a message instead, as:\n\ +\n\ +if (ego_edge_code == horizon_edge){\n\ + print(\"You cannot go that way.\");\n\ + ego_dir = 0;\n\ +}" +,this); + all->addWidget(com); + + Q3GroupBox *edge = new Q3GroupBox(2,Horizontal,"Empty edge controls",this); + + for(i=0;i<4;i++){ + sprintf(tmp,"Include empty code for %s edge",dirs[i]); + c_edge[i]=new QCheckBox(tmp,edge); + } + + all->addWidget(edge); + + Q3GroupBox *messages = new Q3GroupBox(4,Horizontal, +"Messages (if Display is not checked, message will be ignored)",this); + for(i=0;i<4;i++){ + m_edge[i] = new QCheckBox("Display",messages); + b_edge[i] = new QPushButton(messages); + sprintf(tmp,"message for %s edge",dirs[i]); + b_edge[i]->setText(tmp); + switch(i){ + case 0: + connect(b_edge[i],SIGNAL(clicked()),SLOT(left_message())); break; + case 1: + connect(b_edge[i],SIGNAL(clicked()),SLOT(right_message())); break; + case 2: + connect(b_edge[i],SIGNAL(clicked()),SLOT(bot_message())); break; + case 3: + connect(b_edge[i],SIGNAL(clicked()),SLOT(hor_message())); break; + } + } + + all->addWidget(messages); + + Q3BoxLayout *last = new Q3HBoxLayout(all,10); + + QPushButton *ok = new QPushButton("OK",this); + ok->setMaximumSize(80,40); + connect(ok,SIGNAL(clicked()),SLOT(accept())); + last->addWidget(ok,AlignRight); + + QPushButton *cancel = new QPushButton("Cancel",this); + cancel->setMaximumSize(80,40); + connect(cancel,SIGNAL(clicked()),SLOT(reject())); + last->addWidget(cancel,AlignLeft); + + adjustSize(); + + message=NULL; + +} + +void RoomGenEdge::left_message() +{ + + if(message==NULL)message = new RoomGenMessage(); + message->name("Left",e_mes[0].c_str()); + if(message->exec()){ + e_mes[0] = (char *)message->message->text().latin1(); + } +} + +void RoomGenEdge::right_message() +{ + + if(message==NULL)message = new RoomGenMessage(); + message->name("Right",e_mes[1].c_str()); + if(message->exec()){ + e_mes[1] = (char *)message->message->text().latin1(); + } +} + +void RoomGenEdge::bot_message() +{ + + if(message==NULL)message = new RoomGenMessage(); + message->name("Bottom",e_mes[2].c_str()); + if(message->exec()){ + e_mes[2] = (char *)message->message->text().latin1(); + } +} + +void RoomGenEdge::hor_message() +{ + + if(message==NULL)message = new RoomGenMessage(); + message->name("Horizon",e_mes[3].c_str()); + if(message->exec()){ + e_mes[3] = (char *)message->message->text().latin1();; + } +} + +//************************************************ +RoomGenMessage::RoomGenMessage( QWidget *parent, const char *name) + : QDialog( parent, name, true ) +{ + + + Q3BoxLayout *all = new Q3VBoxLayout(this,5); + + l = new QLabel("",this); + //l->setAutoResize(true); // TODO: REPLACE WITH A LAYOUT! + all->addWidget(l); + message = new QLineEdit(this); + all->addWidget(message); + + Q3BoxLayout *last = new Q3HBoxLayout(all,10); + + QPushButton *ok = new QPushButton("OK",this); + ok->setMaximumSize(80,40); + connect(ok,SIGNAL(clicked()),SLOT(accept())); + last->addWidget(ok,AlignRight); + + QPushButton *cancel = new QPushButton("Cancel",this); + cancel->setMaximumSize(80,40); + connect(cancel,SIGNAL(clicked()),SLOT(reject())); + last->addWidget(cancel,AlignLeft); + + adjustSize(); + +} + +void RoomGenMessage::name(const char *title,const char *text) +{ + + sprintf(tmp,"%s Message",title); + setCaption(tmp); + sprintf(tmp,"Enter a message to display when ego\ntouches %c%s edge:",tolower(title[0]),title+1); + l->setText(tmp); + message->setText(text); + message->selectAll(); + +} diff --git a/src/roomgen.h b/src/roomgen.h new file mode 100644 index 0000000..6255676 --- /dev/null +++ b/src/roomgen.h @@ -0,0 +1,148 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * The idea and most of the design of RoomGen module are copied from the + * "AGI Base Logic Generator" utility by Joel McCormick. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef ROOMGEN_H +#define ROOMGEN_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "wutil.h" +#include "logic.h" + + +class RoomGenEntry: public QDialog +{ + + Q_OBJECT + public: + RoomGenEntry( QWidget *parent=0, const char *name=0 ); + QLineEdit *entry_text,*look_text; + +}; + +class RoomGenFirst: public QDialog +{ + + Q_OBJECT + public: + RoomGenFirst( QWidget *parent=0, const char *name=0 ); + QLineEdit *x,*y; + QCheckBox *status,*input; +}; + +class RoomGenPos: public QDialog +{ + + Q_OBJECT + public: + RoomGenPos( QWidget *parent=0, const char *name=0 ); + QLineEdit *x,*y; + +}; + + +class RoomGenMessage: public QDialog +{ + + Q_OBJECT + public: + RoomGenMessage( QWidget *parent=0, const char *name=0); + void name(const char *title, const char *text); + QLabel *l; + QLineEdit *message; +}; + + +class RoomGenEdge: public QDialog +{ + + Q_OBJECT + public: + RoomGenEdge( QWidget *parent=0, const char *name=0 ); + QCheckBox *c_edge[4]; + QCheckBox *m_edge[4]; + QPushButton *b_edge[4]; + RoomGenMessage *message; + string e_mes[4]; + public slots: + void left_message(); + void right_message(); + void bot_message(); + void hor_message(); +}; + + +class RoomGen: public QDialog +{ + Q_OBJECT + public: + RoomGen( QWidget *parent=0, const char *name=0 ); + RoomGenEntry *room_entry; + RoomGenFirst *room_first; + RoomGenPos *ego_advanced; + RoomGenEdge *edge_advanced; + + QLineEdit *lnum,*pnum,*hnum; + QCheckBox *draw_ego,*first_room,*inc_def,*gen_comm; + QLineEdit *from[4],*x[4],*y[4]; + QLineEdit *edge[4]; + QLineEdit *title; + string text; + bool incomplete_input(); + int rn[4],xn[4],yn[4]; //coming from room rn, position ego at xn,yn + int en[4]; //edge controls (goto room) + int ln,pn; //logic number, picture number + int hn; //horizon + int xa,ya; //absolute (unconditional) position + int x1,y1; //first room ego position + bool empty_e[4]; //add empty edge controls + bool display_e[4]; //display edge messages + string e_mes[4]; //edge messages + string entry_mes,look_mes; //room entry & look messages + bool status,input; //1st room - status bar, player input + + bool bad_int(QLineEdit *w,int *res,int nmin,int nmax,bool ignore,const char *text); + bool bad_int(int res,int nmin,int nmax,bool ignore,const char *text); + bool bad_input(); + + public slots: + void ego_advanced_cb(); + void edge_advanced_cb(); + void entry_cb(); + void first_cb(); + void ok_cb(); + void lnum_cb(); + void first_room_cb(); +}; + +#endif + diff --git a/src/toolbar_close.xpm b/src/toolbar_close.xpm new file mode 100644 index 0000000..e804d63 --- /dev/null +++ b/src/toolbar_close.xpm @@ -0,0 +1,201 @@ +/* XPM */ +static const char *toolbar_close[] = { +/* columns rows colors chars-per-pixel */ +"24 24 171 2", +" c black", +". c #A4A400001F1F", +"X c #A8A800001E1E", +"o c #AAAA00001E1E", +"O c #AFAF00001B1B", +"+ c #ACAC00001D1D", +"@ c #B0B000001B1B", +"# c #B2B200001B1B", +"$ c #B0B000001C1C", +"% c #B5B500001A1A", +"& c #B6B600001919", +"* c #B6B600001A1A", +"= c #B5B505051F1F", +"- c #BCBC00001717", +"; c #BEBE00001616", +": c #BEBE01011717", +"> c #B8B800001919", +", c #B9B902021A1A", +"< c #BABA00001818", +"1 c #BBBB00001818", +"2 c #BDBD02021A1A", +"3 c #A2A200002020", +"4 c #B5B509092323", +"5 c #BABA0C0C2323", +"6 c #B9B90D0D2424", +"7 c #BBBB0D0D2424", +"8 c #BEBE0A0A2020", +"9 c #BFBF0E0E2424", +"0 c #C1C100001515", +"q c #C1C100001616", +"w c #C4C400001414", +"e c #C7C702021414", +"r c #C0C005051B1B", +"t c #C0C006061B1B", +"y c #C4C403031818", +"u c #C8C800001212", +"i c #C9C900001313", +"p c #C9C901011313", +"a c #CBCB02021515", +"s c #CCCC02021313", +"d c #CECE00001111", +"f c #CDCD05051616", +"g c #CECE06061616", +"h c #C8C80A0A1E1E", +"j c #CCCC09091A1A", +"k c #CCCC0B0B1E1E", +"l c #D1D101011010", +"z c #D1D102021111", +"x c #D0D003031414", +"c c #D5D502021010", +"v c #D1D10C0C1D1D", +"b c #D4D40A0A1919", +"n c #D9D902021010", +"m c #D8D804041111", +"M c #D8D804041212", +"N c #DBDB04041111", +"B c #DEDE07071212", +"V c #D9D908081414", +"C c #DFDF09091515", +"Z c #DADA0C0C1919", +"A c #DCDC0C0C1919", +"S c #D3D310101F1F", +"D c #DADA13131E1E", +"F c #DCDC10101B1B", +"G c #DDDD11111D1D", +"H c #C1C10E0E2424", +"J c #C3C30F0F2525", +"K c #C5C50E0E2020", +"L c #C5C512122626", +"P c #C9C910102222", +"I c #C9C913132626", +"U c #C8C814142626", +"Y c #CDCD11112222", +"T c #CDCD13132525", +"R c #CFCF16162727", +"E c #D3D312122020", +"W c #D0D016162727", +"Q c #D3D316162525", +"! c #D7D718182626", +"~ c #D2D218182929", +"^ c #D5D51A1A2828", +"/ c #DADA19192626", +"( c #DEDE18182424", +") c #DFDF19192424", +"_ c #D9D91B1B2828", +"` c #DCDC1F1F2B2B", +"' c #DFDF1F1F2929", +"] c #DFDF21212C2C", +"[ c #E7E704040D0D", +"{ c #E3E30A0A1313", +"} c #E1E10B0B1515", +"| c #E4E40D0D1515", +" . c #E7E70F0F1717", +".. c #EEEE0C0C1414", +"X. c #E4E411111B1B", +"o. c #E6E612121A1A", +"O. c #E9E917171E1E", +"+. c #ECEC12121A1A", +"@. c #ECEC15151C1C", +"#. c #EFEF17171C1C", +"$. c #F0F006060B0B", +"%. c #F2F21A1A1D1D", +"&. c #E1E118182323", +"*. c #E1E11F1F2929", +"=. c #E8E818182020", +"-. c #EAEA1F1F2626", +";. c #ECEC1E1E2525", +":. c #E8E81F1F2828", +">. c #F0F01D1D2323", +",. c #F1F11D1D2222", +"<. c #E2E222222B2B", +"1. c #E5E522222B2B", +"2. c #E5E524242C2C", +"3. c #E6E625252D2D", +"4. c #EEEE21212727", +"5. c #EEEE26262D2D", +"6. c #E7E728283030", +"7. c #EAEA2A2A3131", +"8. c #ECEC28283030", +"9. c #ECEC29293030", +"0. c #F5F520202323", +"q. c #F5F523232727", +"w. c #F3F325252929", +"e. c #F2F225252A2A", +"r. c #F0F027272C2C", +"t. c #F6F625252929", +"y. c #F7F72B2B2E2E", +"u. c #F9F928282B2B", +"i. c #F8F82C2C2D2D", +"p. c #FAFA2D2D2F2F", +"a. c #F0F02D2D3333", +"s. c #F3F32D2D3232", +"d. c #F5F52E2E3232", +"f. c #F4F431313535", +"g. c #F4F433333737", +"h. c #F5F536363939", +"j. c #F6F636363838", +"k. c #F6F636363A3A", +"l. c #F7F737373A3A", +"z. c #F6F638383B3B", +"x. c #FAFA31313333", +"c. c #FAFA32323434", +"v. c #F8F834343737", +"b. c #F9F934343737", +"n. c #FBFB36363737", +"m. c #FCFC33333434", +"M. c #FBFB39393B3B", +"N. c #F9F93B3B3D3D", +"B. c #FBFB3B3B3D3D", +"V. c #FCFC39393B3B", +"C. c #FCFC3C3C3D3D", +"Z. c #FDFD3F3F3F3F", +"A. c #FCFC3F3F4141", +"S. c #FBFB40404141", +"D. c #FCFC42424343", +"F. c #FDFD43434343", +"G. c #FEFE41414242", +"H. c #FEFE42424343", +"J. c #FDFD44444545", +"K. c #FDFD45454646", +"L. c #FDFD46464646", +"P. c #FDFD46464747", +"I. c #FEFE44444545", +"U. c #FEFE45454646", +"Y. c #FEFE46464747", +"T. c #FDFD47474848", +"R. c #FEFE47474848", +"E. c #FDFD48484949", +"W. c #FEFE48484848", +"Q. c gray100", +"!. c None", +/* pixels */ +"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.", +"!.!.!.!.!. !.!.!.!.!.!.!.!.!.!.!.!. !.!.!.!.!.", +"!.!.!.!. H. !.!.!.!.!.!.!.!.!.!. $. !.!.!.!.", +"!.!.!. Y.Q.H. !.!.!.!.!.!.!.!. ..Q.[ !.!.!.", +"!.!. T.Q.Y.Y.Y. !.!.!.!.!.!. @.Q.C B n !.!.", +"!. T.Q.T.T.T.T.T. !.!.!.!. 4.Q.F b f p s !.", +"!.!. T.T.W.T.W.W.W. !.!. s.Q.) S h r 2 !.!.", +"!.!.!. W.T.T.T.T.T.Y. k.Q.1./ I 2 4 !.!.!.", +"!.!.!.!. Y.Y.Y.T.Y.Y.Z.N.h.9.' ~ H 4 !.!.!.!.", +"!.!.!.!.!. Y.I.H.D.A.B.k.9.3./ U 6 !.!.!.!.!.", +"!.!.!.!.!.!. H.Z.C.M.b.d.5.] Q L !.!.!.!.!.!.", +"!.!.!.!.!.!.!. M.b.x.y.w.-.( Y !.!.!.!.!.!.!.", +"!.!.!.!.!.!.!. m.p.u.q.;.O.D k !.!.!.!.!.!.!.", +"!.!.!.!.!.!. c.p.t.0.%.@.o.Z j 2 !.!.!.!.!.!.", +"!.!.!.!.!. h.Q.w.;.@.+. .} V f y < !.!.!.!.!.", +"!.!.!.!. k.Q.w.;.@.o. .{ B M x p 2 < !.!.!.!.", +"!.!.!. l.Q.8.:.&.G A M m d s 0 < & !.!.!.", +"!.!. k.Q.7.] / E v !.!. d d p 0 < & # !.!.", +"!. f.Q.6.] ! T K !.!.!.!. p w ; & # O . !.", +"!.!. 3.] ~ U 9 !.!.!.!.!.!. ; & O . . !.!.", +"!.!.!. T L 6 !.!.!.!.!.!.!.!. % . 3 !.!.!.", +"!.!.!.!. 6 !.!.!.!.!.!.!.!.!.!. 3 !.!.!.!.", +"!.!.!.!.!. !.!.!.!.!.!.!.!.!.!.!.!. !.!.!.!.!.", +"!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!." +}; diff --git a/src/toolbar_logedit.xpm b/src/toolbar_logedit.xpm new file mode 100644 index 0000000..47cc724 --- /dev/null +++ b/src/toolbar_logedit.xpm @@ -0,0 +1,124 @@ +/* XPM */ +static const char *toolbar_logedit[] = { +/* columns rows colors chars-per-pixel */ +"24 24 94 2", +" c black", +". c #000000007F7F", +"X c #7F7F00007F7F", +"o c #7F7F7F7F0000", +"O c navy", +"+ c #000000008181", +"@ c #000000008282", +"# c #000000008383", +"$ c #000000008989", +"% c #000000008A8A", +"& c #000000008F8F", +"* c #000000009090", +"= c #000000009292", +"- c #000000009898", +"; c #000000009B9B", +": c #00000000A6A6", +"> c #00000000B2B2", +", c #00000000B4B4", +"< c #00000000BCBC", +"1 c #00000000BFBF", +"2 c #00000000C0C0", +"3 c #00000000C5C5", +"4 c #00000000C6C6", +"5 c #00000000C9C9", +"6 c #00000000CCCC", +"7 c MediumBlue", +"8 c #00000000D1D1", +"9 c #00000000D3D3", +"0 c red", +"q c yellow", +"w c #BCBCBCBCBCBC", +"e c gray74", +"r c gray", +"t c gray75", +"y c #C0C0C0C0C0C0", +"u c #C1C1C1C1C1C1", +"i c gray76", +"p c #C3C3C3C3C3C3", +"a c gray77", +"s c #C5C5C5C5C5C5", +"d c gray78", +"f c #C8C8C8C8C8C8", +"g c gray79", +"h c #CACACACACACA", +"j c gray80", +"k c #CDCDCDCDCDCD", +"l c gray81", +"z c #D0D0D0D0D0D0", +"x c gray82", +"c c #D2D2D2D2D2D2", +"v c LightGray", +"b c gray83", +"n c #D5D5D5D5D5D5", +"m c gray84", +"M c #D7D7D7D7D7D7", +"N c #D8D8D8D8D8D8", +"B c gray85", +"V c #DADADADADADA", +"C c gray86", +"Z c gainsboro", +"A c #DDDDDDDDDDDD", +"S c gray87", +"D c #DFDFDFDFDFDF", +"F c #E1E1E1E1E1E1", +"G c #E2E2E2E2E2E2", +"H c gray89", +"J c #E4E4E4E4E4E4", +"K c gray90", +"L c #E6E6E6E6E6E6", +"P c #E7E7E7E7E7E7", +"I c gray91", +"U c #E9E9E9E9E9E9", +"Y c #EAEAEAEAEAEA", +"T c gray92", +"R c #ECECECECECEC", +"E c gray93", +"W c #EEEEEEEEEEEE", +"Q c #EFEFEFEFEFEF", +"! c gray94", +"~ c #F1F1F1F1F1F1", +"^ c gray95", +"/ c #F3F3F3F3F3F3", +"( c #F4F4F4F4F4F4", +") c gray96", +"_ c #F6F6F6F6F6F6", +"` c gray97", +"' c #F8F8F8F8F8F8", +"] c #F9F9F9F9F9F9", +"[ c gray98", +"{ c #FBFBFBFBFBFB", +"} c gray99", +"| c #FDFDFDFDFDFD", +" . c #FEFEFEFEFEFE", +".. c gray100", +/* pixels */ +"t t t t t t t t t t t t t t t t t t t t t t t t ", +"t ", +"t q o q 9 8 ..5 1 , ..; = % ....@ ..@ ....... ", +"t o q 0 8 6 ..1 , ..; ..% ..@ @ . ... ... . . ", +"t q o 0 6 3 ..> : ..= ..@ ... ... ... ... . . ", +"t X X X 3 < ....- & ..@ @ . ..... ... ....... ", +"t ", +"t ......................................] ( E ", +"t ..................................] ] ( ~ I ", +"t .... ...... ........ ...... ....] K ", +"t .......... .. .... ...... .. ] ( I Z ", +"t .... .... ........ ...... ...... N ", +"t .... .. ...... .... ..( I K ", +"t .... .... ........ ...... ..] ( I Z ", +"t .... .... .......... .... ] ( ~ I z ", +"t ..........................] ] ( ~ E G Z z h ", +"t ........................] ] ~ E K G N z k h ", +"t ..................] ( ~ G N m d d ", +"t ........] ....] .. ( ~ E G Z k y ", +"t ] ..] ..] ] ] ] ( ( E K h h y y ", +"y ( ] ( ( ] ( ( ~ ~ I K N k h d y y y y ", +"y ~ ~ E E E E E I K m z h t t y y ", +"t I K K K K K G G Z N z k d y y t w t t t t y ", +"t Z Z Z Z N N m m m k h d y t t w w w w t y y " +}; diff --git a/src/toolbar_objedit.xpm b/src/toolbar_objedit.xpm new file mode 100644 index 0000000..5b124fc --- /dev/null +++ b/src/toolbar_objedit.xpm @@ -0,0 +1,206 @@ +/* XPM */ +static const char *toolbar_objedit[] = { +/* columns rows colors chars-per-pixel */ +"24 24 176 2", +" c black", +". c #7F7F00000000", +"X c #CDCD00003535", +"o c red", +"O c #8B8B82820000", +"+ c #8C8C82820000", +"@ c #8C8C83830000", +"# c #8D8D83830000", +"$ c #8D8D84840000", +"% c #8E8E85850000", +"& c #8F8F85850000", +"* c #8F8F86860000", +"= c #909086860000", +"- c #909087870000", +"; c #919188880000", +": c #929288880000", +"> c #929289890000", +", c #939389890000", +"< c #93938A8A0000", +"1 c #95958B8B0000", +"2 c #96968C8C0000", +"3 c #97978D8D0000", +"4 c #97978E8E0000", +"5 c #98988E8E0000", +"6 c #9A9A90900000", +"7 c #9B9B91910000", +"8 c #9C9C92920000", +"9 c #9C9C93930000", +"0 c #9D9D93930000", +"q c #9E9E93930000", +"w c #9F9F94940000", +"e c #A0A096960000", +"r c #A0A097970000", +"t c #A2A297970000", +"y c #A2A298980000", +"u c #A3A398980000", +"i c #A2A29B9B0000", +"p c #A4A499990000", +"a c #A4A49A9A0000", +"s c #A6A69B9B0000", +"d c #A6A69C9C0000", +"f c #A7A79D9D0000", +"g c #A8A89E9E0000", +"h c #A9A99E9E0000", +"j c #A9A99F9F0000", +"k c #AAAA9F9F0000", +"l c #A9A9A2A20000", +"z c #AAAAA0A00000", +"x c #ABABA0A00000", +"c c #ABABA1A10000", +"v c #A9A9A4A40000", +"b c #ACACA1A10000", +"n c #ADADA2A20000", +"m c #AEAEA3A30000", +"M c #ADADA7A70000", +"N c #AFAFA4A40000", +"B c #B0B0A5A50000", +"V c #B0B0A6A60000", +"C c #B1B1A6A60000", +"Z c #B1B1A7A70000", +"A c #B2B2A7A70000", +"S c #B2B2A8A80000", +"D c #B3B3A8A80000", +"F c #B2B2ACAC0000", +"G c #B4B4A9A90000", +"H c #B5B5ACAC0000", +"J c #B4B4AEAE0000", +"K c #B5B5AFAF0000", +"L c #B7B7ACAC0000", +"P c #B7B7ADAD0000", +"I c #B8B8ADAD0000", +"U c #B8B8AEAE0000", +"Y c #B9B9AFAF0000", +"T c #B8B8B4B40000", +"R c #BABAB5B50000", +"E c #BBBBB6B60000", +"W c #BCBCB2B20000", +"Q c #BCBCB3B30000", +"! c #BCBCB7B70000", +"~ c #BEBEB4B40000", +"^ c #BFBFB5B50000", +"/ c #BDBDB8B80000", +"( c #C0C0B6B60000", +") c #C0C0BABA0000", +"_ c #C2C2B8B80000", +"` c #C3C3B9B90000", +"' c #C0C0BCBC0000", +"] c #C2C2BDBD0000", +"[ c #C3C3BEBE0000", +"{ c #C4C4BABA0000", +"} c #C4C4BBBB0000", +"| c #C5C5BCBC0000", +" . c #C7C7BFBF0000", +".. c #C5C5C1C10000", +"X. c #C7C7C3C30000", +"o. c #C9C9C0C00000", +"O. c #C9C9C1C10000", +"+. c #C8C8C3C30000", +"@. c #CACAC1C10000", +"#. c #CBCBC3C30000", +"$. c #C8C8C4C40000", +"%. c #C9C9C5C50000", +"&. c #CBCBC6C60000", +"*. c #CBCBC7C70000", +"=. c #CCCCC4C40000", +"-. c #CECEC6C60000", +";. c #CCCCC8C80000", +":. c #CFCFCBCB0000", +">. c #D0D0C8C80000", +",. c #D1D1C9C90000", +"<. c #D2D2CACA0000", +"1. c #D2D2CBCB0000", +"2. c #D0D0CCCC0000", +"3. c #D1D1CDCD0000", +"4. c #D1D1CECE0000", +"5. c #D2D2CFCF0000", +"6. c #D3D3CFCF0000", +"7. c #D4D4CDCD0000", +"8. c #D3D3D0D00000", +"9. c #D7D7D1D10000", +"0. c #D6D6D2D20000", +"q. c #D7D7D3D30000", +"w. c #D7D7D4D40000", +"e. c #D8D8D2D20000", +"r. c #DADAD4D40000", +"t. c #DCDCD6D60000", +"y. c #DADAD8D80000", +"u. c #DCDCD9D90000", +"i. c #DCDCDADA0000", +"p. c #DDDDDADA0000", +"a. c #DFDFD9D90000", +"s. c #DEDEDBDB0000", +"d. c #DFDFDADA0000", +"f. c #DFDFDCDC0000", +"g. c #DFDFDDDD0000", +"h. c #E0E0DBDB0000", +"j. c #E1E1DCDC0000", +"k. c #E1E1DFDF0000", +"l. c #E3E3DEDE0000", +"z. c #E3E3E1E10000", +"x. c #E3E3E2E20000", +"c. c #E6E6E2E20000", +"v. c #E7E7E3E30000", +"b. c #E6E6E4E40000", +"n. c #E6E6E5E50000", +"m. c #E9E9E5E50000", +"M. c #E8E8E6E60000", +"N. c #E9E9E6E60000", +"B. c #EAEAE7E70000", +"V. c #EAEAE8E80000", +"C. c #EBEBE9E90000", +"Z. c #EBEBEBEB0000", +"A. c #ECECE9E90000", +"S. c #EDEDEBEB0000", +"D. c #EDEDECEC0000", +"F. c #EEEEEDED0000", +"G. c #EFEFEDED0000", +"H. c #F0F0EFEF0000", +"J. c #F1F1EFEF0000", +"K. c #F1F1F0F00000", +"L. c #F2F2F0F00000", +"P. c #F3F3F1F10000", +"I. c #F4F4F3F30000", +"U. c #F5F5F4F40000", +"Y. c #F6F6F4F40000", +"T. c #F6F6F5F50000", +"R. c #F7F7F5F50000", +"E. c #F8F8F8F80000", +"W. c #F9F9F8F80000", +"Q. c #FAFAF9F90000", +"!. c #FBFBFAFA0000", +"~. c #FCFCFCFC0000", +"^. c #FDFDFCFC0000", +"/. c #FEFEFEFE0000", +"(. c yellow", +"). c None", +/* pixels */ +").).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).", +").).).). ).).).).", +").).). E.U.I.K.K.H. . . Z.C.n.s.q.:. ).).).", +").). U.K.Z.C.N.N. . . C.x.u.8.%.] ).).", +").). H.C.b.z.s.u. . . g.y.8.X.! P ).).", +").). (. z.u.q.8.4. . . w.4.%.! F ~ ).).", +").). (. u.8.;..... . . :.%.] J z Y ).).", +").). (. 0.;.] ! E . . %.] E N w S ).).", +").). (.(. ..~ P v F z ).).", +").). !.E.U. o o o o o o B n d ).).", +").). R.R.I.H.m. o X X X X X Y B g s 0 ).).", +").). U.J.S.m.l. B g s 7 2 ).).", +").). H.A.v.h.r.7.-. . . G N g s 7 5 > ).).", +").). A.v.h.7.:.#.| . . n g e 7 2 > * ).).", +").). x.j.7.:.#.{ ~ Y z s e 7 2 > $ $ ).).", +").). g.7.<. .` ~ P S n z s e 5 < < # # # ).).", +").). h.7.=.{ W P B z g y 7 5 < * * # # O ).).", +").). 7.-.{ W L B z d e 7 2 < * * # # # O ).).", +").).). .( Y A n s e 7 2 > * $ # # O O ).).).", +").).).). ).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).).", +").).).).).).).).).).).).).).).).).).).).).).).)." +}; diff --git a/src/toolbar_open.xpm b/src/toolbar_open.xpm new file mode 100644 index 0000000..c4d60fe --- /dev/null +++ b/src/toolbar_open.xpm @@ -0,0 +1,210 @@ +/* XPM */ +static const char *toolbar_open[] = { +/* columns rows colors chars-per-pixel */ +"24 24 180 2", +" c black", +". c #76766F6F0000", +"X c #777770700000", +"o c #787871710000", +"O c #797971710000", +"+ c #797972720000", +"@ c #7B7B74740000", +"# c #7C7C74740000", +"$ c #7D7D75750000", +"% c #7E7E76760000", +"& c #7F7F77770000", +"* c #808078780000", +"= c #818179790000", +"- c #82827A7A0000", +"; c #83837B7B0000", +": c #86867E7E0000", +"> c #87877F7F0000", +", c #888880800000", +"< c #8A8A81810000", +"1 c #8A8A82820000", +"2 c #8D8D84840000", +"3 c #8E8E85850000", +"4 c #8E8E86860000", +"5 c #8F8F86860000", +"6 c #919188880000", +"7 c #93938A8A0000", +"8 c #94948B8B0000", +"9 c #95958B8B0000", +"0 c #95958C8C0000", +"q c #95958D8D0000", +"w c #98988E8E0000", +"e c #9A9A90900000", +"r c #9A9A91910000", +"t c #9C9C93930000", +"y c #9E9E93930000", +"u c #9C9C94940000", +"i c #A0A096960000", +"p c #A0A097970000", +"a c #A1A197970000", +"s c #A1A198980000", +"d c #A2A298980000", +"f c #A3A39B9B0000", +"g c #A6A69B9B0000", +"h c #A5A59C9C0000", +"j c #A7A79E9E0000", +"k c #A8A89F9F0000", +"l c #A9A99F9F0000", +"z c #AAAAA0A00000", +"x c #AAAAA1A10000", +"c c #ABABA1A10000", +"v c #AAAAA2A20000", +"b c #ADADA4A40000", +"n c #AFAFA4A40000", +"m c #AFAFA5A50000", +"M c #AEAEA6A60000", +"N c #B0B0A8A80000", +"B c #B2B2A9A90000", +"V c #B3B3A8A80000", +"C c #B2B2AAAA0000", +"Z c #B3B3AAAA0000", +"A c #B4B4ADAD0000", +"S c #B6B6ACAC0000", +"D c #B7B7AFAF0000", +"F c #B8B8ACAC0000", +"G c #B8B8ADAD0000", +"H c #B9B9ADAD0000", +"J c #B8B8AEAE0000", +"K c #B9B9AFAF0000", +"L c #BABAAEAE0000", +"P c #BABAAFAF0000", +"I c #BBBBAFAF0000", +"U c #BBBBB0B00000", +"Y c #BABAB2B20000", +"T c #BBBBB3B30000", +"R c #BCBCB0B00000", +"E c #BCBCB1B10000", +"W c #BCBCB3B30000", +"Q c #BDBDB2B20000", +"! c #BEBEB3B30000", +"~ c #BCBCB4B40000", +"^ c #BEBEB4B40000", +"/ c #BFBFB5B50000", +"( c #BEBEB7B70000", +") c #BFBFB7B70000", +"_ c #C0C0B5B50000", +"` c #C1C1B6B60000", +"' c #C0C0B8B80000", +"] c #C1C1B8B80000", +"[ c #C1C1B9B90000", +"{ c #C2C2B8B80000", +"} c #C3C3B9B90000", +"| c #C3C3BABA0000", +" . c #C4C4BABA0000", +".. c #C5C5BBBB0000", +"X. c #C4C4BCBC0000", +"o. c #C5C5BCBC0000", +"O. c #C4C4BEBE0000", +"+. c #C6C6BCBC0000", +"@. c #C6C6BDBD0000", +"#. c #C6C6BFBF0000", +"$. c #C7C7BEBE0000", +"%. c #C7C7BFBF0000", +"&. c #C8C8BFBF0000", +"*. c #C6C6C0C00000", +"=. c #C9C9C0C00000", +"-. c #C8C8C2C20000", +";. c #CACAC1C10000", +":. c #CBCBC2C20000", +">. c #CBCBC4C40000", +",. c #CCCCC5C50000", +"<. c #CDCDC6C60000", +"1. c #CDCDC7C70000", +"2. c #CECEC5C50000", +"3. c #CECEC6C60000", +"4. c #CECEC7C70000", +"5. c #CFCFC7C70000", +"6. c #CECEC8C80000", +"7. c #CECEC9C90000", +"8. c #D0D0C8C80000", +"9. c #D0D0C9C90000", +"0. c #D2D2CBCB0000", +"q. c #D3D3CBCB0000", +"w. c #D2D2CDCD0000", +"e. c #D4D4CDCD0000", +"r. c #D4D4CECE0000", +"t. c #D5D5CECE0000", +"y. c #D5D5CFCF0000", +"u. c #D6D6CFCF0000", +"i. c #D5D5D0D00000", +"p. c #D6D6D0D00000", +"a. c #D6D6D1D10000", +"s. c #D8D8D1D10000", +"d. c #D8D8D2D20000", +"f. c #DADAD5D50000", +"g. c #DBDBD5D50000", +"h. c #DBDBD6D60000", +"j. c #DCDCD6D60000", +"k. c #DDDDD7D70000", +"l. c #DDDDD8D80000", +"z. c #DDDDD9D90000", +"x. c #DEDED8D80000", +"c. c #DEDEDADA0000", +"v. c #E0E0DADA0000", +"b. c #E0E0DCDC0000", +"n. c #E1E1DCDC0000", +"m. c #E1E1DDDD0000", +"M. c #E2E2DDDD0000", +"N. c #E2E2DEDE0000", +"B. c #E3E3DFDF0000", +"V. c #E4E4DFDF0000", +"C. c #E4E4E0E00000", +"Z. c #E5E5E1E10000", +"A. c #E5E5E2E20000", +"S. c #E6E6E2E20000", +"D. c #E6E6E3E30000", +"F. c #E7E7E4E40000", +"G. c #E9E9E5E50000", +"H. c #EAEAE7E70000", +"J. c #EBEBE8E80000", +"K. c #ECECE8E80000", +"L. c #ECECE9E90000", +"P. c #EDEDEAEA0000", +"I. c #EDEDEBEB0000", +"U. c #EFEFEBEB0000", +"Y. c #EFEFEDED0000", +"T. c #F0F0EEEE0000", +"R. c #F1F1EEEE0000", +"E. c #F1F1EFEF0000", +"W. c #F2F2EFEF0000", +"Q. c #F3F3F0F00000", +"!. c #F3F3F1F10000", +"~. c #F4F4F2F20000", +"^. c #F4F4F3F30000", +"/. c #F5F5F4F40000", +"(. c #F7F7F5F50000", +"). c #F7F7F6F60000", +"_. c #F9F9F8F80000", +"`. c #FAFAF9F90000", +"'. c #FBFBFBFB0000", +"]. c None", +/* pixels */ +"].].].].].].].].].].].].].].].].].].].].].].].].", +"].].].].].].].].].].].].].].].].].].].].].].].].", +"].].].].].].].].].].].].].].].].].].].].].].].].", +"].].].]. ].].].].].].].].].].].].].].", +"].].]. !.T.U.H.C.M. ].].].].].].].].].].].].].", +"].]. T.L.H.C.c.g.d.e. ].].].].].", +"]. T.L.C.M.g.u.q.2.:.&.+.{ ` ! ! Y ! ].].].].", +"]. H.C.c.d.q.2.:.+. .{ ` ! ! I F F F ].].].].", +"]. B.c.u.7.:.:. .` ` ! ! ! F F F F F ].].].].", +"]. g.e.7. ].].].", +"]. e.5.:. '._._.)./.!.I.D.c.u.:.{ F Z b ].].", +"]. 2.:. _././.!.T.I.H.C.f.q.:.{ F m x h ].].", +"]. :. . /.T.T.L.D.M.c.u.1.*.T Z c h s y ].].", +"]. +.{ I.L.C.M.h.u.7.*.( A b h i r w q ].].", +"]. . L.C.M.f.r.7.*.( D M j u r 7 5 4 ].].].", +"]. { C.c.u.7.*.( D C j s r q 4 < < : ].].].", +"]. { c.e.2.| Y C x s u q 5 < : ; - % ].].].", +"]. c.e.2.{ Y C x i r 7 4 > - * % % ].].].].", +"]. f.7.+.~ C x s r 7 2 > - % @ @ . ].].].].", +"]. d.7.{ F b h u q 4 > ; * # @ . . ].].].].", +"].]. ].].].].].", +"].].].].].].].].].].].].].].].].].].].].].].].].", +"].].].].].].].].].].].].].].].].].].].].].].].].", +"].].].].].].].].].].].].].].].].].].].].].].].]." +}; diff --git a/src/toolbar_picedit.xpm b/src/toolbar_picedit.xpm new file mode 100644 index 0000000..8510ad1 --- /dev/null +++ b/src/toolbar_picedit.xpm @@ -0,0 +1,202 @@ +/* XPM */ +static const char *toolbar_picedit[] = { +/* columns rows colors chars-per-pixel */ +"24 24 172 2", +" c black", +". c #000065650000", +"X c #000066660000", +"o c #000067670000", +"O c #000068680000", +"+ c #000069690000", +"@ c #00006A6A0000", +"# c #00006B6B0000", +"$ c #00006C6C0000", +"% c #00006D6D0000", +"& c #00006E6E0000", +"* c #00006F6F0000", +"= c #000070700000", +"- c #000071710000", +"; c #5A5A00000000", +": c #5B5B00000000", +"> c #5C5C00000000", +", c #5D5D00000000", +"< c #5E5E00000000", +"1 c #5F5F00000000", +"2 c #616100000000", +"3 c #626200000000", +"4 c #646400000000", +"5 c #00000000ACAC", +"6 c #00000000ADAD", +"7 c #00000000AEAE", +"8 c #00000000AFAF", +"9 c #00000000B1B1", +"0 c #00000000B2B2", +"q c #00000000B4B4", +"w c #00000000B5B5", +"e c #00000000B7B7", +"r c #00000000B8B8", +"t c #00000000BABA", +"y c #00000000BCBC", +"u c #00000000BEBE", +"i c #00000000BFBF", +"p c #00000000C1C1", +"a c #00000000C2C2", +"s c #00000000C3C3", +"d c #00000000C4C4", +"f c #00000000C6C6", +"g c #00000000C7C7", +"h c #00000000C8C8", +"j c #00000000CACA", +"k c #00000000CBCB", +"l c #00000000CCCC", +"z c #00000000CECE", +"x c #00000000D0D0", +"c c #00000000D2D2", +"v c #00000000D4D4", +"b c #00000000D5D5", +"n c #00000000D6D6", +"m c #00000000D8D8", +"M c #00000000DADA", +"N c #00000000DBDB", +"B c #00000000DCDC", +"V c #00000000DEDE", +"C c #00000000E0E0", +"Z c #00000000E1E1", +"A c #00000000E2E2", +"S c #00000000E3E3", +"D c #00000000E5E5", +"F c #00000000E7E7", +"G c #00000000E9E9", +"H c #00000000EAEA", +"J c #00000000EBEB", +"K c #00000000ECEC", +"L c #00000000EDED", +"P c #00000000EFEF", +"I c #0000ACAC0000", +"U c #0000ADAD0000", +"Y c #0000AFAF0000", +"T c #0000B0B00000", +"R c #0000B1B10000", +"E c #0000B2B20000", +"W c #0000B3B30000", +"Q c #0000B4B40000", +"! c #0000B5B50000", +"~ c #0000B6B60000", +"^ c #0000B7B70000", +"/ c #0000B9B90000", +"( c #0000BBBB0000", +") c #0000BCBC0000", +"_ c #0000BEBE0000", +"` c #0000BFBF0000", +"' c #0000C1C10000", +"] c #0000C2C20000", +"[ c #0000C3C30000", +"{ c #0000C5C50000", +"} c #0000C7C70000", +"| c #0000C8C80000", +" . c #0000C9C90000", +".. c #0000CACA0000", +"X. c #0000CBCB0000", +"o. c #0000CCCC0000", +"O. c #0000CDCD0000", +"+. c #0000CECE0000", +"@. c #0000CFCF0000", +"#. c #0000D0D00000", +"$. c #0000D1D10000", +"%. c #0000D2D20000", +"&. c #0000D3D30000", +"*. c #0000D5D50000", +"=. c #0000D6D60000", +"-. c #0000D7D70000", +";. c #0000D8D80000", +":. c #0000D9D90000", +">. c #0000DADA0000", +",. c #0000DBDB0000", +"<. c #0000DCDC0000", +"1. c #0000DDDD0000", +"2. c #0000DEDE0000", +"3. c #0000DFDF0000", +"4. c #0000E0E00000", +"5. c #0000E1E10000", +"6. c #0000E2E20000", +"7. c #0000E3E30000", +"8. c #0000E4E40000", +"9. c #0000E5E50000", +"0. c #0000E6E60000", +"q. c #0000E7E70000", +"w. c #0000E8E80000", +"e. c #0000E9E90000", +"r. c #0000EAEA0000", +"t. c #0000EBEB0000", +"y. c #0000ECEC0000", +"u. c #0000EDED0000", +"i. c #0000EEEE0000", +"p. c #0000F0F00000", +"a. c #0000F2F20000", +"s. c #0000F4F40000", +"d. c #0000D2D2D2D2", +"f. c #0000D4D4D4D4", +"g. c #0000D7D7D7D7", +"h. c #0000DADADADA", +"j. c #0000DCDCDCDC", +"k. c #0000DDDDDDDD", +"l. c #0000DFDFDFDF", +"z. c #0000E0E0E0E0", +"x. c #0000E1E1E1E1", +"c. c #0000E2E2E2E2", +"v. c #0000E3E3E3E3", +"b. c #0000E4E4E4E4", +"n. c #0000E5E5E5E5", +"m. c #0000E6E6E6E6", +"M. c #0000E7E7E7E7", +"N. c #0000E8E8E8E8", +"B. c #0000E9E9E9E9", +"V. c #0000EAEAEAEA", +"C. c #0000EBEBEBEB", +"Z. c #0000ECECECEC", +"A. c #0000EDEDEDED", +"S. c #0000EEEEEEEE", +"D. c #0000EFEFEFEF", +"F. c #0000F0F0F0F0", +"G. c #0000F1F1F1F1", +"H. c #0000F2F2F2F2", +"J. c #0000F3F3F3F3", +"K. c #0000F4F4F4F4", +"L. c #0000F5F5F5F5", +"P. c #0000F7F7F7F7", +"I. c #0000F8F8F8F8", +"U. c #F5F5F5F50000", +"Y. c #F6F6F6F60000", +"T. c #F7F7F7F70000", +"R. c #F8F8F8F80000", +"E. c #F9F9F9F90000", +"W. c #FAFAFAFA0000", +"Q. c #FBFBFBFB0000", +"!. c #FCFCFCFC0000", +"~. c gray75", +/* pixels */ +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~. ~.", +"~. !.Q.Q.Q.Q.I.I.K.K.K.G.G.S.Z.V.V.V.n.n.z. ~.", +"~. Q.T.Q.T.Q.I.K.K.G.G.S.S.V.V.V.n.n.- - $ ~.", +"~. Q.Q.T.T.T.K.K.G.D.S.S.V.V.V.n.n.$ - $ $ ~.", +"~. Q.Q.T.T.J.G.G.G.S.S.V.M.n.v.z.- $ $ $ $ ~.", +"~. T.T.T.K.G.G.S.S.Z.S.n.n.n.z.- $ $ # # # ~.", +"~. I.K.K.G.G.D.S.V.V.n.n.z.z.l.h.# # # X X ~.", +"~. K.K.G.D.S.S.V.V.n.n.z.z.l.h.g.d.d.X X X ~.", +"~. s.p.p.y.y.y.0.0.5.5.2.2.;.-.&.&.O.X.4 3 ~.", +"~. s.p.y.y.q.0.0.5.5.2.;.;.-.&.&.O.X.} 3 3 ~.", +"~. p.p.y.q.q.0.5.2.2.;.;.-.&.O.O.X.} } 3 , ~.", +"~. P L q.q.q.0.5.2.;.-.-.&.O.X.} } [ ( , , ~.", +"~. L J D 0.5.2.2.;.-.-.O.O.O.} } [ ( , , , ~.", +"~. J J D S 5.2.;.-.-.&.O.X.} } [ [ , , : : ~.", +"~. J D S N N N v v c O.X.X.} [ ( ( / ~ ~ R ~.", +"~. q.S S N N M v c l l g g p i ( / / ~ R Y ~.", +"~. 0.5.2.N M v c c l h g p i i t t 0 0 0 5 ~.", +"~. 0.5.2.;.-.-.&.O.h g p p i t t 0 0 0 5 5 ~.", +"~. 5.5.;.;.-.&.&.X.} } [ ( ( / ~ R R R Y Y ~.", +"~. ~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.", +"~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~." +}; diff --git a/src/toolbar_run.xpm b/src/toolbar_run.xpm new file mode 100644 index 0000000..23760c7 --- /dev/null +++ b/src/toolbar_run.xpm @@ -0,0 +1,130 @@ +/* XPM */ +static const char *toolbar_run[] = { +/* columns rows colors chars-per-pixel */ +"24 24 100 2", +" c black", +". c gray50", +"X c #939300002525", +"o c #929200002626", +"O c #949401012525", +"+ c #959502022626", +"@ c #969601012525", +"# c #979702022626", +"$ c #989803032626", +"% c #9A9A02022525", +"& c #9D9D02022323", +"* c #9C9C05052626", +"= c #AAAA02021F1F", +"- c #AFAF03031F1F", +"; c #B3B304041F1F", +": c #B8B807071F1F", +"> c #A0A000002121", +", c #A2A205052525", +"< c #A4A400002020", +"1 c #A5A501012020", +"2 c #A4A404042323", +"3 c #A8A806062424", +"4 c #AEAE07072222", +"5 c #ABAB09092727", +"6 c #B1B105052020", +"7 c #B4B40C0C2525", +"8 c #BFBF0B0B2020", +"9 c #BCBC0D0D2424", +"0 c #BFBF15152A2A", +"q c #C6C60C0C1F1F", +"w c #C7C70F0F2323", +"e c #C3C312122727", +"r c #C6C618182B2B", +"t c #CDCD16162727", +"y c #CBCB1B1B2D2D", +"u c #CBCB1C1C2E2E", +"i c #CDCD1B1B2C2C", +"p c #D0D011112121", +"a c #D7D715152222", +"s c #D4D415152424", +"d c #D7D719192727", +"f c #D3D31D1D2C2C", +"g c #D5D51A1A2929", +"h c #DCDC18182424", +"j c #DBDB1E1E2B2B", +"k c #D6D622222F2F", +"l c #DDDD20202C2C", +"z c #DDDD21212D2D", +"x c #D9D926263232", +"c c #DADA24243131", +"v c #E3E320202929", +"b c #E3E322222B2B", +"n c #E3E326262F2F", +"m c #E6E620202828", +"M c #E6E623232D2D", +"N c #E5E525252D2D", +"B c #EAEA23232A2A", +"V c #EAEA25252C2C", +"C c #EDED28282D2D", +"Z c #ECEC28282E2E", +"A c #E1E128283131", +"S c #E4E42D2D3636", +"D c #E6E62C2C3434", +"F c #E6E62F2F3737", +"G c #E8E828283030", +"H c #E9E92B2B3232", +"J c #EBEB2D2D3333", +"K c #EAEA2D2D3434", +"L c #EFEF2B2B3131", +"P c #EEEE2F2F3434", +"I c #EFEF32323737", +"U c #ECEC33333939", +"Y c #EFEF37373C3C", +"T c #EFEF38383D3D", +"R c #F3F32F2F3232", +"E c #F1F130303434", +"W c #F2F232323636", +"Q c #F6F634343737", +"! c #F3F335353939", +"~ c #F3F337373B3B", +"^ c #F6F638383A3A", +"/ c #F4F43A3A3D3D", +"( c #F6F63C3C3E3E", +") c #F9F93C3C3E3E", +"_ c #F7F73E3E4040", +"` c #F8F83F3F4040", +"' c #FAFA3F3F4040", +"] c #F8F840404141", +"[ c #FAFA40404141", +"{ c #FBFB42424343", +"} c #F9F942424444", +"| c #FAFA45454646", +" . c #FBFB45454646", +".. c #FBFB47474747", +"X. c #FBFB48484848", +"o. c #FBFB49494A4A", +"O. c #FCFC49494A4A", +"+. c #FCFC4B4B4C4C", +"@. c #FDFD4D4D4E4E", +"#. c None", +/* pixels */ +"#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.", +"#.#.#.#.#.#.#.#.#.#.#.#.#. #.#.#.#.#.#.#.#.", +"#.#.#.#.#.. . . . . #.#. O.[ Q #.#.#.#.#.#.#.", +"#.#.#.#.#.#.#.#.#.#.#. @.X.` W V #.#.#.#.#.#.", +"#.#.#.#.#.#.#.#.#.#.#. +.| ( P b #.#.#.#.#.#.", +"#.#.#.#.#.. . . . . #. X.} ~ H j #.#.#.#.#.#.", +"#.#.#.#.#.#.#.#.#.#.#. ..` U n g #.#.#.#.#.#.", +"#.#.#.#.#.#.#.#.#.#.#.#. / J l #.#.#.#.#.#.#.", +"#.#.#.#.. . . . . #.#. [ W H #.#.#.#.#.#.#.#.", +"#.#.#.#.#.#.#.#.#.#. ..) W M #.#.#.#.#.#.#.#.", +"#.#.#.#.#.#.#.#.#.#. { ^ L v s #.#.#.#.", +"#.#.#.#.. . . . . #. ' Q C t ; = = #.#.#.", +"#.#.#.#.#.#.#.#.#.#.#. R B h 4 = & #.#.#.", +"#.#.#.#.#.#.#.#.#.#.#.#. m a q 8 #.#.#.#.", +"#.#.#.#.#.. . . . . #. V q 6 #.#.#.#.#.#.", +"#.#.#.#.#.#.#.#.#.#.#. n d w #.#.#.#.#.#.#.", +"#.#.#.#.#.#.#.#.#.#. D l t 9 4 2 #.#.#.#.#.#.", +"#.#.. . . . . #.#. U A f e 7 3 & #.#.#.#.#.#.", +"#.#.#.#.#.#.#.#. T S k y 5 , $ X #.#.#.#.#.", +"#.#.#.#.#.#.#. T F x i #. * $ X #.#.#.#.#.", +"#.. . . . . #. D c i #.#. $ X o X #.#.#.#.", +"#.#.#.#.#.#.#.#. i 0 #.#.#. X X o X #.#.#.", +"#.#.#.#.#.#.#.#.#. #.#.#.#.#. #.#.#.", +"#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#." +}; diff --git a/src/toolbar_textedit.xpm b/src/toolbar_textedit.xpm new file mode 100644 index 0000000..fe06dd1 --- /dev/null +++ b/src/toolbar_textedit.xpm @@ -0,0 +1,116 @@ +/* XPM */ +static const char *toolbar_textedit[] = { +/* columns rows colors chars-per-pixel */ +"24 24 86 1", +" c black", +". c #000000007F7F", +"X c #7F7F00007F7F", +"o c #7F7F7F7F0000", +"O c navy", +"+ c #000000008181", +"@ c #000000008282", +"# c #000000008383", +"$ c #000000008686", +"% c #000000008787", +"& c #000000008888", +"* c #000000008B8B", +"= c #000000008C8C", +"- c #000000009393", +"; c #000000009595", +": c #000000009898", +"> c #000000009D9D", +", c #000000009E9E", +"< c #00000000A6A6", +"1 c #00000000A9A9", +"2 c #00000000AAAA", +"3 c #00000000ACAC", +"4 c #00000000B3B3", +"5 c #00000000B9B9", +"6 c #00000000BFBF", +"7 c #00000000C1C1", +"8 c #00000000C3C3", +"9 c #00000000C6C6", +"0 c #00000000C8C8", +"q c #00000000CBCB", +"w c #00000000CCCC", +"e c MediumBlue", +"r c #00000000CECE", +"t c red", +"y c yellow", +"u c gray75", +"i c gray80", +"p c #CDCDCDCDCDCD", +"a c #CECECECECECE", +"s c gray81", +"d c #D0D0D0D0D0D0", +"f c gray82", +"g c #D2D2D2D2D2D2", +"h c LightGray", +"j c gray83", +"k c #D5D5D5D5D5D5", +"l c gray84", +"z c #D7D7D7D7D7D7", +"x c #D8D8D8D8D8D8", +"c c gray85", +"v c #DADADADADADA", +"b c gray86", +"n c gainsboro", +"m c gray87", +"M c #DFDFDFDFDFDF", +"N c #E1E1E1E1E1E1", +"B c #E2E2E2E2E2E2", +"V c gray89", +"C c #E4E4E4E4E4E4", +"Z c gray90", +"A c #E6E6E6E6E6E6", +"S c #E7E7E7E7E7E7", +"D c gray91", +"F c #E9E9E9E9E9E9", +"G c #EAEAEAEAEAEA", +"H c gray92", +"J c #ECECECECECEC", +"K c gray93", +"L c #EEEEEEEEEEEE", +"P c #EFEFEFEFEFEF", +"I c gray94", +"U c #F1F1F1F1F1F1", +"Y c gray95", +"T c #F3F3F3F3F3F3", +"R c #F4F4F4F4F4F4", +"E c gray96", +"W c #F6F6F6F6F6F6", +"Q c gray97", +"! c #F8F8F8F8F8F8", +"~ c #F9F9F9F9F9F9", +"^ c gray98", +"/ c #FBFBFBFBFBFB", +"( c gray99", +") c #FDFDFDFDFDFD", +"_ c #FEFEFEFEFEFE", +"` c gray100", +/* pixels */ +"uuuuuuuuuuuuuuuuuuuuuuuu", +"u ", +"u yoyw```0```2`:`*```+``", +"u oytww`09``2,;`*$+`++``", +"u yot09`65`<,-`$`++`..`.", +"u XXX76`43```*`+`..`..``", +"u ", +"u ``````````````````````", +"u ``````````````````````", +"u ``````` ``````````` ``", +"u `` ``` ``````````` `^", +"u ```` `` ``` `` ^^", +"u `` `` `` ` ``` `` ^U", +"u ` `` `` `` ` ``` `^ WL", +"u `` `` ``` `` LZ", +"u ```````````````^WWULZm", +"u ```````` ``^^^WUULGVmz", +"u `` ``` ` ^UW LG Vbzh", +"u ` `` ^^ WWUL G Vm bzpp", +"u ` W LGZV bz pp", +"u ^ WWUUL ZVmmbz hh pp p", +"u WW ZV mbzh ppp pp p", +"u ULGZVmbzzhhpppppppiipi", +"u GZVmbzzhhhpppppppiiiii" +}; diff --git a/src/toolbar_viewedit.xpm b/src/toolbar_viewedit.xpm new file mode 100644 index 0000000..db15abb --- /dev/null +++ b/src/toolbar_viewedit.xpm @@ -0,0 +1,64 @@ +/* XPM */ +static const char *toolbar_viewedit[] = { +/* columns rows colors chars-per-pixel */ +"24 24 34 1", +" c black", +". c #7F7F00000000", +"X c gray30", +"o c cyan", +"O c #808000000000", +"+ c #CFCF00003333", +"@ c #CDCD00003434", +"# c #CDCD00003535", +"$ c #CECE00003434", +"% c #D2D200002F2F", +"& c #D7D700002B2B", +"* c #D5D500002C2C", +"= c #DADA00002727", +"- c #DFDF00002121", +"; c #DFDF00002222", +": c #D0D000003131", +"> c #D0D000003232", +", c #E1E100001F1F", +"< c #E5E500001C1C", +"1 c #EAEA00001616", +"2 c #EDED00001313", +"3 c #EFEF00001010", +"4 c #F3F300000D0D", +"5 c #F7F700000808", +"6 c #FAFA00000505", +"7 c #FBFB00000404", +"8 c #FEFE00000101", +"9 c #F8F800000808", +"0 c #F0F000001010", +"q c #FFFF50505050", +"w c #FFFFAEAE0000", +"e c yellow", +"r c gray59", +"t c None", +/* pixels */ +"tttttttttttttttttttttttt", +"ttttt..ttttttttttttttttt", +"ttttt....ttttttttttttttt", +"tttttoo..rtttttttttttttt", +"tttttoooooottttttttttttt", +"tttttoooooooottttttttttt", +"tttttXXXXXXeettttttttttt", +"tttttXXXXeeeeeettttttttt", +"tttttXXXXeeeerrttttttttt", +"tttttXXeee tttttttttt", +"ttttttreee www ttttttttt", +"tttttttqqq ww 7 tttttttt", +"tttttqqqqq w 753 ttttttt", +"tttttqqqqqq 8741- tttttt", +"tttttqqeeqqr 53<=% ttttt", +"tttttqqeeqqrt 3,&># tttt", +"tttttqqeeqqrtt -*>## ttt", +"tttttqqeeqqrttt *+## ttt", +"tttttqqeeeertttt >+# ttt", +"tttttqqOOeeeetttt tttt", +"tttttOOOOOOeettttttttttt", +"tttttoooooorrttttttttttt", +"tttttoooooortttttttttttt", +"tttttttttttttttttttttttt" +}; diff --git a/src/toolbar_wordsedit.xpm b/src/toolbar_wordsedit.xpm new file mode 100644 index 0000000..dbc91de --- /dev/null +++ b/src/toolbar_wordsedit.xpm @@ -0,0 +1,208 @@ +/* XPM */ +static const char *toolbar_wordsedit[] = { +/* columns rows colors chars-per-pixel */ +"24 24 178 2", +" c black", +". c #00002F2F6E6E", +"X c #00002F2F6F6F", +"o c #00002D2D7070", +"O c #00002C2C7373", +"+ c #00002F2F7171", +"@ c #00002F2F7373", +"# c #00002D2D7676", +"$ c #00002F2F7B7B", +"% c #000030306D6D", +"& c #000032326C6C", +"* c #000033336C6C", +"= c #000033336E6E", +"- c #000033336F6F", +"; c #000034346B6B", +": c #000035356A6A", +"> c #000037376969", +", c #000036366A6A", +"< c #000033337171", +"1 c #000032327676", +"2 c #000035357373", +"3 c #000030307A7A", +"4 c #000035357878", +"5 c #000034347E7E", +"6 c #000034347F7F", +"7 c #000038387676", +"8 c #00003B3B7A7A", +"9 c #00003A3A7C7C", +"0 c #00003F3F7E7E", +"q c #00003F3F7F7F", +"w c #777777777777", +"e c gray47", +"r c #797979797979", +"t c gray48", +"y c #7B7B7B7B7B7B", +"u c #7C7C7C7C7C7C", +"i c gray49", +"p c #7E7E7E7E7E7E", +"a c gray50", +"s c #00003B3B8282", +"d c #00003B3B8484", +"f c #00003C3C8484", +"g c #000042428686", +"h c #000045458383", +"j c #000043438989", +"k c #000044448989", +"l c #00004B4B8A8A", +"z c #00004D4D8888", +"x c #00004E4E8E8E", +"c c #000053538D8D", +"v c #000054548B8B", +"b c #00005B5B8F8F", +"n c #000055559191", +"m c #000058589292", +"M c #000059599292", +"N c #00005B5B9191", +"B c #00005E5E9494", +"V c #000061619292", +"C c #000061619494", +"Z c #000060609797", +"A c #000061619696", +"S c #000066669696", +"D c #000066669797", +"F c #000067679999", +"G c #000069699A9A", +"H c #00006B6B9898", +"J c #00006B6B9A9A", +"K c #00006C6C9B9B", +"L c #00006F6F9A9A", +"P c #00006F6F9B9B", +"I c #00006D6D9C9C", +"U c #000072729B9B", +"Y c #000071719D9D", +"T c #000072729C9C", +"R c #000073739E9E", +"E c #000074749E9E", +"W c #000075759E9E", +"Q c #000076769E9E", +"! c #000076769F9F", +"~ c #000077779E9E", +"^ c #000077779F9F", +"/ c #000078789F9F", +"( c #000079799F9F", +") c #808080808080", +"_ c #818181818181", +"` c gray51", +"' c #838383838383", +"] c #848484848484", +"[ c gray52", +"{ c #868686868686", +"} c gray53", +"| c #888888888888", +" . c #8B8B8B8B8B8B", +".. c gray55", +"X. c #8D8D8D8D8D8D", +"o. c #8E8E8E8E8E8E", +"O. c gray56", +"+. c gray57", +"@. c #939393939393", +"#. c gray58", +"$. c #959595959595", +"%. c gray59", +"&. c #979797979797", +"*. c #989898989898", +"=. c #9B9B9B9B9B9B", +"-. c #9D9D9D9D9D9D", +";. c #9F9F9F9F9F9F", +":. c #A0A0A0A0A0A0", +">. c gray63", +",. c gray64", +"<. c #A4A4A4A4A4A4", +"1. c gray65", +"2. c gray66", +"3. c #A9A9A9A9A9A9", +"4. c #AAAAAAAAAAAA", +"5. c #ACACACACACAC", +"6. c gray68", +"7. c #AEAEAEAEAEAE", +"8. c gray69", +"9. c #B1B1B1B1B1B1", +"0. c #B2B2B2B2B2B2", +"q. c gray70", +"w. c gray71", +"e. c #B6B6B6B6B6B6", +"r. c gray72", +"t. c gray73", +"y. c #BBBBBBBBBBBB", +"u. c #BCBCBCBCBCBC", +"i. c gray74", +"p. c gray75", +"a. c #C0C0C0C0C0C0", +"s. c #C1C1C1C1C1C1", +"d. c gray76", +"f. c #C3C3C3C3C3C3", +"g. c gray77", +"h. c #C5C5C5C5C5C5", +"j. c gray78", +"k. c #C8C8C8C8C8C8", +"l. c gray79", +"z. c #CACACACACACA", +"x. c #CBCBCBCBCBCB", +"c. c gray80", +"v. c #CDCDCDCDCDCD", +"b. c #CECECECECECE", +"n. c gray81", +"m. c #D2D2D2D2D2D2", +"M. c LightGray", +"N. c gray83", +"B. c #D7D7D7D7D7D7", +"V. c #D8D8D8D8D8D8", +"C. c #DADADADADADA", +"Z. c gainsboro", +"A. c #DDDDDDDDDDDD", +"S. c #DFDFDFDFDFDF", +"D. c gray88", +"F. c #E1E1E1E1E1E1", +"G. c #E2E2E2E2E2E2", +"H. c #E4E4E4E4E4E4", +"J. c #E6E6E6E6E6E6", +"K. c #E7E7E7E7E7E7", +"L. c gray91", +"P. c gray92", +"I. c #ECECECECECEC", +"U. c gray93", +"Y. c #EEEEEEEEEEEE", +"T. c #EFEFEFEFEFEF", +"R. c gray94", +"E. c #F1F1F1F1F1F1", +"W. c gray95", +"Q. c #F3F3F3F3F3F3", +"!. c gray96", +"~. c #F6F6F6F6F6F6", +"^. c #F8F8F8F8F8F8", +"/. c #F9F9F9F9F9F9", +"(. c gray98", +"). c #FBFBFBFBFBFB", +"_. c gray99", +"`. c None", +/* pixels */ +"`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.", +"`.`.`. `.`.`.", +"`.`. ).(._.(.(.).~.W.W.I.K.F.Z.V.m.b.z.j. `.`.", +"`. )._._.(.(.^.!.W.R.P.K.F.Z.B.m.c.k.g.s.s. `.", +"`. ).).E E E ( ( ( ( ( E E E E P F B n p.t. `.", +"`. ).).(.^.!.W.I.L.G.Z.V.B.n.x.j.s.s.i.t.y. `.", +"`. ).).( ( ( ( ( ( E E T K F A c n j s e.q. `.", +"`. ).).~.W.I.K.F.C.M.n.z.j.f.s.p.i.w.q.8.7. `.", +"`. ^.^.( ( E E T P F D B c x k s 6 $ $ 2.1. `.", +"`. ~.W.Y.K.F.V.B.b.z.s.a.i.y.w.0.5.2.<.;.-. `.", +"`. W.Y.U K H D B N c l g s 6 3 # O . . &.$. `.", +"`. U.K.G.C.m.b.s.i.y.w.0.7.4.<.,.=.&.@.O... `.", +"`. K.Z.V b v z h 0 9 4 1 @ @ . = & : : [ [ `.", +"`. V.N.b.g.y.w.7.4.<.;.-.*.$.+.o. .[ [ ` ` `.", +"`. n.z.h 0 9 7 2 < = = = : : : : > : : i i `.", +"`. s.y.0.4.<.*.$.+... .| [ [ ` ) p i y y w `.", +"`.`. 7.,.-.$.....| [ ` ` i ` i y y y w w `.`.", +"`.`.`. | ` ` `.`.`.", +"`.`.`.`.`.`. ` i i `.`.`.`.`.`.`.`.`.`.`.`.`.", +"`.`.`.`. ` i y `.`.`.`.`.`.`.`.`.`.`.`.`.`.", +"`.`.`. ` i i y `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.", +"`.`.`. `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.", +"`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.", +"`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`." +}; diff --git a/src/uparrow_x.xpm b/src/uparrow_x.xpm new file mode 100644 index 0000000..affedec --- /dev/null +++ b/src/uparrow_x.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char *uparrow_x[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +" c black", +". c None", +/* pixels */ +"....... .......", +"...... ......", +"..... .....", +".... ....", +"... ...", +".. ..", +". .", +" ", +" ", +"...... ......", +"...... ......", +"...... ......", +"...... ......", +"...... ......", +"...... ......", +"................" +}; diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..6b6b4f4 --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,242 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "util.h" +#include +#include +#include +#include + +TStringList::TStringList () +{ + + num=0; + max=0; + inc=16; + data=NULL; + +} + + +void TStringList::toLower(void) +{ + + for(int i=0;i=max){ + max+=inc; + string *data1 = new string[max]; + for(int i=0;i=max){ + max+=inc; + string *data1 = new string[max]; + for(int i=0;i s){ + for(int k=num;k>i;k--){ + data[k]=data[k-1]; + } + data[i]=s; + num++; + return; + } + } + data[num++]=s; + +} + +void TStringList::copy(const TStringList& list) +{ + + num=list.num; + max=list.max; + delete [] data; + data = new string[max]; + for(int i=0;i0){ + delete [] data; + data=NULL; + num=0; + max=0; + } + +} + +//************************************** + +string MultStr(const char *str,int NumCopies) +{ + char tmp[256]; + + tmp[0]=0; + for(int i=0;ilength();i++){ + str->at(i)=tolower(str->at(i)); + } + + +} +void toLower(char *str) +{ + + for(int i=0;i<(int)strlen(str);i++){ + str[i]=tolower(str[i]); + } + + +} +//********************************* diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..f1593b4 --- /dev/null +++ b/src/util.h @@ -0,0 +1,64 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef UTIL_H +#define UTIL_H + +#include +using namespace std; + +#include "global.h" + +#define MAX(a,b) ((a>b)?(a):(b)) +#define MIN(a,b) ((a +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include +#include + +static int ResPos,DescPos,ResSize; +//************************************************** +View::View() +{ + + Description = ""; + loops = NULL; + opened = false; + +} + +//************************************************** +void View::init() +{ + ReadViewInfo(); + CurLoop = 0; + CurCel = 0; + opened = true; + +} +//************************************************* +int View::open(char *filename) +{ + + FILE *fptr = fopen(filename,"rb"); + if(fptr==NULL){ + menu->errmes("Can't open file %s ! ",filename); + return 1; + } + + struct stat buf; + fstat(fileno(fptr),&buf); + ResourceData.Size=buf.st_size; + fread(ResourceData.Data,ResourceData.Size,1,fptr); + fclose(fptr); + + init(); + return 0; +} + +//************************************************** +int View::open(int ResNum) +{ + + int err = game->ReadResource(VIEW,ResNum); + if(err)return 1; + init(); + return 0; + +} +//************************************************* +static byte ReadByte(void) +{ + + if(ResPos < ResourceData.Size){ + return ResourceData.Data[ResPos++]; + } + return 0; +} + +//************************************************** +static int ReadLSMSWord(void) +{ + byte MSbyte,LSbyte; + + LSbyte = ReadByte(); + MSbyte = ReadByte(); + return (LSbyte + MSbyte*256); + +} +//************************************************** +static void SeekRes(int seekpos) +{ + if (seekpos>=0 && seekpos<=ResourceData.Size-1){ + ResPos = seekpos; + } +} +//************************************************* +void View::ReadViewInfo() +{ + int CurLoop,CurCel,NumCels,curbyte,i,cel_width,cel_height,cel_transcol; + bool cel_mirror; + + NumLoops=0; + CurLoop = 0; + CurCel = 0; + SeekRes(2); + NumLoops = ReadByte(); + + loops = new Loop[NumLoops]; + Description = ""; + DescPos = ReadLSMSWord(); + if (DescPos > 0){ + SeekRes(DescPos); + curbyte=1; + while(curbyte != 0){ + curbyte = ReadByte(); + if(curbyte !=0){ + if(curbyte==0x0a) + Description.append("\\n"); + else + Description.append(1,(char)curbyte); + } + } + } + + SeekRes(5); + + for(CurLoop=0;CurLoop= 0x80) + cel_mirror= true; + else + cel_mirror = false; + + loops[CurLoop].cel(CurCel,cel_width,cel_height,cel_transcol,cel_mirror); + LoadCel(CurLoop,CurCel); + } + } + +} + +//************************************************* + +void View::LoadCel(int loopno,int celno){ + int i0,i1,celX,celY,ChunkLength,ChunkCol,Width, Height,transcol; + byte k,curbyte; + bool mirror; + + Width = loops[loopno].cels[celno].width; + Height = loops[loopno].cels[celno].height; + transcol = loops[loopno].cels[celno].transcol; + mirror = loops[loopno].cels[celno].mirror; + SeekRes(loops[loopno].LoopLoc+loops[loopno].CelLoc[celno]+3); + celX = 0; + celY = 0; + while(celY != Height){ + curbyte = ReadByte(); + if (curbyte > 0){ + ChunkCol = (curbyte & 0xF0) / 0x10; + ChunkLength = curbyte & 0x0F; + i0=celX; + i1=i0+ChunkLength*2-1; + for(celX=i0;celX<=i1;celX++){ + loops[loopno].cels[celno].data[celY*Width*2+celX] = ChunkCol; + } + } + else{ + for(;celXerrmes("Can't open file %s ! ",filename); + return 1; + } + save(); + fwrite(ResourceData.Data,ResourceData.Size,1,fptr); + fclose(fptr); + return 0; + +} +//************************************************* +int View::save(int ResNum) +{ + + save(); + return(game->AddResource(VIEW,ResNum)); + +} +//************************************************* +void WriteByte(byte b) +{ + + if(ResPos >= MaxResourceSize){ + menu->errmes("Resource too big !"); + return; + } + ResourceData.Data[ResPos++]=b; + if(ResPos > ResSize)ResSize=ResPos; + +} +//************************************************* +void View::save() +{ + + byte c; + int i,j,x,y,length,mirror,k,k1; + int NumCels,CelSize,CelMirrorSize,DescLoc; + bool ColDiff; + short LoopLoc[MaxLoops]; + short CelLoc[MaxLoops][MaxCels]; + + ResSize = 0; + ResPos = 0; + + + WriteByte(1); //what do these two bytes do? + WriteByte(1); + WriteByte((byte)NumLoops); + WriteByte(0); //write description later, if it exists + WriteByte(0); + + LoopLoc[0] = 5 + NumLoops*2; + + //fix mirroring so (according to the AGI specs) the loops>=8 do not use it, + //and the mirroring loop number is always higher than the mirrored loop + for (i = 0;i=8){ + if(k!=-1)unsetMirror(k); + if(k1!=-1)unsetMirror(k1); + } + else if(k!=-1){ + if(k>i){ + unsetMirror(i); + setMirror(k,i); + } + } + } + + for (i = 0;i=15 || x+length>=width)); + if(x>0 || (x==0 && c!=transcol))CelMirrorSize++; + x+=length; + if(x=width && c!=transcol)){ + WriteByte((c<<4)|length); + CelSize++; + } + }while(xCurLoop) + loops1[i]=loops[i-1]; + else{ + loops1[i]=Loop(); + loops1[i].numcels(1); + if(i>0){ + w=loops[0].cels[0].width; + h=loops[0].cels[0].height; + c=loops[0].cels[0].transcol; + } + else{ + w=loops[NumLoops-1].cels[0].width; + h=loops[NumLoops-1].cels[0].height; + c=loops[NumLoops-1].cels[0].transcol; + } + loops1[i].cel(0,w,h,c,false); + } + } + delete [] loops; + loops=loops1; + NumLoops++;; + for(i=0;i= CurLoop){ + loops[i].mirror++; + } + } + + fixmirror(); + +} +//************************************************* +void View::insertLoop_after() + //after current +{ + int w,h,c,i; + + Loop *loops1 = new Loop[NumLoops+1]; + + for(i=0;iCurLoop+1) + loops1[i]=loops[i-1]; + else{ + loops1[i]=Loop(); + loops1[i].numcels(1); + if(i>0){ + w=loops[0].cels[0].width; + h=loops[0].cels[0].height; + c=loops[0].cels[0].transcol; + } + else{ + w=loops[NumLoops-1].cels[0].width; + h=loops[NumLoops-1].cels[0].height; + c=loops[NumLoops-1].cels[0].transcol; + } + loops1[i].cel(0,w,h,c,false); + } + } + delete [] loops; + loops=loops1; + NumLoops++;; + for(i=0;i CurLoop){ + loops[i].mirror++; + } + } + + fixmirror(); + +} +//************************************************* +void View::appendLoop() + //append to end +{ + + Loop *loops1 = new Loop[NumLoops+1]; + + for(int i=0;i CurLoop){ + loops[i].mirror--; + } + else if(loops[i].mirror == CurLoop){ + unsetMirror(i); + } + } + for(i=CurLoop;i1;x-=2){ + data[y*width*2+x]=data[y*width*2+x-2]; + data[y*width*2+x-1]=data[y*width*2+x-3]; + } + data[y*width*2+1]=k0; + data[y*width*2]=k1; + } +} + +//************************************************* +void Cel::left(){ + int x,y; + byte k0,k1; + + for(y=0;y0;y--){ + data[y*width*2+x]=data[(y-1)*width*2+x]; + } + data[x]=k0; + } +} +//************************************************* +void Cel::mirrorh(){ + int x,y; + byte k0; + + for(y=0;ywidth-1||yn<0||yn>height-1)return 0; + if(data[width*2*yn+xn*2]==c){ + return 0; + } + if(data[width*2*yn+xn*2]==c0){ + data[width*2*yn+xn*2]=c; + data[width*2*yn+xn*2+1]=c; + return 1; + } + else{ + return 0; + } +} +//************************************************* +void Cel::fill1(int xn,int yn,byte c0,byte c){ + + if(setc(xn,yn-1,c0,c)==1){ + fill1(xn,yn-1,c0,c); + } + if(setc(xn-1,yn,c0,c)==1){ + fill1(xn-1,yn,c0,c); + } + if(setc(xn,yn,c0,c)==1){ + fill1(xn,yn,c0,c); + } + if(setc(xn+1,yn,c0,c)==1){ + fill1(xn+1,yn,c0,c); + } + if(setc(xn,yn+1,c0,c)==1){ + fill1(xn,yn+1,c0,c); + } +} +//************************************************* +void Cel::fill(int xn,int yn,byte c){ + byte c0; + + c0=data[width*2*yn+xn*2]; + fill1(xn,yn,c0,c); +} +//************************************************** +Loop::Loop() +{ + + mirror = mirror1 = -1; + cels = NULL; + CelLoc = NULL; +} +//************************************************** +void Loop::numcels(int n) +{ + NumCels = n; + if(cels) + delete [] cels; + if(CelLoc) + delete [] CelLoc; + cels = new Cel[NumCels]; + CelLoc = new int[NumCels]; +} + +void Loop::cel(int n,int w,int h,int c,bool m) +{ + cels[n]=Cel(w,h,c,m); +} + +//************************************************** +void Loop::insertCel_before(int n) + //insert cell before 'n' +{ + + Cel *cels1 = new Cel[NumCels+1]; + for(int i=0;in) + cels1[i] = cels[i-1]; + else{ + if(i>0) + cels1[i]=Cel(cels[i-1].width,cels[i-1].height,cels[i-1].transcol,cels[i-1].mirror); + else //can't be NumCels==0 ! + cels1[i]=Cel(cels[NumCels-1].width,cels[NumCels-1].height,cels[NumCels-1].transcol,cels[NumCels-1].mirror); + cels1[i].clear(); + } + } + delete [] cels; + cels = cels1; + NumCels++; +} +//************************************************** +void Loop::insertCel_after(int n) + //insert cell after 'n' +{ + + Cel *cels1 = new Cel[NumCels+1]; + for(int i=0;in+1) + cels1[i] = cels[i-1]; + else{ + if(i>0) + cels1[i]=Cel(cels[i-1].width,cels[i-1].height,cels[i-1].transcol,cels[i-1].mirror); + else //can't be NumCels==0! + cels1[i]=Cel(cels[NumCels-1].width,cels[NumCels-1].height,cels[NumCels-1].transcol,cels[NumCels-1].mirror); + cels1[i].clear(); + } + } + delete [] cels; + cels = cels1; + NumCels++; +} +//************************************************** +void Loop::appendCel() +{ + + Cel *cels1 = new Cel[NumCels+1]; + for(int i=0;i +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zoom_minus_x.xpm" +#include "zoom_plus_x.xpm" +#include "right_x.xpm" +#include "left_x.xpm" +#include "rightarrow_x.xpm" +#include "leftarrow_x.xpm" +#include "uparrow_x.xpm" +#include "downarrow_x.xpm" + +Cel saveCel = Cel(); //cel "clipboard" +bool cel_copied = false; + +//********************************************* +ViewEdit::ViewEdit( QWidget *parent, const char *name,int win_num, ResourcesWin *res) + : QWidget( parent, name, Qt::WDestructiveClose) +{ + + setCaption("View Editor"); + + winnum = win_num; + resources_win = res; + view = new View(); + + Q3PopupMenu *file = new Q3PopupMenu( this ); + Q_CHECK_PTR( file ); + + file->insertItem( "New", this, SLOT(open()) ); + file->insertItem( "Load from file", this, SLOT(open_file()) ); + file->insertItem( "Save to game", this, SLOT(save_to_game()) ); + file->insertItem( "Save to game as...", this, SLOT(save_to_game_as()) ); + file->insertItem( "Save to file", this, SLOT(save_file()) ); + file->insertSeparator(); + file->insertItem( "Delete", this, SLOT(delete_view()) ); + file->insertSeparator(); + file->insertItem( "Close", this, SLOT(close()) ); + + Q3PopupMenu *edit = new Q3PopupMenu( this ); + Q_CHECK_PTR( edit ); + + edit->insertItem( "Undo", this, SLOT(undo_cel()) ); + edit->insertSeparator(); + edit->insertItem( "&Copy cel", this, SLOT(copy_cel()) ,Qt::CTRL+Qt::Key_C ); + edit->insertItem( "&Paste cel", this, SLOT(paste_cel()), Qt::CTRL+Qt::Key_V ); + + Q3PopupMenu *loop = new Q3PopupMenu( this ); + Q_CHECK_PTR( loop ); + + loop->insertItem( "Next", this, SLOT(next_loop()) ); + loop->insertItem( "Previous", this, SLOT(previous_loop()) ); + loop->insertItem( "First", this, SLOT(first_loop()) ); + loop->insertItem( "Last", this, SLOT(last_loop()) ); + loop->insertSeparator(); + loop->insertItem( "Insert before", this, SLOT(insert_loop_before()) ); + loop->insertItem( "Insert after", this, SLOT(insert_loop_after()) ); + loop->insertItem( "Append", this, SLOT(append_loop()) ); + loop->insertItem( "Delete", this, SLOT(delete_loop()) ); + loop->insertItem( "Clear", this, SLOT(clear_loop()) ); + + + Q3PopupMenu *cel = new Q3PopupMenu( this ); + Q_CHECK_PTR( cel ); + + cel->insertItem( "Next", this, SLOT(next_cel()) ); + cel->insertItem( "Previous", this, SLOT(previous_cel()) ); + cel->insertItem( "First", this, SLOT(first_cel()) ); + cel->insertItem( "Last", this, SLOT(last_cel()) ); + cel->insertSeparator(); + cel->insertItem( "Insert before", this, SLOT(insert_cel_before()) ); + cel->insertItem( "Insert after", this, SLOT(insert_cel_after()) ); + cel->insertItem( "Append", this, SLOT(append_cel()) ); + cel->insertItem( "Delete", this, SLOT(delete_cel()) ); + cel->insertItem( "Clear", this, SLOT(clear_cel()) ); + cel->insertSeparator(); + cel->insertItem( "Flip Horizontally", this, SLOT(fliph_cel()) ); + cel->insertItem( "Flip Vertically", this, SLOT(flipv_cel()) ); + + QMenuBar *menu = new QMenuBar(this); + Q_CHECK_PTR( menu ); + menu->insertItem( "File", file ); + menu->insertItem( "Edit", edit ); + menu->insertItem( "Loop", loop ); + menu->insertItem( "Cel", cel ); + menu->insertItem( "Animate", this, SLOT(animate_cb()) ); + menu->setSeparator( QMenuBar::InWindowsStyle ); + + Q3BoxLayout *all = new Q3HBoxLayout(this,10); + all->setMenuBar(menu); + + Q3BoxLayout *left = new Q3VBoxLayout(all,1); + + + QPixmap pright=QPixmap(right_x); + QPixmap pleft=QPixmap(left_x); + + + Q3Frame *frame1 = new Q3Frame(this); + frame1->setFrameStyle(Q3Frame::Box | Q3Frame::Sunken); + frame1->setLineWidth(1); + frame1->setMinimumSize(200,180); + frame1->setMargin(10); + left->addWidget(frame1); + + + int maxrow1 = 9,maxcol1 = 4; + Q3GridLayout *grid1 = new Q3GridLayout( frame1, maxrow1,maxcol1, 1 ); + + int i; + + for(i=0;isetColStretch(i,1); + grid1->addColSpacing(i,1); + } + + for(i=0;isetRowStretch(i,1); + grid1->addRowSpacing(i,2); + } + + + int row=1;int col=0; + + QLabel *looplabel = new QLabel("Loop:",frame1); + grid1->addWidget(looplabel,row,col,Qt::AlignRight); col++; + + + loopnum = new QLabel("0/0",frame1); + grid1->addWidget(loopnum,row,col,Qt::AlignLeft); col++; + + + QPushButton *loopleft = new QPushButton(frame1); + // loopleft->setFocusPolicy(ClickFocus); + loopleft->setPixmap(pleft); + connect( loopleft, SIGNAL(clicked()), SLOT(previous_loop()) ); + grid1->addWidget(loopleft,row,col,Qt::AlignRight); col++; + + QPushButton *loopright = new QPushButton(frame1); + // loopright->setFocusPolicy(ClickFocus); + loopright->setPixmap(pright); + connect( loopright, SIGNAL(clicked()), SLOT(next_loop()) ); + grid1->addWidget(loopright,row,col,Qt::AlignLeft); col++; + + row++;col=0; + + QLabel *cellabel = new QLabel("Cel:",frame1); + grid1->addWidget(cellabel,row,col,Qt::AlignRight); col++; + + celnum = new QLabel("0/0",frame1); + grid1->addWidget(celnum,row,col,Qt::AlignLeft); col++; + + QPushButton *celleft = new QPushButton(frame1); + // celleft->setFocusPolicy(ClickFocus); + celleft->setPixmap(pleft); + connect( celleft, SIGNAL(clicked()), SLOT(previous_cel()) ); + grid1->addWidget(celleft,row,col,Qt::AlignRight); col++; + + QPushButton *celright = new QPushButton(frame1); + celright->setPixmap(pright); + // celright->setFocusPolicy(ClickFocus); + connect( celright, SIGNAL(clicked()), SLOT(next_cel()) ); + grid1->addWidget(celright,row,col,Qt::AlignLeft); col++; + + row++;col=0; + + QLabel *lwidth = new QLabel("Width:",frame1); + grid1->addWidget(lwidth,row,col,Qt::AlignRight); col++; + + width = new QLineEdit(frame1); + width->setMinimumWidth(40); + width->setMaximumWidth(60); + connect( width, SIGNAL(returnPressed()), SLOT(change_width_height()) ); + grid1->addWidget(width,row,col,Qt::AlignLeft); col++; + + QPushButton *widthleft = new QPushButton(frame1); + // widthleft->setFocusPolicy(ClickFocus); + widthleft->setPixmap(pleft); + // widthleft->setFocusPolicy(ClickFocus); + connect( widthleft, SIGNAL(clicked()), SLOT(dec_width()) ); + grid1->addWidget(widthleft,row,col,Qt::AlignRight); col++; + + QPushButton *widthright = new QPushButton(frame1); + // widthright->setFocusPolicy(ClickFocus); + widthright->setPixmap(pright); + // widthright->setFocusPolicy(ClickFocus); + connect( widthright, SIGNAL(clicked()), SLOT(inc_width()) ); + grid1->addWidget(widthright,row,col,Qt::AlignLeft); col++; + + row++;col=0; + + QLabel *lheight = new QLabel("Height:",frame1); + grid1->addWidget(lheight,row,col,Qt::AlignRight); col++; + + height = new QLineEdit(frame1); + height->setMinimumWidth(40); + height->setMaximumWidth(60); + connect( height, SIGNAL(returnPressed()), SLOT(change_width_height()) ); + grid1->addWidget(height,row,col,Qt::AlignLeft); col++; + + QPushButton *heightleft = new QPushButton(frame1); + // heightleft->setFocusPolicy(ClickFocus); + heightleft->setPixmap(pleft); + // heightleft->setFocusPolicy(ClickFocus); + connect( heightleft, SIGNAL(clicked()), SLOT(dec_height()) ); + grid1->addWidget(heightleft,row,col,Qt::AlignRight); col++; + + QPushButton *heightright = new QPushButton(frame1); + // heightright->setFocusPolicy(ClickFocus); + heightright->setPixmap(pright); + // heightright->setFocusPolicy(ClickFocus); + connect( heightright, SIGNAL(clicked()), SLOT(inc_height()) ); + grid1->addWidget(heightright,row,col,Qt::AlignLeft); col++; + + + row++;col=0; + is_descriptor = new QCheckBox("Description",frame1); + // is_descriptor->setFocusPolicy(ClickFocus); + connect( is_descriptor, SIGNAL(clicked()), SLOT(is_descriptor_cb()) ); + + grid1->addMultiCellWidget(is_descriptor,row,row,0,2,Qt::AlignCenter); + + edit_descriptor = new QPushButton(frame1); + // edit_descriptor->setFocusPolicy(ClickFocus); + edit_descriptor->setText("Edit"); + edit_descriptor->setMaximumHeight(20); + edit_descriptor->setEnabled(false); + connect( edit_descriptor, SIGNAL(clicked()), SLOT(show_description()) ); + grid1->addMultiCellWidget(edit_descriptor,row,row,maxcol1-2,maxcol1-1,Qt::AlignCenter); + + + row++;col=0; + + + QLabel *mirrorloop = new QLabel("This loop mirrors: ", frame1, 0); + grid1->addMultiCellWidget(mirrorloop,row,row,0,maxcol1-1,Qt::AlignCenter); + + + row++;col=0; + + + mirror_loop = new QComboBox( FALSE, frame1,0 ); + mirror_loop->insertItem(" no other loop "); + mirror_loop->setMinimumSize(100,20); + connect( mirror_loop, SIGNAL(activated(int)), this, SLOT(change_mirror(int)) ); + + grid1->addMultiCellWidget(mirror_loop,row,row,0,maxcol1-1,Qt::AlignCenter); + + + Q3Frame *frame2 = new Q3Frame(this); + frame2->setFrameStyle(Q3Frame::Box | Q3Frame::Sunken); + frame2->setLineWidth(1); + frame2->setMinimumSize(180,100); + frame2->setMargin(1); + left->addWidget(frame2); + + + Q3BoxLayout *h_frame2 = new Q3HBoxLayout(frame2, 10); + + + Q3GridLayout *grid2 = new Q3GridLayout( h_frame2, 3, 2, 1); + + for(i=0;i<2;i++){ + grid2->setColStretch(i,1); + grid2->addColSpacing(i,1); + } + for(i=0;i<3;i++){ + grid2->setRowStretch(i,1); + grid2->addRowSpacing(i,2); + } + + + QPushButton *zoom_minus = new QPushButton(frame2); + // zoom_minus->setFocusPolicy(ClickFocus); + zoom_minus->setPixmap(QPixmap(zoom_minus_x)); + connect( zoom_minus, SIGNAL(clicked()), SLOT(zoom_minus()) ); + grid2->addWidget(zoom_minus,0,0,Qt::AlignLeft); + + QPushButton *zoom_plus = new QPushButton(frame2); + // zoom_plus->setFocusPolicy(ClickFocus); + zoom_plus->setPixmap(QPixmap(zoom_plus_x)); + connect( zoom_plus, SIGNAL(clicked()), SLOT(zoom_plus()) ); + grid2->addWidget(zoom_plus,0,1,Qt::AlignRight); + + + view_draw = new QRadioButton("Draw",frame2); + // view_draw->setFocusPolicy(ClickFocus); + view_draw->setChecked(true); + drawing_mode=V_DRAW; + grid2->addMultiCellWidget(view_draw,1,1,0,1,Qt::AlignLeft); + + view_fill = new QRadioButton("Fill",frame2); + // view_fill->setFocusPolicy(ClickFocus); + grid2->addMultiCellWidget(view_fill,2,2,0,1,Qt::AlignLeft); + + + Q3ButtonGroup *bg = new Q3ButtonGroup(frame2); + bg->setExclusive(true); + bg->hide(); + bg->insert(view_draw); + bg->insert(view_fill,1); + connect( bg, SIGNAL(clicked(int)), SLOT(change_mode(int)) ); + + + Q3GridLayout *grid3 = new Q3GridLayout( h_frame2, 3, 3, 0); + + for(i=0;i<3;i++){ + grid3->setColStretch(i,1); + grid3->addColSpacing(i,0); + } + for(i=0;i<3;i++){ + grid3->setRowStretch(i,1); + grid3->addRowSpacing(i,0); + } + + + QPushButton *view_up = new QPushButton(frame2); + // view_up->setFocusPolicy(ClickFocus); + view_up->setPixmap(QPixmap(uparrow_x)); + connect( view_up, SIGNAL(clicked()), SLOT(shift_up()) ); + grid3->addWidget(view_up,0,1,Qt::AlignBottom|Qt::AlignHCenter); + + QPushButton *view_left = new QPushButton(frame2); + // view_left->setFocusPolicy(ClickFocus); + view_left->setPixmap(QPixmap(leftarrow_x)); + connect( view_left, SIGNAL(clicked()), SLOT(shift_left()) ); + grid3->addWidget(view_left,1,0,Qt::AlignRight|Qt::AlignVCenter); + + QPushButton *view_right = new QPushButton(frame2); + // view_right->setFocusPolicy(ClickFocus); + view_right->setPixmap(QPixmap(rightarrow_x)); + connect( view_right, SIGNAL(clicked()), SLOT(shift_right()) ); + grid3->addWidget(view_right,1,2,Qt::AlignLeft|Qt::AlignVCenter); + + QPushButton *view_down = new QPushButton(frame2); + // view_down->setFocusPolicy(ClickFocus); + view_down->setPixmap(QPixmap(downarrow_x)); + connect( view_down, SIGNAL(clicked()), SLOT(shift_down()) ); + grid3->addWidget(view_down,2,1,Qt::AlignTop|Qt::AlignHCenter); + + + + Q3Frame *frame3 = new Q3Frame(this); + frame3->setFrameStyle(Q3Frame::Box | Q3Frame::Sunken); + frame3->setLineWidth(1); + frame3->setMinimumSize(420,300); + frame3->setMargin(4); + all->addWidget(frame3,1); + + + Q3BoxLayout *right = new Q3VBoxLayout(frame3,10); + + // QScrollView *canvas = new QScrollView(frame3); + canvas = new Canvas(frame3,0,this); + canvas->setMinimumSize(400,200); + right->addWidget(canvas,1); + canvas->setFocusPolicy(Qt::ClickFocus); + setFocusProxy(canvas); + + Q3Frame *frame4 = new Q3Frame(frame3); + frame4->setFrameStyle(Q3Frame::Box | Q3Frame::Sunken); + frame4->setLineWidth(1); + frame4->setMinimumSize(400,80); + frame4->setMargin(10); + right->addWidget(frame4); + + + int maxcol2 = 6; + Q3GridLayout *grid4 = new Q3GridLayout( frame4, 2, maxcol2, 2); + + for(i=0;isetColStretch(i,1); + grid4->addColSpacing(i,4); + } + for(i=0;i<2;i++){ + grid4->setRowStretch(i,1); + grid4->addRowSpacing(i,2); + } + + + + QLabel *trans_color = new QLabel("Transparency colour:",frame4); + trans_color->setMaximumHeight(20); + grid4->addWidget(trans_color,0,0,Qt::AlignLeft); + + transcolor = new QWidget(frame4); + transcolor->setPalette( QPalette( egacolor[0] ) ); + transcolor->setMinimumSize(40,16); + transcolor->setMaximumSize(100,30); + grid4->addWidget(transcolor,0,1,Qt::AlignCenter); + + QPushButton *set_trans_color = new QPushButton(frame4); + // set_trans_color->setFocusPolicy(ClickFocus); + set_trans_color->setText("Set"); + set_trans_color->setMaximumHeight(20); + connect( set_trans_color, SIGNAL(clicked()), SLOT(set_transcolor()) ); + grid4->addWidget(set_trans_color,0,2,Qt::AlignRight); + + QWidget *dummy = new QWidget(frame4); + grid4->addMultiCellWidget(dummy,0,3,maxcol2-1,Qt::AlignCenter); + + palette = new Palette(frame4); + palette->setMinimumSize(250,40); + palette->setMaximumSize(350,80); + // palette->setPalette( QPalette( QColor(255, 255, 80) ) ); + grid4->addMultiCellWidget(palette,1,1,0,maxcol2-2,Qt::AlignLeft); + + description = NULL; + + changed=false; + undo=false; + undoCel=Cel(); + animate=NULL; + canvas->setFocus(); + + adjustSize(); + hide(); +} + +//********************************************* +void ViewEdit::save(char *filename) +{ + + view->save(filename); + changed = false; + +} + +//********************************************* +void ViewEdit::display() +{ + + showlooppar(); + showcelpar(); + + if(view->Description != ""){ + is_descriptor->setChecked(true); + edit_descriptor->setEnabled(true); + } + else{ + is_descriptor->setChecked(false); + edit_descriptor->setEnabled(false); + } + if(description)description->hide(); + DisplayView(); + show(); +} + +//********************************************* +void ViewEdit::open(int ResNum) +{ + + if(view->open(ResNum))return ; + ViewNum = ResNum; + sprintf(tmp,"View editor: view.%d",ViewNum); + setCaption(tmp); + changed=false; + display(); + +} + +//********************************************* +void ViewEdit::open(char *filename) +{ + + if(view->open(filename))return; + ViewNum = -1; + sprintf(tmp,"View editor"); + setCaption(tmp); + changed=false; + display(); +} +//********************************************* +void ViewEdit::DisplayView() +{ + int w,h; + w = canvas->x0+canvas->cur_w*canvas->pixsize*2+10; + h = canvas->y0+canvas->cur_h*canvas->pixsize+10; + + int i=view->loops[view->CurLoop].mirror; + if(i!=-1){ + canvas->DrawCel(view->loops[i].cels[view->CurCel].width,view->loops[i].cels[view->CurCel].height,view->loops[i].cels[view->CurCel].data,true); + } + else{ + canvas->DrawCel(view->loops[view->CurLoop].cels[view->CurCel].width,view->loops[view->CurLoop].cels[view->CurCel].height,view->loops[view->CurLoop].cels[view->CurCel].data,false); + } + if(view->loops[view->CurLoop].cels[view->CurCel].transcol != transcol){ + set_transcolor(view->loops[view->CurLoop].cels[view->CurCel].transcol); + } + +} + +//********************************************* +void ViewEdit::DisplayView(int pixsize) +{ + + int w,h; + w = canvas->x0+canvas->cur_w*pixsize*2+10; + h = canvas->y0+canvas->cur_h*pixsize+10; + + if(canvas->contentsWidth() < w || canvas->contentsHeight() < h){ + canvas->resizeContents(w,h); + } + + + int i=view->loops[view->CurLoop].mirror; + if(i!=-1){ + canvas->DrawCel(view->loops[i].cels[view->CurCel].width,view->loops[i].cels[view->CurCel].height,view->loops[i].cels[view->CurCel].data,true,pixsize); + } + else{ + canvas->DrawCel(view->loops[view->CurLoop].cels[view->CurCel].width,view->loops[view->CurLoop].cels[view->CurCel].height,view->loops[view->CurLoop].cels[view->CurCel].data,false,pixsize); + } + if(view->loops[view->CurLoop].cels[view->CurCel].transcol != transcol){ + set_transcolor(view->loops[view->CurLoop].cels[view->CurCel].transcol); + } + +} + +//********************************************* +void ViewEdit::showlooppar() +{ + + sprintf(tmp,"%d/%d",view->CurLoop,view->NumLoops-1); + loopnum->setText(tmp); + showmirror(); + +} + +//********************************************* +void ViewEdit::showmirror() +{ + + int m=view->loops[view->CurLoop].mirror; + int m1=view->loops[view->CurLoop].mirror1; + + mirror_loop->clear(); + mirror_loop->insertItem("no other loop"); + mirror_loop->setCurrentItem(0); + int item=1; + for(int i=0;iNumLoops;i++){ + if(i==view->CurLoop)continue; + if((view->loops[i].mirror==-1 && view->loops[i].mirror1==-1)||i==m||i==m1){ + + sprintf(tmp,"Loop %d",i); + mirror_loop->insertItem(tmp); + if(m==i) + mirror_loop->setCurrentItem(item); + else if(m==-1&&m1==i) + mirror_loop->setCurrentItem(item); + item++; + + } + } + +} + +//********************************************* +void ViewEdit::showcelpar() +{ + + sprintf(tmp,"%d/%d",view->CurCel,view->loops[view->CurLoop].NumCels-1); + celnum->setText(tmp); + sprintf(tmp,"%d",view->loops[view->CurLoop].cels[view->CurCel].width); + width->setText(tmp); + sprintf(tmp,"%d",view->loops[view->CurLoop].cels[view->CurCel].height); + height->setText(tmp); + + +} + +//********************************************* +void ViewEdit::deinit() +{ + if(description){ + description->close(true); + description=NULL; + } + if(animate)animate->closeall(); + delete view; + winlist[winnum].type=-1; + if(window_list && window_list->isVisible())window_list->draw(); +} + + +//********************************************* +void ViewEdit::hideEvent( QHideEvent * ) +{ + + if(description){ + description->close(true); + description=NULL; + } + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//********************************************* +void ViewEdit::showEvent( QShowEvent * ) +{ + + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//*********************************************** +void ViewEdit::closeEvent( QCloseEvent *e ) +{ + + if(changed){ + if(ViewNum != -1){ + sprintf(tmp,"Save changes to view.%d ?",ViewNum); + } + else{ + sprintf(tmp,"Save changes to view ?"); + } + strcat(tmp,"\n(view will be saved to game)"); + + switch ( QMessageBox::warning( this, "View editor", + tmp, + "Yes", + "No", + "Cancel", + 0, 2) ) { + case 0: // yes + save_to_game(); + deinit(); + e->accept(); + + // else + //e->ignore(); + break; + case 1: // no + deinit(); + e->accept(); + break; + default: // cancel + e->ignore(); + break; + } + + } + else{ + deinit(); + e->accept(); + } + + +} + +//********************************************* +void ViewEdit::open_file() +{ + + Q3FileDialog *f = new Q3FileDialog(0,"Open",true); + const char *filters[] = {"view*.*","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Open view"); + f->setMode(Q3FileDialog::ExistingFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ) + open((char *)f->selectedFile().latin1()); + } + +} + +//********************************************* +void ViewEdit::open() +{ + + setCaption("View editor"); + view->newView(); + ViewNum = -1; + showlooppar(); + showcelpar(); + DisplayView(); + changed=false; + show(); +} + +//********************************************* +void ViewEdit::save_file() +{ + + + Q3FileDialog *f = new Q3FileDialog(0,"Save",true); + const char *filters[] = {"view*.*","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Save view"); + f->setMode(Q3FileDialog::AnyFile); + f->setDir(game->srcdir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ) + save((char *)f->selectedFile().latin1()); + } + +} + +//********************************************* +void ViewEdit::save_to_game() +{ + if(ViewNum != -1){ + view->save(ViewNum); + if(resources_win){ + if(resources_win->preview==NULL)resources_win->preview=new Preview(); + resources_win->preview->open(ViewNum,VIEW); + } + changed=false; + } + else + save_to_game_as(); + +} + +//********************************************* +void ViewEdit::save_to_game_as() +{ + + AskNumber *view_number = new AskNumber(0,0,"View number","Enter view number: [0-255]"); + + if(!view_number->exec())return; + + QString str = view_number->num->text(); + int num = atoi((char *)str.latin1()); + + if(num<0||num>255){ + menu->errmes("View number must be between 0 and 255 !"); + return ; + } + if(game->ResourceInfo[VIEW][num].Exists){ + sprintf(tmp,"Resource view.%d already exists. Replace it ?",num); + + switch( QMessageBox::warning( this, "View", tmp, + "Replace", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + view->save(num); + changed=false; + ViewNum = num; + if(resources_win){ + if(resources_win->preview==NULL)resources_win->preview=new Preview(); + resources_win->preview->open(ViewNum,VIEW); + } + break; + case 1: + break; + } + } + else{ + view->save(num); + changed=false; + ViewNum = num; + if(resources_win){ + resources_win->select_resource_type(VIEW); + resources_win->set_current(num); + } + open(num); + } + +} + +//********************************************* +void ViewEdit::delete_view() +{ + int k; + + if(ViewNum==-1)return; + + sprintf(tmp,"Really delete view %d ?",ViewNum); + switch( QMessageBox::warning( this, "View", tmp, + "Delete", "Cancel", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: + game->DeleteResource(VIEW,ViewNum); + if(resources_win){ + k = resources_win->list->currentItem(); + resources_win->select_resource_type(VIEW); + resources_win->list->setCurrentItem(k); + } + break; + case 1: + break; + } + +} + +//********************************************* +void ViewEdit::flipv_cel() +{ + + view->loops[curIndex()].cels[view->CurCel].mirrorv(); + DisplayView(); + changed=true; +} + +//********************************************* +void ViewEdit::fliph_cel() +{ + + view->loops[curIndex()].cels[view->CurCel].mirrorh(); + DisplayView(); + changed=true; +} + +//********************************************* +void ViewEdit::copy_cel() +{ + saveCel.deinit(); + saveCel.copy(view->loops[curIndex()].cels[view->CurCel]); + cel_copied=true; +} + +//********************************************* +void ViewEdit::paste_cel() +{ + if(!cel_copied)return; + saveundo(); + view->loops[curIndex()].cels[view->CurCel].copy(saveCel); + showcelpar(); + DisplayView(); + changed=true; +} + +//********************************************* +void ViewEdit::next_loop() +{ + + if(view->CurLoopNumLoops-1){ + view->CurLoop++; + view->CurCel=0; + showlooppar(); + showcelpar(); + DisplayView(); + } + + +} + +//********************************************* +void ViewEdit::previous_loop() +{ + + if(view->CurLoop>0){ + view->CurLoop--; + view->CurCel=0; + showlooppar(); + showcelpar(); + DisplayView(); + } + + +} + +//********************************************* +void ViewEdit::first_loop() +{ + + view->CurLoop=0; + showlooppar(); + showcelpar(); + DisplayView(); + +} + +//********************************************* +void ViewEdit::last_loop() +{ + + view->CurLoop=view->NumLoops-1; + showlooppar(); + showcelpar(); + DisplayView(); + + +} + +//********************************************* +void ViewEdit::insert_loop_before() +{ + + if(view->NumLoopsinsertLoop_before(); + showlooppar(); + showcelpar(); + DisplayView(); + changed=true; + } + else{ + menu->errmes("Max of 16 loops already reached."); + } + +} + +//********************************************* +void ViewEdit::insert_loop_after() +{ + + if(view->NumLoopsinsertLoop_after(); + showlooppar(); + showcelpar(); + DisplayView(); + changed=true; + } + else{ + menu->errmes("Max of 16 loops already reached."); + } + +} + +//********************************************* +void ViewEdit::append_loop() +{ + if(view->NumLoopsappendLoop(); + showlooppar(); + showcelpar(); + DisplayView(); + changed=true; + } + else{ + menu->errmes("Max of 16 loops already reached."); + } + +} + +//********************************************* + +void ViewEdit::delete_loop() +{ + if(view->NumLoops>1){ + view->deleteLoop(); + if(view->CurLoop>view->NumLoops-1){ + view->CurLoop--; + } + showlooppar(); + showcelpar(); + DisplayView(); + changed=true; + } +} + +//********************************************* +void ViewEdit::clear_loop() +{ + + view->loops[view->CurLoop].clear(); + if(view->loops[view->CurLoop].mirror != -1){ + view->loops[view->loops[view->CurLoop].mirror].clear(); + } + showlooppar(); + showcelpar(); + DisplayView(); + changed=true; + +} + +//********************************************* +void ViewEdit::change_mirror(int i) +{ + + if(i==0){ + + printf("unset mirror %d\n",view->CurLoop); + + if (view->loops[view->CurLoop].mirror !=-1) + view->unsetMirror(view->CurLoop); + else if (view->loops[view->CurLoop].mirror1 !=-1) + view->unsetMirror(view->loops[view->CurLoop].mirror1); + } + else{ + QString str = mirror_loop->currentText(); + int k = atoi((char *)str.latin1()+5); + printf("set %d to mirror %d\n",view->CurLoop,k); + if(view->loops[view->CurLoop].mirror != k){ + + + for(int j=0;jNumLoops;j++){ + if(view->loops[j].mirror == view->CurLoop){ + view->unsetMirror(j); + } + if(view->loops[j].mirror1 == view->CurLoop){ + view->loops[j].mirror1 = -1; + } + } + + + if(view->loops[k].mirror != -1) + view->unsetMirror(k); + view->setMirror(view->CurLoop,k); + + } + } + + showlooppar(); + DisplayView(); + changed=true; +} + + +//********************************************************** +void ViewEdit::next_cel() +{ + + if(view->CurCelloops[view->CurLoop].NumCels-1){ + view->CurCel++; + showcelpar(); + DisplayView(); + } + +} + +//********************************************* +void ViewEdit::next_cel_cycle() +{ + + if(view->loops[view->CurLoop].NumCels<=1)return; + if(view->CurCelloops[view->CurLoop].NumCels-1){ + view->CurCel++; + } + else{ + view->CurCel=0; + } + showcelpar(); + DisplayView(); + +} + +//********************************************* +void ViewEdit::previous_cel() +{ + if(view->CurCel>0){ + view->CurCel--; + showcelpar(); + DisplayView(); + } + +} + +//********************************************* +void ViewEdit::prev_cel_cycle() +{ + if(view->loops[view->CurLoop].NumCels<=1)return; + if(view->CurCel>0){ + view->CurCel--; + } + else{ + view->CurCel=view->loops[view->CurLoop].NumCels-1; + } + showcelpar(); + DisplayView(); + +} + +//********************************************* +void ViewEdit::first_cel() +{ + + view->CurCel=0; + showcelpar(); + DisplayView(); + + +} + +//********************************************* +void ViewEdit::last_cel() +{ + + view->CurCel=view->loops[view->CurLoop].NumCels-1; + showcelpar(); + DisplayView(); + +} + +//********************************************* +void ViewEdit::insert_cel_before() +{ + + if(view->loops[view->CurLoop].NumCels < MaxCels-1){ + view->loops[view->CurLoop].insertCel_before(view->CurCel); + if(view->loops[view->CurLoop].mirror != -1){ + view->loops[view->loops[view->CurLoop].mirror].insertCel_before(view->CurCel); + } + showcelpar(); + DisplayView(); + changed=true; + } + else{ + menu->errmes("Max of 32 cels already reached in this loop."); + } +} + +//********************************************* +void ViewEdit::insert_cel_after() +{ + + if(view->loops[view->CurLoop].NumCels < MaxCels-1){ + view->loops[view->CurLoop].insertCel_after(view->CurCel); + if(view->loops[view->CurLoop].mirror != -1){ + view->loops[view->loops[view->CurLoop].mirror].insertCel_after(view->CurCel); + } + showcelpar(); + DisplayView(); + changed=true; + } + else{ + menu->errmes("Max of 32 cels already reached in this loop."); + } +} + +//********************************************* +void ViewEdit::append_cel() +{ + + if(view->loops[view->CurLoop].NumCels < MaxCels-1){ + view->loops[view->CurLoop].appendCel(); + if(view->loops[view->CurLoop].mirror != -1){ + view->loops[view->loops[view->CurLoop].mirror].appendCel(); + } + showcelpar(); + DisplayView(); + changed=true; + } + else{ + menu->errmes("Max of 32 cels already reached in this loop."); + } + +} + +//********************************************* +void ViewEdit::delete_cel() +{ + + if(view->loops[view->CurLoop].NumCels > 1){ + view->loops[view->CurLoop].deleteCel(view->CurCel); + if(view->loops[view->CurLoop].mirror != -1){ + view->loops[view->loops[view->CurLoop].mirror].deleteCel(view->CurCel); + } + if(view->CurCel>=view->loops[view->CurLoop].NumCels) + view->CurCel--; + showcelpar(); + DisplayView(); + changed=true; + } +} + +//********************************************* +void ViewEdit::dec_width() +{ + int w; + + if((w=view->loops[view->CurLoop].cels[view->CurCel].width)>1){ + w--; + view->loops[view->CurLoop].cels[view->CurCel].setW(w); + sprintf(tmp,"%d",w); + width->setText(tmp); + DisplayView(); + changed=true; + } +} + +//********************************************* +void ViewEdit::inc_width() +{ + + int w=view->loops[view->CurLoop].cels[view->CurCel].width+1; + if(w<160){ + view->loops[view->CurLoop].cels[view->CurCel].setW(w); + sprintf(tmp,"%d",w); + width->setText(tmp); + DisplayView(); + changed=true; + } + else{ + menu->errmes("Maximum width is 160."); + } +} + +//********************************************* +void ViewEdit::dec_height() +{ + + int h; + if((h=view->loops[view->CurLoop].cels[view->CurCel].height)>1){ + h--; + view->loops[view->CurLoop].cels[view->CurCel].setH(h); + sprintf(tmp,"%d",h); + height->setText(tmp); + DisplayView(); + changed=true; + } +} + +//********************************************* +void ViewEdit::inc_height() +{ + + int h=view->loops[view->CurLoop].cels[view->CurCel].height+1; + + if(h<168){ + view->loops[view->CurLoop].cels[view->CurCel].setH(h); + sprintf(tmp,"%d",h); + height->setText(tmp); + DisplayView(); + changed=true; + } + else{ + menu->errmes("Maximum height is 168."); + } +} + +//********************************************* +void ViewEdit::change_width_height() +{ + + QString str = width->text(); + int w = atoi((char *)str.latin1()); + view->loops[view->CurLoop].cels[view->CurCel].setW(w); + + str = height->text(); + int h = atoi((char *)str.latin1()); + view->loops[view->CurLoop].cels[view->CurCel].setH(h); + + DisplayView(); + changed=true; + width->clearFocus(); + height->clearFocus(); + setFocus(); +} + + +//********************************************* +void ViewEdit::shift_right() +{ + + if(view->loops[view->CurLoop].mirror==-1){ + view->loops[view->CurLoop].cels[view->CurCel].right(); + } + else{ + view->loops[curIndex()].cels[view->CurCel].left(); + } + DisplayView(); + changed=true; +} + +//********************************************* +void ViewEdit::shift_left(){ + + if(view->loops[view->CurLoop].mirror==-1){ + view->loops[view->CurLoop].cels[view->CurCel].left(); + } + else{ + view->loops[curIndex()].cels[view->CurCel].right(); + } + DisplayView(); + changed=true; +} + +//********************************************* +void ViewEdit::shift_up() +{ + view->loops[curIndex()].cels[view->CurCel].up(); + DisplayView(); + changed=true; +} + +//********************************************* +void ViewEdit::shift_down() +{ + view->loops[curIndex()].cels[view->CurCel].down(); + DisplayView(); + changed=true; +} + +//********************************************* +void ViewEdit::fillCel(int x,int y,byte color) +{ + + saveundo(); + view->loops[curIndex()].cels[view->CurCel].fill(x,y,color); + DisplayView(); + changed=true; +} + +//********************************************* +void ViewEdit::clear_cel() +{ + saveundo(); + view->loops[curIndex()].cels[view->CurCel].clear(); + DisplayView(); + changed=true; +} + +//********************************************* +void ViewEdit::saveundo() +{ + undoCel.deinit(); + undoCel.copy(view->loops[curIndex()].cels[view->CurCel]); + undo=true; + +} + +//********************************************* +void ViewEdit::undo_cel() +{ + if(undo){ + view->loops[curIndex()].cels[view->CurCel].copy(undoCel); + undo=false; + } + DisplayView(); +} + +/*************************************************/ +int ViewEdit::curIndex() +{ + int i=view->loops[view->CurLoop].mirror; + if(i==-1)return view->CurLoop; + else return i; +} + +/*************************************************/ +void ViewEdit::show_description() +{ + if(!description)description = new Description(0,0,this); + description->set(); + description->show(); +} + +/*******************************************************/ +void ViewEdit::change_mode(int m) +{ + + drawing_mode=m; + + +} +/*******************************************************/ +void ViewEdit::change_mode1(int m) +{ + + drawing_mode=m; + if(m==V_DRAW) + view_draw->setChecked(true); + else + view_fill->setChecked(true); + +} +/*******************************************************/ +void ViewEdit::is_descriptor_cb() +{ + + if(is_descriptor->isChecked()){ + edit_descriptor->setEnabled(true); + } + else{ + edit_descriptor->setEnabled(false); + } + +} +/*******************************************************/ +void ViewEdit::set_transcolor() +{ + + transcolor->setPalette( QPalette( egacolor[palette->left] ) ); + transcol=palette->left; + view->loops[view->CurLoop].cels[view->CurCel].transcol = transcol; +} + +/*******************************************************/ +void ViewEdit::set_transcolor(int col) +{ + + transcolor->setPalette( QPalette( egacolor[col] ) ); + transcol=col; + view->loops[view->CurLoop].cels[view->CurCel].transcol = transcol; +} + +/*******************************************************/ +void ViewEdit::zoom_minus() + //zoom_out +{ + + if(canvas->pixsize>1){ + DisplayView(canvas->pixsize-1); + } + +} +/*******************************************************/ +void ViewEdit::zoom_plus() + //zoom_in +{ + + if(canvas->pixsize<10){ + DisplayView(canvas->pixsize+1); + } + +} + +/*******************************************************/ +bool ViewEdit::focusNextPrevChild ( bool ) +{ + + if(width->hasFocus()){ + height->setFocus(); + } + else if(height->hasFocus()){ + width->setFocus(); + } + else{ + canvas->setFocus(); + } + return true; + +} +/*******************************************************/ +void ViewEdit::animate_cb() +{ + + if(animate==NULL)animate=new Animate(0,0,0,this); + animate->show(); + +} +/*******************************************************/ +Animate::Animate( QWidget *parent, const char *name, Preview *p, ViewEdit *v) + : QWidget( parent, name ) +{ + + viewedit = v; + preview = p; + setCaption("Animate"); + Q3BoxLayout *b = new Q3VBoxLayout(this,10); + + Q3HBoxLayout *b1 = new Q3HBoxLayout(b,4); + QLabel *l = new QLabel("Delay (ms)",this); + b1->addWidget(l); + delay = new QLineEdit(this); + delay->setText("200"); + delay->setMaximumWidth(100); + b1->addWidget(delay); + + Q3ButtonGroup *fb = new Q3ButtonGroup(2,Qt::Horizontal,"",this); + fb->setExclusive(true); + forward = new QRadioButton("Forward",fb); + forward->setChecked(true); + backward = new QRadioButton("Backward",fb); + connect(fb,SIGNAL(clicked(int)),SLOT(fb_cb())); + b->addWidget(fb); + + Q3HBoxLayout *b2 = new Q3HBoxLayout(b,4); + button = new QPushButton(this); + button->setText("Start"); + b2->addWidget(button); + connect(button,SIGNAL(clicked()),SLOT(start_stop())); + QPushButton *close = new QPushButton(this); + close->setText("Close"); + b2->addWidget(close); + connect(close,SIGNAL(clicked()),SLOT(hide())); + + timer = new QTimer(this); + connect(timer,SIGNAL(timeout()), SLOT(next_cel()) ); + +} + +/*******************************************************/ +void Animate::start_stop() +{ + + if(timer->isActive()){ + timer->stop(); + button->setText("Start"); + } + else{ + QString str = delay->text(); + num = atoi((char *)str.latin1()); + button->setText("Stop"); + fwd = forward->isChecked(); + timer->start(num); + } + +} +/*******************************************************/ +void Animate::fb_cb() +{ + + fwd = forward->isChecked(); + +} +/*******************************************************/ +void Animate::next_cel() +{ + + if(viewedit){ + if(fwd)viewedit->next_cel_cycle(); + else viewedit->prev_cel_cycle(); + } + else{ + if(fwd)preview->next_cel_cycle(); + else preview->prev_cel_cycle(); + } +} +/*******************************************************/ +void Animate::closeall() +{ + + if(timer->isActive())timer->stop(); + close(true); +} + +/*******************************************************/ +Description::Description( QWidget *parent, const char *name , ViewEdit *v) + : QWidget( parent, name ,Qt::WDestructiveClose) +{ + + setCaption("View description"); + viewedit = v; + + Q3BoxLayout *d1 = new Q3VBoxLayout(this,10); + d1->addSpacing(10); + + smallview = new ViewIcon(this,0,viewedit); + smallview->setMinimumSize(64,64); + + d1->addWidget(smallview,0,Qt::AlignCenter); + + desc = new Q3MultiLineEdit(this); + desc->setMinimumSize(300,100); + d1->addWidget(desc,1); + + Q3BoxLayout *d2 = new Q3HBoxLayout(d1,10); + d2->addSpacing(10); + + QPushButton *ok = new QPushButton(this); + ok->setText("OK"); + ok->setMaximumWidth(80); + connect( ok, SIGNAL(clicked()), SLOT(ok_cb()) ); + d2->addWidget(ok); + + QPushButton *cancel = new QPushButton(this); + cancel->setText("Cancel"); + cancel->setMaximumWidth(80); + connect( cancel, SIGNAL(clicked()), SLOT(cancel_cb()) ); + d2->addWidget(cancel); + + adjustSize(); + hide(); + getmaxcol(); + +} + +//********************************************* +void Description::getmaxcol() + //get maximum number of columns on screen (approx.) + //to wrap the long lines +{ + + QFontMetrics f = fontMetrics(); + maxcol = desc->width()/f.width('a'); + +} + +//********************************************* +void Description::resizeEvent( QResizeEvent * ) +{ + getmaxcol(); + set(); +} + +//********************************************* +void Description::set() +{ + int n; + + desc->clear(); + + if(viewedit->view->Description == ""){ + return; + } + + string ThisLine = ""; + string ThisMessage = viewedit->view->Description; + + do{ + if(ThisMessage.length() + ThisLine.length() > maxcol){ + n = maxcol - ThisLine.length(); + do{ n--; }while(!(n == 0 || ThisMessage[n]==' ')); + if (n <= 0)n = maxcol-ThisLine.length(); + ThisLine += ThisMessage.substr(0,n); + ThisMessage = (n < (int)ThisMessage.length())?ThisMessage.substr(n+1):""; + desc->insertLine(ThisLine.c_str(),-1); + ThisLine = ""; + } + else{ + ThisLine += ThisMessage; + ThisMessage = ""; + } + }while(ThisMessage != ""); + + if(ThisLine != ""){ + desc->insertLine(ThisLine.c_str(),-1); + } + +} + +//********************************************* +void Description::ok_cb() +{ + int i; + + QString str = desc->text(); + char *s = (char *)str.latin1(); + tmp[0]=0; + for(i=0;*s;s++){ + if(*s!='\n') + tmp[i++]=*s; + else if(i>1 && tmp[i-1]!=' '){ + tmp[i++]=' '; + } + } + tmp[i]=0; + + if(strcmp(viewedit->view->Description.c_str(),tmp)){ + viewedit->view->Description = string(tmp); + viewedit->changed=true; + } + hide(); + +} +//********************************************* + +void Description::cancel_cb() +{ + hide(); +} +//********************************************** +Canvas::Canvas ( QWidget *parent, const char *name, ViewEdit *v) + : Q3ScrollView( parent, name ) +{ + + viewedit = v; + x0=10;y0=10; + pixsize=2; + cur_mirror = false; + pixmap = QPixmap(); + cur_w=cur_h=0; + +} + +//********************************************* +void Canvas::setSize(int w,int h) +{ + if(cur_w != w || cur_h != h){ + pixmap.resize(w*pixsize*2,h*pixsize); + cur_w=w; + cur_h=h; + } +} + +//********************************************* +void Canvas::viewportMousePressEvent(QMouseEvent* event) +{ + int x, y; + viewportToContents( event->x(), event->y(), x, y ); + + if (event->button() & Qt::LeftButton){ + CurColor = viewedit->palette->left; + } + else if (event->button() & Qt::RightButton){ + CurColor = viewedit->palette->right; + } + UpdateCel(x-x0,y-y0); + viewedit->changed=true; +} + +//********************************************* +void Canvas::viewportMouseMoveEvent(QMouseEvent* event) +{ + int x, y; + + viewportToContents( event->x(), event->y(), x, y ); + UpdateCel(x-x0,y-y0); +} + +//********************************************* +void Canvas::drawContents(QPainter* p, int , int , int, int ) +{ + + if(cur_w==0 ||cur_h==0)return; + p->drawPixmap( x0, y0, pixmap ); + +} + +//********************************************* +void Canvas::DrawCel(int w,int h,byte *celdata,bool mirror, int size) +{ + int x,y,ww,hh,w0,h0,ww0,hh0; + + w0=cur_w; + h0=cur_h; + ww0=(x0+w0)*2*pixsize; + hh0=(y0+h0)*pixsize; + pixsize=size; + pixmap.resize(cur_w*pixsize*2,cur_h*pixsize); + ww=(x0+w)*2*pixsize; + hh=(y0+h)*pixsize; + + QPainter p(&pixmap); + + data=celdata; + + if(mirror){ + for(y=0;y=0&&xn=0&&yndrawing_mode == V_DRAW){ + + x=xn*2*pixsize; + y=yn*pixsize; + + p.fillRect(x,y,pixsize*2,pixsize,egacolor[CurColor]); + repaintContents(x0+x,y0+y,pixsize*2,pixsize,false); + if(cur_mirror){ + data[yn*cur_w*2+cur_w*2-2-xn*2]=CurColor; + data[yn*cur_w*2+cur_w*2-2-xn*2+1]=CurColor; + } + else{ + data[yn*cur_w*2+xn*2]=CurColor; + data[yn*cur_w*2+xn*2+1]=CurColor; + } + } + else{ //FILL + if(cur_mirror) + viewedit->fillCel(cur_w-1-xn,yn,CurColor); + else + viewedit->fillCel(xn,yn,CurColor); + } + + } + +} + +//********************************************* +void Canvas::keyPressEvent( QKeyEvent *k ) +{ + + // printf("key ! %d\n",k->key()); + switch(k->key()){ + case Qt::Key_Q: + viewedit->previous_loop(); + break; + case Qt::Key_W: + viewedit->next_loop(); + break; + case Qt::Key_A: + viewedit->previous_cel(); + break; + case Qt::Key_S: + viewedit->next_cel(); + break; + case Qt::Key_Z: + viewedit->zoom_minus(); + break; + case Qt::Key_X: + viewedit->zoom_plus(); + break; + case Qt::Key_T: + viewedit->set_transcolor(); + break; + case Qt::Key_D: + viewedit->change_mode1(V_DRAW); + break; + case Qt::Key_F: + viewedit->change_mode1(V_FILL); + break; + case Qt::Key_I: + viewedit->shift_up(); + break; + case Qt::Key_K: + viewedit->shift_down(); + break; + case Qt::Key_J: + viewedit->shift_left(); + break; + case Qt::Key_L: + viewedit->shift_right(); + break; + default: + k->ignore(); + break; + } + +} + +//********************************************* +bool Canvas::focusNextPrevChild ( bool ) +{ + + setFocus(); + return true; + +} +//******************************************** +ViewIcon::ViewIcon ( QWidget *parent, const char *name , ViewEdit *v) + : QWidget( parent, name ) +{ + + viewedit=v; + +} + +//********************************************* +void ViewIcon::paintEvent(QPaintEvent *) +{ + + int x,y; + + QPainter p(this); + + int w = viewedit->view->loops[viewedit->view->CurLoop].cels[viewedit->view->CurCel].width; + int h = viewedit->view->loops[viewedit->view->CurLoop].cels[viewedit->view->CurCel].height; + bool mirror = viewedit->view->loops[viewedit->view->CurLoop].cels[viewedit->view->CurCel].mirror; + byte *data = viewedit->view->loops[viewedit->view->CurLoop].cels[viewedit->view->CurCel].data; + + int pixsize=2; + + int W = viewedit->description->width(); + setGeometry((W-pixsize*w*2)/2,10,pixsize*w*2,pixsize*h); + + // if(pixsize*w*2>width() || pixsize*h>height()){ + // resize(pixsize*w*2,pixsize*h); + + + if(mirror){ + for(y=0;y +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" +#include "wutil.h" +#include "view.h" +#include "preview.h" +#include "resources.h" + +#define V_DRAW 0 +#define V_FILL 1 + +class ViewEdit; +//******************************************************** +class ViewIcon : public QWidget +//small non-editable picture in the description window +{ + Q_OBJECT +public: + ViewIcon( QWidget *parent=0, const char *name=0,ViewEdit *v=0); + protected: + ViewEdit *viewedit; + void paintEvent(QPaintEvent *); + +}; +//******************************************************** +class Canvas : public Q3ScrollView +//view drawing area +{ + Q_OBJECT +public: + Canvas( QWidget *parent=0, const char *name=0, ViewEdit *v=0); + int x0,y0; + int pixsize; + int cur_w,cur_h; + void DrawCel(int w,int h,byte *data,bool mirror); + void DrawCel(int w,int h,byte *data,bool mirror,int pixsize); + void setSize(int w,int h); + void UpdateCel(int x,int y); + protected: + int CurColor; + QPixmap pixmap; + bool cur_mirror; + byte *data; + ViewEdit *viewedit; + void keyPressEvent( QKeyEvent * ); + void viewportMousePressEvent(QMouseEvent* e); + void viewportMouseMoveEvent(QMouseEvent* e); + void drawContents ( QPainter * p,int,int,int,int); + bool focusNextPrevChild ( bool next ) ; +}; + +//******************************************************** +class Description: public QWidget +{ + + Q_OBJECT +public: + Description( QWidget *parent=0, const char *name=0, ViewEdit *v=0); +public slots: + void set(); + void ok_cb(); + void cancel_cb(); + void getmaxcol(); +protected: + ViewIcon *smallview; + ViewEdit *viewedit; + Q3MultiLineEdit *desc; + unsigned int maxcol; + void resizeEvent( QResizeEvent * ); +}; + +//******************************************************** +class Animate: public QWidget +{ + + Q_OBJECT +public: + Animate( QWidget *parent=0, const char *name=0, Preview *p=0, ViewEdit *v=0); + QTimer *timer; +public slots: + void start_stop(); + void next_cel(); + void closeall(); + void fb_cb(); + protected: + QLineEdit *delay; + QPushButton *button; + QRadioButton *forward,*backward; + int num; + ViewEdit *viewedit; + Preview *preview; + bool fwd; +}; + +//******************************************************** +class ViewEdit : public QWidget +{ + Q_OBJECT +public: + ViewEdit( QWidget *parent=0, const char *name=0,int winnum=0, ResourcesWin *res=0); + Description *description; + Palette *palette; + View *view; + ResourcesWin *resources_win; + int drawing_mode; + bool changed; + void open(int ResNum); + void fillCel(int x,int y,byte color); + void change_mode1(int); +public slots: + void open(); + void open_file(); + void save_file(); + void save_to_game(); + void save_to_game_as(); + void delete_view(); + + void undo_cel(); + void copy_cel(); + void paste_cel(); + + void next_loop(); + void previous_loop(); + void first_loop(); + void last_loop(); + void insert_loop_before(); + void insert_loop_after(); + void append_loop(); + void delete_loop(); + void clear_loop(); + + void change_mirror(int i); + + void next_cel(); + void previous_cel(); + void first_cel(); + void last_cel(); + void insert_cel_before(); + void insert_cel_after(); + void append_cel(); + void delete_cel(); + void clear_cel(); + void flipv_cel(); + void fliph_cel(); + + void set_transcolor(); + void change_mode(int); + void is_descriptor_cb(); + void show_description(); + + void shift_right(); + void shift_left(); + void shift_up(); + void shift_down(); + + void zoom_minus(); + void zoom_plus(); + + void change_width_height(); + void inc_width(); + void dec_width(); + void inc_height(); + void dec_height(); + + void animate_cb(); + void next_cel_cycle(); + void prev_cel_cycle(); + protected: + + QWidget *transcolor; + QPushButton *edit_descriptor; + QCheckBox *is_descriptor; + Canvas *canvas; + QLabel *loopnum,*celnum; + QLineEdit *width,*height; + QComboBox *mirror_loop; + QRadioButton *view_draw,*view_fill; + Animate *animate; + int ViewNum; + int transcol; + Cel undoCel; + bool undo; + int winnum; + void closeEvent( QCloseEvent *e ); + void showEvent( QShowEvent * ); + void hideEvent( QHideEvent * ); + void open(char *filename); + void save(char *filename); + void do_open(); + void deinit(); + void display(); + void DisplayView(); + void DisplayView(int pixsize); + void set_transcolor(int col); + void showmirror(); + void showlooppar(); + void showcelpar(); + int curIndex(); + void saveundo(); + bool focusNextPrevChild ( bool next ) ; + +}; + +#endif diff --git a/src/words.cpp b/src/words.cpp new file mode 100644 index 0000000..805f3ee --- /dev/null +++ b/src/words.cpp @@ -0,0 +1,527 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * Almost all of this code was adapted from the Windows AGI Studio + * developed by Peter Kelly. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "game.h" +#include "words.h" +#include "menu.h" +#include "wordsedit.h" + +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include + + +static TWordGroup NewWordGroup[MaxWordGroups]; +static int ResPos; +static bool EndOfFileReached; + +//*************************************************** +WordList::WordList() +{ + + +} +//*************************************************** +static byte ReadByte(void) +{ + byte ret; + if(ResPos < ResourceData.Size){ + ret = ResourceData.Data[ResPos]; + ResPos++; + } + else{ + ret = 0; + EndOfFileReached = true; + } + return ret; +} +//*************************************************** +static int ReadMSLSWord(void) +{ + byte MSbyte,LSbyte; + + MSbyte = ReadByte(); + LSbyte = ReadByte(); + return (MSbyte*256 + LSbyte); + +} +//*************************************************** +int WordList::GetNew_GroupIndex(int GroupNum) +{ + int CurIndex; + + if (NumGroups > 0){ + for(CurIndex = 0; CurIndex < NumGroups; CurIndex++){ + if (NewWordGroup[CurIndex].GroupNum == GroupNum){ + return CurIndex; + } + } + } + return -1; + +} +//************************************************ +int WordList::GetWordGroupIndex(int GroupNum) +{ + int CurIndex; + + if (NumGroups > 0){ + for (CurIndex = 0;CurIndexerrmes("Error opening file %s",filename); + return 1; + } + + struct stat buf; + fstat(fileno(fptr),&buf); + int size=buf.st_size; + if(size > MaxResourceSize){ + menu->errmes("Error: File %s is too big (>%d bytes)",filename,MaxResourceSize); + return 1; + } + + EndOfFileReached = false; + ResourceData.Size=size; + fread(ResourceData.Data,size,1,fptr); + fclose(fptr); + NumGroups = 0; + ResPos = 0; + ResPos = ReadMSLSWord(); //start of words section + PrevWord = ""; + do{ + CurWord = ""; + CharsFromPrevWord = ReadByte(); + if (CharsFromPrevWord > PrevWord.length()){ + CharsFromPrevWord = PrevWord.length(); + } + if (CharsFromPrevWord > 0){ + CurWord = PrevWord.substr(0,CharsFromPrevWord); + } + do{ + CurByte = ReadByte(); + if (CurByte < 0x80)CurWord += (CurByte ^ 0x7f); + }while(CurByte < 0x80 && !EndOfFileReached); + //we must check for end of file, otherwise if the file is invalid, the + //program may read indefinitely. + if(EndOfFileReached){ + menu->errmes("Error! Invalid WORDS.TOK file."); + return 1; + } + CurWord += (0x7F ^ (CurByte-0x80)); + GroupNum = ReadMSLSWord(); + if (CurWord != PrevWord){ //this word different to previous, so add it + //in this way, no duplicates are added + GroupIndex = GetNew_GroupIndex(GroupNum); + if (GroupIndex >= 0){ //group exists + NewWordGroup[GroupIndex].Words.add(CurWord); + } + else{ + if (NumGroups >= MaxWordGroups){ + menu->errmes("Error ! Too many groups !"); + return 1; + } + NumGroups++; + NewWordGroup[NumGroups-1].GroupNum = GroupNum; + NewWordGroup[NumGroups-1].Words = TStringList(); + NewWordGroup[NumGroups-1].Words.add(CurWord); + }//group doesn't exist - create new one + PrevWord = CurWord; + } + CurByte = ReadByte(); + if (CurByte == 0 && ResPos >= ResourceData.Size-1) EndOfFileReached = true; + else ResPos--; + }while(!EndOfFileReached); + + LowestRemainingGroup = -1; + for (CurAddGroup = 0; CurAddGroup < NumGroups; CurAddGroup++){ + SecondLowestRemainingGroup = 65536; + for (CurIndex = 0; CurIndex < NumGroups; CurIndex++){ + if (NewWordGroup[CurIndex].GroupNum < SecondLowestRemainingGroup && + NewWordGroup[CurIndex].GroupNum > LowestRemainingGroup){ + SecondLowestRemainingGroup = NewWordGroup[CurIndex].GroupNum; + SecondLowestRemainingGroupIndex = CurIndex; + } + } + GroupAddOrder[CurAddGroup] = SecondLowestRemainingGroupIndex; + LowestRemainingGroup = SecondLowestRemainingGroup; + } + for (CurIndex = 0; CurIndex < NumGroups; CurIndex++){ + WordGroup[CurIndex].GroupNum = NewWordGroup[GroupAddOrder[CurIndex]].GroupNum; + WordGroup[CurIndex].Words.lfree(); + WordGroup[CurIndex].Words.copy(NewWordGroup[GroupAddOrder[CurIndex]].Words); + NewWordGroup[GroupAddOrder[CurIndex]].Words.lfree(); + } + return 0; +} +//************************************************** +void WordList::clear() +{ + for (int i = 0;i< NumGroups;i++){ + WordGroup[i].Words.lfree(); + } + NumGroups = 3; + + WordGroup[0].GroupNum = 0; + WordGroup[0].Words = TStringList(); + WordGroup[0].Words.add("a"); + WordGroup[1].GroupNum = 1; + WordGroup[1].Words = TStringList(); + WordGroup[1].Words.add("anyword"); + WordGroup[2].GroupNum = 9999; + WordGroup[2].Words = TStringList(); + WordGroup[2].Words.add("rol"); + +} +//************************************************** +int WordList::save(char *filename) +{ + + FILE *fptr; + int CurGroupIndex,NumEmptyWordGroups; + int CurWord,CurChar; + byte CurByte; + int LetterLoc[28]; + string ThisWord,PrevWord; + int CurFirstLetter; + char FirstLetter; + int ThisGroupNum; + byte CharsFromPrevWord; + string s; + + for(CurGroupIndex=0,NumEmptyWordGroups=0;CurGroupIndex 0){ + sprintf(tmp,"Warning: There are %d empty word groups.\nThese will not be saved.",NumEmptyWordGroups); + menu->warnmes(tmp); + } + + if((fptr=fopen(filename,"wb"))==NULL){ + menu->errmes("Error opening file %s",filename); + return 1; + } + + TStringList AllWords = TStringList(); + for(CurGroupIndex = 0; CurGroupIndex 0){ + for(CurWord =0;CurWord=97 && ThisWord[0]<=122){ + FirstLetter = ThisWord[0]; + LetterLoc[FirstLetter-96] = ftell(fptr); + } + ThisGroupNum = GetGroupNum(AllWords.at(CurWord)); + //work out # chars from prev word + CharsFromPrevWord = 0; + CurChar = 0; + bool FinishedComparison = false; + do{ + if(CurChar < (int)ThisWord.length() && (int)PrevWord.length() > CurChar && PrevWord[CurChar] == ThisWord[CurChar]) + CharsFromPrevWord++; + else FinishedComparison=true; + CurChar++; + }while(! FinishedComparison); + if (CharsFromPrevWord >= ThisWord.length()){ + CharsFromPrevWord = ThisWord.length()-1; + } + //write # chars from prev word + fwrite(&CharsFromPrevWord,1,1,fptr); + PrevWord = ThisWord; + ThisWord = ThisWord.substr( CharsFromPrevWord,ThisWord.length()-CharsFromPrevWord); + if (ThisWord.length() > 1){ + for(CurChar =0;CurChar <(int)ThisWord.length()-1;CurChar++){ + CurByte = 0x7f ^ ThisWord[CurChar]; + fwrite(&CurByte,1,1,fptr); + } + } + CurByte = 0x80 + (0x7f ^ ThisWord[ThisWord.length()-1]); + fwrite(&CurByte,1,1,fptr); + //write group number + CurByte = ThisGroupNum / 256; + fwrite(&CurByte,1,1,fptr); + CurByte = ThisGroupNum % 256; + fwrite(&CurByte,1,1,fptr); + } + CurByte = 0; + fwrite(&CurByte,1,1,fptr); + fseek(fptr,0,SEEK_SET); + for(CurFirstLetter = 1;CurFirstLetter <=26;CurFirstLetter++){ + CurByte = LetterLoc[CurFirstLetter] / 256; + fwrite(&CurByte,1,1,fptr); + CurByte = LetterLoc[CurFirstLetter] % 256; + fwrite(&CurByte,1,1,fptr); + } + AllWords.lfree(); + fclose(fptr); + return 0; + +} +//************************************************** +int WordList::add_group(int num) +{ + int i; + + for (i = 0;i< NumGroups;i++){ + if(num == WordGroup[i].GroupNum){ + menu->errmes("Group %d already exists.",num); + return -1; + } + if(WordGroup[i].GroupNum > num){ + break; + } + } + + NumGroups++; + for(int k=NumGroups;k>i;k--){ + WordGroup[k]=WordGroup[k-1]; + } + WordGroup[i].Words = TStringList(); + WordGroup[i].GroupNum = num; + return i; + +} +//************************************************** +int WordList::delete_group(int num) +{ + + for(int i=num;ierrmes("Group %d already exists.",newnum); + return -1; + } + if(WordGroup[i].GroupNum > newnum){ + break; + } + } + + + TStringList cur_g = TStringList(); + cur_g.copy(WordGroup[oldnum].Words); + if(oldnum < i){ + i--; + for(int k=oldnum;ki;k--){ + WordGroup[k]=WordGroup[k-1]; + } + } + WordGroup[i].Words = cur_g; + WordGroup[i].GroupNum = newnum; + return i; + +} +//************************************************************ +bool WordList::GroupExists(int GroupNum) +{ + int CurGroupIndex; + if (NumGroups > 0){ + for (CurGroupIndex=0;CurGroupIndex= MaxWordGroups){ + menu->errmes("Error! Too many groups (max %d).",MaxWordGroups); + return false; + } + + CurGroupIndex = 0; + InsertPositionFound = false; + do{ + if (WordGroup[CurGroupIndex].GroupNum > GroupNum){ + InsertPosition = CurGroupIndex; + InsertPositionFound = true; + } + else CurGroupIndex++; + }while(!InsertPositionFound && (CurGroupIndex < NumGroups)); + if (CurGroupIndex > NumGroups - 1)InsertPosition = NumGroups; + WordGroup[NumGroups].Words = TStringList(); + if (NumGroups > 0){ + for (CurGroupIndex = NumGroups - 1;CurGroupIndex>=InsertPosition;CurGroupIndex--){ + WordGroup[CurGroupIndex+1].GroupNum = WordGroup[CurGroupIndex].GroupNum; + WordGroup[CurGroupIndex+1].Words.lfree(); + WordGroup[CurGroupIndex+1].Words.copy(WordGroup[CurGroupIndex].Words); + } + } + NumGroups++; + WordGroup[InsertPosition].GroupNum = GroupNum; + WordGroup[InsertPosition].Words.lfree(); + return true; +} +//************************************************************ + +int WordList::GroupIndexOfWord(string word) + //returns the group index of the group containing the specified word} +{ + + for (int i = 0;i< NumGroups;i++){ + for(int k = 0;k= 0 && NewWordList.WordGroup[CurIndex].Words.num > 0){ + for (CurWord= 0;CurWord= 0) && (OKToReplaceWord(NewWordList.WordGroup[CurIndex].Words.at(CurWord),WordGroup[GroupIndexOfExistingWord].GroupNum,WordGroup[GroupIndex].GroupNum)))){ + + delete_word((char *)NewWordList.WordGroup[CurIndex].Words.at(CurWord).c_str(),GroupIndexOfExistingWord); + WordGroup[GroupIndex].Words.addsorted(NewWordList.WordGroup[CurIndex].Words.at(CurWord)); + NumWordsAdded++; + } + } + }//{if (GroupIndex >= 0) and (NewWordList.WordGroup[CurIndex].Words.Count > 0)} + + } +} + +//************************************************************ +bool WordList::OKToReplaceWord(string TheWord,int OldGroupNum, int NewGroupNum) +{ + + if (WhatToDoWithExistingWords == AlwaysReplace)return true; + if (WhatToDoWithExistingWords == NeverReplace)return false; + if (OldGroupNum == NewGroupNum)return true; + ReplaceWord *ask = new ReplaceWord(TheWord,OldGroupNum,NewGroupNum); + int AskResult = ask->exec(); + + if (AskResult == mrYesToAll)WhatToDoWithExistingWords = AlwaysReplace; + if (AskResult == mrNoToAll)WhatToDoWithExistingWords = NeverReplace; + if (AskResult == mrYes || AskResult == mrYesToAll)return true; + else return false; + +} +//************************************************************ diff --git a/src/words.h b/src/words.h new file mode 100644 index 0000000..539d8d9 --- /dev/null +++ b/src/words.h @@ -0,0 +1,65 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef WORDS_H +#define WORDS_H + +#include "util.h" + +typedef struct{ + TStringList Words; + int GroupNum; +}TWordGroup; + +#define MaxGroupNum 65535 +#define MaxWordGroups 10000 + +class WordList +{ + public: + WordList(); + TWordGroup WordGroup[MaxWordGroups]; + int NumGroups; + char WhatToDoWithExistingWords; + void clear(); + int read(char *filename); + int save(char *filename); + int add_group(int num); + int delete_group(int num); + int delete_word(char *word,int SelectedGroup); + int change_number(int oldnum, int newnum); + int GetWordGroupIndex(int GroupNum); + int GetNew_GroupIndex(int GroupNum); + void merge(const WordList& w); + int GroupIndexOfWord(string word); + bool OKToReplaceWord(string TheWord,int OldGroupNum, int NewGroupNum); + bool InsertWordGroup(int GroupNum); + bool GroupExists(int GroupNum); +}; + + +#define mrYes 1 +#define mrYesToAll 2 +#define mrNo 3 +#define mrNoToAll 4 +#define AskUser 0 +#define AlwaysReplace 1 +#define NeverReplace 2 +#endif diff --git a/src/wordsedit.cpp b/src/wordsedit.cpp new file mode 100644 index 0000000..bfbef4a --- /dev/null +++ b/src/wordsedit.cpp @@ -0,0 +1,904 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "game.h" +#include "words.h" +#include "menu.h" +#include "wordsedit.h" +#include "resources.h" + +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include +#include +#include + + +WordsEdit::WordsEdit( QWidget *parent, const char *name, int win_num, ResourcesWin *res ) + : QWidget( parent, name ,Qt::WDestructiveClose ) +{ + + setCaption("WORDS.TOK Editor"); + wordlist = new WordList(); + + winnum = win_num; + resources_win = res; + wordsfind = NULL; + + Q3PopupMenu *file = new Q3PopupMenu( this ); + Q_CHECK_PTR( file ); + + file->insertItem( "New", this, SLOT(new_file()) ); + file->insertItem( "Open", this, SLOT(open_file()) ); + file->insertItem( "Merge", this, SLOT(merge_file()) ); + file->insertItem( "Save", this, SLOT(save_file()) ); + file->insertItem( "Save As", this, SLOT(save_as_file()) ); + file->insertSeparator(); + file->insertItem( "Close", this, SLOT(close()) ); + + Q3PopupMenu *words = new Q3PopupMenu( this ); + Q_CHECK_PTR( words ); + + words->insertItem( "Add word group", this, SLOT(add_group_cb()) ); + words->insertItem( "Delete word group", this, SLOT(delete_group_cb()) ); + words->insertItem( "Change group number", this, SLOT(change_group_number_cb()) ); + words->insertSeparator(); + words->insertItem( "Add word", this, SLOT(add_word_cb()) ); + words->insertItem( "Delete word", this, SLOT(delete_word_cb()) ); + words->insertSeparator(); + words->insertItem( "Count word groups", this, SLOT(count_groups_cb()) ); + words->insertItem( "Count words", this, SLOT(count_words_cb()) ); + words->insertItem( "&Find...", this, SLOT(find_cb()) , Qt::CTRL+Qt::Key_F); + + + QMenuBar *menu = new QMenuBar(this); + Q_CHECK_PTR( menu ); + menu->insertItem( "File", file ); + menu->insertItem( "Words", words ); + menu->setSeparator( QMenuBar::InWindowsStyle ); + + Q3BoxLayout *all = new Q3VBoxLayout(this,10); + + QSplitter *split = new QSplitter(Qt::Horizontal,this); + + + QWidget *left = new QWidget(split); + Q3BoxLayout *lgroup = new Q3VBoxLayout(left,4); + QLabel *labelgroup = new QLabel("Word groups",left,"Word groups"); + labelgroup->setAlignment(Qt::AlignCenter); + lgroup->addWidget(labelgroup); + + listgroup = new Q3ListBox(left); + listgroup->setColumnMode (1); + listgroup->setMinimumSize(200,300); + connect( listgroup, SIGNAL(highlighted(int)), SLOT(select_group(int)) ); + connect( listgroup, SIGNAL(selected(int)), SLOT(select_group(int)) ); + + lgroup->addWidget(listgroup); + + + QWidget *right = new QWidget(split); + Q3BoxLayout *lwords = new Q3VBoxLayout(right,4); + labelword = new QLabel("Word group",right,"Word group"); + labelword->setAlignment(Qt::AlignCenter); + lwords->addWidget(labelword); + + listwords = new Q3ListBox(right); + listwords->setColumnMode (1); + listwords->setMinimumSize(200,300); + connect( listwords, SIGNAL(highlighted(int)), SLOT(select_word(int)) ); + connect( listwords, SIGNAL(selected(int)), SLOT(select_word(int)) ); + lwords->addWidget(listwords); + + lineword = new QLineEdit(right); + lineword->setEnabled(false); + connect( lineword, SIGNAL(returnPressed()), SLOT(do_add_word()) ); + lwords->addWidget(lineword); + + + all->addWidget(split); + + Q3BoxLayout *buttons = new Q3HBoxLayout(all,20); + + add_group = new QPushButton("Add group",this); + connect( add_group, SIGNAL(clicked()), SLOT(add_group_cb()) ); + buttons->addWidget(add_group); + + delete_group = new QPushButton("Delete group",this); + connect( delete_group, SIGNAL(clicked()), SLOT(delete_group_cb()) ); + buttons->addWidget(delete_group); + + add_word = new QPushButton("Add word",this); + connect( add_word, SIGNAL(clicked()), SLOT(add_word_cb()) ); + buttons->addWidget(add_word); + + delete_word = new QPushButton("Delete word",this); + connect( delete_word, SIGNAL(clicked()), SLOT(delete_word_cb()) ); + buttons->addWidget(delete_word); + + Q3BoxLayout *buttons1 = new Q3HBoxLayout(all,20); + + change_group_number = new QPushButton("&Change group number",this); + connect( change_group_number, SIGNAL(clicked()), SLOT(change_group_number_cb()) ); + buttons1->addWidget(change_group_number); + + find = new QPushButton("Find",this); + connect( find, SIGNAL(clicked()), SLOT(find_cb()) ); + buttons1->addWidget(find); + + + adjustSize(); + + changed=false; + filename=""; + SelectedGroup=0; + FindLastGroup = FindLastWord = -1; +} +//******************************************************** +void WordsEdit::deinit() +{ + delete wordlist; + winlist[winnum].type=-1; + if(window_list && window_list->isVisible())window_list->draw(); +} + + +//********************************************* +void WordsEdit::hideEvent( QHideEvent * ) +{ + + if(wordsfind){ + wordsfind->close(true); + wordsfind=NULL; + } + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//********************************************* +void WordsEdit::showEvent( QShowEvent * ) +{ + + if(window_list && window_list->isVisible())window_list->draw(); + +} + +//******************************************************** +void WordsEdit::closeEvent( QCloseEvent *e ) +{ + + if(changed){ + + switch ( QMessageBox::warning( this, "WORDS.TOK edit", + "Save changes to WORDS.TOK ?", + "Yes", + "No", + "Cancel", + 0, 2) ) { + case 0: // yes + save_file() ; + deinit(); + e->accept(); + + // else + // e->ignore(); + break; + case 1: // no + deinit(); + e->accept(); + break; + default: // cancel + e->ignore(); + break; + } + } + else{ + deinit(); + e->accept(); + } + +} +//******************************************************** +void WordsEdit::update_all() +{ + + listgroup->clear(); + listwords->clear(); + if (wordlist->NumGroups > 0){ + for (int i = 0;i< wordlist->NumGroups;i++){ + sprintf(tmp,"%d. ",wordlist->WordGroup[i].GroupNum); + for(int k=0;kWordGroup[i].Words.num;k++){ + if(k>0)strcat(tmp," | "); + strcat(tmp,wordlist->WordGroup[i].Words.at(k).c_str()); + } + QString str = tmp; + listgroup->insertItem( str ); + } + } + show(); + changed=false; +} + +//******************************************************** +void WordsEdit::open(char *filenam) +{ + int ret = wordlist->read(filenam); + if(ret)return ; + filename = filenam; + update_all(); + return; +} + +//******************************************************** +void WordsEdit::open() +{ + + sprintf(tmp,"%s/words.tok",game->dir.c_str()); + open(tmp); + +} + +//******************************************************** +void WordsEdit::add_group_cb(void) +{ + + AskNumber *addgroup = new AskNumber(0,0,"Add group","Enter group number:"); + if(!addgroup->exec())return; + + int i; + QString str = addgroup->num->text(); + int num = atoi((char *)str.latin1()); + + if(num < 0 || num > 65535){ + menu->errmes("Wordsedit","You must enter an integer from 0 to 65535."); + return; + } + + + if((i=wordlist->add_group(num))==-1)return; + + str.sprintf("%d. ",num); + listgroup->insertItem(str,i); + listgroup->setCurrentItem(i); + changed=true; +} + +//******************************************************** +void WordsEdit::delete_group_cb(void) +{ + + int rm = listgroup->currentItem(); + if(rm != -1){ + wordlist->delete_group(rm); + listgroup->removeItem(rm); + if(wordlist->NumGroups>0){ + listgroup->setCurrentItem(rm); + select_group(rm); + } + else listwords->clear(); + changed=true; + } +} + +//******************************************************** +void WordsEdit::print_group(int curgroup) +{ + sprintf(tmp,"%d. ",wordlist->WordGroup[curgroup].GroupNum); + for(int i=0;iWordGroup[curgroup].Words.num;i++){ + if(i>0)strcat(tmp," | "); + strcat(tmp,wordlist->WordGroup[curgroup].Words.at(i).c_str()); + } +} + +//******************************************************** +void WordsEdit::update_group(int curgroup) +{ + + print_group(curgroup); + listgroup->changeItem(tmp,curgroup); + +} + +//******************************************************** +void WordsEdit::delete_word_cb(void) +{ + + QString str = lineword->text(); + char *word = (char *)str.latin1(); + int k=wordlist->delete_word(word,SelectedGroup); + if(k!=-1){ + lineword->setText(""); + listwords->removeItem(k); + update_group(SelectedGroup); + changed=true; + return; + } + +} + +//******************************************************** +void WordsEdit::change_group_number_cb(void) +{ + + + AskNumber *newnumber = new AskNumber(0,0,"Change group number","Enter group number:"); + if(!newnumber->exec())return; + int i; + QString str = newnumber->num->text(); + int num = atoi((char *)str.latin1()); + + if(num < 0 || num > 65535){ + menu->errmes("Wordsedit","You must enter an integer from 0 to 65535."); + return; + } + int currentgroup = listgroup->currentItem(); + if((i=wordlist->change_number(currentgroup,num))==-1)return ; + + listgroup->removeItem(currentgroup); + listgroup->insertItem("",i); + update_group(i); + changed=true; +} + +//******************************************************** +void WordsEdit::find_cb(void) +{ + + if(wordsfind == NULL){ + wordsfind = new WordsFind(0,0,this); + } + wordsfind->show(); + wordsfind->find_field->setFocus(); +} + +//******************************************************** +int WordsEdit::find_down(char *word) +{ + + for (int i = FindLastGroup;i< wordlist->NumGroups;i++){ + for(int k = FindLastWord;kWordGroup[i].Words.num;k++){ + if(!strcmp(wordlist->WordGroup[i].Words.at(k).c_str(),word)){ + FindLastWord = k; + FindLastGroup = i; + return 1; + } + } + FindLastWord=0; + } + FindLastGroup = wordlist->NumGroups-1; + FindLastWord = wordlist->WordGroup[FindLastGroup].Words.num-1; + return 0; + +} + +//******************************************************** +int WordsEdit::find_up(char *word) +{ + + for (int i = FindLastGroup;i>= 0;i--){ + for(int k = FindLastWord;k>=0;k--){ + if(!strcmp(wordlist->WordGroup[i].Words.at(k).c_str(),word)){ + FindLastWord = k; + FindLastGroup = i; + return 1; + } + } + if(i>0)FindLastWord=wordlist->WordGroup[i-1].Words.num-1; + } + FindLastWord=0; + FindLastGroup=0; + return 0; + +} + +//******************************************************** +void WordsEdit::select_group(int num) +{ + QString str; + str.sprintf("Word group %d",wordlist->WordGroup[num].GroupNum); + labelword->setText(str); + + SelectedGroup = num; + + listwords->clear(); + for(int k=0;kWordGroup[num].Words.num;k++){ + string str2 = wordlist->WordGroup[num].Words.at(k); + const char *str1 = str2.c_str(); + listwords->insertItem(str1); + } + delete_word->setEnabled(false); + lineword->setText(""); + lineword->setEnabled(false); + listwords->show(); + +} +//******************************************************** +void WordsEdit::select_word(int num) +{ + + lineword->setText(wordlist->WordGroup[SelectedGroup].Words.at(num).c_str()); + delete_word->setEnabled(true); + +} + +//******************************************************** +void WordsEdit::add_word_cb(void) +{ + + lineword->setEnabled(true); + lineword->setText("new word"); + lineword->selectAll(); + lineword->setFocus(); +} + +//******************************************************** +void WordsEdit::do_add_word(void) +{ + + QString str = lineword->text(); + char *word = (char *)str.latin1(); + + FindLastWord = 0; + FindLastGroup = 0; + int curgroup = listgroup->currentItem(); + if(find_down(word)){ + sprintf(tmp,"This word already exists (in group %d).\nDo you wish to remove this occurance and add it to this group ?",wordlist->WordGroup[FindLastGroup].GroupNum); + + switch( QMessageBox::information( this, "Remove duplicate word ?", + tmp, + "Yes", "No", + 0, // Enter == button 0 + 1 ) ) { // Escape == button 1 + case 0: //yes + wordlist->WordGroup[FindLastGroup].Words.del(FindLastWord); + update_group(FindLastGroup); + changed=true; + break; + case 1: //no + return; + } + } + + wordlist->WordGroup[curgroup].Words.addsorted(word); + changed=true; + select_group(curgroup); + update_group(curgroup); + +} + +//******************************************************** +void WordsEdit::count_groups_cb(void) +{ + + sprintf(tmp,"There are %d word groups.",wordlist->NumGroups); + QMessageBox::information( this, "AGI studio", + tmp, + "OK", + 0, 0); + +} + +//******************************************************** +void WordsEdit::count_words_cb(void) +{ + int n = 0; + for (int i = 0;i< wordlist->NumGroups;i++){ + n+=wordlist->WordGroup[i].Words.num; + } + sprintf(tmp,"There are %d words.",n); + QMessageBox::information( this, "AGI studio", + tmp, + "OK", + 0, 0); + +} +//******************************************************** + +void WordsEdit::open_file() +{ + + Q3FileDialog *f = new Q3FileDialog(0,"Open",true); + const char *filters[] = {"words.tok","*.tok","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Open"); + f->setMode(Q3FileDialog::ExistingFile); + f->setDir(game->dir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ) + open((char *)f->selectedFile().latin1()); + } + +} + +//******************************************************** +void WordsEdit::save_as_file() +{ + + Q3FileDialog *f = new Q3FileDialog(0,"Save",true); + const char *filters[] = {"words.tok","*.tok","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Save"); + f->setMode(Q3FileDialog::AnyFile); + f->setDir(game->dir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ) + save((char *)f->selectedFile().latin1()); + } + +} + +//******************************************************** +void WordsEdit::new_file() +{ + + setCaption("WORDS.TOK Editor"); + wordlist->clear(); + listgroup->clear(); + listwords->clear(); + for(int i=0;i<3;i++){ + print_group(i); + listgroup->insertItem(tmp); + } + filename=""; + +} + +//******************************************************** +void WordsEdit::save(char *filename) +{ + + if (wordlist->NumGroups == 0){ + menu->errmes("Wordsedit","Error: Could not save the file as there are no word groups."); + return; + } + if(!wordlist->save(filename)){ + changed=false; + } + +} + +//******************************************************** +void WordsEdit::save_file() +{ + + if(filename!="") + save((char *)filename.c_str()); + else + save_as_file(); + +} + +//******************************************************** +void WordsEdit::merge_file() +{ + + WordList w = WordList(); + Q3FileDialog *f = new Q3FileDialog(0,"Open",true); + const char *filters[] = {"words.tok","*.tok","All files (*)",NULL}; + + f->setFilters(filters); + f->setCaption("Open"); + f->setMode(Q3FileDialog::ExistingFile); + f->setDir(game->dir.c_str()); + if ( f->exec() == QDialog::Accepted ) { + if ( !f->selectedFile().isEmpty() ){ + int ret = w.read((char *)f->selectedFile().latin1()); + if(ret)return ; + wordlist->merge(w); + update_all(); + } + } + +} + +//******************************************************** +WordsFind::WordsFind( QWidget *parent, const char *name , WordsEdit *w) + : QWidget( parent, name ) +{ + + wordsedit = w; + wordlist=w->wordlist; + setCaption("Find"); + Q3BoxLayout *all = new Q3VBoxLayout(this,10); + + Q3BoxLayout *txt = new Q3HBoxLayout(all,4); + + QLabel *label = new QLabel("Find what:",this); + txt->addWidget(label); + + find_field = new QLineEdit(this); + find_field->setMinimumWidth(200); + connect( find_field, SIGNAL(returnPressed()), SLOT(find_first_cb()) ); + txt->addWidget(find_field); + + Q3BoxLayout *left1 = new Q3HBoxLayout(all,10); + + Q3ButtonGroup *direction = new Q3ButtonGroup(2,Qt::Vertical,"Dir",this); + up = new QRadioButton("Up",direction); + up->setChecked(false); + down = new QRadioButton("Down",direction); + down->setChecked(true); + left1->addWidget(direction); + + Q3ButtonGroup *from = new Q3ButtonGroup(2,Qt::Vertical,"From",this); + start = new QRadioButton("Start",from); + start->setChecked(true); + current = new QRadioButton("Current",from); + current->setChecked(false); + left1->addWidget(from); + + Q3ButtonGroup *type = new Q3ButtonGroup(2,Qt::Vertical,"Match",this); + exact = new QRadioButton("Exact",type); + exact->setChecked(false); + substring = new QRadioButton("Substr",type); + substring->setChecked(true); + left1->addWidget(type); + + Q3BoxLayout *right = new Q3VBoxLayout(left1,5); + find_first = new QPushButton("Find",this); + right->addWidget(find_first); + connect( find_first, SIGNAL(clicked()), SLOT(find_first_cb()) ); + find_next = new QPushButton("Find next",this); + connect( find_next, SIGNAL(clicked()), SLOT(find_next_cb()) ); + right->addWidget(find_next); + cancel = new QPushButton("Cancel",this); + connect( cancel, SIGNAL(clicked()), SLOT(cancel_cb()) ); + right->addWidget(cancel); + + adjustSize(); + + FindLastWord=-1; + FindLastGroup=-1; + +} + +//******************************************************** +int WordsFind::find_down(char *word) +{ + bool sub = substring->isChecked(); + + for (int i = FindLastGroup;i< wordlist->NumGroups;i++){ + for(int k = FindLastWord;kWordGroup[i].Words.num;k++){ + if((sub && strstr(wordlist->WordGroup[i].Words.at(k).c_str(),word))|| + !strcmp(wordlist->WordGroup[i].Words.at(k).c_str(),word)){ + FindLastWord = k; + FindLastGroup = i; + return 1; + } + } + FindLastWord=0; + } + FindLastGroup = wordlist->NumGroups-1; + FindLastWord = wordlist->WordGroup[FindLastGroup].Words.num-1; + return 0; + +} + +//******************************************************** +int WordsFind::find_up(char *word) +{ + bool sub = substring->isChecked(); + + for (int i = FindLastGroup;i>= 0;i--){ + for(int k = FindLastWord;k>=0;k--){ + if((sub && strstr(wordlist->WordGroup[i].Words.at(k).c_str(),word))|| + !strcmp(wordlist->WordGroup[i].Words.at(k).c_str(),word)){ + FindLastWord = k; + FindLastGroup = i; + return 1; + } + } + if(i>0)FindLastWord=wordlist->WordGroup[i-1].Words.num-1; + } + FindLastWord=0; + FindLastGroup=0; + return 0; + +} + +//******************************************************** +void WordsFind::find_first_cb() +{ + int ret; + QString str = find_field->text(); + char *word = (char *)str.latin1(); + + if(down->isChecked()){ + if(start->isChecked()){ + FindLastGroup=0; + FindLastWord=0; + } + else{ + if(wordsedit->listgroup->currentItem()!=-1) + FindLastGroup=wordsedit->listgroup->currentItem(); + else + FindLastGroup=0; + if(wordsedit->listwords->currentItem()!=-1) + FindLastWord=wordsedit->listwords->currentItem(); + else + FindLastWord=0; + } + ret = find_down(word); + } + else{ + if(start->isChecked()){ + FindLastGroup=wordlist->NumGroups -1; + FindLastWord = wordlist->WordGroup[FindLastGroup].Words.num-1; + } + else{ + if(wordsedit->listgroup->currentItem()!=-1) + FindLastGroup=wordsedit->listgroup->currentItem(); + else + FindLastGroup=wordlist->NumGroups -1; + if(wordsedit->listwords->currentItem()!=-1) + FindLastWord=wordsedit->listwords->currentItem(); + else + FindLastWord=wordlist->WordGroup[FindLastGroup].Words.num-1; + } + ret = find_up(word); + } + + if(ret){ + wordsedit->listgroup->setCurrentItem(FindLastGroup); + wordsedit->listwords->setCurrentItem(FindLastWord); + } + else{ + menu->errmes("Find","'%s' not found !",word); + } + +} +//******************************************************** +void WordsFind::find_next_cb() +{ + int ret; + QString str = find_field->text(); + char *word = (char *)str.latin1(); + + if(FindLastGroup==-1||FindLastWord==-1){ + find_first_cb(); + return; + } + + if(down->isChecked()){ + if(FindLastWord+1 >= wordlist->WordGroup[FindLastGroup].Words.num){ + if(FindLastGroup+1 >= wordlist->NumGroups){ + menu->errmes("Find","'%s' not found !",word); + return ; + } + else{ + FindLastWord = 0; + FindLastGroup++; + } + } + else{ + FindLastWord++; + } + ret = find_down(word); + } + else{ + if(FindLastWord -1 < 0){ + if(FindLastGroup-1 < 0){ + menu->errmes("Find","'%s' not found !",word); + return; + } + else{ + FindLastGroup--; + FindLastWord = wordlist->WordGroup[FindLastGroup].Words.num-1; + } + } + else{ + FindLastWord--; + } + ret = find_up(word); + } + + if(ret){ + wordsedit->listgroup->setCurrentItem(FindLastGroup); + wordsedit->listwords->setCurrentItem(FindLastWord); + } + else{ + menu->errmes("Find","'%s' not found !",word); + } + +} + +//************************************************ +void WordsFind::cancel_cb() +{ + + hide(); + +} + +//************************************************ +ReplaceWord::ReplaceWord(string word,int OldGroupNum, int NewGroupNum, QWidget *parent, QString name ) + : QDialog( parent, name, TRUE ,Qt::WDestructiveClose) +{ + + setCaption("Replace word"); + + Q3BoxLayout *all = new Q3VBoxLayout(this,10); + sprintf(tmp,"The word %s already exists in group %d of the currently open file.",word.c_str(),OldGroupNum); + QLabel *l1 = new QLabel(tmp,this); + all->add(l1); + + sprintf(tmp,"Do you wish to replace it with the occurance in the merge file (group %d )?",NewGroupNum); + QLabel *l2 = new QLabel(tmp,this); + all->add(l2); + + Q3BoxLayout *b = new Q3HBoxLayout(all,10); + + QPushButton *yes = new QPushButton( "Yes", this ); + connect( yes, SIGNAL(clicked()), SLOT(yes() )); + b->addWidget(yes); + QPushButton *yes_to_all = new QPushButton( "Yes to all", this ); + connect( yes_to_all, SIGNAL(clicked()), SLOT(yes_to_all() )); + b->addWidget(yes_to_all); + QPushButton *no = new QPushButton( "No", this ); + connect( no, SIGNAL(clicked()), SLOT(no() )); + b->addWidget(no); + QPushButton *no_to_all = new QPushButton( "No to all", this ); + connect( no_to_all, SIGNAL(clicked()), SLOT(no_to_all() )); + b->addWidget(no_to_all); + + adjustSize(); + +} +//************************************************ +void ReplaceWord::yes() +{ + done(mrYes); +} +//************************************************ +void ReplaceWord::yes_to_all() +{ + done(mrYesToAll); +} +//************************************************ +void ReplaceWord::no() +{ + done(mrNo); +} +//************************************************ +void ReplaceWord::no_to_all() +{ + done(mrNoToAll); +} +//************************************************ diff --git a/src/wordsedit.h b/src/wordsedit.h new file mode 100644 index 0000000..b45a9ce --- /dev/null +++ b/src/wordsedit.h @@ -0,0 +1,141 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef WORDSEDIT_H +#define WORDSEDIT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include + +#include "util.h" +#include "wutil.h" +#include "words.h" +#include "resources.h" + +class WordsFind; + +//****************************************************** +class WordsEdit : public QWidget +{ + Q_OBJECT +public: + WordsEdit( QWidget *parent=0, const char *name=0, int winnum=0, ResourcesWin *res=0); + Q3ListBox *listgroup,*listwords; + ResourcesWin *resources_win; + WordList *wordlist; + void open(); +public slots: + void add_group_cb(void); + void delete_group_cb(void); + void add_word_cb(void); + void do_add_word(void); + void delete_word_cb(void); + void change_group_number_cb(void); + void find_cb(void); + void select_group(int); + void select_word(int); + void update_group(int); + void count_groups_cb(void); + void count_words_cb(void); + + void new_file(); + void open_file(); + void merge_file(); + void save_file(); + void save_as_file(); + protected: + void open(char *); + void save(char *); + void deinit(); + int winnum; + QLabel *labelword; + QLineEdit *lineword; + QPushButton *add_group,*delete_group,*add_word,*delete_word, + *change_group_number,*find; + WordsFind *wordsfind; + bool changed; + string filename; + int FindLastGroup,FindLastWord; + int SelectedGroup; + int find_down(char *word); + int find_up(char *word); + void print_group(int curgroup); + void add_group_ok_cb(); + void change_group_ok_cb(); + void closeEvent( QCloseEvent *e ); + void showEvent( QShowEvent * ); + void hideEvent( QHideEvent * ); + void update_all(); +}; + +//****************************************************** +class WordsFind : public QWidget +{ + Q_OBJECT +public: + WordsFind( QWidget *parent=0, const char *name=0,WordsEdit *w=0); + void open(); + QLineEdit *find_field; + bool first; +public slots: + void find_next_cb(); + void find_first_cb(); + void cancel_cb(); + protected: + WordList *wordlist; + WordsEdit *wordsedit; + QPushButton *find_first,*find_next,*cancel; + QRadioButton *up,*down; + QRadioButton *start,*current; + QRadioButton *exact,*substring; + int FindLastGroup,FindLastWord; + int find_down(char *word); + int find_up(char *word); + +}; + +//****************************************************** +class ReplaceWord : public QDialog +{ + Q_OBJECT +public: + ReplaceWord(string word=0,int OldGroupNum=0, int NewGroupNum=0, QWidget *parent=0, QString name=(const char*)0); +public slots: + void yes(); + void yes_to_all(); + void no(); + void no_to_all(); +}; + + +#endif diff --git a/src/wutil.cpp b/src/wutil.cpp new file mode 100644 index 0000000..be5684e --- /dev/null +++ b/src/wutil.cpp @@ -0,0 +1,185 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +//Added by qt3to4: +#include +#include +#include +#include +#include +#include + +#include "wutil.h" + +QColor egacolor[16]; + +//********************************************** + +AskNumber::AskNumber( QWidget *parent, const char *name, const char *caption,const char *prompt) + : QDialog( parent, name ,TRUE) +{ + + + setCaption(caption); + Q3BoxLayout *all = new Q3VBoxLayout(this,20); + + Q3BoxLayout *top = new Q3HBoxLayout(all,4); + QLabel *label = new QLabel(prompt,this); + top->addWidget(label); + num = new QLineEdit(this); + num->setMinimumWidth(80); + connect( num, SIGNAL(returnPressed()), SLOT(accept()) ); + top->addWidget(num); + + Q3BoxLayout *bottom = new Q3HBoxLayout(all,40); + QPushButton *ok = new QPushButton(this); + ok->setText("OK"); + connect( ok, SIGNAL(clicked()), SLOT(accept()) ); + bottom->addWidget(ok); + QPushButton *cancel = new QPushButton(this); + cancel->setText("Cancel"); + connect( cancel, SIGNAL(clicked()), SLOT(reject()) ); + bottom->addWidget(cancel); + +} + +AskText::AskText( QWidget *parent, const char *name, const char *caption,const char *prompt) + : QDialog( parent, name ,TRUE) +{ + + + setCaption(caption); + Q3BoxLayout *all = new Q3VBoxLayout(this,20); + + QLabel *label = new QLabel(prompt,this); + all->addWidget(label); + text = new QLineEdit(this); + text->setMinimumWidth(120); + connect( text, SIGNAL(returnPressed()), SLOT(accept()) ); + all->addWidget(text); + + Q3BoxLayout *bottom = new Q3HBoxLayout(all,40); + QPushButton *ok = new QPushButton(this); + ok->setText("OK"); + connect( ok, SIGNAL(clicked()), SLOT(accept()) ); + bottom->addWidget(ok); + QPushButton *cancel = new QPushButton(this); + cancel->setText("Cancel"); + connect( cancel, SIGNAL(clicked()), SLOT(reject()) ); + bottom->addWidget(cancel); + +} + + + +//********************************************** +void make_egacolors(void) +{ + static bool ok=false; + + if(ok)return; + + egacolor[0]= QColor(0,0,0); //black + egacolor[1]= QColor(0,0,0xa0); //blue + egacolor[2]= QColor(0,0xa0,0); //green + egacolor[3]= QColor(0,0xa0,0xa0); //cyan + egacolor[4]= QColor(0xa0,0,0); //red + egacolor[5]= QColor(0xa0,0,0xa0); //magenta + egacolor[6]= QColor(0xa0,0x50,0); //brown + egacolor[7]= QColor(0xa0,0xa0,0xa0); //lightgray + egacolor[8]= QColor(0x50,0x50,0x50); //gray + egacolor[9]= QColor(0x50,0x50,0xff); //lightblue + egacolor[10]=QColor(0x50,0xff,0x50); //lightgreen + egacolor[11]=QColor(0x50,0xff,0xff); //lightcyan + egacolor[12]=QColor(0xff,0x50,0x50); //lightred + egacolor[13]=QColor(0xff,0x50,0xff); //lightmagenta + egacolor[14]=QColor(0xff,0xff,0x50); //yellow + egacolor[15]=QColor(0xff,0xff,0xff); //white + + ok=true; +} + +//********************************************* + +/*******************************************************/ +Palette::Palette( QWidget *parent, const char *name ) + : QWidget( parent, name ) +{ + + left=right=0; + +} + + +void Palette::paintEvent( QPaintEvent * ) +{ + QPainter p (this ); + int w,h,x,y,dx,dy,i; + + w = this->width(); + h = this->height(); + dx=w/8; + dy=h/2; + w=dx*8; + h=dy*2; + + for(y=0,i=0;ywidth(); + h = this->height(); + dx=w/8; + dy=h/2; + w=dx*8; + h=dy*2; + + x=event->x() / dx; + y=event->y() / dy; + i=y*8+x; + + if (event->button() & Qt::LeftButton){ + left = i; + } + else if (event->button() & Qt::RightButton){ + right = i; + } + + repaint(); +} + diff --git a/src/wutil.h b/src/wutil.h new file mode 100644 index 0000000..37436b4 --- /dev/null +++ b/src/wutil.h @@ -0,0 +1,73 @@ +/* + * QT AGI Studio :: Copyright (C) 2000 Helen Zommer + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef WUTIL_H +#define WUTIL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Added by qt3to4: +#include +#include +#include + +#include "global.h" + +//***************************************************** +class AskNumber : public QDialog +{ + Q_OBJECT +public: + AskNumber( QWidget *parent=0, const char *name=0,const char *caption=0,const char *prompt=0); + QLineEdit *num; +}; + +//***************************************************** +class AskText : public QDialog +{ + Q_OBJECT +public: + AskText( QWidget *parent=0, const char *name=0,const char *caption=0,const char *prompt=0); + QLineEdit *text; +}; + +//***************************************************** +class Palette : public QWidget +{ + Q_OBJECT +public: + Palette( QWidget *parent=0, const char *name=0); + void paintEvent(class QPaintEvent *); + void mousePressEvent(QMouseEvent* event); + int left,right; +}; + +//***************************************************** +extern QColor egacolor[]; +extern void make_egacolors(void); + +#endif diff --git a/src/zoom_minus.xpm b/src/zoom_minus.xpm new file mode 100644 index 0000000..53e3ad1 --- /dev/null +++ b/src/zoom_minus.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static const char *zoom_minus[] = { +/* columns rows colors chars-per-pixel */ +"30 30 2 1", +" c black", +". c gray100", +/* pixels */ +"..............................", +"..............................", +"..............................", +"..............................", +"................. ........", +"............... ..... ......", +".............. ......... .....", +"............. ........... ....", +"............ ............. ...", +"............ ............. ...", +"........... ............... ..", +"........... ... .. ..", +"........... ... .. ..", +"........... ............... ..", +"........... ............... ..", +"............ ............. ...", +"............ ............. ...", +"............. ........... ....", +"............ ......... .....", +"........... .. ..... ......", +".......... .. ... ........", +"......... .. .................", +"........ .. ..................", +"....... .. ...................", +"...... .. ....................", +"..... .. .....................", +".... .. ......................", +"... .. .......................", +".. ........................", +".............................." +}; diff --git a/src/zoom_minus_x.xpm b/src/zoom_minus_x.xpm new file mode 100644 index 0000000..496224c --- /dev/null +++ b/src/zoom_minus_x.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static const char *zoom_minus_x[] = { +/* columns rows colors chars-per-pixel */ +"30 30 2 1", +" c black", +". c None", +/* pixels */ +"..............................", +"..............................", +"..............................", +"..............................", +"................. ........", +"............... ..... ......", +".............. ......... .....", +"............. ........... ....", +"............ ............. ...", +"............ ............. ...", +"........... ............... ..", +"........... ... .. ..", +"........... ... .. ..", +"........... ............... ..", +"........... ............... ..", +"............ ............. ...", +"............ ............. ...", +"............. ........... ....", +"............ ......... .....", +"........... .. ..... ......", +".......... .. ... ........", +"......... .. .................", +"........ .. ..................", +"....... .. ...................", +"...... .. ....................", +"..... .. .....................", +".... .. ......................", +"... .. .......................", +".. ........................", +".............................." +}; diff --git a/src/zoom_plus.xpm b/src/zoom_plus.xpm new file mode 100644 index 0000000..b79bdb7 --- /dev/null +++ b/src/zoom_plus.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static const char *zoom_plus[] = { +/* columns rows colors chars-per-pixel */ +"30 30 2 1", +" c black", +". c gray100", +/* pixels */ +"..............................", +"..............................", +"..............................", +"..............................", +"................. ........", +"............... ..... ......", +".............. ......... .....", +"............. ..... .... ....", +"............ ...... ..... ...", +"............ ...... ..... ...", +"........... ....... ...... ..", +"........... ... .. ..", +"........... ... .. ..", +"........... ....... ...... ..", +"........... ....... ...... ..", +"............ ...... ..... ...", +"............ ...... ..... ...", +"............. ........... ....", +"............ ......... .....", +"........... .. ..... ......", +".......... .. ... ........", +"......... .. .................", +"........ .. ..................", +"....... .. ...................", +"...... .. ....................", +"..... .. .....................", +".... .. ......................", +"... .. .......................", +".. ........................", +".............................." +}; diff --git a/src/zoom_plus_x.xpm b/src/zoom_plus_x.xpm new file mode 100644 index 0000000..4037ca6 --- /dev/null +++ b/src/zoom_plus_x.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static const char *zoom_plus_x[] = { +/* columns rows colors chars-per-pixel */ +"30 30 2 1", +" c black", +". c None", +/* pixels */ +"..............................", +"..............................", +"..............................", +"..............................", +"................. ........", +"............... ..... ......", +".............. ......... .....", +"............. ..... .... ....", +"............ ...... ..... ...", +"............ ...... ..... ...", +"........... ....... ...... ..", +"........... ... .. ..", +"........... ... .. ..", +"........... ....... ...... ..", +"........... ....... ...... ..", +"............ ...... ..... ...", +"............ ...... ..... ...", +"............. ........... ....", +"............ ......... .....", +"........... .. ..... ......", +".......... .. ... ........", +"......... .. .................", +"........ .. ..................", +"....... .. ...................", +"...... .. ....................", +"..... .. .....................", +".... .. ......................", +"... .. .......................", +".. ........................", +".............................." +}; diff --git a/template/logdir b/template/logdir new file mode 100644 index 0000000000000000000000000000000000000000..e98393df35f3c27f0f994cfee635d71b1b54f725 GIT binary patch literal 300 wcmZQzU|?W*$iQm+e-!-x&%m~dfqfeThY 0) { + call(98); // error handler - IMPORTANT +} + +if (room_no == 0) { + call(91); // initialization + + // Put test object to room2: + va=2; + put("test object", va); + + if (game_restarted) { + disable.item(menu_fileseparator); + set(menu_enabled); + reset(disable_game_functions); + assignn(score,0); + new.room(2); // go to first room here + } + else { + set.menu("AGI"); + set.menu.item("About ", menu_about); + set.menu.item("Help ", menu_help); + set.menu("File"); + set.menu.item("Save ", menu_save); + set.menu.item("Restore ", menu_restore); + set.menu.item("-------------", menu_fileseparator); + set.menu.item("Restart ", menu_restart); + set.menu.item("Quit ", menu_quit); + set.menu("Action"); + set.menu.item("See Object ", menu_seeobject); + set.menu.item("Inventory ", menu_inventory); + set.menu("Special"); + set.menu.item("Sound On/Off ", menu_soundonoff); + set.menu.item("Clock On/Off ", menu_clock); + set.menu.item("Joystick ", menu_joystick); + set.menu.item("Pause ", menu_pause); + set.menu("Speed"); + set.menu.item("Normal ", menu_normalspeed); + set.menu.item("Slow ", menu_slowspeed); + set.menu.item("Fast ", menu_fastspeed); + set.menu.item("Fastest", menu_fastestspeed); + submit.menu(); + disable.item(menu_fileseparator); + //set(disable_game_functions); + new.room(1); // intro/opening screen + } +} + +if (new_room) { // First interpreter cycle in a new room + // Note: Everything other than logic 0 is discarded + // from memory when new.room is executed + load.logics(90); // Load game specific functions logic into memory // Load game specific functions logic into memory + + // Use debug mode? + if (v1!=v1) { + reset(debug_active); + } else { + set(debug_active); + load.logics(99); // debug code + } + + + clear.lines(24,24,0); // clear bottom line of screen (remove ego's coords if shown) + animate.obj(ego); + load.view.v(ego_view_no); + set.view.v(ego, ego_view_no); + observe.objs(ego); + old_clock_seconds = 255; // make sure clock gets updated this cycle + // on this cycle (if turned on) +} + +if (death_type > 0) { // player is dead + if (death_type != 255) { // first cycle since player died. disable + // some menu items and load logic 94 into + // memory as it will be called from now on. + disable.item(menu_about); + disable.item(menu_help); + disable.item(menu_save); + disable.item(menu_pause); + disable.item(menu_soundonoff); + disable.item(menu_seeobject); + disable.item(menu_joystick); + disable.item(menu_normalspeed); + disable.item(menu_fastestspeed); + disable.item(menu_fastspeed); + disable.item(menu_slowspeed); + load.logics(94); + } + call(94); // death handler + goto(End); +} + +if (!disable_game_functions) { + if (controller(key_activiate_menu)) { + menu.input(); + } +} + +if (controller(menu_about)) { + print(game_about_message); +} + +if ((controller(menu_fastestspeed) || + said("fastest") || + said("fastest", "speed"))) { + cycle_delay = 0; // no delay between interpreter cycles +} + +if ((controller(menu_fastspeed) || + said("fast") || + said("fast", "speed"))) { + cycle_delay = 1; // 1/20th of a second delay between interpreter cycles +} + +if ((controller(menu_normalspeed) || + said("normal") || + said("normal", "speed"))) { + cycle_delay = 2; // 2/20ths of a second delay between interpreter cycles +} + +if ((controller(menu_slowspeed) || + said("slow") || + said("slow", "speed"))) { + cycle_delay = 4; // 4/20ths of a second delay between interpreter cycles +} + +if (controller(key_decreasevolume)) { + sound_volume--; // decrease volume +} + +if (controller(key_increasevolume) && sound_volume < 15) { + sound_volume++; // increase volume +} + +if (controller(menu_soundonoff)) { + toggle(sound_on); +} + +if (!disable_game_functions) { + + if (!debug_active) { + if (controller(key_debug)) { + set(debug_active); + print(game_version_message); + version(); + load.logics(99); // load debug logic into memory + } + } + + if ((controller(menu_save) || + said("save", "game") || + said("save"))) { + stop.sound(); + save.game(); + } + + if ((controller(menu_restore) || + said("restore", "game") || + said("restore"))) { + stop.sound(); + restore.game(); + } + + if ((controller(menu_restart) || + said("restart", "game") || + said("restart"))) { + restart.game(); + } + + if ((controller(menu_help) || + said("help"))) { + call(92); + } + + if (controller(key_echoline)) { + echo.line(); + } + + if (controller(key_clearinputline)) { + cancel.line(); + } + + if (controller(menu_joystick)) { + init.joy(); + } + + if ((controller(menu_pause) || + said("pause", "game") || + said("pause"))) { + pause(); + } + + if ((controller(menu_inventory) || + said("inventory"))) { + status(); + } + + if ((controller(menu_seeobject) || + controller(key_seeobject))) { + set(inventory_select_enabled); // enable choice of inventory item in inventory screen + status(); // show inventory screen - player selects an inventory item + if (selected_inventory_item > 0 && + selected_inventory_item != 255) { // note: selected_inventory_item is set to 255 + // if ESC is pressed in the inventory screen. + // player has chosen an object (value of selected_inventory_item). We now display this object. + + if (selected_inventory_item == 1) { // test object + show.obj(220); + } + + // NOTE: If you have several objects, it is easier to give them + // consecutive view numbers. Then you can do the following (view + // numbers start at 220 for this example): + // v255 = selected_inventory_item; v255 += 219; + // show.obj.v(v255); + // If you this, you don't have to have separate statements for each + // object. + + reset(inventory_select_enabled); // disable choice of inventory item in inventory screen + } + } + + if ((controller(menu_quit) || + said("quit", "game") || + said("quit"))) { + stop.sound(); + quit(0); + } +} + +get.posn(ego, new_ego_x, new_ego_y); // get ego's current position + +if (ego_dir == old_ego_dir && + new_ego_x == old_ego_x && + new_ego_y == old_ego_y) { + // ego hasn't moved or changed direction since last cycle + stop.cycling(ego); +} +else { + if (!never_animate_ego) { + start.cycling(ego); + } +} + +old_ego_x = new_ego_x; +old_ego_y = new_ego_y; +old_ego_dir = ego_dir; + +if (always_animate_ego) { + start.cycling(ego); +} +else { + if ((ego_dir == stopped || never_animate_ego)) { + stop.cycling(ego); + } +} + +if ((said("clock") || controller(menu_clock))) { + toggle(clock_active); + if (!clock_active) { + status.line.on(); // remove clock text from status line + } + else { + old_clock_seconds = 255; // make sure clock gets updated this cycle + } +} + +if (clock_active && !disable_game_functions) { + if (old_clock_seconds != clock_seconds) { + set.text.attribute(0,15); + display(0, 18, " %v13:%v12|2:%v11|2 "); // update clock + set.text.attribute(15,0); + old_clock_seconds = clock_seconds; + } +} + + +if (isset(game_restored)) { // first cycle since restore game executed + clear.lines(23, 24, 0); + reset(debug_active); + disable.item(menu_fileseparator); +} + +call.v(room_no); // IMPORTANT: This calls the logic for the current room - this + // is not done automatically by the interpreter so it has to be + // called manually by logic 0. Logic 0 cycles round and on each + // cycle the current room's logic is called, so it is also + // executed with each cycle. + +if (debug_active) { + call(99); // debug logic +} + +call(90); // game specific functions + +if (input_recieved && + unknown_word_no > 0) { + reset(input_recieved); + if (unknown_word_no == 1) { + print("I don't understand \"%w1\""); + } + if (unknown_word_no == 2) { + print("I don't understand \"%w2\""); + } + if (unknown_word_no == 3) { + print("I don't understand \"%w3\""); + } +} + +if (input_recieved && + !input_parsed) { // no command has been recognised + print("I don't understand your request."); + reset(input_recieved); +} + +reset(input_parsed); + +End: +return(); + + + + + + diff --git a/template/src/logic1.txt b/template/src/logic1.txt new file mode 100644 index 0000000..ceca3fa --- /dev/null +++ b/template/src/logic1.txt @@ -0,0 +1,30 @@ +// **************************************************************************** +// +// Logic 1: Opening/intro +// +// **************************************************************************** + +#include "defines.txt" + +if (new_room) { + load.pic(room_no); + draw.pic(room_no); + discard.pic(room_no); + set.horizon(50); + status.line.off(); + prevent.input(); + program.control(); + show.pic(); + display(23,1," Intro/Opening screen"); +} + +if (have.key()) { + set(menu_enabled); + clear.lines(22, 24, 0); + stop.motion(ego); + reset(disable_game_functions); + new.room(2); +} + +return(); + diff --git a/template/src/logic2.txt b/template/src/logic2.txt new file mode 100644 index 0000000..f6f6361 --- /dev/null +++ b/template/src/logic2.txt @@ -0,0 +1,92 @@ +// **************************************************************************** +// +// Logic 2: First room +// +// **************************************************************************** +#include "defines.txt" +if (new_room) { + load.pic(room_no); + draw.pic(room_no); + discard.pic(room_no); + set.horizon(60); + // The next 6 lines need only be in the first room of the game + if ((prev_room_no == 1 || // just come from intro screen + prev_room_no == 0)) { // or just started game + position(ego,76,90); + status.line.on(); + accept.input(); + } + + load.view(2); // ego in water -view + ignore.objs(ego); // allow ego to walk over objects + + // Show test object on the floor if the player hasn't piced it up + if (!has("test object")) { + animate.obj(o2); + load.view(221); + set.view(o2,221); + position(o2,70,130); + set.priority(o2,4); // = floor + draw(o2); + } + +// Check what room the player came from and position them on the +// screen accordingly here, e.g: +// if (prev_room_no == 5) { +// position(ego,12,140); +// } + draw(ego); + show.pic(); +} + +// Change ego's view when on water +if (ego_on_water) { + set.view(ego,2); +} +else { + set.view(ego,0); +} + +if (said("look")) { + if (!has("test object")) { + print("This is a test room. There is a test object on the ground."); + } else { + print("This is an empty test room."); + } +} + +if (said("get","test object")) { + if (!has("test object")) { + if (center.posn(ego, 64,125, 80,135)) { + get("test object"); + erase(o2); + score += 1; + print("Ok. It looks like some kind of text plate."); + } else { + print("It's too far away. Move closer."); + } + } else { + print("You already got it."); + } +} + +//if (ego_edge_code == horizon_edge) { // ego touching horizon +// new.room(2); +//} +if (ego_edge_code == right_edge) { // ego touching right edge of screen + new.room(2); +} +if (ego_edge_code == bottom_edge) { // ego touching bottom edge of screen + new.room(2); +} +if (ego_edge_code == left_edge) { // ego touching left edge of screen + new.room(2); +} +return(); + + + + + + + diff --git a/template/src/logic90.txt b/template/src/logic90.txt new file mode 100644 index 0000000..36ae237 --- /dev/null +++ b/template/src/logic90.txt @@ -0,0 +1,74 @@ +// **************************************************************************** +// +// Logic 90: Game-specific functions +// +// You should use this logic to perform any game specific functions, such as +// counting down timers, etc and processing player input related to the game +// (such as examining/using inventory items) and any other things that are +// required in several rooms that you don't want to duplicate in each room. +// +// This logic is called from logic 0, on every cycle. +// If you like, you could only make it called only when disable_game_functions +// is not set. +// +// Sierra did not use a separate logic for all this - they just did it all +// from logic 0. I find it is neater this way, as you can keep your game +// specific processing separate from other system-related things (although +// these may require some modification for your game). Also, this makes logic 0 +// easier to manage. +// +// **************************************************************************** + +#include "defines.txt" + +// put all non-input-reponse game functions here + +if (input_recieved && + unknown_word_no == 0 && + !input_parsed) { + +// put various input responses here + + if (said("die")) { // this one should not be in your game - it is + score += 1; + if ( ego_on_water ) { + print("Blub! You drowned."); + erase(ego); + } else { + load.view(1); // only to demostrate the death handler (logic 94) + set.view(ego,1); + } + program.control(); + stop.motion(ego); + death_type = 1; + } + + if (said("look", "test object")) { + if (has("test object")) { + show.obj(220); + } + else { + print("You don't have it."); + } + } + + if ((said("look", "anyword") || + said("look", "anyword", "anyword"))) { + print("What? Where?"); + } + + if ((said("get", "anyword") || + said("get", "anyword", "anyword"))) { + print("You can't get that here!"); + } + + if ((said("use", "anyword") || + said("use", "anyword", "anyword"))) { + print("What do you want me to do with it?"); + } +} + +return(); + + + diff --git a/template/src/logic91.txt b/template/src/logic91.txt new file mode 100644 index 0000000..8f6979b --- /dev/null +++ b/template/src/logic91.txt @@ -0,0 +1,65 @@ +// **************************************************************************** +// +// Logic 91: Initialization +// +// **************************************************************************** + +#include "defines.txt" + +// Key settings with set.key are as follows: +// First number: +// 1-26 CTRL-A - CTRL-Z +// 8 - Backspace +// 9 - Tab +// 59-68 F1-F10 +// +// There are other keys in the 1-26 range that can be assigned +// Both the CTRL-Letter and that key will be assigned if you do this +// eg. most AGI games use both TAB and CTRL-I for inventory. +// +// Second number: +// 16-25 ALT: Q W E R T Y U I O P +// 30-38 ALT: A S D F G H J K L +// 44-50 ALT: Z X C V B N M + +if (new_room) { + trace.info(95, 3, 10); + set.key(0, 59, menu_help); // F1 - Help + set.key(0, 60, menu_soundonoff); // F2 - Sound on/off + set.key(19, 0, menu_soundonoff); // CTRL-S - Sound on/off + set.key(0, 61, key_echoline); // F3 - Echo line + set.key(5, 0, key_echoline); // CTRL-E - Echo line + set.key(0, 62, key_seeobject); // F4 - See object + set.key(0, 63, menu_save); // F5 - Save game + set.key(0, 64, menu_clock); // F6 - Clock on/off + set.key(0, 65, menu_restore); // F7 - Restore game + set.key(0, 67, menu_restart); // F9 - Restart game + set.key(9, 0, menu_inventory); // CTRL-I/TAB - inventory + set.key(0, 32, key_debug); // ALT-D - Enter debug mode + set.key(10, 0, menu_joystick); // CTRL-J - Configure joystick + set.key(3, 0, key_clearinputline); // CTRL-C - Clear input line + set.key(0, 44, menu_quit); // ALT-Z - quit game + set.key(45, 0, key_decreasevolume); // - - decrease volume + set.key(43, 0, key_increasevolume); // + - increase volume + set.key(27, 0, key_activiate_menu); // ESC - activate menu + + set(joystick_sensitivity_set); + joystick_sensitivity = 3; + sound_volume = 15; // full volume + +//set.game.id("AGI"); // We don't actually need to set the game ID. It's + // best not to, then the game can run on any + // interpreter (provided it's the right version). + configure.screen(1, 22, 0); + set.string(prompt_char, ">"); + set.cursor.char("_"); + max_score = 2; + cycle_delay = 1; // set speed to fast (delay=1/20ths of a second) +} + +return(); + + + + + diff --git a/template/src/logic92.txt b/template/src/logic92.txt new file mode 100644 index 0000000..2ef527c --- /dev/null +++ b/template/src/logic92.txt @@ -0,0 +1,38 @@ +// **************************************************************************** +// +// Logic 92: Help screen +// +// **************************************************************************** + +#include "defines.txt" + +prevent.input(); +status.line.off(); +text.screen(); +key_pressed = 0; +reset(input_parsed); +display(3, 0, " AGI Help"); + +display(6, 0," F1 displays this message."); +display(7, 0," F2 turns the sound off and on."); +display(8, 0," F3 retypes the last line typed."); +display(9, 0," F5 saves your current game."); +display(10,0," F7 restores a saved game."); +display(11,0," F9 restarts the game."); +display(12,0," ALT-Z quits the game."); +display(13,0," TAB shows the inventory screen."); +display(14,0," ESC pops up menus."); +display(15,0," Ctrl-J sets up your joystick."); +display(16,0," + Increases volume."); +display(17,0," - Decreases volume."); + +WaitForKey: +if (!have.key()) { + goto(WaitForKey); +} + +accept.input(); +status.line.on(); +graphics(); +set(input_parsed); +return(); \ No newline at end of file diff --git a/template/src/logic93.txt b/template/src/logic93.txt new file mode 100644 index 0000000..3b6360d --- /dev/null +++ b/template/src/logic93.txt @@ -0,0 +1,47 @@ +// **************************************************************************** +// +// Logic 93: Debug mode help screen +// +// **************************************************************************** + +#include "defines.txt" + +prevent.input(); +status.line.off(); +text.screen(); +key_pressed = 0; +reset(input_parsed); +display(1, 1, " DEBUG MODE HELP "); + +display( 3,0,"trace on - enables tracing "); +display( 4,0," (SCROLL LOCK to activate)"); +display( 5,0,"show mem - display memory stats "); +display( 6,0,"tp - teleport "); +display( 7,0,"pos - change ego's position "); +display( 8,0,"show var - display value of a var "); +display( 9,0,"set var - change value of a var "); +display(10,0,"show flag - display status of a flag "); +display(11,0,"set flag - set a flag "); +display(12,0,"reset flag - reset (clear) a flag "); +display(13,0,"object - display information about"); +display(14,0," a screen object "); +display(15,0,"show pri - display priority screen "); +display(16,0,"get object - get any inventory object "); +display(17,0,"gimme gimme - get all inventory objects"); +display(18,0,"object room - display room number of "); +display(19,0," an inventory object "); +display(20,0,"set pri - set ego's priority "); +display(21,0,"release pri - release ego's priority "); +display(22,0,"coords - ego's coordinates on/off "); + + +WaitForKey: +if (!have.key()) { + goto(WaitForKey); +} + +accept.input(); +status.line.on(); +graphics(); +set(input_parsed); +return(); diff --git a/template/src/logic94.txt b/template/src/logic94.txt new file mode 100644 index 0000000..8de6d5b --- /dev/null +++ b/template/src/logic94.txt @@ -0,0 +1,73 @@ +// **************************************************************************** +// +// Logic 94: Death handler +// This logic is run when the player dies. +// The death message displayed depends on the value of death_type. +// +// **************************************************************************** + +#include "defines.txt" + +if (death_type != 255) { // if death_type = 255, the death message has + // already been displayed + accept.input(); + cancel.line(); + program.control(); + clear.lines(23, 24, 0); + thankyou_timer = 12; + + if (death_type == 1) { + print("You are now dead."); + } + + // add messages for other death types here + + death_type = 255; // set death_type to 255 so this logic does not display + // the death message again +} + +thankyou_timer--; + +if (thankyou_timer == 1) { + print("Thank you for playing this game. Better luck next time!"); +} + +if (controller(key_activiate_menu)) { + menu.input(); +} + +if ((controller(menu_help) || + said("help"))) { + call(92); +} + +if ((controller(menu_restore) || + said("restore", "game") || + said("restore"))) { + restore.game(); +} + +if ((controller(menu_restart) || + said("restart", "game") || + said("restart"))) { + restart.game(); +} + +if ((controller(menu_inventory) || + said("inventory"))) { + status(); +} + +if ((controller(menu_quit) || + said("quit"))) { + stop.sound(); + quit(0); +} + +if (input_recieved && + !input_parsed) { + print("You are dead! You can only restore, restart, quit the game" + " or view your inventory."); +} + +return(); \ No newline at end of file diff --git a/template/src/logic95.txt b/template/src/logic95.txt new file mode 100644 index 0000000..56d6dd6 --- /dev/null +++ b/template/src/logic95.txt @@ -0,0 +1,190 @@ +return(); + +// Messages (all messages are here) +#message 1 "increment" +#message 2 "decrement" +#message 3 "assignn" +#message 4 "assignv" +#message 5 "addn" +#message 6 "addv" +#message 7 "subn" +#message 8 "subv" +#message 9 "lindirectv" +#message 10 "rindirect" +#message 11 "lindirectn" +#message 12 "set" +#message 13 "reset" +#message 14 "toggle" +#message 15 "set.v" +#message 16 "reset.v" +#message 17 "toggle.v" +#message 18 "new.room" +#message 19 "new.room.v" +#message 20 "load.logics" +#message 21 "load.logics.v" +#message 22 "call" +#message 23 "call.v" +#message 24 "load.pic" +#message 25 "draw.pic" +#message 26 "show.pic" +#message 27 "discard.pic" +#message 28 "overlay.pic" +#message 29 "show.pri.screen" +#message 30 "load.view" +#message 31 "load.view.v" +#message 32 "discard.view" +#message 33 "animate.obj" +#message 34 "unanimate.all" +#message 35 "draw" +#message 36 "erase" +#message 37 "position" +#message 38 "position.v" +#message 39 "get.posn" +#message 40 "reposition" +#message 41 "set.view" +#message 42 "set.view.v" +#message 43 "set.loop" +#message 44 "set.loop.v" +#message 45 "fix.loop" +#message 46 "release.loop" +#message 47 "set.cel" +#message 48 "set.cel.v" +#message 49 "last.cel" +#message 50 "current.cel" +#message 51 "current.loop" +#message 52 "current.view" +#message 53 "number.of.loops" +#message 54 "set.priority" +#message 55 "set.priority.v" +#message 56 "release.priority" +#message 57 "get.priority" +#message 58 "stop.update" +#message 59 "start.update" +#message 60 "force.update" +#message 61 "ignore.horizon" +#message 62 "observe.horizon" +#message 63 "set.horizon" +#message 64 "object.on.water" +#message 65 "object.on.land" +#message 66 "object.on.anything" +#message 67 "ignore.objs" +#message 68 "observe.objs" +#message 69 "distance" +#message 70 "stop.cycling" +#message 71 "start.cycling" +#message 72 "normal.cycle" +#message 73 "end.of.loop" +#message 74 "reverse.cycle" +#message 75 "reverse.loop" +#message 76 "cycle.time" +#message 77 "stop.motion" +#message 78 "start.motion" +#message 79 "step.size" +#message 80 "step.time" +#message 81 "move.obj" +#message 82 "move.obj.v" +#message 83 "follow.ego" +#message 84 "wander" +#message 85 "normal.motion" +#message 86 "set.dir" +#message 87 "get.dir" +#message 88 "ignore.blocks" +#message 89 "observe.blocks" +#message 90 "block" +#message 91 "unblock" +#message 92 "get" +#message 93 "get.v" +#message 94 "drop" +#message 95 "put" +#message 96 "put.v" +#message 97 "get.room.v" +#message 98 "load.sound" +#message 99 "sound" +#message 100 "stop.sound" +#message 101 "print" +#message 102 "print.v" +#message 103 "display" +#message 104 "display.v" +#message 105 "clear.lines" +#message 106 "text.screen" +#message 107 "graphics" +#message 108 "set.cursor.char" +#message 109 "set.text.attribute" +#message 110 "shake.screen" +#message 111 "configure.screen" +#message 112 "status.line.on" +#message 113 "status.line.off" +#message 114 "set.string" +#message 115 "get.string" +#message 116 "word.to.string" +#message 117 "parse" +#message 118 "get.num" +#message 119 "prevent.input" +#message 120 "accept.input" +#message 121 "set.key" +#message 122 "add.to.pic" +#message 123 "add.to.pic.v" +#message 124 "status" +#message 125 "save.game" +#message 126 "restore.game" +#message 127 "init.disk" +#message 128 "restart.game" +#message 129 "show.obj" +#message 130 "random" +#message 131 "program.control" +#message 132 "player.control" +#message 133 "obj.status.v" +#message 134 "quit" +#message 135 "show.mem" +#message 136 "pause" +#message 137 "echo.line" +#message 138 "cancel.line" +#message 139 "init.joy" +#message 140 "toggle.monitor" +#message 141 "version" +#message 142 "script.size" +#message 143 "set.game.id" +#message 144 "log" +#message 145 "set.scan.start" +#message 146 "reset.scan.start" +#message 147 "reposition.to" +#message 148 "reposition.to.v" +#message 149 "trace.on" +#message 150 "trace.info" +#message 151 "print.at" +#message 152 "print.at.v" +#message 153 "discard.view.v" +#message 154 "clear.text.rect" +#message 155 "set.upper.left" +#message 156 "set.menu" +#message 157 "set.menu.item" +#message 158 "submit.menu" +#message 159 "enable.item" +#message 160 "disable.item" +#message 161 "menu.input" +#message 162 "show.obj.v" +#message 163 "open.dialogue" +#message 164 "close.dialogue" +#message 165 "mul.n" +#message 166 "mul.v" +#message 167 "div.n" +#message 168 "div.v" +#message 169 "close.window" +#message 221 "equaln" +#message 222 "equalv" +#message 223 "lessn" +#message 224 "lessv" +#message 225 "greatern" +#message 226 "greaterv" +#message 227 "isset" +#message 228 "isset.v" +#message 229 "has" +#message 230 "obj.in.room" +#message 231 "posn" +#message 232 "controller" +#message 233 "have.key" +#message 234 "said" +#message 235 "compare.strings" +#message 236 "obj.in.box" +#message 237 "center.posn" +#message 238 "right.posn" diff --git a/template/src/logic98.txt b/template/src/logic98.txt new file mode 100644 index 0000000..003403c --- /dev/null +++ b/template/src/logic98.txt @@ -0,0 +1,36 @@ +print.v(v17); +quit(1); +return(); + +// Messages (all messages are here) +#message 1 "discard.view(%v18):%m30" +#message 2 "set.view(%v18,_):%m26" +#message 3 "set.view(_,%v18):%m30" +#message 4 "set.loop(%v18,_):%m26" +#message 5 "set.loop(%v18,_):\nBad loop #.%m25" +#message 6 "set.loop(%v18,_):%m31" +#message 7 "set.cel(%v18,_):%m26" +#message 8 "set.cel(%v18,_):\nBad cel #.%m25" +#message 9 "sound(%v18):\nSound not loaded.%m25" +#message 10 "set.cel(%v18,_):%m31" +#message 11 "Script buffer overflow.\nMaximum size = %v18%m25" +#message 12 "erase(%v18):%m26" +#message 13 "animate.obj(%v18):%m26" +#message 14 "stop.update(%v18):%m28" +#message 15 "Bad test: %v18%m25" +#message 16 "Bad action: %v18%m25" +#message 17 "start.update(%v18):%m28" +#message 18 "draw.pic(%v18):%m32" +#message 19 "draw(%v18):%m26" +#message 20 "draw(%v18):%m31" +#message 21 "discard.pic(%v18):%m32" +#message 22 "" +#message 23 "get(%v18) or put(%v18):%m26" +#message 25 "\nPress ESC to quit." +#message 26 "%m27.%m25" +#message 27 "\nBad object number" +#message 28 "%m27 or object not drawn.%m25" +#message 29 "\nView not " +#message 30 "%m29loaded.%m25" +#message 31 "%m29set.%m25" +#message 32 "Picture not loaded.%m25" diff --git a/template/src/logic99.txt b/template/src/logic99.txt new file mode 100644 index 0000000..cc6ed1b --- /dev/null +++ b/template/src/logic99.txt @@ -0,0 +1,135 @@ +// **************************************************************************** +// +// Logic 99: Debug mode +// +// **************************************************************************** + +#include "defines.txt" + +if (said("debug", "help")) { + call(93); +} + +if (said("trace", "on")) { + set(trace_enabled); +} + +if (said("show", "mem")) { + show.mem(); +} + +if (said("tp")) { + get.num("new room: ", v255); + new.room.v(v255); +} + +if (said("pos")) { + get.num("x: ", v254); + get.num("y: ", v255); + erase(ego); + reposition.to.v(ego, v254, v255); + draw(ego); +} + +if (said("show", "var")) { + get.num("var number: ", v255); + v254 = *v255; + print("var %v255: %v254"); +} + +if (said("set", "var")) { + get.num("var number: ", v254); + get.num("var value: ", v255); + *v254 = v255; +} + +if (said("show", "flag")) { + get.num("flag number: ", v255); + if (issetv(v255)) { + print("flag %v255 is set"); + } + else { + print("flag %v255 is not set"); + } +} + +if (said("set", "flag")) { + get.num("flag number: ", v255); + set.v(v255); +} + +if (said("reset", "flag")) { + get.num("flag number: ", v255); + reset.v(v255); +} + +if (said("object")) { + get.num("object #: ", v255); + obj.status.v(v255); +} + +if (said("show", "pri")) { + show.pri.screen(); +} + +if (said("get", "object")) { + get.num("object number: ", v255); + if (v255 > num_invobjects) { + print("Invalid object number!"); + } + else { + get.v(v255); + } +} + +if (said("gimme", "gimme")) { + print("You gottum!"); + v255 = 0; +GetNextObject: + get.v(v255); + if (v255 < num_invobjects) { + v255++; + goto(GetNextObject); + } +} + +if (said("object", "room")) { + get.num("Object number: ", v255); + if (v255 > num_invobjects) { + print("Invalid object number!"); + } + else { + get.room.v(v255,v254); + if (v254 == 255) { + print("Object %v255 is in your inventory."); + } + else { + print("Object %v255 is in room %v254."); + } + } +} + +if (said("set", "pri")) { + get.num("New priority: ",v255); + set.priority.v(ego,v255); +} + +if (said("release", "pri")) { + release.priority(ego); +} + +if (said("coords")) { + toggle(coords_shown); + if (!coords_shown) { + clear.lines(24,24,0); + } +} + +if (coords_shown) { + get.posn(ego, v253, v254); + get.priority(ego,v255); + display(23,15,"Rm %v0|3 Pri %v255|2 x:%v253|3 y:%v254|3"); +} + +return(); + diff --git a/template/src/newroom.txt b/template/src/newroom.txt new file mode 100644 index 0000000..6c17c57 --- /dev/null +++ b/template/src/newroom.txt @@ -0,0 +1,35 @@ +// **************************************************************************** +// +// Logic *: new room +// +// **************************************************************************** +#include "defines.txt" +if (new_room) { + load.pic(room_no); + draw.pic(room_no); + discard.pic(room_no); + set.horizon(50); +// Check what room the player came from and position them on the +// screen accordingly here, e.g: +// if (prev_room_no == 5) { +// position(ego,12,140); +// } + draw(ego); + show.pic(); +} +if (said("look")) { + print("This is an empty room."); +} +if (ego_edge_code == horizon_edge) { // ego touching horizon + new.room(2); +} +if (ego_edge_code == right_edge) { // ego touching right edge of screen + new.room(2); +} +if (ego_edge_code == bottom_edge) { // ego touching bottom edge of screen + new.room(2); +} +if (ego_edge_code == left_edge) { // ego touching left edge of screen + new.room(2); +} +return(); diff --git a/template/viewdir b/template/viewdir new file mode 100644 index 0000000000000000000000000000000000000000..d4c77e766d89fa6af4bd0c8a02e6835b8c75026b GIT binary patch literal 666 ecmZS36JW52Ww4m{e-w;{z~Bf01_yNp$20(T(2Gj| literal 0 HcmV?d00001 diff --git a/template/vol.0 b/template/vol.0 new file mode 100644 index 0000000000000000000000000000000000000000..d5686cfe3e0c31355db33f715d6d195eab054830 GIT binary patch literal 16799 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 wofNw-wO=1YJwA|2b>?p<#