Handle object 0 (nothing) gracefully in object parser
Per the Z-machine spec, object 0 means "nothing" and operations on it should be safe no-ops: get_child/get_sibling/get_parent return 0, test_attr returns false, set/clear_attr are no-ops, etc. Previously these threw ZObjectIllegalObjectNumber, crashing on games like Curses that pass object 0 to get_child during room transitions.
This commit is contained in:
parent
5a98adb6ee
commit
74538756d5
1 changed files with 24 additions and 0 deletions
|
|
@ -163,6 +163,8 @@ class ZObjectParser:
|
||||||
def get_attribute(self, objectnum, attrnum):
|
def get_attribute(self, objectnum, attrnum):
|
||||||
"""Return value (0 or 1) of attribute number ATTRNUM of object
|
"""Return value (0 or 1) of attribute number ATTRNUM of object
|
||||||
number OBJECTNUM."""
|
number OBJECTNUM."""
|
||||||
|
if objectnum == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
object_addr = self._get_object_addr(objectnum)
|
object_addr = self._get_object_addr(objectnum)
|
||||||
|
|
||||||
|
|
@ -183,6 +185,8 @@ class ZObjectParser:
|
||||||
|
|
||||||
def set_attribute(self, objectnum, attrnum):
|
def set_attribute(self, objectnum, attrnum):
|
||||||
"""Set attribute number ATTRNUM of object number OBJECTNUM to 1."""
|
"""Set attribute number ATTRNUM of object number OBJECTNUM to 1."""
|
||||||
|
if objectnum == 0:
|
||||||
|
return
|
||||||
|
|
||||||
object_addr = self._get_object_addr(objectnum)
|
object_addr = self._get_object_addr(objectnum)
|
||||||
|
|
||||||
|
|
@ -206,6 +210,8 @@ class ZObjectParser:
|
||||||
|
|
||||||
def clear_attribute(self, objectnum, attrnum):
|
def clear_attribute(self, objectnum, attrnum):
|
||||||
"""Clear attribute number ATTRNUM of object number OBJECTNUM to 0."""
|
"""Clear attribute number ATTRNUM of object number OBJECTNUM to 0."""
|
||||||
|
if objectnum == 0:
|
||||||
|
return
|
||||||
|
|
||||||
object_addr = self._get_object_addr(objectnum)
|
object_addr = self._get_object_addr(objectnum)
|
||||||
|
|
||||||
|
|
@ -247,18 +253,24 @@ class ZObjectParser:
|
||||||
|
|
||||||
def get_parent(self, objectnum):
|
def get_parent(self, objectnum):
|
||||||
"""Return object number of parent of object number OBJECTNUM."""
|
"""Return object number of parent of object number OBJECTNUM."""
|
||||||
|
if objectnum == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
[parent, sibling, child] = self._get_parent_sibling_child(objectnum)
|
[parent, sibling, child] = self._get_parent_sibling_child(objectnum)
|
||||||
return parent
|
return parent
|
||||||
|
|
||||||
def get_child(self, objectnum):
|
def get_child(self, objectnum):
|
||||||
"""Return object number of child of object number OBJECTNUM."""
|
"""Return object number of child of object number OBJECTNUM."""
|
||||||
|
if objectnum == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
[parent, sibling, child] = self._get_parent_sibling_child(objectnum)
|
[parent, sibling, child] = self._get_parent_sibling_child(objectnum)
|
||||||
return child
|
return child
|
||||||
|
|
||||||
def get_sibling(self, objectnum):
|
def get_sibling(self, objectnum):
|
||||||
"""Return object number of sibling of object number OBJECTNUM."""
|
"""Return object number of sibling of object number OBJECTNUM."""
|
||||||
|
if objectnum == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
[parent, sibling, child] = self._get_parent_sibling_child(objectnum)
|
[parent, sibling, child] = self._get_parent_sibling_child(objectnum)
|
||||||
return sibling
|
return sibling
|
||||||
|
|
@ -298,6 +310,8 @@ class ZObjectParser:
|
||||||
|
|
||||||
def remove_object(self, objectnum):
|
def remove_object(self, objectnum):
|
||||||
"""Detach object OBJECTNUM from its parent (unlink from sibling chain)."""
|
"""Detach object OBJECTNUM from its parent (unlink from sibling chain)."""
|
||||||
|
if objectnum == 0:
|
||||||
|
return
|
||||||
|
|
||||||
parent = self.get_parent(objectnum)
|
parent = self.get_parent(objectnum)
|
||||||
if parent == 0:
|
if parent == 0:
|
||||||
|
|
@ -335,6 +349,8 @@ class ZObjectParser:
|
||||||
Per the Z-spec: if new_child already has a parent, it is first
|
Per the Z-spec: if new_child already has a parent, it is first
|
||||||
removed from that parent's child list, then made the first child
|
removed from that parent's child list, then made the first child
|
||||||
of parent_object."""
|
of parent_object."""
|
||||||
|
if parent_object == 0 or new_child == 0:
|
||||||
|
return
|
||||||
|
|
||||||
# Remove from old parent first (spec says "first removed")
|
# Remove from old parent first (spec says "first removed")
|
||||||
self.remove_object(new_child)
|
self.remove_object(new_child)
|
||||||
|
|
@ -347,6 +363,8 @@ class ZObjectParser:
|
||||||
|
|
||||||
def get_shortname(self, objectnum):
|
def get_shortname(self, objectnum):
|
||||||
"""Return 'short name' of object number OBJECTNUM as ascii string."""
|
"""Return 'short name' of object number OBJECTNUM as ascii string."""
|
||||||
|
if objectnum == 0:
|
||||||
|
return ""
|
||||||
|
|
||||||
addr = self._get_proptable_addr(objectnum)
|
addr = self._get_proptable_addr(objectnum)
|
||||||
return self._stringfactory.get(addr + 1)
|
return self._stringfactory.get(addr + 1)
|
||||||
|
|
@ -354,6 +372,8 @@ class ZObjectParser:
|
||||||
def get_prop(self, objectnum, propnum):
|
def get_prop(self, objectnum, propnum):
|
||||||
"""Return either a byte or word value of property PROPNUM of
|
"""Return either a byte or word value of property PROPNUM of
|
||||||
object OBJECTNUM."""
|
object OBJECTNUM."""
|
||||||
|
if objectnum == 0:
|
||||||
|
return 0
|
||||||
(addr, size) = self.get_prop_addr_len(objectnum, propnum)
|
(addr, size) = self.get_prop_addr_len(objectnum, propnum)
|
||||||
if size == 1:
|
if size == 1:
|
||||||
return self._memory[addr]
|
return self._memory[addr]
|
||||||
|
|
@ -467,6 +487,8 @@ class ZObjectParser:
|
||||||
def get_property_data_address(self, objectnum, propnum):
|
def get_property_data_address(self, objectnum, propnum):
|
||||||
"""Return the address of property PROPNUM's data bytes for object
|
"""Return the address of property PROPNUM's data bytes for object
|
||||||
OBJECTNUM. Return 0 if the object doesn't have that property."""
|
OBJECTNUM. Return 0 if the object doesn't have that property."""
|
||||||
|
if objectnum == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
addr, size = self.get_prop_addr_len(objectnum, propnum)
|
addr, size = self.get_prop_addr_len(objectnum, propnum)
|
||||||
|
|
@ -484,6 +506,8 @@ class ZObjectParser:
|
||||||
"""If PROPNUM is 0, return the first property number of object OBJECTNUM.
|
"""If PROPNUM is 0, return the first property number of object OBJECTNUM.
|
||||||
Otherwise, return the property number after PROPNUM in the property list.
|
Otherwise, return the property number after PROPNUM in the property list.
|
||||||
Return 0 if there are no more properties."""
|
Return 0 if there are no more properties."""
|
||||||
|
if objectnum == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
if propnum == 0:
|
if propnum == 0:
|
||||||
# Return first property number
|
# Return first property number
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue