Expression "this" in Functions

Liam315
26 Apr 2013, 16:54
I currently have an object which I clone each time the player takes it, and therefore am using the "this" expression in the verb scripts to avoid making multiple copies of the object and scripting them individually (e.g. if this.attribute = x then, if this.attribute = y etc.). Using the object causes changes in it's own attributes but when a new, identical object is taken I need them to be fresh.

Ideally I want to call these scripts from a function, but it seems to invalidate the use of "this" in the expressions and I get an error message along the lines of "unknown variable or object "this"". Is there any way around this or perhaps something I'm doing wrong?

Cheers,
Liam.

jaynabonne
26 Apr 2013, 20:30
Be sure you use "do" instead of invoke. That is, if your script attribute is named "MyScript", be sure you do:

do (object, "MyScript")

and not

invoke (object.MyScript)

Liam315
27 Apr 2013, 05:01
Sorry, I didn't explain myself properly. It's not an object's script attribute I want to run, I want to use the expression "this" in a separate function. Then call the function in a script and have it understand that the object I'm referring to is the one calling the function.

So what I have is:

The object "beverage" has a verb "Drink."
It also has a attribute "mouthfuls" (as in mouthfuls left until the beverage is finished).

Performing the verb calls a function "drinkbeverage"

The function has the set variable script "this.mouthfuls = this.mouthfuls -1"

When I just have the script "this.mouthfuls = this.mouthfuls -1" as the result of the verb "drink" it works fine. But if it calls the same script from a function I get:

Error running script: Error compiling expression 'this.mouthfuls -1': Unknown object or variable 'this'

This is a simplified version to make things clearer, the actual script is a bit more involved which is why I'd like to call functions rather than copy and paste the script into everywhere that might need it. If it can't be done then so be it, I'm just interested in understanding the architecture of the program as much as anything.


EDIT:
I've found a solution to my original problem. I was originally using "beverage1" to refer to the cloned object instead of "this," which worked until the second one was taken. I tried removing the object and removing dictionary keys but no matter what the second object was always "beverage2." What I didn't realise is that there is a "destroy" script command that solves my problem by allowing the script to be called from a function and reused by each cloned object.

I'd still be interested to know why my original problem occurred though for future reference if anyone has an answer.

jaynabonne
27 Apr 2013, 09:10
"this" is a reference to the called object in the context of a script which has been called via "do". It's an extra parameter passed into that script (here, I'm using "script" to mean a sequence of statements hung off an object with a "script" attribute, not an individual statement). It doesn't exist anywhere else, primarily because it doesn't have any meaning.

What you need to do is pass "this" explicitly into the function so that it knows what it is. Parameters don't automatically chain.

<function name="DrinkBeverage" parameters="this">
this.mouthfuls = this.mouthfuls -1
</function>

<drink type="script">
DrinkBeverage(this)
</drink>


Of course, I wouldn't call the function parameter "this" myself, as it's a bit non-descript. I'd probably call it "beverage" or something. But if you want to use "this", that's how you can do it.

Liam315
27 Apr 2013, 09:16
That makes things so much clearer to me now. I was actually going to create a thread asking for parameters to be explained because I didn't really understand what they did, now it all makes sense. I only started using the software about a month ago (and have no coding experience at all) so I'm still learning the finer points. Thanks for your help! :D

HegemonKhan
27 Apr 2013, 12:33
further about parameters:

as I can't really explain them that well myself, let me give an example of them in action:

(This is from the thread, ~ "Noob HK's Help Me Thread", in the latest posts, with my working on creating a combat system)

<command name="fight">
<pattern>fight #text#</pattern>
<script>
fight_function (game.pov,text)
</script>
</command>

parameters used:

game.pov
text

as this is a fight, combat, you vs "text"

there's an orc in the colloseum, you type: fight orc

the command runs the "fight_function" function, which will use the two objects: game.pov (you) and text (the orc)

<function name="fight_function" parameters="self,target">
enemy = GetObject (target)
If (enemy = null) {
msg ("That is not an object or it's not the object's NAME attribute.")
}
If (enemy.hostile = true) {
msg ("The " + enemy + " attacks you!")
self.hp = self.hp - enemy.damage
msg ("The " + enemy + " attacks you for " + enemy.damage + " damage!")
msg ("You attack the " + enemy +"!")
enemy.hp = enemy.hp - self.damage
msg ("You attack the " + enemy + " for " + self.damage + " damage!")
} else {
msg ("You can't attack that, it's not your enemy or it's not yet ... your enemy, silly!")
}
</function>

now, inside the function, "fight_function", game.pov -> self and text (orc) -> target -> enemy, as internally the game engine is substituting in "game.pov" for the function's new parameter~variable "self", and "text (orc)" for the function's new parameter~variable "enemy"

so, the use of parameters is like a way to "carry over" (and rename them too if you want to)* local variables from one script to another (and "non-nested" ~ separate) script (scripts, functions, and through~with call~ing functions).

*you don't have to rename the parameters:

<command name="fight">
<pattern>fight #text#</pattern>
<script>
fight_function (game.pov,text)
</script>
</command>

<function name="fight_function" parameters="game.pov,text">
enemy = GetObject (text)
If (enemy = null) {
msg ("That is not an object or it's not the object's NAME attribute.")
}
If (enemy.hostile = true) {
msg ("The " + enemy + " attacks you!")
game.pov.hp = game.pov.hp - enemy.damage
msg ("The " + enemy + " attacks you for " + enemy.damage + " damage!")
msg ("You attack the " + enemy +"!")
enemy.hp = enemy.hp - game.pov.damage
msg ("You attack the " + enemy + " for " + game.pov.damage + " damage!")
} else {
msg ("You can't attack that, it's not your enemy or it's not yet ... your enemy, silly!")
}
</function>

you have to convert "text" to "enemy" because you got to get the actual object of "text", so you've can actually work with it in the function, and also, it'll try to apply the string "text" and the object "enemy" to the "text" in the would-be: "text (instead of "enemy") = GetObject (text). Otherwise, in the Command script, you'd use for the pattern, fight #object# , as this will get the object right there, of what you typed in.

you can go many levels deep too with variables through parameters:

[code]<command name="fight">
<pattern>fight #text#</pattern>
<script>
fight_function (game.pov,text)
</script>
</command>

<function name="fight_function" parameters="self,target">
enemy = GetObject (target)
If (enemy = null) {
msg ("That is not an object or it's not the object's NAME attribute.")
}
If (enemy.hostile = true) {
msg ("The " + enemy + " attacks you!")
enemy_attack_function (self,enemy)
msg ("The " + enemy + " attacks you for " + enemy.damage + " damage!")
msg ("You attack the " + enemy +"!")
self_attack_function (self,enemy)
msg ("You attack the " + enemy + " for " + self.damage + " damage!")
} else {
msg ("You can't attack that, it's not your enemy or it's not yet ... your enemy, silly!")
}
</function>

<function name="enemy_attack_function" parameters="human,monster">
human.hp = human.hp - monster.damage
</function>

<function name="self_attack_function" parameters="human,monster">
monster.hp = monster.hp - human.damage
</function>

game.pov => self => human
(typed in: orc) => text => target => enemy => monster

also, last detail about parameters:

function 1: parameters="1A,2A,3A"
function 2: parameters="1B,2B,3B"

parameters="1st slot , 2nd slot , 3rd slot"

they always match up by order ("slot") of them being listed as I've shown above, as seen here below:

1A <=> 1B
2A <=> 2B
3A <=> 3B

Liam315
27 Apr 2013, 16:32
Thanks for the extra info. Everything in the game that I'm making has so far been quite specific so I haven't really needed to use parameters on any of my functions yet. I'm glad I understand them now though so I know what I can achieve with them should the need arise, which I think it will in a couple of the things I have planned so this will be a good reference.

Thanks again.