Placing things in scope [SOLVED]

K.V.
27 Jan 2018, 02:38Before you read anything in this thread, you should familiarize yourself with the actual information.
http://docs.textadventures.co.uk/quest/scopes.html
http://docs.textadventures.co.uk/quest/commands_with_unusual.html
http://docs.textadventures.co.uk/quest/advanced_scope.html
http://docs.textadventures.co.uk/quest/ui-callback.html
http://docs.textadventures.co.uk/quest/advanced_game_script.html
I am attempting to wrap my mind around things which can be accomplished with scope.
...but I'm not doing a very good job.
Anyone have any good examples?

K.V.
02 Feb 2018, 06:36In Quest 5.7.2 you can just put world
in the Scope field of the command.
jmnevil54
02 Feb 2018, 20:13K.V., why do you talk to yourself?
adran06
02 Feb 2018, 20:42XD I read this post when it first went up, and totally missed that

K.V.
02 Feb 2018, 20:58POP QUIZ
Why do I talk to myself?
A. I am a crazy person.
B. I can come back to this thread months from now (after I've forgotten the details), and I'll be proud of myself for leaving good notes.
C. I was just trying to help you guys and gals.
D. No one else listens to me.
E. All of the above.
adran06
02 Feb 2018, 21:48E obviously. Mostly A, but definitely E.

K.V.
02 Feb 2018, 23:20Absolutely right!
You get a star for the day!!!
☆

Dcoder
05 Feb 2018, 12:34F. You are one of the few people smart enough to understand yourself. : )
XanMag
06 Feb 2018, 00:24D.
Definitely D. With a little A sprinkled in.

K.V.
19 Feb 2018, 02:34I still can't do very much with scope...
(To see what brought me back to this, click here: http://textadventures.co.uk/forum/quest/topic/egoik0xgukucht6dikjtrw/make-npc-companion-carry-objects#2295ed97-4720-49e5-8e5f-26448b8132c4)
The Kindergarten Stuff
I can make a game with a clock object, which does not exist in the game world (meaning it isn't in a room).
I then enable 'Advanced features' on the game object, and put this in the Scope backdrop thingy:
Now I can interact with the clock, no matter what.
That clock is IN SCOPE!
Example game's code:
<!--Saved by Quest 5.7.6623.30864-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Scoping Things Out">
<gameid>0d1663e9-87f0-47b1-8ca1-49cb3cc40ec6</gameid>
<version>0.0.1</version>
<firstpublished>2018</firstpublished>
<scopebackdrop type="script">
list add (items, clockobject)
</scopebackdrop>
</game>
<object name="room">
<inherit name="editor_room" />
<isroom />
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
</object>
<object name="clock_object">
<inherit name="editor_object" />
<alias>clock</alias>
<look type="script">
msg ("You check the time.")
// I have ClockLib.aslx included in all of my games in my Core.aslx file.
// This runs the 'clock' command's script, which just prints the clock message.
invoke (clock.script)
</look>
<listalias>clock (which reads {game.clock})</listalias>
<displayverbs type="stringlist">
<value>Look at</value>
</displayverbs>
</object>
<function name="GetListDisplayAlias" parameters="obj" type="string">
if (HasString(obj, "listalias")) {
result = ProcessText(obj.listalias)
}
else {
result = GetDisplayAlias(obj)
}
return (result)
</function>
</asl>
First Grade Stuff
In a totally different example, I can place the direct children of Fred (who is carrying things) in scope in a command.
In this example, if you ASK FRED FOR [SOMETHING], the direct children of Fred are placed in scope before that command runs the main script, allowing you to interact with them.
(You can enter FRED, INVENTORY to get a list of the things he's carrying in this example. (It was a very rough draft, and I didn't write the code which listed his belongings in any other scripts, such as LOOK AT (or just in his alias string).))
Example game's code:
<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Fred Carries Things">
<gameid>803a9ebb-d611-4253-b116-698982bba250</gameid>
<version>1.0</version>
<firstpublished>2018</firstpublished>
</game>
<object name="room">
<inherit name="editor_room" />
<isroom />
<enter type="script">
</enter>
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
<object name="Fred">
<inherit name="editor_object" />
<inherit name="namedmale" />
<givedict type="scriptdictionary">
<item key="thingy"><![CDATA[
msg ("\"It's my favorite thingy,\" says Fred. \"Take good care of it.\"<br/><br/>He hands it over.")
AddToInventory (thingy)
]]></item>
<item key="widget"><![CDATA[
firsttime {
msg ("\"This widget is mine,\" says Fred. \"Go find your own.\"<br/>")
}
otherwise {
msg ("\"I've already told you,\" says Fred. \"You can't have it.\"<br/>")
}
]]></item>
</givedict>
<giver />
<object name="widget">
<inherit name="editor_object" />
</object>
<object name="thingy">
<inherit name="editor_object" />
</object>
<object name="cane">
<inherit name="editor_object" />
</object>
</object>
</object>
<command name="npc_inventory_cmd">
<pattern>#object#, inventory;#object#, i;#object# inventory;#object# i</pattern>
<script>
PrintNpcInventory (object)
</script>
</command>
<command name="ask_npc_for_object_cmd">
<pattern>ask #object1# for #object2#;#object1#, give me #object2#;get #object2# from #object1#;take #object2# from #object1#</pattern>
<scope>Fred</scope>
<script>
if (not HasAttribute(object1,"giver")) {
msg (CapFirst(object1.gender) + " can't do that.")
}
else {
if (DictionaryContains(object1.givedict,object2.name)) {
invoke (ScriptDictionaryItem(object1.givedict, object2.name))
}
else {
msg (CapFirst(GetDisplayName(object1)) + " shakes " + object1.possessive + " head.")
}
}
</script>
</command>
<function name="FormatNpcInventory" parameters="npc" type="string"><![CDATA[
if (ListCount(GetDirectChildren(npc))<1) {
return ("nothing")
}
return (FormatObjectList("", npc, "and", ""))
]]></function>
<function name="PrintNpcInventory" parameters="npc">
msg (CapFirst(GetDisplayName(npc)) + " is carrying " + FormatNpcInventory(npc) + ".")
</function>
</asl>
After Dropping Out
That's right. I dropped of scope school (although it was actually more of a "learn by trial and error" thing).
I decided it would be much easier to alter the ScopeReachableNotHeldForRoom()
function like so:
<function name="ScopeReachableNotHeldForRoom" parameters="room" type="objectlist">
<![CDATA[
result = NewObjectList()
foreach (obj, GetAllChildObjects(room)) {
if (ContainsReachable(room, obj) and obj <> game.pov and not Contains(game.pov, obj)) {
list add (result, obj)
}
}
if (HasScript(game, "scopebackdrop")) {
dict = NewDictionary()
dictionary add (dict, "items", result)
do (game, "scopebackdrop", dict)
}
else if (HasAttribute(game, "scopebackdrop")) {
result = ListCombine (game.scopebackdrop, result)
dict = NewDictionary()
dictionary add (dict, "items", result)
}
return (result)
]]>
</function>
Then, I added these two functions:
<function name="AddToScope" parameters="obj">
if (not ListContains(game.scopebackdrop,obj)) {
list add (game.scopebackdrop, obj)
}
</function>
<function name="RemoveFromScope" parameters="obj">
if (ListContains(game.scopebackdrop,obj)) {
list remove (game.scopebackdrop, obj)
}
</function>
Now I can place things in scope (and vice-versa) at will.
AddToScope(object)
RemoveFromScope(object)
The same thing may be possible with the default functions (using variables and attributes, as well as object names), but I tried, and tried, and I could never get much of anything to work for me. (This is probably due to ignorance on my part, but I digress.)
I've added those functions to the example game with the clock.
There are two test commands:
test1
adds an object named "dummy" to scope, and test2
removes it.
NOTE: You can still make an object scenery if you don't want it displayed in the Places and Objects pane, but you would still like the player to be able to interact with it.
Revised example game with clock:
<!--Saved by Quest 5.7.6623.30864-->
<asl version="550">
<include ref="English.aslx" />
<include ref="Core.aslx" />
<game name="Scoping Things Out">
<gameid>0d1663e9-87f0-47b1-8ca1-49cb3cc40ec6</gameid>
<version>0.0.1</version>
<firstpublished>2018</firstpublished>
<scopebackdrop type="objectlist">clock_object</scopebackdrop>
</game>
<object name="room">
<inherit name="editor_room" />
<isroom />
<description><![CDATA[{command:test1}<br/><br/>{command:test2}]]></description>
<object name="player">
<inherit name="editor_object" />
<inherit name="editor_player" />
</object>
</object>
<object name="clock_object">
<inherit name="editor_object" />
<alias>clock</alias>
<listalias>clock (which reads {game.clock})</listalias>
<displayverbs type="stringlist">
<value>Look at</value>
</displayverbs>
<look type="script">
msg ("You check the time.")
// I have ClockLib.aslx included in all of my games in my Core.aslx file.
// This runs the 'clock' command's script, which just prints the clock message.
invoke (clock.script)
</look>
</object>
<object name="dummy">
<inherit name="editor_object" />
</object>
<command name="scope_test1_cmd">
<pattern>test1</pattern>
<script>
AddToScope (dummy)
</script>
</command>
<command name="scope_test2_cmd">
<pattern>test2</pattern>
<script>
RemoveFromScope (dummy)
</script>
</command>
<function name="ScopeReachableNotHeldForRoom" parameters="room" type="objectlist"><![CDATA[
result = NewObjectList()
foreach (obj, GetAllChildObjects(room)) {
if (ContainsReachable(room, obj) and obj <> game.pov and not Contains(game.pov, obj)) {
list add (result, obj)
}
}
if (HasAttribute(game, "scopebackdrop")) {
result = ListCombine (game.scopebackdrop, result)
dict = NewDictionary()
dictionary add (dict, "items", result)
}
return (result)
]]></function>
<function name="GetListDisplayAlias" parameters="obj" type="string">
if (HasString(obj, "listalias")) {
result = ProcessText(obj.listalias)
}
else {
result = GetDisplayAlias(obj)
}
return (result)
</function>
<function name="AddToScope" parameters="obj">
if (not ListContains(game.scopebackdrop,obj)) {
list add (game.scopebackdrop, obj)
}
</function>
<function name="RemoveFromScope" parameters="obj">
if (ListContains(game.scopebackdrop,obj)) {
list remove (game.scopebackdrop, obj)
}
</function>
</asl>

K.V.
19 Feb 2018, 03:39I'm trying to learn how to work with what is built into Quest instead of using my functions I modded and/or created (which you can find at the end of my previous post in this thread).
I've read this numerous times:
http://docs.textadventures.co.uk/quest/advanced_scope.html
...but I still can't figure out how to make this work for the life of me:
EDIT: See the next post for the correct version of this script.
<command name="ask_npc_for_object_cmd">
<pattern>ask #object1# for #object2#;#object1#, give me #object2#;get #object2# from #object1#;take #object2# from #object1#</pattern>
<scope>object2=object1</scope>
<script>
if (not HasAttribute(object1,"giver")) {
msg (CapFirst(object1.gender) + " can't do that.")
}
else {
if (DictionaryContains(object1.givedict,object2.name)) {
invoke (ScriptDictionaryItem(object1.givedict, object2.name))
}
else {
msg (CapFirst(GetDisplayName(object1)) + " shakes " + object1.possessive + " head.")
}
}
</script>
</command>
giver
is an attribute which only exists on NPCs who will give you things.
Each "giver" has a script dictionary called givedict
, with an entry for each item they may be carrying.
PS
Fred is the only NPC in this game.
I even changed object2=object1
to object2=Fred
, but it didn't work.
The only thing that I've tried that worked (without altering any functions) was putting Fred
in the scope field.

K.V.
19 Feb 2018, 04:01UPDATE
mrangel posted code that made this work for this command without altering any built-in functions.
http://textadventures.co.uk/forum/quest/topic/egoik0xgukucht6dikjtrw/make-npc-companion-carry-objects#881090f2-ad95-4139-958a-5050fde36a8d
<command name="ask_npc_for_object_cmd">
<pattern>ask #object1# for #object2#;#object1#, give me #object2#</pattern>
<scope>object1=room|object2=none</scope>
<changecommandscope type="script">
if (variable = "object1") {
// for 'object1', remove all non-giver items from scope
// I'm assuming "giver" is a boolean attribute?
foreach (to_remove, FilterByNotAttribute (items, "giver", true)) {
list remove (items, to_remove)
}
}
else if (variable = "object2") {
giver = DictionaryItem(matched, "object1")
// get the first matched object (giver), and add its children to scope
foreach (o, GetDirectChildren(giver)) {
list add (items, o)
}
}
</changecommandscope>
<script>
if (not HasAttribute(object1,"giver")) {
msg (CapFirst(object1.gender) + " can't do that.")
}
else {
if (DictionaryContains(object1.givedict,object2.name)) {
invoke (ScriptDictionaryItem(object1.givedict, object2.name))
}
else {
msg (CapFirst(GetDisplayName(object1)) + " shakes " + object1.possessive + " head.")
}
}
</script>
</command>
I am very happy now that I have seen this work!!!
I still prefer my method, where I alter one function, add two small functions, then change game.scopebackdrop
to an object list. This way, I can place whatever I please in or out of scope in any given situation before any command is entered (or before anything else happens, for that matter). Thus negating the need to doctor numerous commands, which would to lead to me forgetting to change the scope of a command or two, which would mean my game had bugs.
I'm sure Quest's default scripts are better than the hack I came up with in most instances, and it works for me either way now (thanks to mrangel and The Pixie), so I'm calling this one [SOLVED].
mrangel
19 Feb 2018, 09:11I still prefer my method, where I alter one function, add two small functions, then change
game.scopebackdrop
to an object list.
That has its uses; but as far as I can tell, it only works if you want to change the scope for all commands whose scope is currently room
.
changecommandscope
is designed for the circumstances where you want a specific command (like this one) to have an unusual scope.
I even changed object2=object1 to object2=Fred, but it didn't work.
You'd want the scope to be object1=room|object2=Fred
in that case. It doesn't check for the presence of an =
in the string unless there's also a |
, I believe.

K.V.
19 Feb 2018, 20:50I still prefer my method, where I alter one function, add two small functions, then change game.scopebackdrop to an object list.
That has its uses; but as far as I can tell, it only works if you want to change the scope for all commands whose scope is currently
room
.
Sorry, I'm scatter-brained, and my posts reflect that.
I meant this:
<function name="ScopeReachableNotHeldForRoom" parameters="room" type="objectlist">
<![CDATA[
result = NewObjectList()
foreach (obj, GetAllChildObjects(room)) {
if (ContainsReachable(room, obj) and obj <> game.pov and not Contains(game.pov, obj)) {
list add (result, obj)
}
}
// If the game is set up the normal way, where scopebackdrop is a script attribute
if (HasScript(game, "scopebackdrop")) {
dict = NewDictionary()
dictionary add (dict, "items", result)
do (game, "scopebackdrop", dict)
}
// Else, if the game is set up my new way, where scopebackdrop is an object list
else if (HasAttribute(game, "scopebackdrop")) {
result = ListCombine (game.scopebackdrop, result)
dict = NewDictionary()
dictionary add (dict, "items", result)
}
return (result)
]]>
</function>
<function name="AddToScope" parameters="obj">
if (not HasScript(game, "scopebackdrop")) {
if (not ListContains(game.scopebackdrop,obj)) {
list add (game.scopebackdrop, obj)
}
}
</function>
<!--
This will only remove things from scopebackdrop!
Anything actually in scope will not be effected.
-->
<function name="RemoveFromScope" parameters="obj">
if (not HasScript(game, "scopebackdrop")) {
if (ListContains(game.scopebackdrop,obj)) {
list remove (game.scopebackdrop, obj)
}
}
</function>
The room
variable will (or should) always be game.pov.parent
, since the ScopeReachableNotHeldForRoom()
function is being called internally. (I never directly call that function, at any rate.)
One issue with my setup is you'd need a script to place an object in (or out of) scope BEFORE the player enters a command, but, as long as I use a room enter (and/or exit) script, possibly a turn script, this solves a lot of scenery object problems in regards to all available commands.
Okay... I say "problems", but that may be poor wording.
I mean I don't like to clone (or create duplicate) scenery objects. I also don't like to move objects around. (I'm thinking mainly of doors in games where rooms move around.)
I might also wish to change the items in the scopebackdrop
script around at any given point.
The way it's set up by default, we can't add or remove items from the existing script. We can replace the script, or we can remove it, but that's it.
(I actually found a way to retrieve the items from the existing scopebackdrop
script by creating a script with its own "items" list, then running the scopebackdrop
script from within the newly created script, then copying that items
list to a newly created list: game.backdrop_items
. Then, I added my object to that list, and, finally, I replaced the scopebackdrop
script with a new one: list add(items,game.backdrop_items)
. That was a bunch of stuff going on, especially considering I've neglected to mention all the code checking to see if things actually existed, and... blah. I decided it was much easier to switch over to the method at the very beginning of this post!)
I know there are many ways any given scenario could be handled, but I wanted to get a handle on controlling the scope to handle a few things, and I wanted it to effect all available commands sometimes, but only specific commands other times. (The latter is where I will use the newly added scope features, once I've learned how to do so.)
In Inform (and I know I can get Quest to do whatever Inform can do; once I acquire the know-how), I can put a tree in my front yard and make it so you can see it from the street like so:
After deciding the scope of the player when location is The Street:
place tree in scope.
If I wanted to add the house (or anything else), it would be:
After deciding the scope of the player when location is The Street:
place tree in scope;
place house in scope.
Now, I can pretty much cover that particular scenario in Quest with a before enter script on the street:
AddToScope(tree)
AddToScope(house)
Then, the exit script:
RemoveFromScope(tree)
RemoveFromScope(house)
WITH THE DEFAULT SETUP:
If we could put things like Ralph.parent
as the scope (which we probably can, and I just don't know that), we could keep him in scope, wherever he may roam.
(One problem with this is that it places everything in a room in scope. We can't just place one object in scope (I don't think). That happens to be what we want here, but it is not always the case.)
Let's say we have a pair of spy glasses, complete with audio and video features.
Ralph has a pair, as well.
When you don your glasses, you wish to see (or examine) everything in whatever room Ralph is in.
You also want to be able to enter commands like, "RALPH, GET THE PINK PANTHER", and have Ralph get the diamond without having to use #text#
in your command pattern.
In fact, you want to be able to enter ANY command to interact with things you can "see", without Quest saying, "I can't see that (the thing I just mentioned)."
I was thinking maybe something like this would work with the default setup, but you can't use things like Ralph.parent
:
if (whatever){
foreach(cmd,AllCommands()){
if(HasString(cmd,"scope")){
cmd.scope = cmd.scope + ",Ralph.parent"
}
}
}
So, I ended up with this:
To enable:
game.pov.parent.ralph_parent = Ralph.parent
foreach (cmd, AllCommands()) {
if (not cmd.name = "go") {
if (HasString(cmd,"scope")) {
cmd.scope_bak = cmd.scope
cmd.scope = cmd.scope + ";ralph_parent"
}
else {
cmd.scope_bak = ""
cmd.scope = "ralph_parent"
}
}
}
To disable::
foreach (cmd, AllCommands()) {
if (HasString(cmd,"scope")) {
cmd.scope = cmd.scope_bak
}
}
this.ralph_parent = null
You'd want the scope to be
object1=room|object2=Fred
in that case. It doesn't check for the presence of an=
in the string unless there's also a|
, I believe.
Aha!
That's a tasty nugget, if I ever saw one!
All in all, I'm thinking there are times when I'd need to use the scope
attribute of a command and other times when I'd want to add or remove items from the scopebackdrop
"list".
All I've really done is change the scopebackdrop
attribute to an object list which can be very easily modified.
Conversely, mrangel has written some awesome code which allows us to do all sorts of things with scope of a specific command. I'm just not smart enough to be able to work it.

K.V.
19 Feb 2018, 21:02Just for the record, I am not on the same level as mrangel, Pixie, or Pertex. (I'm sure I've left someone out. Sorry!)
Those guys are playing chess. I'm just playing checkers.
When I drone on and on about things (i.e., scope), it's either because:
A. Whoever I'm corresponding with isn't understanding what I'm trying to accomplish (and/or why).
B. I believe A to be the case when it isn't, and I'm just being dumb silly.

CheeseMyBaby
09 Apr 2018, 08:56I have a question about scope (I've read and read and read about it, I get the point of scopes, I understand the commands but still I can't put them to use.)
I have a book case.
As it is now I have to:
- Open it
- Type 'look', to see what's inside.
I want to:
- Open it and get the content listed.
I'm about to pull my hair out. And my beard.
Edith: And my head. GAAAAH!

CheeseMyBaby
09 Apr 2018, 08:57And I apologize for hijacking a perfectly informative thread and making it about me and my total inability to get things done.
mrangel
09 Apr 2018, 10:21@CheeseMyBaby
On the "container" tab, there is an option "List contents when object is looked at or opened".
Or if you want a little more control over the format of the message, you could use the 'script when the object is opened':
msg (FormatObjectList("You manage to open it, and inside you see ", this, ", and", "nothing but dust"))

CheeseMyBaby
09 Apr 2018, 11:27@mrangel
I had picked open/closeable instead of container. Sheeeeeeeeeeeeeeez!
Thank you!
hegemonkhan
10 Apr 2018, 01:26those options in the GUI/Editor, are built-in Object Types, which you can read about here (scroll down to the bottom/last section):
http://docs.textadventures.co.uk/quest/elements/object.html
you used the 'openable' Object Type / Inherited Attribute, which is used for 'door' applications, as opposed to a openable/closable/lockable 'container' applications
(though they're connected to/with a lot of other code, so there's a lot more issues going on with using them, the documentation doesn't cover all this interwoven-ness and other attributes that they have)
(a cool/sneaky idea: having a 'door' Object be a container: the door has a secret compartment, hehe. Few people would ever think of a door having something hidden within it, hehe)

CheeseMyBaby
10 Apr 2018, 08:11Very true hege!
hegemonkhan
10 Apr 2018, 18:02HK is quite clever/creative in hiding things/spaces, HK grins toothily :D
If HK hid something, no one could ever find it, muwhahaha!

CheeseMyBaby
12 Apr 2018, 07:51Could you please hide my inability to code then HK? =)