home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / Epoc / Palmtime / files / FrotzS5_src.ZIP / OBJECT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-12  |  17.4 KB  |  906 lines

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