Move [object] to [other object]

psymann
31 Mar 2013, 17:58
Hello

I just discovered Quest recently and have been making some progress figuring out most of the basics. What a clever program! :D

But I'm stuck on one particular action that I can't figure out or find on the wiki, so hoping someone here can help. :?


I have a room called "Kitchen".
I have a room called "Study".
In the "Kitchen" is an object called "Box".

What I want is to set up a command called "Drag".

Because what I want my user to do is type in:

DRAG Box TO Study

And I want the outcome to be that the object, and the player, both simultaneously move out of the "Kitchen" and into the "Study".

I'm ok on the script bit - I can see an option "Move" that allows me to:

Move object: object [box] to object [study]
and
Move object: object [player] to object [study]

What I can't figure out is how to set up the verb "Drag" to allow my user to specify both the object he wants to move, and the destination to which he wants to move it. Since it's a big box that's too heavy to lift, I don't want him to have to 'take' the box and then 'drop' it, unless there's a way of using take/drop to make it look like a drag. I suppose I could have him 'take' it, and then lock all the exits other than the one to the study, and then unlock them all again if he drops it, but it doesn't seem fully intuitive to do it that way.

So - how to set up verb Drag so that:

DRAG [object 1] TO [object 2]
lets me set up scripts
Move object: object [object 1] to object [object 2]
and
Move object: object [player] to object [object 2]

Does the question make sense?
And is it possible?

Thanks!

psymann

jaynabonne
31 Mar 2013, 18:14
I don't think using an object for the room will work, because the room will not be visible in *this* room, and so it won't be found.

You can create a command with this pattern:

drag #object# to #text#

Then in the script, you can query the "text" argument to see what they typed. It will match anything they type for the "to" object, so you'll have to check if it exists and is a room (e.g. use GetObject(text) to get the object), etc and put up an appropriate error message if not.

Or if you only want to drag to one room, you can just make the command pattern:

drag #object# to kitchen

and be done with it! Hope that helps!

psymann
31 Mar 2013, 19:07
The hardwired "to kitchen" option is clever, hadn't thought of that. :) Though I might still stick with #text# so that I can give different error messages depending on the differently wrong places the user tries to drag it to ;-)

Then in the script, you can query the "text" argument to see what they typed



How do I do that? Maybe I'm trying to run before I can walk, but I'm getting in a muddle as to:

- whether I am trying to create a 'verb' or a 'command' to do this
- whether I'm trying to use IF or SWITCH to do the test (eg "If object = 'box'" or "Switch object, Case box".

I was thinking I wanted to create a command with a pattern of drag #object_to_drag# to #text_to_drag_to# and then do a Switch to check (a) what the object_to_drag was, and (b) what the text_to_drag_to was, to determine what (if any) course of action could be taken. So far all I've managed to get is compile errors where it says it doesn't understand the box.

psymann

jaynabonne
31 Mar 2013, 21:14
I would say that if you could post what you have so far here, it will be easier to debug. Otherwise, it will be a guess. :)

As far as verbs and commands, verbs are a targetted form of command. The verb defines a script attribute which is invoked on the object which matches the pattern. There is also a "multi-verb" form, which I'd have to revisit (but I do remember I had to rewrite some core code to use it the way I wanted before).

If you wanted to be able to use "drag" generally on different objects and to different targets, that might be a way to go, but it will be tricky. If you just have a couple of cases to implement, a command should be simpler.

sonic102
31 Mar 2013, 21:34
Command pattern: drag #objectdrag to #textplace

Script
if textplace has attirbute [visited]
if textplace.visited = true
move [player] to [textplace]
move [objectdrag] to [textplace]
print "You drag it."
else
print "I don't know that place."
else
"I don't know that place."

The problem with this is that if you lock a place that the player has entered, the player can still go back there. This can be solved with a simple flag.

Anyway, this is a cool feature! Waiting to see it.

psymann
31 Mar 2013, 22:24
I don't really have any code yet worth sharing, jaynabonne, as I keep trying different things ;-) When I get a bit closer to what I'm after I may revisit with some code, but thanks for now :)

Sonic, I'll give your structure a try - the wiki says that "visited" is a standard attribute that's part of the Core library, but I can't see it listed on the attributes tab of my rooms. Do I have to do something to set it up before I can start using it?

I should be ok to add the flags etc to validate which items can/can't go into which rooms at which times - once I've got a basic structure working for dragging anything anywhere at all ;)

psymann

jaynabonne
31 Mar 2013, 22:39
"visited" is set by the core code when you visit a room for the first time. So before you visit a room, it will be undefined (so be sure to use GetBoolean, which returns false if an attribute is not defined). So the sequence sonic gave allows you to drag to a room you have already visited (and only if you have). If that's not the behavior you want, then you'll need to eliminate that part.

You will also want to validate the text parameter. Either you can have hard-coded values that work (e.g. "kitchen", "bedroom") or you can use GetObject(textplace) and see if it returns a non-null value. That return value is what you would move the object to. Note that just checking that non-null return value won't ensure the text they typed is actually a room (e.g. they could indicate some other object). So you will need a way to ensure that what they have typed is a valid place to drag whatever it is they want to drag. I don't know of a standard way to do that in Quest. One thing you could do is attach an attribute to valid rooms (e.g. "dragtarget") or something that you can explicitly check. Then if it has that attribute, it's a good drag target. Otherwise, it isn't.

HegemonKhan
31 Mar 2013, 23:06
I did this quickly just now, so it may need to be fixed up a bit (the syntax may be wrong), but otherwise, I think it'll work, lol

<command name="drag_command">
<pattern>drag #text1# to #text2#</pattern>
<script>
drag_function (text1,text2)
</script>
</command>

<function name="drag_function" parameters="text1,text2">
drag_target_object = GetObject (text1)
drag_target_destination_room = GetObject (text2)
if (drag_target_object = null) {
foreach (obj1,GetAllChildObjects(game.pov.parent)) {
if (obj1.alias=text1) {
drag_target_object = obj1
} else {
msg ("There seemingly is no " + text1 + " in the vicinity.")
}
}
}
if (drag_target_destination_room = null) {
foreach (obj2,AllObjects()) {
if (obj2.alias=text2) {
drag_target_destination_room = obj2
} else {
msg (text2 + "seemingly doesn't exist.")
}
}
}
if (not drag_target_object.dragable) {
msg ("You can't drag " + drag_target_object + ", as it's too big and heavy!")
} else if (not drag_target_destination_room.dragable) {
msg ("You can't drag " + drag_target_object + ", as it can't fit in the " + drag_target_destination_room +"!")
} else if (not drag_target_destination_room.visited) {
msg ("You seemingly can't drag " + drag_target_object + " to " + drag_target_destination_room +".")
} else if (not drag_target_object, "ScopeReachable") {
msg ("There seemingly is no " + drag_target_object + " in the vicinity.")
} else {
msg ("You drag " + drag_target_object + " to " + drag_target_destination_room +".")
game.pov.parent = drag_target_destination_room
drag_target_object.parent = drag_target_destination_room
}
</function>


--------------------

@psymann,

wait for someone to look over this and correct it (assuming that it does work), then you'd just need to copy and paste this into your game code, (and you can alter it to how you want it, too, of course), then, all you got to do is to add in (create) the boolean attribute "dragable" to~on the objects and rooms that you want, set them to false, and then simply add in setting them to true into where you want to do so.

I can and will help you do all of this stuff, (it's good to learn to work with the code, as it is much faster and easier, lol), once my code is corrected and verified as being able to work.

jaynabonne
31 Mar 2013, 23:17
Wow, HK, that's impressive! :) Quite comprehensive. My only critique: if you use #object# instead of #text1#, then you can eliminate all the code that's checking for it being a valid object, being in the vicinity, etc as Quest will do that for you.

Beyond that - nicely done!

HegemonKhan
31 Mar 2013, 23:26
thanks, I've been working on something similar to this, so it wasn't too much to try to transfer over to doing what psymann wanted. heh, I knew my code wouldn't be perfect, between syntax and~or "redundency" (or poor or unneeded extra coding). I'm just happy that I then presume this code would work?

----------

P.S.

Your (and sonic's) mentioning that the core already has a visited attribute, saved me a lot of grief, in trying to code in some complex stuff, lol.

I was just about to try to make my own "visited" coding (via using scriptdictionaries), when I just thankfully decided to refresh and look at the forum, reading your post, lol.

----------

(HK Edit: nvm, with trying to rewrite my code better, atm anyways, as I got family coming soon for Easter. I'll try to work on it another day, when I can. Psymann, feel free to ask on how to get my code set up if you want to use it, and when I've got the time, I'll walk you through getting it set up correctly)

psymann
31 Mar 2013, 23:48
Ooh, thanks HK - that looks very exciting and I'll certainly give it a go (after a short while to see what other comments there are on it!).

In the meantime I had managed to get something that did work ... but in a really horrid fudgey sort of way... using entirely objects and not text at all because I've not got my head round all the error-checking code yet:

jaynabonne wrote:I don't think using an object for the room will work, because the room will not be visible in *this* room, and so it won't be found.


So with that new knowledge, what I can do with a bit of fudging is create a dummy object called "Roomdummy" with an Alias of "Room". So the user thinks they're dragging the object to the real room, but actually they're dragging it to a dummy room-named object which triggers an action to do the drag to the intended real room. Hmm.

 <command name="drag">
<pattern>drag #objecttodrag# to #objectdestination#</pattern>
<script>
if (HasAttribute(objecttodrag, "draggable")) {
msg ("Can be dragged")
if (HasAttribute(objectdestination, "canbedraggedto")) {
msg ("Can be dragged to this location")
MoveObject (player, Study)
MoveObject (objecttodrag, Study)
}
else {
msg ("Cannot be dragged to this location")
}
}
else {
msg ("Cannot be dragged")
}
</script>
</command>

And Studydummy has an attribute called "canbedraggedto", whereas Bathroomdummy does not.
And Box has an attribute called "draggable", whereas Wall does not.


It does seem to work although I had to hardwire in the name "Study" in the MoveObject code because what I wanted to do was put in a Switch/Case to move to different options based on objectdestination, but then my coding (non-)skills failed me again. But anyway - if I type "Drag box to Study", then both box and player move into the Study :)
If I type "Drag box to Bathroom", it tells me it can't be dragged to that location, and if I try to "Drag wall to Study" it tells me it can't be dragged.

(And no, I have no idea how many G's there are in drag(g)able! :lol: )

Anyway, that works but is horrid, so I will now go and look at your version which looks as if it will be miles nicer!

psymann

HegemonKhan
31 Mar 2013, 23:59
a quick mistake that I think exists (lol as in I'm not sure if it's wrong on not) in your code....

either:

change HasAttribute to GetAttribute
~OR~
use: if (HasAttribute (the_object,"it's_attribute") = true) {

IF HasAttribute: needs to be set = to true/false, and if it matches your setup, then it continues ~it does the additional nested script

IF GetAttribute: simply checks if you've got the attribute or not (if you do, then it continues ~ it does the additional nested script)

jaynabonne
01 Apr 2013, 00:14

It does seem to work although I had to hardwire in the name "Study" in the MoveObject code because what I wanted to do was put in a Switch/Case to move to different options based on objectdestination



You can create an attribute on the "shadow" objects which points to the real room. It would be of type "object".

<object name="ShadowStudy">
<alias>study</alias>
<realroom type="object">Study</realroom>
</object>

Then just do:

realroom = objectdestination.realroom
MoveObject (player, realroom)
MoveObject (objecttodrag, realroom)

jaynabonne
01 Apr 2013, 00:24
HegemonKhan wrote:a quick mistake that I think exists (lol as in I'm not sure if it's wrong on not) in your code....

either:

change HasAttribute to GetAttribute
~OR~
use: if (HasAttribute (the_object,"it's_attribute") = true) {

IF HasAttribute: needs to be set = to true/false, and if it matches your setup, then it continues ~it does the additional nested script

IF GetAttribute: simply checks if you've got the attribute or not (if you do, then it continues ~ it does the additional nested script)



The way he has it is fine. He's just using the *existence* of the attribute to key off of, not the value of it. At least, based on the code, I'm assuming that's what he's doing. :)

psymann
01 Apr 2013, 17:32
One tangential question:

HK wrote:
msg ("You drag " + drag_target_object + " to " + drag_target_destination_room +".")


When I try this in game, it comes out with the message:

You drag Object: Box to Object: Study.

Any idea why it's putting the "Object:" bit in there and how I get rid of that?

Oh, and I like that realroom trick, thanks jay :)

Thanks,
psy

jaynabonne
01 Apr 2013, 17:43
Because you're just printing out the object reference. The safest way to show the object name is:

msg ("You drag " + GetDisplayAlias(drag_target_object) + " to " + GetDisplayAlias(drag_target_destination_room) +".")

GetDisplayAlias will return the alias attribute if there is one; else it will return the name attribute.

psymann
01 Apr 2013, 18:48
Aha, thanks. There's more coding to this writing-an-adventure than I first realised ;) Still, making progress at least!

jaynabonne
01 Apr 2013, 19:11
To be honest, if you always give your objects and rooms aliases (which I do and highly recommend), then you can just use

drag_target_object.alias

instead of

GetDisplayAlias(drag_target_object)

The latter just handles the case where an alias is not defined. I rarely use GetDisplayAlias myself. :)

HegemonKhan
01 Apr 2013, 21:05
I'm terribly sorry psymann, I forgot to add the ' .alias ' onto the "drag objects (object and room)" usage in my posts.

so, just add the ' .alias ' onto the ' drag_target_object ' and ' drag_target_destination_room ' in the msg code lines.

for example:

msg ("You drag " + drag_target_object.alias + " to " + drag_target_destination_room.alias ".")

*you do need to actually set an alias for the objects (in the actual objects' coding or those objects' GUI~Editor window), if you want to have aliases for them anyways.

----------------------

if you don't want to give or have your objects with aliases, then just do this instead:

.name

so, for example:

msg ("You drag " + drag_target_object.name + " to " + drag_target_destination_room.name ".")

jaynabonne
01 Apr 2013, 21:43
And if you can't decide (alias vs name) or have a mixture of both, then GetDisplayAlias will cover it. :)

sonic102
01 Apr 2013, 21:50
For aliases, I just add a script to the game start that checks if an object has no alias, and if it doesn't, it sets the alias = the name.

psymann
01 Apr 2013, 23:23
All good advice, thanks. All my objects now have aliases :-)