forcing a before property to not use up a turn
Posted: Mon Jun 10, 2024 11:28 pm
I had a couple conversations with Kent recently about the possible future of Hugo- not to get anyone's hopes up; it was just a casual chat daydreaming about what might be appealing one day. At one point, I shared some features that I would like to see. After the email was sent, I remembered how there have been times in Hugo where I wished the author had more control over whether a command used up a turn, but after thinking about it, I thought, hey, that's all handled by the library so that's completely under our control already.
Mainly, the issue is this: especially when an author is new to Hugo, one of the most appealing ways to give special responses is to use the before property routine system. In some of these cases, the author will want to do something like a "You can't get pass the rubble." message. "You can't go that way." messages normally don't use up a turn, so it's kind of jarring when there's no easy way to use a before property routine and have a matching behavior.
So, today, I attempted to allow for cases like this. Here is the necessary code:
The relevant parts of the Perform replacement are near the beginning and the end. Perform can be called several times for one command (as one command is sometimes directed to another), so we want to make sure we are checking for our "force_false" global only once. To do this, I check the values of verbroutine, object, and xobject (which are initially set by the engine) against the routine arguments. If they match, the local variable "first_call_ is set true. At the end of the routine, we check the values of force_false, first_call, and queue (used by commands that support "all", like >GET ALL) and if the conditions are right, Perform will return false and no turn will be used.
So then we could have code like this for, say, a mine shaft or something:
I don't think I'll add this as a permanent feature to Roodylib or even write a Not Dead Hugo post about it since it's kind of hacky, so this goes here in case this would be useful to someone.
Mainly, the issue is this: especially when an author is new to Hugo, one of the most appealing ways to give special responses is to use the before property routine system. In some of these cases, the author will want to do something like a "You can't get pass the rubble." message. "You can't go that way." messages normally don't use up a turn, so it's kind of jarring when there's no easy way to use a before property routine and have a matching behavior.
So, today, I attempted to allow for cases like this. Here is the necessary code:
Code: Select all
global force_false
replace Perform(action, obj, xobj, queue, isxverb)
{
local r
local objtemp, xobjtemp, verbtemp, actortemp, first_call
#ifclear NO_XVERBS
local restoring
if verbroutine = &DoRestore: restoring = true
#endif
if action = verbroutine and obj = object and xobj = xobject
first_call = true
#ifset DEBUG
if debug_flags & D_PARSE
{
print "\B[Perform("; number action; ", "; obj.name;
if (debug_flags & D_OBJNUM) or queue = -1
print " ["; number obj; "]";
print ", "; xobj.name;
if (debug_flags & D_OBJNUM) or queue = -1
print " ["; number xobj; "]";
if queue
print ", "; number queue;
print ")]\b"
}
#endif
if queue
parser_data[PARSER_STATUS] |= PERFORM_QUEUE
if not queue and object
parser_data[LAST_SINGLE_OBJECT] = object
else
parser_data[LAST_SINGLE_OBJECT] = 0
parser_data[VERB_IS_XVERB] = isxverb
! These temp objects guarantee we go back to whatever the previous
! settings were before Perform was called
objtemp = object
xobjtemp = xobject
verbtemp = verbroutine
actortemp = actor
object = obj
xobject = xobj
verbroutine = action
actor = player
! some stuff we do when Perform is called by the engine
if (parser_data[PARSER_STATUS] & PARSER_ACTIVE) and not isxverb
DeactivateParser
#ifclear NO_OBJLIB
if verbroutine = &DoGo and not object
SetupDirectionObjects
#endif
! Itemize each object in a list of multiple objects
if queue > 0 and object > display
{
#ifset USE_CHECKHELD
! Check if an ImplicitTakeForDrop was just done, meaning we
! need a newline before printing the next "object:"
if checkheld is workflag
print ""
checkheld is not workflag
#endif
print object.name; ": ";
}
r = BeforeRoutines(queue)
if not r ! if action not stopped by before routines
{
r = call action ! object.after and xobject.after
! run by verbroutine
#ifclear NO_XVERBS
if restoring
verbroutine = &DoRestore
#endif
if r ! if action was successful, run after routines
{
AfterRoutines
}
}
!:DonePerform area
#ifset USE_CHECKHELD
ResetCheckHeld
#endif
last_object = object
verbroutine = verbtemp
object = objtemp
xobject = xobjtemp
actor = actortemp
if queue = -1
last_object = -1
parser_data[PARSER_STATUS] = PARSER_RESET
if force_false and first_call
{
force_false = 0
if not queue
return false
}
return r
}
So then we could have code like this for, say, a mine shaft or something:
Code: Select all
before
{
object DoGo
{
if rubble in location
{
"You can't get past the rubble."
force_false = true
return true
}
else
return false
}
}