Inheriting commands from the direct parent object - Is it possible?

K.V.
23 Aug 2017, 11:01I have one room called 'region 1', which has two rooms in it: room1 and room2.
I have another room called 'region 2', which has two rooms: room3 and room4.
Now, if I set up a command: enjoy #object#
on region 1, the parser has no clue what enjoying something is in room1 or room2 (although it does work if the player is actually in region 1 itself).
Is there any way to make a room within a room 'inherit' the room-specific command(s) of its direct parent object?
ShadowsEdge19
26 Aug 2017, 09:33The only way I know how to do what you have is to create a base object that holds your attributes and commands you want to share between all of the rooms in the game and then any actual rooms will inherit that base object much like the default objects will inherit some core Quest object type.

K.V.
27 Aug 2017, 03:13Hello, ShadowsEdge19!
You wouldn't happen to have a link concerning base objects, would you?
I searched and found quite a few things, but most of them concerned backdrops. (I got the idea to try this after doing the backdrop thing.)
I was just trying to be lazy, anyway... If you don't just have something bookmarked, I'm cool.
hegemonkhan
27 Aug 2017, 06:44I think... this would be the underlying code of quest itself:
(see quest's source code, I think Pixie has it on his github, else, look where to find it via the 'QuestKit' forum board and/or google search for "quest text adventure development", to find where Alex has it, for the public to use/develop quest with it)
(I think the base OBJECTS/CLASSES can be found here, under/within the 'world model' hyperlink, aka just click on this link here: https://github.com/textadventures/quest/tree/master/WorldModel/WorldModel ) --- yep, this is it, but you're going to have to learn/understand a lot of the full-bore programming languages, aka: C++/Java/Python, aspects: namespaces, OBJECTS, instantiating, CLASSES, etc
(I think here it is: https://github.com/textadventures/quest ) --- this probably has important stuff too (lots of inter-connected/complex code)
(here's the main github page for quest products, accessed via the quest site at the bottom, under 'resources -> github': https://github.com/textadventures/ )
quest's base (OOP/OOD) OBJECTS/CLASSES:
quest's Elements: Objects, Verbs, Commands, Functions, Turnscripts, Timers, Object Types, etc
and
quest's Attribute Types: Booleans, Strings, Integers, Doubles, Object references/pointers, Lists, Dictionaries, etc
ShadowsEdge19
27 Aug 2017, 08:14I don't know how to do this in the Web editor of this is where you are coming from but I use the desktop editor and work mainly from the files themselves in a text editor.
Create the object as you want it with all of the attributes and create a 2nd object you want to base this off.
I'm the Attribute tab of the 2nd object there is a list of inherited types, go and add the reference to your first object in there and that should mean any attributes and display verbs and such things are copied across from object 1 and should display as greyed out in their respective lists.
If you manually add a version of that same display verb/attribute to the 2nd object then it now belongs solely to that object instead of the 1st and will show as black bold writing.
The Pixie
29 Aug 2017, 10:27You could override the ScopeCommands
function to get it to include other commands. This code would do it:
result = NewObjectList()
foreach (command, AllCommands()) {
if (command.parent = null or command.parent = game.pov.parent) {
list add (result, command)
}
if (not game.pov.parent.parent = null) {
if (command.parent = game.pov.parent.parent) {
list add (result, command)
}
}
}
return (result)
mrangel
29 Aug 2017, 13:31The Pixie, I was just looking through CoreScope.aslx in search of something else (which I think is impossible. Bah) and realised you could do that, so came here to post a similar answer.
Though my version would have been
result = NewObjectList()
foreach (command, AllCommands()) {
if (command.parent = null) {
list add(result, command)
}
else {
i = game.pov.parent
while (i.parent <> null) {
if (i = command.parent) {
list add (result, command)
}
i = i.parent
}
}
}
return (result)
I would have thought it'd be easier to just replace "command.parent = game.pov.parent" with "Contains(command.parent, game.pov)" … but I think the parser will take the first matching candidate it finds, so iterating upwards through the room stack probably gives the desired result if you end up wanting to have nested containers for your rooms.

K.V.
29 Aug 2017, 18:33Awesome!
Thanks, everyone!

K.V.
30 Aug 2017, 04:47What can you not find out how to do, mrangel?
We'll figure that out, too!

K.V.
30 Aug 2017, 05:54Pixie's code works!
The game I'm using it in is going to ♫♫♫ ROCK! ♫♫♫
Good to have ya' back, Pix!
mrangel,
This line is blowing my mind:
i = i.parent
In context:
i = game.pov.parent
while (i.parent <> null) {
if (i = command.parent) {
list add (result, command)
}
i = i.parent
}
Just to keep my 'i's from getting crossed, I'm gonna substitute 'peanut_butter_cup' for the 'i':
result = NewObjectList()
foreach (command, AllCommands()) {
if (command.parent = null) {
list add(result, command)
}
else {
peanut_butter_cup = game.pov.parent
while (peanut_butter_cup.parent <> null) {
if (peanut_butter_cup = command.parent) {
list add (result, command)
}
peanut_butter_cup = peanut_butter_cup.parent
}
}
}
return (result)
// KV added the next bit:
create ("kv_peanut_butter_cup")
kv_peanut_butter_cup.parent = KV
msg ("You suddenly realize that you have a peanut butter cup!<br/><br/>You eat it. (Good stuff!)")
destroy ("kv_peanut_butter_cup")
Oh, okay...
That code should work, too. (Even without my additions!)
The Pixie
30 Aug 2017, 07:03By the way, I am not sure what will happen if you have a command in the room and in the region with the same pattern. You would want the command in the room to take priority, but I would guess it would depend on their position in the file.
Also, kind of related, if the pattern is different, then the match strength is the first thing that determines which is chosen. Match strength is the number of characters not in capture groups (i.e., not inside brackets). If you had:
^(?<text>push|pull|move) (?<object>.*)$
The regex will match PUSH CRATE, and put "PUSH" into text
. However, the built in PUSH command will take priority, as it has a higher match strength of 5, rather than 1.

K.V.
30 Aug 2017, 08:11@Pix
So ^
means from the beginning, (?<text>push|pull|move)
means if this string is 'push', 'pull', or 'move', #text# will be whichever one it is (and Quest turns #text# back into (?<text>.*)
), and the rest has to be and #object# at $
the end?
The Pixie
30 Aug 2017, 08:53Correct. (?<text>push|pull|move)
is called a capture group, as is (?<object>.*)
. The brackets and question mark denote it as such. The bit in ankle brackets is the name, and will become the name of the variable (if if it starts "object", Quest will try to match to an object in scope). The rest is the pattern to match against. The .
means match anything, and the *
means match any number, so the object is matched to any text. Then, push|pull|move
means it has to be one of those.
mrangel
30 Aug 2017, 22:14Just realised my code was broken. Should have the loop iterating through parents (from game.pov.parent all the way up to the top, and then null) on the outside, and looping over AllCommands() inside that. That way, the result list has commands from the room first, then the region, then the outer region, (or however many levels there are), and finally the commands whose parent is null. As far as I understand it, the parser looks through the command list in order until it finds a match; so putting the innermost one first means that regions can override global commands, and rooms can override their regions.
Off the top of my head…
result = NewObjectList()
room = game.pov
while (room <> null) {
room = room.parent
foreach (command, AllCommands()) {
if (room = command.parent) {
list add (result, command)
}
}
}
return (result)
So it returns a list of all the commands in game.pov.parent, then the ones in game.pov.parent.parent, then game.pov.parent.parent.parent, and so on… and I believe (haven't actually checked, because I'm writing on my phone) that the top level region's parent will be null, so the last iteration of the loop puts the global commands on the end of the list.