Packard Bell Vibe 500: change a not so lucky keymap for the bookmark delete.
[kugel-rb.git] / apps / plugins / frotz / object.c
blob676b6c93c572f7e2ed27c49f10111d0571cc48ba
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
21 #include "frotz.h"
23 #define MAX_OBJECT 2000
25 #define O1_PARENT 4
26 #define O1_SIBLING 5
27 #define O1_CHILD 6
28 #define O1_PROPERTY_OFFSET 7
29 #define O1_SIZE 9
31 #define O4_PARENT 6
32 #define O4_SIBLING 8
33 #define O4_CHILD 10
34 #define O4_PROPERTY_OFFSET 12
35 #define O4_SIZE 14
38 * object_address
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 ");
52 print_num(obj);
53 print_string(". This is normally fatal.");
54 new_line();
55 runtime_error (ERR_ILL_OBJ);
58 /* Return object address */
60 if (h_version <= V3)
61 return h_objects + ((obj - 1) * O1_SIZE + 62);
62 else
63 return h_objects + ((obj - 1) * O4_SIZE + 126);
65 }/* object_address */
68 * object_name
70 * Return the address of the given object's name.
74 zword object_name (zword object)
76 zword obj_addr;
77 zword name_addr;
79 obj_addr = object_address (object);
81 /* The object name address is found at the start of the properties */
83 if (h_version <= V3)
84 obj_addr += O1_PROPERTY_OFFSET;
85 else
86 obj_addr += O4_PROPERTY_OFFSET;
88 LOW_WORD (obj_addr, name_addr)
90 return name_addr;
92 }/* object_name */
95 * first_property
97 * Calculate the start address of the property list associated with
98 * an object.
102 static zword first_property (zword obj)
104 zword prop_addr;
105 zbyte size;
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 */
122 * next_property
124 * Calculate the address of the next property in a property list.
128 static zword next_property (zword prop_addr)
130 zbyte value;
132 /* Load the current property id */
134 LOW_BYTE (prop_addr, value)
135 prop_addr++;
137 /* Calculate the length of this property */
139 if (h_version <= V3)
140 value >>= 5;
141 else if (!(value & 0x80))
142 value >>= 6;
143 else {
145 LOW_BYTE (prop_addr, value)
146 value &= 0x3f;
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;
156 }/* next_property */
159 * unlink_object
161 * Unlink an object from its parent and siblings.
165 static void unlink_object (zword object)
167 zword obj_addr;
168 zword parent_addr;
169 zword sibling_addr;
171 if (object == 0) {
172 runtime_error (ERR_REMOVE_OBJECT_0);
173 return;
176 obj_addr = object_address (object);
178 if (h_version <= V3) {
180 zbyte parent;
181 zbyte younger_sibling;
182 zbyte older_sibling;
183 zbyte zero = 0;
185 /* Get parent of object, and return if no parent */
187 obj_addr += O1_PARENT;
188 LOW_BYTE (obj_addr, parent)
189 if (!parent)
190 return;
192 /* Get (older) sibling of object and set both parent and sibling
193 pointers to 0 */
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)
209 else {
210 do {
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)
217 } else {
219 zword parent;
220 zword younger_sibling;
221 zword older_sibling;
222 zword zero = 0;
224 /* Get parent of object, and return if no parent */
226 obj_addr += O4_PARENT;
227 LOW_WORD (obj_addr, parent)
228 if (!parent)
229 return;
231 /* Get (older) sibling of object and set both parent and sibling
232 pointers to 0 */
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)
248 else {
249 do {
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)
258 }/* unlink_object */
261 * z_clear_attr, clear an object attribute.
263 * zargs[0] = object
264 * zargs[1] = number of attribute to be cleared
268 void z_clear_attr (void)
270 zword obj_addr;
271 zbyte value;
273 if (story_id == SHERLOCK)
274 if (zargs[1] == 48)
275 return;
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) {
283 stream_mssg_on ();
284 print_string ("@clear_attr ");
285 print_object (zargs[0]);
286 print_string (" ");
287 print_num (zargs[1]);
288 stream_mssg_off ();
291 if (zargs[0] == 0) {
292 runtime_error (ERR_CLEAR_ATTR_0);
293 return;
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)
306 }/* z_clear_attr */
309 * z_jin, branch if the first object is inside the second.
311 * zargs[0] = first object
312 * zargs[1] = second object
316 void z_jin (void)
318 zword obj_addr;
320 /* If we are monitoring object locating display a short note */
322 if (f_setup.object_locating) {
323 stream_mssg_on ();
324 print_string ("@jin ");
325 print_object (zargs[0]);
326 print_string (" ");
327 print_object (zargs[1]);
328 stream_mssg_off ();
331 if (zargs[0] == 0) {
332 runtime_error (ERR_JIN_0);
333 branch (0 == zargs[1]);
334 return;
337 obj_addr = object_address (zargs[0]);
339 if (h_version <= V3) {
341 zbyte parent;
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]);
352 } else {
354 zword parent;
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]);
367 }/* z_jin */
370 * z_get_child, store the child of an object.
372 * zargs[0] = object
376 void z_get_child (void)
378 zword obj_addr;
380 /* If we are monitoring object locating display a short note */
382 if (f_setup.object_locating) {
383 stream_mssg_on ();
384 print_string ("@get_child ");
385 print_object (zargs[0]);
386 stream_mssg_off ();
389 if (zargs[0] == 0) {
390 runtime_error (ERR_GET_CHILD_0);
391 store (0);
392 branch (FALSE);
393 return;
396 obj_addr = object_address (zargs[0]);
398 if (h_version <= V3) {
400 zbyte child;
402 /* Get child id from object */
404 obj_addr += O1_CHILD;
405 LOW_BYTE (obj_addr, child)
407 /* Store child id and branch */
409 store (child);
410 branch (child);
412 } else {
414 zword child;
416 /* Get child id from object */
418 obj_addr += O4_CHILD;
419 LOW_WORD (obj_addr, child)
421 /* Store child id and branch */
423 store (child);
424 branch (child);
428 }/* z_get_child */
431 * z_get_next_prop, store the number of the first or next property.
433 * zargs[0] = object
434 * zargs[1] = address of current property (0 gets the first property)
438 void z_get_next_prop (void)
440 zword prop_addr;
441 zbyte value;
442 zbyte mask;
444 if (zargs[0] == 0) {
445 runtime_error (ERR_GET_NEXT_PROP_0);
446 store (0);
447 return;
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]);
458 if (zargs[1] != 0) {
460 /* Scan down the property list */
462 do {
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.
484 * zargs[0] = object
488 void z_get_parent (void)
490 zword obj_addr;
492 /* If we are monitoring object locating display a short note */
494 if (f_setup.object_locating) {
495 stream_mssg_on ();
496 print_string ("@get_parent ");
497 print_object (zargs[0]);
498 stream_mssg_off ();
501 if (zargs[0] == 0) {
502 runtime_error (ERR_GET_PARENT_0);
503 store (0);
504 return;
507 obj_addr = object_address (zargs[0]);
509 if (h_version <= V3) {
511 zbyte parent;
513 /* Get parent id from object */
515 obj_addr += O1_PARENT;
516 LOW_BYTE (obj_addr, parent)
518 /* Store parent */
520 store (parent);
522 } else {
524 zword parent;
526 /* Get parent id from object */
528 obj_addr += O4_PARENT;
529 LOW_WORD (obj_addr, parent)
531 /* Store parent */
533 store (parent);
537 }/* z_get_parent */
540 * z_get_prop, store the value of an object property.
542 * zargs[0] = object
543 * zargs[1] = number of property to be examined
547 void z_get_prop (void)
549 zword prop_addr;
550 zword wprop_val;
551 zbyte bprop_val;
552 zbyte value;
553 zbyte mask;
555 if (zargs[0] == 0) {
556 runtime_error (ERR_GET_PROP_0);
557 store (0);
558 return;
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 */
571 for (;;) {
572 LOW_BYTE (prop_addr, value)
573 if ((value & mask) <= zargs[1])
574 break;
575 prop_addr = next_property (prop_addr);
578 if ((value & mask) == zargs[1]) { /* property found */
580 /* Load property (byte or word sized) */
582 prop_addr++;
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 */
602 store (wprop_val);
604 }/* z_get_prop */
607 * z_get_prop_addr, store the address of an object property.
609 * zargs[0] = object
610 * zargs[1] = number of property to be examined
614 void z_get_prop_addr (void)
616 zword prop_addr;
617 zbyte value;
618 zbyte mask;
620 if (zargs[0] == 0) {
621 runtime_error (ERR_GET_PROP_ADDR_0);
622 store (0);
623 return;
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 */
640 for (;;) {
641 LOW_BYTE (prop_addr, value)
642 if ((value & mask) <= zargs[1])
643 break;
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))
652 prop_addr++;
653 store ((zword) (prop_addr + 1));
655 } else store (0);
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)
668 zword addr;
669 zbyte value;
671 /* Back up the property pointer to the property id */
673 addr = zargs[0] - 1;
674 LOW_BYTE (addr, value)
676 /* Calculate length of property */
678 if (h_version <= V3)
679 value = (value >> 5) + 1;
680 else if (!(value & 0x80))
681 value = (value >> 6) + 1;
682 else {
684 value &= 0x3f;
686 if (value == 0) value = 64; /* demanded by Spec 1.0 */
690 /* Store length of property */
692 store (value);
694 }/* z_get_prop_len */
697 * z_get_sibling, store the sibling of an object.
699 * zargs[0] = object
703 void z_get_sibling (void)
705 zword obj_addr;
707 if (zargs[0] == 0) {
708 runtime_error (ERR_GET_SIBLING_0);
709 store (0);
710 branch (FALSE);
711 return;
714 obj_addr = object_address (zargs[0]);
716 if (h_version <= V3) {
718 zbyte sibling;
720 /* Get sibling id from object */
722 obj_addr += O1_SIBLING;
723 LOW_BYTE (obj_addr, sibling)
725 /* Store sibling and branch */
727 store (sibling);
728 branch (sibling);
730 } else {
732 zword sibling;
734 /* Get sibling id from object */
736 obj_addr += O4_SIBLING;
737 LOW_WORD (obj_addr, sibling)
739 /* Store sibling and branch */
741 store (sibling);
742 branch (sibling);
746 }/* z_get_sibling */
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];
760 zword obj1_addr;
761 zword obj2_addr;
763 /* If we are monitoring object movements display a short note */
765 if (f_setup.object_movement) {
766 stream_mssg_on ();
767 print_string ("@move_obj ");
768 print_object (obj1);
769 print_string (" ");
770 print_object (obj2);
771 stream_mssg_off ();
774 if (obj1 == 0) {
775 runtime_error (ERR_MOVE_OBJECT_0);
776 return;
779 if (obj2 == 0) {
780 runtime_error (ERR_MOVE_OBJECT_TO_0);
781 return;
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) {
797 zbyte child;
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)
807 } else {
809 zword 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)
821 }/* z_insert_obj */
824 * z_put_prop, set the value of an object property.
826 * zargs[0] = object
827 * zargs[1] = number of property to set
828 * zargs[2] = value to set property to
832 void z_put_prop (void)
834 zword prop_addr;
835 zword value;
836 zbyte mask;
838 if (zargs[0] == 0) {
839 runtime_error (ERR_PUT_PROP_0);
840 return;
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 */
853 for (;;) {
854 LOW_BYTE (prop_addr, value)
855 if ((value & mask) <= zargs[1])
856 break;
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) */
867 prop_addr++;
869 if ((h_version <= V3 && !(value & 0xe0)) || (h_version >= V4 && !(value & 0xc0))) {
870 zbyte v = zargs[2];
871 SET_BYTE (prop_addr, v)
872 } else {
873 zword v = zargs[2];
874 SET_WORD (prop_addr, v)
877 }/* z_put_prop */
880 * z_remove_obj, unlink an object from its parent and siblings.
882 * zargs[0] = object
886 void z_remove_obj (void)
889 /* If we are monitoring object movements display a short note */
891 if (f_setup.object_movement) {
892 stream_mssg_on ();
893 print_string ("@remove_obj ");
894 print_object (zargs[0]);
895 stream_mssg_off ();
898 /* Call unlink_object to do the job */
900 unlink_object (zargs[0]);
902 }/* z_remove_obj */
905 * z_set_attr, set an object attribute.
907 * zargs[0] = object
908 * zargs[1] = number of attribute to set
912 void z_set_attr (void)
914 zword obj_addr;
915 zbyte value;
917 if (story_id == SHERLOCK)
918 if (zargs[1] == 48)
919 return;
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) {
927 stream_mssg_on ();
928 print_string ("@set_attr ");
929 print_object (zargs[0]);
930 print_string (" ");
931 print_num (zargs[1]);
932 stream_mssg_off ();
935 if (zargs[0] == 0) {
936 runtime_error (ERR_SET_ATTR_0);
937 return;
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)
956 }/* z_set_attr */
959 * z_test_attr, branch if an object attribute is set.
961 * zargs[0] = object
962 * zargs[1] = number of attribute to test
966 void z_test_attr (void)
968 zword obj_addr;
969 zbyte value;
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) {
977 stream_mssg_on ();
978 print_string ("@test_attr ");
979 print_object (zargs[0]);
980 print_string (" ");
981 print_num (zargs[1]);
982 stream_mssg_off ();
985 if (zargs[0] == 0) {
986 runtime_error (ERR_TEST_ATTR_0);
987 branch (FALSE);
988 return;
991 /* Get attribute address */
993 obj_addr = object_address (zargs[0]) + zargs[1] / 8;
995 /* Load attribute byte */
997 LOW_BYTE (obj_addr, value)
999 /* Test attribute */
1001 branch (value & (0x80 >> (zargs[1] & 7)));
1003 }/* z_test_attr */