First, let's look at our new grammar definition:
verb "empty", "unload"
* DoVague
#ifset NEW_EMPTY
* (CheckEmpty) "on"/"onto" "ground"/"floor" DoEmptyGround
#else
* object "on"/"onto" "ground"/"floor" DoEmptyGround
#endif
* multi "from"/"off"/"on"/"in" parent DoGet
* multi "offof"/"outof" parent DoGet
* multi "from" "offof"/"outof"/"on"/"in" parent DoGet
! Send >UNLOAD OBJECT to DoEmptyoOrGet, which dispatches to DoEmpty or DoGet
! * object DoEmpty
#ifset NEW_EMPTY
* (CheckEmpty) DoEmpty ! DoEmptyOrGet
#else
* object DoEmpty
#endif
In no cases does it run DoEmptyOrGet anymore as I think it's so general that it just leads to trouble. Next, let's take a look at our object classes:
#ifset NEW_EMPTYIf it's not self-explanatory, that consists of a class that represents objects that must be held and empty out to player (like unloading bullets from a gun), objects that must be not held and empty out to player (like unloading a laundry machine), objects that must be held and empty out to ground (like a bottle of liquid), and objects that can't be emptied (for containers and platforms that deserve a "You can't empty that." message).
property empty_type
class unheld_to_player
{
empty_type NOTHELD_T
before
{
object DoEmpty
{
local a, b, obj, xobj
local thisobj, nextobj
CalculateHolding(object)
if object is container, openable, not open
{
VMessage(&DoEmpty, 1) ! "It's closed."
return true
}
if object is not container, platform
{
ParseError(12, object)
return false
}
if not children(object)
{
VMessage(&DoEmpty, 2) ! "It's already empty."
return true
}
thisobj = child(object)
while thisobj
{
nextobj = sibling(thisobj)
print thisobj.name; ": ";
if thisobj is static
VMessage(&DoEmpty, 3) ! "You can't move that."
else
{
a = player.holding
b = thisobj
obj = object
xobj = xobject
if Perform(&DoGet, b)
player.holding = a + b.size
else
player.holding = a
object = obj
xobject = xobj
if b not in object
object.holding = object.holding - b.size
}
thisobj = nextobj
}
run object.after
return true
}
}
}
class held_to_player
{
empty_type HELD_T
inherits unheld_to_player
}
class held_to_ground
{
empty_type HELD_T
}
constant NO_EMPTY_T 16
class no_empty
{
empty_type NO_EMPTY_T
}
Here is the grammar helper routine:
routine CheckEmpty(obj)
{
if obj.empty_type
{
TOKEN = obj.empty_type
if not CheckObject(obj)
{
return false
}
elseif obj.empty_type = NO_EMPTY_T
{
ParseError(12, obj)
return false
}
return true
}
elseif not CheckObject(obj)
return false
return true
}
#endif NEW_EMPTY
Lastly, whether or not players use this new system, I think Roodylib will replace DoEmpty to switch around the platform/container check before the children check:
replace DoEmptyEDIT: Just throwing in that, yeah, I know my code does nothing about the "multi from/outof/etc xobject" grammar that points to DoGet, but I think that would go to DoGet in most cases anyway and I'm comfortable with people having to write their own before routines to catch the rest.
{
local a, b, obj, xobj
local thisobj, nextobj
CalculateHolding(object)
if object is container, openable, not open
{
VMessage(&DoEmpty, 1) ! "It's closed."
return true
}
if object is not container, platform
{
ParseError(12, object)
return false
}
if not children(object)
{
VMessage(&DoEmpty, 2) ! "It's already empty."
return true
}
thisobj = child(object)
while thisobj
{
nextobj = sibling(thisobj)
print thisobj.name; ": ";
if thisobj is static
VMessage(&DoEmpty, 3) ! "You can't move that."
else
{
a = player.holding
b = thisobj
obj = object
xobj = xobject
if player not in location and
(parent(player) is platform or
parent(player) is container) and
not xobject:
Perform(&DoPutIn, b, parent(player))
else
Perform(&DoDrop, b)
object = obj
xobject = xobj
player.holding = a
if b not in object
object.holding = object.holding - b.size
}
thisobj = nextobj
}
run object.after
return true
}
No comments:
Post a Comment