1 /* object.c - Object manipulation opcodes
2 * Copyright (c) 1995-1997 Stefan Jokisch
4 * This file is part of Frotz.
6 * Frotz is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Frotz is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
23 #define MAX_OBJECT 2000
28 #define O1_PROPERTY_OFFSET 7
34 #define O4_PROPERTY_OFFSET 12
40 * Calculate the address of an object.
44 static zword object_address (zword obj)
46 /* zchar obj_num[10]; */
48 /* Check object number */
50 if (obj > ((h_version <= V3) ? 255 : MAX_OBJECT)) {
51 print_string("@Attempt to address illegal object ");
53 print_string(". This is normally fatal.");
55 runtime_error (ERR_ILL_OBJ);
58 /* Return object address */
61 return h_objects + ((obj - 1) * O1_SIZE + 62);
63 return h_objects + ((obj - 1) * O4_SIZE + 126);
70 * Return the address of the given object's name.
74 zword object_name (zword object)
79 obj_addr = object_address (object);
81 /* The object name address is found at the start of the properties */
84 obj_addr += O1_PROPERTY_OFFSET;
86 obj_addr += O4_PROPERTY_OFFSET;
88 LOW_WORD (obj_addr, name_addr)
97 * Calculate the start address of the property list associated with
102 static zword first_property (zword obj)
107 /* Fetch address of object name */
109 prop_addr = object_name (obj);
111 /* Get length of object name */
113 LOW_BYTE (prop_addr, size)
115 /* Add name length to pointer */
117 return prop_addr + 1 + 2 * size;
119 }/* first_property */
124 * Calculate the address of the next property in a property list.
128 static zword next_property (zword prop_addr)
132 /* Load the current property id */
134 LOW_BYTE (prop_addr, value)
137 /* Calculate the length of this property */
141 else if (!(value & 0x80))
145 LOW_BYTE (prop_addr, value)
148 if (value == 0) value = 64; /* demanded by Spec 1.0 */
152 /* Add property length to current property pointer */
154 return prop_addr + value + 1;
161 * Unlink an object from its parent and siblings.
165 static void unlink_object (zword object)
172 runtime_error (ERR_REMOVE_OBJECT_0);
176 obj_addr = object_address (object);
178 if (h_version <= V3) {
181 zbyte younger_sibling;
185 /* Get parent of object, and return if no parent */
187 obj_addr += O1_PARENT;
188 LOW_BYTE (obj_addr, parent)
192 /* Get (older) sibling of object and set both parent and sibling
195 SET_BYTE (obj_addr, zero)
196 obj_addr += O1_SIBLING - O1_PARENT;
197 LOW_BYTE (obj_addr, older_sibling)
198 SET_BYTE (obj_addr, zero)
200 /* Get first child of parent (the youngest sibling of the object) */
202 parent_addr = object_address (parent) + O1_CHILD;
203 LOW_BYTE (parent_addr, younger_sibling)
205 /* Remove object from the list of siblings */
207 if (younger_sibling == object)
208 SET_BYTE (parent_addr, older_sibling)
211 sibling_addr = object_address (younger_sibling) + O1_SIBLING;
212 LOW_BYTE (sibling_addr, younger_sibling)
213 } while (younger_sibling != object);
214 SET_BYTE (sibling_addr, older_sibling)
220 zword younger_sibling;
224 /* Get parent of object, and return if no parent */
226 obj_addr += O4_PARENT;
227 LOW_WORD (obj_addr, parent)
231 /* Get (older) sibling of object and set both parent and sibling
234 SET_WORD (obj_addr, zero)
235 obj_addr += O4_SIBLING - O4_PARENT;
236 LOW_WORD (obj_addr, older_sibling)
237 SET_WORD (obj_addr, zero)
239 /* Get first child of parent (the youngest sibling of the object) */
241 parent_addr = object_address (parent) + O4_CHILD;
242 LOW_WORD (parent_addr, younger_sibling)
244 /* Remove object from the list of siblings */
246 if (younger_sibling == object)
247 SET_WORD (parent_addr, older_sibling)
250 sibling_addr = object_address (younger_sibling) + O4_SIBLING;
251 LOW_WORD (sibling_addr, younger_sibling)
252 } while (younger_sibling != object);
253 SET_WORD (sibling_addr, older_sibling)
261 * z_clear_attr, clear an object attribute.
264 * zargs[1] = number of attribute to be cleared
268 void z_clear_attr (void)
273 if (story_id == SHERLOCK)
277 if (zargs[1] > ((h_version <= V3) ? 31 : 47))
278 runtime_error (ERR_ILL_ATTR);
280 /* If we are monitoring attribute assignment display a short note */
282 if (f_setup.attribute_assignment) {
284 print_string ("@clear_attr ");
285 print_object (zargs[0]);
287 print_num (zargs[1]);
292 runtime_error (ERR_CLEAR_ATTR_0);
296 /* Get attribute address */
298 obj_addr = object_address (zargs[0]) + zargs[1] / 8;
300 /* Clear attribute bit */
302 LOW_BYTE (obj_addr, value)
303 value &= ~(0x80 >> (zargs[1] & 7));
304 SET_BYTE (obj_addr, value)
309 * z_jin, branch if the first object is inside the second.
311 * zargs[0] = first object
312 * zargs[1] = second object
320 /* If we are monitoring object locating display a short note */
322 if (f_setup.object_locating) {
324 print_string ("@jin ");
325 print_object (zargs[0]);
327 print_object (zargs[1]);
332 runtime_error (ERR_JIN_0);
333 branch (0 == zargs[1]);
337 obj_addr = object_address (zargs[0]);
339 if (h_version <= V3) {
343 /* Get parent id from object */
345 obj_addr += O1_PARENT;
346 LOW_BYTE (obj_addr, parent)
348 /* Branch if the parent is obj2 */
350 branch (parent == zargs[1]);
356 /* Get parent id from object */
358 obj_addr += O4_PARENT;
359 LOW_WORD (obj_addr, parent)
361 /* Branch if the parent is obj2 */
363 branch (parent == zargs[1]);
370 * z_get_child, store the child of an object.
376 void z_get_child (void)
380 /* If we are monitoring object locating display a short note */
382 if (f_setup.object_locating) {
384 print_string ("@get_child ");
385 print_object (zargs[0]);
390 runtime_error (ERR_GET_CHILD_0);
396 obj_addr = object_address (zargs[0]);
398 if (h_version <= V3) {
402 /* Get child id from object */
404 obj_addr += O1_CHILD;
405 LOW_BYTE (obj_addr, child)
407 /* Store child id and branch */
416 /* Get child id from object */
418 obj_addr += O4_CHILD;
419 LOW_WORD (obj_addr, child)
421 /* Store child id and branch */
431 * z_get_next_prop, store the number of the first or next property.
434 * zargs[1] = address of current property (0 gets the first property)
438 void z_get_next_prop (void)
445 runtime_error (ERR_GET_NEXT_PROP_0);
450 /* Property id is in bottom five (six) bits */
452 mask = (h_version <= V3) ? 0x1f : 0x3f;
454 /* Load address of first property */
456 prop_addr = first_property (zargs[0]);
460 /* Scan down the property list */
463 LOW_BYTE (prop_addr, value)
464 prop_addr = next_property (prop_addr);
465 } while ((value & mask) > zargs[1]);
467 /* Exit if the property does not exist */
469 if ((value & mask) != zargs[1])
470 runtime_error (ERR_NO_PROP);
474 /* Return the property id */
476 LOW_BYTE (prop_addr, value)
477 store ((zword) (value & mask));
479 }/* z_get_next_prop */
482 * z_get_parent, store the parent of an object.
488 void z_get_parent (void)
492 /* If we are monitoring object locating display a short note */
494 if (f_setup.object_locating) {
496 print_string ("@get_parent ");
497 print_object (zargs[0]);
502 runtime_error (ERR_GET_PARENT_0);
507 obj_addr = object_address (zargs[0]);
509 if (h_version <= V3) {
513 /* Get parent id from object */
515 obj_addr += O1_PARENT;
516 LOW_BYTE (obj_addr, parent)
526 /* Get parent id from object */
528 obj_addr += O4_PARENT;
529 LOW_WORD (obj_addr, parent)
540 * z_get_prop, store the value of an object property.
543 * zargs[1] = number of property to be examined
547 void z_get_prop (void)
556 runtime_error (ERR_GET_PROP_0);
561 /* Property id is in bottom five (six) bits */
563 mask = (h_version <= V3) ? 0x1f : 0x3f;
565 /* Load address of first property */
567 prop_addr = first_property (zargs[0]);
569 /* Scan down the property list */
572 LOW_BYTE (prop_addr, value)
573 if ((value & mask) <= zargs[1])
575 prop_addr = next_property (prop_addr);
578 if ((value & mask) == zargs[1]) { /* property found */
580 /* Load property (byte or word sized) */
584 if ((h_version <= V3 && !(value & 0xe0)) || (h_version >= V4 && !(value & 0xc0))) {
586 LOW_BYTE (prop_addr, bprop_val)
587 wprop_val = bprop_val;
589 } else LOW_WORD (prop_addr, wprop_val)
591 } else { /* property not found */
593 /* Load default value */
595 prop_addr = h_objects + 2 * (zargs[1] - 1);
596 LOW_WORD (prop_addr, wprop_val)
600 /* Store the property value */
607 * z_get_prop_addr, store the address of an object property.
610 * zargs[1] = number of property to be examined
614 void z_get_prop_addr (void)
621 runtime_error (ERR_GET_PROP_ADDR_0);
626 if (story_id == BEYOND_ZORK)
627 if (zargs[0] > MAX_OBJECT)
628 { store (0); return; }
630 /* Property id is in bottom five (six) bits */
632 mask = (h_version <= V3) ? 0x1f : 0x3f;
634 /* Load address of first property */
636 prop_addr = first_property (zargs[0]);
638 /* Scan down the property list */
641 LOW_BYTE (prop_addr, value)
642 if ((value & mask) <= zargs[1])
644 prop_addr = next_property (prop_addr);
647 /* Calculate the property address or return zero */
649 if ((value & mask) == zargs[1]) {
651 if (h_version >= V4 && (value & 0x80))
653 store ((zword) (prop_addr + 1));
657 }/* z_get_prop_addr */
660 * z_get_prop_len, store the length of an object property.
662 * zargs[0] = address of property to be examined
666 void z_get_prop_len (void)
671 /* Back up the property pointer to the property id */
674 LOW_BYTE (addr, value)
676 /* Calculate length of property */
679 value = (value >> 5) + 1;
680 else if (!(value & 0x80))
681 value = (value >> 6) + 1;
686 if (value == 0) value = 64; /* demanded by Spec 1.0 */
690 /* Store length of property */
694 }/* z_get_prop_len */
697 * z_get_sibling, store the sibling of an object.
703 void z_get_sibling (void)
708 runtime_error (ERR_GET_SIBLING_0);
714 obj_addr = object_address (zargs[0]);
716 if (h_version <= V3) {
720 /* Get sibling id from object */
722 obj_addr += O1_SIBLING;
723 LOW_BYTE (obj_addr, sibling)
725 /* Store sibling and branch */
734 /* Get sibling id from object */
736 obj_addr += O4_SIBLING;
737 LOW_WORD (obj_addr, sibling)
739 /* Store sibling and branch */
749 * z_insert_obj, make an object the first child of another object.
751 * zargs[0] = object to be moved
752 * zargs[1] = destination object
756 void z_insert_obj (void)
758 zword obj1 = zargs[0];
759 zword obj2 = zargs[1];
763 /* If we are monitoring object movements display a short note */
765 if (f_setup.object_movement) {
767 print_string ("@move_obj ");
775 runtime_error (ERR_MOVE_OBJECT_0);
780 runtime_error (ERR_MOVE_OBJECT_TO_0);
784 /* Get addresses of both objects */
786 obj1_addr = object_address (obj1);
787 obj2_addr = object_address (obj2);
789 /* Remove object 1 from current parent */
791 unlink_object (obj1);
793 /* Make object 1 first child of object 2 */
795 if (h_version <= V3) {
799 obj1_addr += O1_PARENT;
800 SET_BYTE (obj1_addr, obj2)
801 obj2_addr += O1_CHILD;
802 LOW_BYTE (obj2_addr, child)
803 SET_BYTE (obj2_addr, obj1)
804 obj1_addr += O1_SIBLING - O1_PARENT;
805 SET_BYTE (obj1_addr, child)
811 obj1_addr += O4_PARENT;
812 SET_WORD (obj1_addr, obj2)
813 obj2_addr += O4_CHILD;
814 LOW_WORD (obj2_addr, child)
815 SET_WORD (obj2_addr, obj1)
816 obj1_addr += O4_SIBLING - O4_PARENT;
817 SET_WORD (obj1_addr, child)
824 * z_put_prop, set the value of an object property.
827 * zargs[1] = number of property to set
828 * zargs[2] = value to set property to
832 void z_put_prop (void)
839 runtime_error (ERR_PUT_PROP_0);
843 /* Property id is in bottom five or six bits */
845 mask = (h_version <= V3) ? 0x1f : 0x3f;
847 /* Load address of first property */
849 prop_addr = first_property (zargs[0]);
851 /* Scan down the property list */
854 LOW_BYTE (prop_addr, value)
855 if ((value & mask) <= zargs[1])
857 prop_addr = next_property (prop_addr);
860 /* Exit if the property does not exist */
862 if ((value & mask) != zargs[1])
863 runtime_error (ERR_NO_PROP);
865 /* Store the new property value (byte or word sized) */
869 if ((h_version <= V3 && !(value & 0xe0)) || (h_version >= V4 && !(value & 0xc0))) {
871 SET_BYTE (prop_addr, v)
874 SET_WORD (prop_addr, v)
880 * z_remove_obj, unlink an object from its parent and siblings.
886 void z_remove_obj (void)
889 /* If we are monitoring object movements display a short note */
891 if (f_setup.object_movement) {
893 print_string ("@remove_obj ");
894 print_object (zargs[0]);
898 /* Call unlink_object to do the job */
900 unlink_object (zargs[0]);
905 * z_set_attr, set an object attribute.
908 * zargs[1] = number of attribute to set
912 void z_set_attr (void)
917 if (story_id == SHERLOCK)
921 if (zargs[1] > ((h_version <= V3) ? 31 : 47))
922 runtime_error (ERR_ILL_ATTR);
924 /* If we are monitoring attribute assignment display a short note */
926 if (f_setup.attribute_assignment) {
928 print_string ("@set_attr ");
929 print_object (zargs[0]);
931 print_num (zargs[1]);
936 runtime_error (ERR_SET_ATTR_0);
940 /* Get attribute address */
942 obj_addr = object_address (zargs[0]) + zargs[1] / 8;
944 /* Load attribute byte */
946 LOW_BYTE (obj_addr, value)
948 /* Set attribute bit */
950 value |= 0x80 >> (zargs[1] & 7);
952 /* Store attribute byte */
954 SET_BYTE (obj_addr, value)
959 * z_test_attr, branch if an object attribute is set.
962 * zargs[1] = number of attribute to test
966 void z_test_attr (void)
971 if (zargs[1] > ((h_version <= V3) ? 31 : 47))
972 runtime_error (ERR_ILL_ATTR);
974 /* If we are monitoring attribute testing display a short note */
976 if (f_setup.attribute_testing) {
978 print_string ("@test_attr ");
979 print_object (zargs[0]);
981 print_num (zargs[1]);
986 runtime_error (ERR_TEST_ATTR_0);
991 /* Get attribute address */
993 obj_addr = object_address (zargs[0]) + zargs[1] / 8;
995 /* Load attribute byte */
997 LOW_BYTE (obj_addr, value)
1001 branch (value & (0x80 >> (zargs[1] & 7)));