diff options
author | Paul Gilbert | 2018-11-11 21:18:50 -0800 |
---|---|---|
committer | Paul Gilbert | 2018-12-08 19:05:59 -0800 |
commit | a083eb3d5ca682a0b465d383413f62ff38b8e814 (patch) | |
tree | b31a455c695ddfe2f68eb8d237e3cbd09281e10e /engines/gargoyle/frotz/processor_objects.cpp | |
parent | 38a458139aef488acf48abfcf61233c529984cb1 (diff) | |
download | scummvm-rg350-a083eb3d5ca682a0b465d383413f62ff38b8e814.tar.gz scummvm-rg350-a083eb3d5ca682a0b465d383413f62ff38b8e814.tar.bz2 scummvm-rg350-a083eb3d5ca682a0b465d383413f62ff38b8e814.zip |
GLK: FROTZ: Added bulk of game processor
Diffstat (limited to 'engines/gargoyle/frotz/processor_objects.cpp')
-rw-r--r-- | engines/gargoyle/frotz/processor_objects.cpp | 735 |
1 files changed, 735 insertions, 0 deletions
diff --git a/engines/gargoyle/frotz/processor_objects.cpp b/engines/gargoyle/frotz/processor_objects.cpp new file mode 100644 index 0000000000..3d2b17162d --- /dev/null +++ b/engines/gargoyle/frotz/processor_objects.cpp @@ -0,0 +1,735 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "gargoyle/frotz/processor.h" + +namespace Gargoyle { +namespace Frotz { + +// TODO: Method stubs to implement +static void new_line() {} + +#define MAX_OBJECT 2000 + +enum O1 { + O1_PARENT = 4, + O1_SIBLING = 5, + O1_CHILD = 6, + O1_PROPERTY_OFFSET = 7, + O1_SIZE = 9 +}; + +enum O4 { + O4_PARENT = 6, + O4_SIBLING = 8, + O4_CHILD = 10, + O4_PROPERTY_OFFSET = 12, + O4_SIZE = 14 +}; + +zword Processor::object_address(zword obj) { + // Check object number + if (obj > ((h_version <= V3) ? 255 : MAX_OBJECT)) { + print_string("@Attempt to address illegal object "); + print_num(obj); + print_string(". This is normally fatal."); + new_line(); + runtimeError(ERR_ILL_OBJ); + } + + // Return object address + if (h_version <= V3) + return h_objects + ((obj - 1) * O1_SIZE + 62); + else + return h_objects + ((obj - 1) * O4_SIZE + 126); +} + +zword Processor::object_name(zword object) { + zword obj_addr; + zword name_addr; + + obj_addr = object_address(object); + + // The object name address is found at the start of the properties + if (h_version <= V3) + obj_addr += O1_PROPERTY_OFFSET; + else + obj_addr += O4_PROPERTY_OFFSET; + + LOW_WORD(obj_addr, name_addr); + + return name_addr; +} + +zword Processor::first_property(zword obj) { + zword prop_addr; + zbyte size; + + // Fetch address of object name + prop_addr = object_name (obj); + + // Get length of object name + LOW_BYTE(prop_addr, size); + + // Add name length to pointer + return prop_addr + 1 + 2 * size; +} + +zword Processor::next_property(zword prop_addr) { + zbyte value; + + // Load the current property id + LOW_BYTE(prop_addr, value); + prop_addr++; + + // Calculate the length of this property + if (h_version <= V3) + value >>= 5; + else if (!(value & 0x80)) + value >>= 6; + else { + LOW_BYTE(prop_addr, value); + value &= 0x3f; + + if (value == 0) + // demanded by Spec 1.0 + value = 64; + } + + // Add property length to current property pointer + return prop_addr + value + 1; +} + +void Processor::unlink_object(zword object) { + zword obj_addr; + zword parent_addr; + zword sibling_addr; + + if (object == 0) { + runtimeError(ERR_REMOVE_OBJECT_0); + return; + } + + obj_addr = object_address(object); + + if (h_version <= V3) { + + zbyte parent; + zbyte younger_sibling; + zbyte older_sibling; + zbyte zero = 0; + + // Get parent of object, and return if no parent + obj_addr += O1_PARENT; + LOW_BYTE(obj_addr, parent); + if (!parent) + return; + + // Get (older) sibling of object and set both parent and sibling pointers to 0 + SET_BYTE(obj_addr, zero); + obj_addr += O1_SIBLING - O1_PARENT; + LOW_BYTE(obj_addr, older_sibling); + SET_BYTE(obj_addr, zero); + + // Get first child of parent (the youngest sibling of the object) + parent_addr = object_address(parent) + O1_CHILD; + LOW_BYTE(parent_addr, younger_sibling); + + // Remove object from the list of siblings + if (younger_sibling == object) + SET_BYTE(parent_addr, older_sibling); + else { + do { + sibling_addr = object_address(younger_sibling) + O1_SIBLING; + LOW_BYTE(sibling_addr, younger_sibling); + } while (younger_sibling != object); + SET_BYTE(sibling_addr, older_sibling); + } + } else { + zword parent; + zword younger_sibling; + zword older_sibling; + zword zero = 0; + + // Get parent of object, and return if no parent + obj_addr += O4_PARENT; + LOW_WORD(obj_addr, parent); + if (!parent) + return; + + // Get (older) sibling of object and set both parent and sibling pointers to 0 + SET_WORD(obj_addr, zero); + obj_addr += O4_SIBLING - O4_PARENT; + LOW_WORD(obj_addr, older_sibling); + SET_WORD(obj_addr, zero); + + // Get first child of parent (the youngest sibling of the object) + parent_addr = object_address(parent) + O4_CHILD; + LOW_WORD(parent_addr, younger_sibling); + + // Remove object from the list of siblings + if (younger_sibling == object) { + SET_WORD(parent_addr, older_sibling); + } else { + do { + sibling_addr = object_address(younger_sibling) + O4_SIBLING; + LOW_WORD(sibling_addr, younger_sibling); + } while (younger_sibling != object); + SET_WORD(sibling_addr, older_sibling); + } + } +} + +void Processor::z_clear_attr() { + zword obj_addr; + zbyte value; + + if (_storyId == SHERLOCK) + if (zargs[1] == 48) + return; + + if (zargs[1] > ((h_version <= V3) ? 31 : 47)) + runtimeError(ERR_ILL_ATTR); + + // If we are monitoring attribute assignment display a short note + if (_attribute_assignment) { + stream_mssg_on(); + print_string("@clear_attr "); + print_object(zargs[0]); + print_string(" "); + print_num(zargs[1]); + stream_mssg_off(); + } + + if (zargs[0] == 0) { + runtimeError(ERR_CLEAR_ATTR_0); + return; + } + + // Get attribute address + obj_addr = object_address(zargs[0]) + zargs[1] / 8; + + // Clear attribute bit + LOW_BYTE(obj_addr, value); + value &= ~(0x80 >> (zargs[1] & 7)); + SET_BYTE(obj_addr, value); +} + +void Processor::z_jin() { + zword obj_addr; + + // If we are monitoring object locating display a short note + if (_object_locating) { + stream_mssg_on(); + print_string("@jin "); + print_object(zargs[0]); + print_string(" "); + print_object(zargs[1]); + stream_mssg_off(); + } + + if (zargs[0] == 0) { + runtimeError(ERR_JIN_0); + branch(0 == zargs[1]); + return; + } + + obj_addr = object_address(zargs[0]); + + if (h_version <= V3) { + zbyte parent; + + // Get parent id from object + obj_addr += O1_PARENT; + LOW_BYTE(obj_addr, parent); + + // Branch if the parent is obj2 + branch(parent == zargs[1]); + + } else { + zword parent; + + // Get parent id from object + obj_addr += O4_PARENT; + LOW_WORD(obj_addr, parent); + + // Branch if the parent is obj2 + branch(parent == zargs[1]); + } +} + +void Processor::z_get_child() { + zword obj_addr; + + // If we are monitoring object locating display a short note + if (_object_locating) { + stream_mssg_on(); + print_string("@get_child "); + print_object(zargs[0]); + stream_mssg_off(); + } + + if (zargs[0] == 0) { + runtimeError(ERR_GET_CHILD_0); + store(0); + branch(false); + return; + } + + obj_addr = object_address(zargs[0]); + + if (h_version <= V3) { + zbyte child; + + // Get child id from object + obj_addr += O1_CHILD; + LOW_BYTE(obj_addr, child); + + // Store child id and branch + store(child); + branch(child); + } else { + zword child; + + // Get child id from object + obj_addr += O4_CHILD; + LOW_WORD(obj_addr, child); + + // Store child id and branch + store(child); + branch(child); + } +} + +void Processor::z_get_next_prop() { + zword prop_addr; + zbyte value; + zbyte mask; + + if (zargs[0] == 0) { + runtimeError(ERR_GET_NEXT_PROP_0); + store(0); + return; + } + + // Property id is in bottom five (six) bits + mask = (h_version <= V3) ? 0x1f : 0x3f; + + // Load address of first property + prop_addr = first_property(zargs[0]); + + if (zargs[1] != 0) { + // Scan down the property list + do { + LOW_BYTE(prop_addr, value); + prop_addr = next_property(prop_addr); + } while ((value & mask) > zargs[1]); + + // Exit if the property does not exist + if ((value & mask) != zargs[1]) + runtimeError(ERR_NO_PROP); + } + + // Return the property id + LOW_BYTE(prop_addr, value); + store((zword) (value & mask)); +} + +void Processor::z_get_parent() { + zword obj_addr; + + // If we are monitoring object locating display a short note + if (_object_locating) { + stream_mssg_on(); + print_string("@get_parent "); + print_object(zargs[0]); + stream_mssg_off(); + } + + if (zargs[0] == 0) { + runtimeError(ERR_GET_PARENT_0); + store(0); + return; + } + + obj_addr = object_address(zargs[0]); + + if (h_version <= V3) { + zbyte parent; + + // Get parent id from object + obj_addr += O1_PARENT; + LOW_BYTE(obj_addr, parent); + + // Store parent + store(parent); + + } else { + zword parent; + + // Get parent id from object + obj_addr += O4_PARENT; + LOW_WORD(obj_addr, parent); + + // Store parent + store(parent); + } +} + +void Processor::z_get_prop() { + zword prop_addr; + zword wprop_val; + zbyte bprop_val; + zbyte value; + zbyte mask; + + if (zargs[0] == 0) { + runtimeError(ERR_GET_PROP_0); + store(0); + return; + } + + // Property id is in bottom five (six) bits + mask = (h_version <= V3) ? 0x1f : 0x3f; + + // Load address of first property + prop_addr = first_property(zargs[0]); + + // Scan down the property list + for (;;) { + LOW_BYTE(prop_addr, value); + if ((value & mask) <= zargs[1]) + break; + prop_addr = next_property(prop_addr); + } + + if ((value & mask) == zargs[1]) { + // property found + + // Load property(byte or word sized) + prop_addr++; + + if ((h_version <= V3 && !(value & 0xe0)) || (h_version >= V4 && !(value & 0xc0))) { + LOW_BYTE(prop_addr, bprop_val); + wprop_val = bprop_val; + } else { + LOW_WORD(prop_addr, wprop_val); + } + } else { + // property not found + + // Load default value + prop_addr = h_objects + 2 * (zargs[1] - 1); + LOW_WORD(prop_addr, wprop_val); + } + + // Store the property value + store(wprop_val); +} + +void Processor::z_get_prop_addr() { + zword prop_addr; + zbyte value; + zbyte mask; + + if (zargs[0] == 0) { + runtimeError(ERR_GET_PROP_ADDR_0); + store(0); + return; + } + + if (_storyId == BEYOND_ZORK) + if (zargs[0] > MAX_OBJECT) + { store(0); return; } + + // Property id is in bottom five (six) bits + mask = (h_version <= V3) ? 0x1f : 0x3f; + + // Load address of first property + prop_addr = first_property(zargs[0]); + + // Scan down the property list + for (;;) { + LOW_BYTE(prop_addr, value); + if ((value & mask) <= zargs[1]) + break; + prop_addr = next_property(prop_addr); + } + + // Calculate the property address or return zero + if ((value & mask) == zargs[1]) { + + if (h_version >= V4 && (value & 0x80)) + prop_addr++; + store((zword) (prop_addr + 1)); + + } else { + store(0); + } +} + +void Processor::z_get_prop_len() { + zword addr; + zbyte value; + + // Back up the property pointer to the property id + addr = zargs[0] - 1; + LOW_BYTE(addr, value); + + // Calculate length of property + if (h_version <= V3) + value = (value >> 5) + 1; + else if (!(value & 0x80)) + value = (value >> 6) + 1; + else { + value &= 0x3f; + + if (value == 0) + value = 64; // demanded by Spec 1.0 + } + + // Store length of property + store(value); +} + +void Processor::z_get_sibling() { + zword obj_addr; + + if (zargs[0] == 0) { + runtimeError(ERR_GET_SIBLING_0); + store(0); + branch(false); + return; + } + + obj_addr = object_address(zargs[0]); + + if (h_version <= V3) { + zbyte sibling; + + // Get sibling id from object + obj_addr += O1_SIBLING; + LOW_BYTE(obj_addr, sibling); + + // Store sibling and branch + store(sibling); + branch(sibling); + + } else { + zword sibling; + + // Get sibling id from object + obj_addr += O4_SIBLING; + LOW_WORD(obj_addr, sibling); + + // Store sibling and branch + store(sibling); + branch(sibling); + } +} + +void Processor::z_insert_obj() { + zword obj1 = zargs[0]; + zword obj2 = zargs[1]; + zword obj1_addr; + zword obj2_addr; + + // If we are monitoring object movements display a short note + if (_object_movement) { + stream_mssg_on(); + print_string("@move_obj "); + print_object(obj1); + print_string(" "); + print_object(obj2); + stream_mssg_off(); + } + + if (obj1 == 0) { + runtimeError(ERR_MOVE_OBJECT_0); + return; + } + + if (obj2 == 0) { + runtimeError(ERR_MOVE_OBJECT_TO_0); + return; + } + + // Get addresses of both objects + obj1_addr = object_address(obj1); + obj2_addr = object_address(obj2); + + // Remove object 1 from current parent + unlink_object(obj1); + + // Make object 1 first child of object 2 + if (h_version <= V3) { + zbyte child; + + obj1_addr += O1_PARENT; + SET_BYTE(obj1_addr, obj2); + obj2_addr += O1_CHILD; + LOW_BYTE(obj2_addr, child); + SET_BYTE(obj2_addr, obj1); + obj1_addr += O1_SIBLING - O1_PARENT; + SET_BYTE(obj1_addr, child); + + } else { + zword child; + + obj1_addr += O4_PARENT; + SET_WORD(obj1_addr, obj2); + obj2_addr += O4_CHILD; + LOW_WORD(obj2_addr, child); + SET_WORD(obj2_addr, obj1); + obj1_addr += O4_SIBLING - O4_PARENT; + SET_WORD(obj1_addr, child); + } +} + +void Processor::z_put_prop() { + zword prop_addr; + zword value; + zbyte mask; + + if (zargs[0] == 0) { + runtimeError(ERR_PUT_PROP_0); + return; + } + + // Property id is in bottom five or six bits + mask = (h_version <= V3) ? 0x1f : 0x3f; + + // Load address of first property + prop_addr = first_property(zargs[0]); + + // Scan down the property list + for (;;) { + LOW_BYTE(prop_addr, value); + if ((value & mask) <= zargs[1]) + break; + + prop_addr = next_property(prop_addr); + } + + // Exit if the property does not exist + if ((value & mask) != zargs[1]) + runtimeError(ERR_NO_PROP); + + // Store the new property value (byte or word sized) + prop_addr++; + + if ((h_version <= V3 && !(value & 0xe0)) || (h_version >= V4 && !(value & 0xc0))) { + zbyte v = zargs[2]; + SET_BYTE(prop_addr, v); + } else { + zword v = zargs[2]; + SET_WORD(prop_addr, v); + } +} + +void Processor::z_remove_obj() { + // If we are monitoring object movements display a short note + if (_object_movement) { + stream_mssg_on(); + print_string("@remove_obj "); + print_object(zargs[0]); + stream_mssg_off(); + } + + // Call unlink_object to do the job + unlink_object(zargs[0]); +} + +void Processor::z_set_attr() { + zword obj_addr; + zbyte value; + + if (_storyId == SHERLOCK) + if (zargs[1] == 48) + return; + + if (zargs[1] > ((h_version <= V3) ? 31 : 47)) + runtimeError(ERR_ILL_ATTR); + + // If we are monitoring attribute assignment display a short note + if (_attribute_assignment) { + stream_mssg_on(); + print_string("@set_attr "); + print_object(zargs[0]); + print_string(" "); + print_num(zargs[1]); + stream_mssg_off(); + } + + if (zargs[0] == 0) { + runtimeError(ERR_SET_ATTR_0); + return; + } + + // Get attribute address + obj_addr = object_address(zargs[0]) + zargs[1] / 8; + + // Load attribute byte + LOW_BYTE(obj_addr, value); + + // Set attribute bit + value |= 0x80 >> (zargs[1] & 7); + + // Store attribute byte + SET_BYTE(obj_addr, value); +} + +void Processor::z_test_attr() { + zword obj_addr; + zbyte value; + + if (zargs[1] > ((h_version <= V3) ? 31 : 47)) + runtimeError(ERR_ILL_ATTR); + + // If we are monitoring attribute testing display a short note + if (_attribute_testing) { + stream_mssg_on(); + print_string("@test_attr "); + print_object(zargs[0]); + print_string(" "); + print_num(zargs[1]); + stream_mssg_off(); + } + + if (zargs[0] == 0) { + runtimeError(ERR_TEST_ATTR_0); + branch(false); + return; + } + + // Get attribute address + obj_addr = object_address(zargs[0]) + zargs[1] / 8; + + // Load attribute byte + LOW_BYTE(obj_addr, value); + + // Test attribute + branch(value & (0x80 >> (zargs[1] & 7))); +} + +} // End of namespace Scott +} // End of namespace Gargoyle |