summaryrefslogtreecommitdiff
path: root/apps/plugins/frotz/object.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/frotz/object.c')
-rw-r--r--apps/plugins/frotz/object.c1003
1 files changed, 1003 insertions, 0 deletions
diff --git a/apps/plugins/frotz/object.c b/apps/plugins/frotz/object.c
new file mode 100644
index 0000000000..676b6c93c5
--- /dev/null
+++ b/apps/plugins/frotz/object.c
@@ -0,0 +1,1003 @@
1/* object.c - Object manipulation opcodes
2 * Copyright (c) 1995-1997 Stefan Jokisch
3 *
4 * This file is part of Frotz.
5 *
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.
10 *
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.
15 *
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
19 */
20
21#include "frotz.h"
22
23#define MAX_OBJECT 2000
24
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
30
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
36
37/*
38 * object_address
39 *
40 * Calculate the address of an object.
41 *
42 */
43
44static zword object_address (zword obj)
45{
46/* zchar obj_num[10]; */
47
48 /* Check object number */
49
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);
56 }
57
58 /* Return object address */
59
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);
64
65}/* object_address */
66
67/*
68 * object_name
69 *
70 * Return the address of the given object's name.
71 *
72 */
73
74zword object_name (zword object)
75{
76 zword obj_addr;
77 zword name_addr;
78
79 obj_addr = object_address (object);
80
81 /* The object name address is found at the start of the properties */
82
83 if (h_version <= V3)
84 obj_addr += O1_PROPERTY_OFFSET;
85 else
86 obj_addr += O4_PROPERTY_OFFSET;
87
88 LOW_WORD (obj_addr, name_addr)
89
90 return name_addr;
91
92}/* object_name */
93
94/*
95 * first_property
96 *
97 * Calculate the start address of the property list associated with
98 * an object.
99 *
100 */
101
102static zword first_property (zword obj)
103{
104 zword prop_addr;
105 zbyte size;
106
107 /* Fetch address of object name */
108
109 prop_addr = object_name (obj);
110
111 /* Get length of object name */
112
113 LOW_BYTE (prop_addr, size)
114
115 /* Add name length to pointer */
116
117 return prop_addr + 1 + 2 * size;
118
119}/* first_property */
120
121/*
122 * next_property
123 *
124 * Calculate the address of the next property in a property list.
125 *
126 */
127
128static zword next_property (zword prop_addr)
129{
130 zbyte value;
131
132 /* Load the current property id */
133
134 LOW_BYTE (prop_addr, value)
135 prop_addr++;
136
137 /* Calculate the length of this property */
138
139 if (h_version <= V3)
140 value >>= 5;
141 else if (!(value & 0x80))
142 value >>= 6;
143 else {
144
145 LOW_BYTE (prop_addr, value)
146 value &= 0x3f;
147
148 if (value == 0) value = 64; /* demanded by Spec 1.0 */
149
150 }
151
152 /* Add property length to current property pointer */
153
154 return prop_addr + value + 1;
155
156}/* next_property */
157
158/*
159 * unlink_object
160 *
161 * Unlink an object from its parent and siblings.
162 *
163 */
164
165static void unlink_object (zword object)
166{
167 zword obj_addr;
168 zword parent_addr;
169 zword sibling_addr;
170
171 if (object == 0) {
172 runtime_error (ERR_REMOVE_OBJECT_0);
173 return;
174 }
175
176 obj_addr = object_address (object);
177
178 if (h_version <= V3) {
179
180 zbyte parent;
181 zbyte younger_sibling;
182 zbyte older_sibling;
183 zbyte zero = 0;
184
185 /* Get parent of object, and return if no parent */
186
187 obj_addr += O1_PARENT;
188 LOW_BYTE (obj_addr, parent)
189 if (!parent)
190 return;
191
192 /* Get (older) sibling of object and set both parent and sibling
193 pointers to 0 */
194
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)
199
200 /* Get first child of parent (the youngest sibling of the object) */
201
202 parent_addr = object_address (parent) + O1_CHILD;
203 LOW_BYTE (parent_addr, younger_sibling)
204
205 /* Remove object from the list of siblings */
206
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)
215 }
216
217 } else {
218
219 zword parent;
220 zword younger_sibling;
221 zword older_sibling;
222 zword zero = 0;
223
224 /* Get parent of object, and return if no parent */
225
226 obj_addr += O4_PARENT;
227 LOW_WORD (obj_addr, parent)
228 if (!parent)
229 return;
230
231 /* Get (older) sibling of object and set both parent and sibling
232 pointers to 0 */
233
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)
238
239 /* Get first child of parent (the youngest sibling of the object) */
240
241 parent_addr = object_address (parent) + O4_CHILD;
242 LOW_WORD (parent_addr, younger_sibling)
243
244 /* Remove object from the list of siblings */
245
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)
254 }
255
256 }
257
258}/* unlink_object */
259
260/*
261 * z_clear_attr, clear an object attribute.
262 *
263 * zargs[0] = object
264 * zargs[1] = number of attribute to be cleared
265 *
266 */
267
268void z_clear_attr (void)
269{
270 zword obj_addr;
271 zbyte value;
272
273 if (story_id == SHERLOCK)
274 if (zargs[1] == 48)
275 return;
276
277 if (zargs[1] > ((h_version <= V3) ? 31 : 47))
278 runtime_error (ERR_ILL_ATTR);
279
280 /* If we are monitoring attribute assignment display a short note */
281
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 ();
289 }
290
291 if (zargs[0] == 0) {
292 runtime_error (ERR_CLEAR_ATTR_0);
293 return;
294 }
295
296 /* Get attribute address */
297
298 obj_addr = object_address (zargs[0]) + zargs[1] / 8;
299
300 /* Clear attribute bit */
301
302 LOW_BYTE (obj_addr, value)
303 value &= ~(0x80 >> (zargs[1] & 7));
304 SET_BYTE (obj_addr, value)
305
306}/* z_clear_attr */
307
308/*
309 * z_jin, branch if the first object is inside the second.
310 *
311 * zargs[0] = first object
312 * zargs[1] = second object
313 *
314 */
315
316void z_jin (void)
317{
318 zword obj_addr;
319
320 /* If we are monitoring object locating display a short note */
321
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 ();
329 }
330
331 if (zargs[0] == 0) {
332 runtime_error (ERR_JIN_0);
333 branch (0 == zargs[1]);
334 return;
335 }
336
337 obj_addr = object_address (zargs[0]);
338
339 if (h_version <= V3) {
340
341 zbyte parent;
342
343 /* Get parent id from object */
344
345 obj_addr += O1_PARENT;
346 LOW_BYTE (obj_addr, parent)
347
348 /* Branch if the parent is obj2 */
349
350 branch (parent == zargs[1]);
351
352 } else {
353
354 zword parent;
355
356 /* Get parent id from object */
357
358 obj_addr += O4_PARENT;
359 LOW_WORD (obj_addr, parent)
360
361 /* Branch if the parent is obj2 */
362
363 branch (parent == zargs[1]);
364
365 }
366
367}/* z_jin */
368
369/*
370 * z_get_child, store the child of an object.
371 *
372 * zargs[0] = object
373 *
374 */
375
376void z_get_child (void)
377{
378 zword obj_addr;
379
380 /* If we are monitoring object locating display a short note */
381
382 if (f_setup.object_locating) {
383 stream_mssg_on ();
384 print_string ("@get_child ");
385 print_object (zargs[0]);
386 stream_mssg_off ();
387 }
388
389 if (zargs[0] == 0) {
390 runtime_error (ERR_GET_CHILD_0);
391 store (0);
392 branch (FALSE);
393 return;
394 }
395
396 obj_addr = object_address (zargs[0]);
397
398 if (h_version <= V3) {
399
400 zbyte child;
401
402 /* Get child id from object */
403
404 obj_addr += O1_CHILD;
405 LOW_BYTE (obj_addr, child)
406
407 /* Store child id and branch */
408
409 store (child);
410 branch (child);
411
412 } else {
413
414 zword child;
415
416 /* Get child id from object */
417
418 obj_addr += O4_CHILD;
419 LOW_WORD (obj_addr, child)
420
421 /* Store child id and branch */
422
423 store (child);
424 branch (child);
425
426 }
427
428}/* z_get_child */
429
430/*
431 * z_get_next_prop, store the number of the first or next property.
432 *
433 * zargs[0] = object
434 * zargs[1] = address of current property (0 gets the first property)
435 *
436 */
437
438void z_get_next_prop (void)
439{
440 zword prop_addr;
441 zbyte value;
442 zbyte mask;
443
444 if (zargs[0] == 0) {
445 runtime_error (ERR_GET_NEXT_PROP_0);
446 store (0);
447 return;
448 }
449
450 /* Property id is in bottom five (six) bits */
451
452 mask = (h_version <= V3) ? 0x1f : 0x3f;
453
454 /* Load address of first property */
455
456 prop_addr = first_property (zargs[0]);
457
458 if (zargs[1] != 0) {
459
460 /* Scan down the property list */
461
462 do {
463 LOW_BYTE (prop_addr, value)
464 prop_addr = next_property (prop_addr);
465 } while ((value & mask) > zargs[1]);
466
467 /* Exit if the property does not exist */
468
469 if ((value & mask) != zargs[1])
470 runtime_error (ERR_NO_PROP);
471
472 }
473
474 /* Return the property id */
475
476 LOW_BYTE (prop_addr, value)
477 store ((zword) (value & mask));
478
479}/* z_get_next_prop */
480
481/*
482 * z_get_parent, store the parent of an object.
483 *
484 * zargs[0] = object
485 *
486 */
487
488void z_get_parent (void)
489{
490 zword obj_addr;
491
492 /* If we are monitoring object locating display a short note */
493
494 if (f_setup.object_locating) {
495 stream_mssg_on ();
496 print_string ("@get_parent ");
497 print_object (zargs[0]);
498 stream_mssg_off ();
499 }
500
501 if (zargs[0] == 0) {
502 runtime_error (ERR_GET_PARENT_0);
503 store (0);
504 return;
505 }
506
507 obj_addr = object_address (zargs[0]);
508
509 if (h_version <= V3) {
510
511 zbyte parent;
512
513 /* Get parent id from object */
514
515 obj_addr += O1_PARENT;
516 LOW_BYTE (obj_addr, parent)
517
518 /* Store parent */
519
520 store (parent);
521
522 } else {
523
524 zword parent;
525
526 /* Get parent id from object */
527
528 obj_addr += O4_PARENT;
529 LOW_WORD (obj_addr, parent)
530
531 /* Store parent */
532
533 store (parent);
534
535 }
536
537}/* z_get_parent */
538
539/*
540 * z_get_prop, store the value of an object property.
541 *
542 * zargs[0] = object
543 * zargs[1] = number of property to be examined
544 *
545 */
546
547void z_get_prop (void)
548{
549 zword prop_addr;
550 zword wprop_val;
551 zbyte bprop_val;
552 zbyte value;
553 zbyte mask;
554
555 if (zargs[0] == 0) {
556 runtime_error (ERR_GET_PROP_0);
557 store (0);
558 return;
559 }
560
561 /* Property id is in bottom five (six) bits */
562
563 mask = (h_version <= V3) ? 0x1f : 0x3f;
564
565 /* Load address of first property */
566
567 prop_addr = first_property (zargs[0]);
568
569 /* Scan down the property list */
570
571 for (;;) {
572 LOW_BYTE (prop_addr, value)
573 if ((value & mask) <= zargs[1])
574 break;
575 prop_addr = next_property (prop_addr);
576 }
577
578 if ((value & mask) == zargs[1]) { /* property found */
579
580 /* Load property (byte or word sized) */
581
582 prop_addr++;
583
584 if ((h_version <= V3 && !(value & 0xe0)) || (h_version >= V4 && !(value & 0xc0))) {
585
586 LOW_BYTE (prop_addr, bprop_val)
587 wprop_val = bprop_val;
588
589 } else LOW_WORD (prop_addr, wprop_val)
590
591 } else { /* property not found */
592
593 /* Load default value */
594
595 prop_addr = h_objects + 2 * (zargs[1] - 1);
596 LOW_WORD (prop_addr, wprop_val)
597
598 }
599
600 /* Store the property value */
601
602 store (wprop_val);
603
604}/* z_get_prop */
605
606/*
607 * z_get_prop_addr, store the address of an object property.
608 *
609 * zargs[0] = object
610 * zargs[1] = number of property to be examined
611 *
612 */
613
614void z_get_prop_addr (void)
615{
616 zword prop_addr;
617 zbyte value;
618 zbyte mask;
619
620 if (zargs[0] == 0) {
621 runtime_error (ERR_GET_PROP_ADDR_0);
622 store (0);
623 return;
624 }
625
626 if (story_id == BEYOND_ZORK)
627 if (zargs[0] > MAX_OBJECT)
628 { store (0); return; }
629
630 /* Property id is in bottom five (six) bits */
631
632 mask = (h_version <= V3) ? 0x1f : 0x3f;
633
634 /* Load address of first property */
635
636 prop_addr = first_property (zargs[0]);
637
638 /* Scan down the property list */
639
640 for (;;) {
641 LOW_BYTE (prop_addr, value)
642 if ((value & mask) <= zargs[1])
643 break;
644 prop_addr = next_property (prop_addr);
645 }
646
647 /* Calculate the property address or return zero */
648
649 if ((value & mask) == zargs[1]) {
650
651 if (h_version >= V4 && (value & 0x80))
652 prop_addr++;
653 store ((zword) (prop_addr + 1));
654
655 } else store (0);
656
657}/* z_get_prop_addr */
658
659/*
660 * z_get_prop_len, store the length of an object property.
661 *
662 * zargs[0] = address of property to be examined
663 *
664 */
665
666void z_get_prop_len (void)
667{
668 zword addr;
669 zbyte value;
670
671 /* Back up the property pointer to the property id */
672
673 addr = zargs[0] - 1;
674 LOW_BYTE (addr, value)
675
676 /* Calculate length of property */
677
678 if (h_version <= V3)
679 value = (value >> 5) + 1;
680 else if (!(value & 0x80))
681 value = (value >> 6) + 1;
682 else {
683
684 value &= 0x3f;
685
686 if (value == 0) value = 64; /* demanded by Spec 1.0 */
687
688 }
689
690 /* Store length of property */
691
692 store (value);
693
694}/* z_get_prop_len */
695
696/*
697 * z_get_sibling, store the sibling of an object.
698 *
699 * zargs[0] = object
700 *
701 */
702
703void z_get_sibling (void)
704{
705 zword obj_addr;
706
707 if (zargs[0] == 0) {
708 runtime_error (ERR_GET_SIBLING_0);
709 store (0);
710 branch (FALSE);
711 return;
712 }
713
714 obj_addr = object_address (zargs[0]);
715
716 if (h_version <= V3) {
717
718 zbyte sibling;
719
720 /* Get sibling id from object */
721
722 obj_addr += O1_SIBLING;
723 LOW_BYTE (obj_addr, sibling)
724
725 /* Store sibling and branch */
726
727 store (sibling);
728 branch (sibling);
729
730 } else {
731
732 zword sibling;
733
734 /* Get sibling id from object */
735
736 obj_addr += O4_SIBLING;
737 LOW_WORD (obj_addr, sibling)
738
739 /* Store sibling and branch */
740
741 store (sibling);
742 branch (sibling);
743
744 }
745
746}/* z_get_sibling */
747
748/*
749 * z_insert_obj, make an object the first child of another object.
750 *
751 * zargs[0] = object to be moved
752 * zargs[1] = destination object
753 *
754 */
755
756void z_insert_obj (void)
757{
758 zword obj1 = zargs[0];
759 zword obj2 = zargs[1];
760 zword obj1_addr;
761 zword obj2_addr;
762
763 /* If we are monitoring object movements display a short note */
764
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 ();
772 }
773
774 if (obj1 == 0) {
775 runtime_error (ERR_MOVE_OBJECT_0);
776 return;
777 }
778
779 if (obj2 == 0) {
780 runtime_error (ERR_MOVE_OBJECT_TO_0);
781 return;
782 }
783
784 /* Get addresses of both objects */
785
786 obj1_addr = object_address (obj1);
787 obj2_addr = object_address (obj2);
788
789 /* Remove object 1 from current parent */
790
791 unlink_object (obj1);
792
793 /* Make object 1 first child of object 2 */
794
795 if (h_version <= V3) {
796
797 zbyte child;
798
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)
806
807 } else {
808
809 zword child;
810
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)
818
819 }
820
821}/* z_insert_obj */
822
823/*
824 * z_put_prop, set the value of an object property.
825 *
826 * zargs[0] = object
827 * zargs[1] = number of property to set
828 * zargs[2] = value to set property to
829 *
830 */
831
832void z_put_prop (void)
833{
834 zword prop_addr;
835 zword value;
836 zbyte mask;
837
838 if (zargs[0] == 0) {
839 runtime_error (ERR_PUT_PROP_0);
840 return;
841 }
842
843 /* Property id is in bottom five or six bits */
844
845 mask = (h_version <= V3) ? 0x1f : 0x3f;
846
847 /* Load address of first property */
848
849 prop_addr = first_property (zargs[0]);
850
851 /* Scan down the property list */
852
853 for (;;) {
854 LOW_BYTE (prop_addr, value)
855 if ((value & mask) <= zargs[1])
856 break;
857 prop_addr = next_property (prop_addr);
858 }
859
860 /* Exit if the property does not exist */
861
862 if ((value & mask) != zargs[1])
863 runtime_error (ERR_NO_PROP);
864
865 /* Store the new property value (byte or word sized) */
866
867 prop_addr++;
868
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)
875 }
876
877}/* z_put_prop */
878
879/*
880 * z_remove_obj, unlink an object from its parent and siblings.
881 *
882 * zargs[0] = object
883 *
884 */
885
886void z_remove_obj (void)
887{
888
889 /* If we are monitoring object movements display a short note */
890
891 if (f_setup.object_movement) {
892 stream_mssg_on ();
893 print_string ("@remove_obj ");
894 print_object (zargs[0]);
895 stream_mssg_off ();
896 }
897
898 /* Call unlink_object to do the job */
899
900 unlink_object (zargs[0]);
901
902}/* z_remove_obj */
903
904/*
905 * z_set_attr, set an object attribute.
906 *
907 * zargs[0] = object
908 * zargs[1] = number of attribute to set
909 *
910 */
911
912void z_set_attr (void)
913{
914 zword obj_addr;
915 zbyte value;
916
917 if (story_id == SHERLOCK)
918 if (zargs[1] == 48)
919 return;
920
921 if (zargs[1] > ((h_version <= V3) ? 31 : 47))
922 runtime_error (ERR_ILL_ATTR);
923
924 /* If we are monitoring attribute assignment display a short note */
925
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 ();
933 }
934
935 if (zargs[0] == 0) {
936 runtime_error (ERR_SET_ATTR_0);
937 return;
938 }
939
940 /* Get attribute address */
941
942 obj_addr = object_address (zargs[0]) + zargs[1] / 8;
943
944 /* Load attribute byte */
945
946 LOW_BYTE (obj_addr, value)
947
948 /* Set attribute bit */
949
950 value |= 0x80 >> (zargs[1] & 7);
951
952 /* Store attribute byte */
953
954 SET_BYTE (obj_addr, value)
955
956}/* z_set_attr */
957
958/*
959 * z_test_attr, branch if an object attribute is set.
960 *
961 * zargs[0] = object
962 * zargs[1] = number of attribute to test
963 *
964 */
965
966void z_test_attr (void)
967{
968 zword obj_addr;
969 zbyte value;
970
971 if (zargs[1] > ((h_version <= V3) ? 31 : 47))
972 runtime_error (ERR_ILL_ATTR);
973
974 /* If we are monitoring attribute testing display a short note */
975
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 ();
983 }
984
985 if (zargs[0] == 0) {
986 runtime_error (ERR_TEST_ATTR_0);
987 branch (FALSE);
988 return;
989 }
990
991 /* Get attribute address */
992
993 obj_addr = object_address (zargs[0]) + zargs[1] / 8;
994
995 /* Load attribute byte */
996
997 LOW_BYTE (obj_addr, value)
998
999 /* Test attribute */
1000
1001 branch (value & (0x80 >> (zargs[1] & 7)));
1002
1003}/* z_test_attr */