Page 1 of 2
Variable Variables?
Posted: Fri Aug 27, 2004 11:16 am
by AfterDeath
My question is concerned with the MoHAA scripting language itself rather than something that I am trying to do specifically. Hopefully I will be able to explain myself clearly.
Let say I want to do the following ("hyphotetical" coding):
Code: Select all
spawn trigger_use "targetname" "bla1"
$bla1.origin = ( 11 11 11 )
$bla1.angles = ( 11 11 11 )
// more properties
But I want that code to be repeated several times, for "bla2" etc. Also, instead of having to write all that, I would just do something like this:
Code: Select all
new_bla local.origin local.angles:
local.ent = spawn trigger_use
local.ent.origin = local.origin
local.ent.angles = local.angles
// more properties
end local.ent
level.blas[0] = waitthread new_bla ( 11 11 11 ) ( 11 11 11 )
level.blas[1] = waitthread new_bla ( 22 22 22 ) ( 22 22 22 )
level.blas[2] = waitthread new_bla ( 33 33 33 ) ( 33 33 33 )
// etc.
So far so good, except I need each "bla" created in "new_bla" to have a different name (bla1, bla2, etc.). Actually, not necessarily a different name, but a different object, so it could be bla[0], bla[1]. It will also have to be accessible outside the thread.
What I want to know is if there's any way I can dynamically "targetname" the trigger_use I spawned, so that I can refer to it using the "$" symbol using the concept of variable variables (such as in PHP, with $$x returning $a if $x=='a').
This would be something like this (note I added local.id to this... I don't know if it would be necessary):
Code: Select all
new_bla local.id local.origin local.angles:
spawn trigger_use "targetname" "bla"+local.id
// Would this create a variable that I can refer to using $bla0 ?
// If so, would I be able to do something like the following? How would it actually spell out? -->
$bla+local.id = local.origin // eg. $bla1 = local.origin
$bla+local.id = local.angles
// more properties
end local.ent
level.blas[0] = waitthread new_bla 0 ( 11 11 11 ) ( 11 11 11 )
level.blas[1] = waitthread new_bla 1 ( 22 22 22 ) ( 22 22 22 )
level.blas[2] = waitthread new_bla 2 ( 33 33 33 ) ( 33 33 33 )
// etc.
I realize that the above explaination might suck, but I am strongly hoping someone will understand what I'm trying to convey, eheh. Thanks!
Read next post...

Posted: Fri Aug 27, 2004 11:22 am
by AfterDeath
If you don't understand what I meant to ask in the post above, maybe you can help me otherwise... here are some more direct questions.
- Are there variable variables in the MoHAA scripting language (as in PHP)?
In PHP, it works like this:
$a = 5;
$varname = 'a';
echo $$varname;
If MoHAA scripting provides for this, can you give me an example of how it is used?
Posted: Fri Aug 27, 2004 11:24 am
by jv_map
It took me a while but I finally think I understand what you are going for... basically a variable targetname is all you want
Example:
Code: Select all
local.id = 1
waitthread makebla local.id local.origin local.angles
// ...
$("bla" + local.id) dosomething
end
makebla local.id local.origin local.angles:
local.bla = spawn bla origin local.origin angles local.angles
local.bla.targetname = "bla" + local.id // string concatenation
end
Posted: Fri Aug 27, 2004 11:26 am
by AfterDeath
Aha! Thanks a lot man. All I had to do was look at...
And all of the sudden I had this HUGE smile in my face
I love how it works... thanks a lot man!

Posted: Fri Aug 27, 2004 11:26 am
by jv_map
Cool

g/l

Posted: Fri Aug 27, 2004 11:42 am
by AfterDeath
While we're at it, is there a difference between ending a thread/method with "end local.whatever" or simply "end" ?
I've seen places where they end it with the variable being used... is this necessary? If so, what if you have more than one variable being manipulated? Thanks...
Added: I just came across another question while trying to implement your solution (above). It explains how to make "bla0" "bla1" etc, but what if I want them to be arrays -- bla[0], bla[1], etc.?
I understand I can access them by simply doing $bla[local.id], but how would I make...
Code: Select all
local.bla.targetname = "bla" + local.id
... work for an array? Would this work? (probably not, lol)
Code: Select all
local.bla.targetname = "bla[" + local.id + "]"
Thanks!!
Posted: Fri Aug 27, 2004 12:48 pm
by jv_map
Targetnames can only be strings, not arrays (but if you have multiple entities with the same targetname they'll form a targetname array, and you can use $bla[1], $bla[2] etc all having targetname 'bla'). A nicer way however is to just use level.bla[1] etc, like you have in your first post.
end local.bla is to return a value, like
local.somevalue = waitthread somemethod local.somearg1 local.somearg2 //...
If you do not want your method to return a value, simply use 'end'.
If you want your method to return more than one value, there are a number of solutions available:
1) use an array:
Code: Select all
local.somearray = waitthread somemethod local.somearg
local.someresult1 = local.somearray[1]
local.someresult2 = local.somearray[2]
//..
end
somemethod local.somearg:
local.result1 = dosomething
local.result2 = dosomething
end (local.result1::local.result2) // const array
2) use a dummy listener object
Code: Select all
local.listener = spawn listener // or 'local createlistener'
waitthread somemethod local.listener
local.result1 = local.listener.result1
local.result2 = local.listener.result2
// remove the listener to free up mem
local.listener remove
//..
end
somemethod local.listener:
local.listener.result1 = dosomething
local.listener.result2 = dosomething
end
There may be even more ways but this should get you started

Posted: Fri Aug 27, 2004 2:55 pm
by AfterDeath
Sweet. Thanks for all the info.
The idea behind having it as an array instead, is so that I don't have to pass the local.id as an argument, as in:
Code: Select all
waitthread makebla 0 ( a b c ) ( x y z )
waitthread makebla 1 ( a b c ) ( x y z )
// ...
waitthread makebla N ( a b c ) ( x y z )
Also, because this is actually for a script that will spawn multiple bombs in a map (and is intented to work for any map... code reuse), I would like to be able to do the following...
(And have that thread loop through the $bombs array to check if all (or any) bombs have been blown up)... instead of something like:
Code: Select all
thread win_bomb $bomb0 $bomb1 $bomb2 // for 3 bombs
And though it seems too small of a detail for me to be worried about, I am really looking forward to learning some specifics about the language.
Now you did say that "if you have multiple entities with the same targetname they'll form a targetname array", however I am left wondering how that works. I am thinking that the array is generated as soon as I run...
Code: Select all
local.bomb = spawn script_model
local.bomb.targetname = "bomb"
... for the second time. Am I correct? Is there a size-1 array already there even after the very first run? (bomb[0]) Also, if multiple entities with the same targetname form a target name array, how do I refer to the "current" (the most recently created) one? Would it be something like the following...?
$bombs[bombs.size-1].property
Hopefully you will be able to understand what I am trying to accomplish.

In any case, thank you VERY much for trying to understand my poorly explained scenarios.

Posted: Fri Aug 27, 2004 3:48 pm
by jv_map
Not sure where the problem lies but maybe this helps
docs/Script Files.txt wrote:Targetname array
Created by the $ targetname operator if more than one entity exists for that targetname.
For example, $player is an array if more than one player is in the game.
Targetname arrays start their indexing at 1.
Posted: Fri Aug 27, 2004 4:14 pm
by AfterDeath
Clears it up a bit, but I'm still not sure how I'd use it. But because I don't need it at any cost at this point, I'll pass. Maybe latter on I'll run some tests to answer my own questions.
Though not exactly how I wanted it first, I got my thingie working in a very nice way which suffices. Thought I would share with you:
Code: Select all
place_bombs:
waitthread place_bomb 1 ( -2884 2752 92 ) ( 0 0 0 )
waitthread place_bomb 2 ( -3267 1190 335 ) ( 0 0 0 )
thread win_bomb ($bomb1::$bomb2)
thread win_time
end
win_bomb local.bombs:
local.whileloop = 1
while (local.whileloop) {
local.whileloop = 0
for (local.i = 1; local.i < (local.bombs.size + 1); local.i++)
if (!local.bombs[local.i].exploded)
local.whileloop = 1
wait .1
}
teamwin allies
end
With one line of coding ("waitthread place_bomb X (abc) (ijk)") a new bomb is placed, everything is done at the place_bomb thread. Then you update the "thread win_bomb ($bomb1::$bomb2)" line to reflect the number of bombs you have.
Round is over (with allies winning) once ALL bombs are blown up, no matter how many you have.
Not bad for a guy with some C++ experience who had a hard time with copying/pasting parts of scripts 8 hours ago.

(maybe I should be in the bragging section now

)
Thanks JV

Posted: Fri Aug 27, 2004 4:57 pm
by jv_map
Not bad I agree

, but I do think your code is a bit expedient... I was actually gonna type another sentence here to reassure you your script is good, but realised I suck at sentence making so I'll just skip to some scripting right away
Code: Select all
win_bomb local.bombs:
for(local.i = 1; local.i <= local.bombs.size; local.i++)
{
local.bomb = local.bombs[local.i]
while(local.bomb.exploded != 1)
waitframe
}
teamwin allies
end
I'm not claiming that this is better than what you made, but it seems shorter and easier when you look at it (I could be biased, though

).
On a sidenote, notice that the exact same code (both yours and mine) would work perfectly with a targetname array, i.e. you'd make a number of bombs with targetname 'bomb' and then do:
thread win_bomb $bomb
Anyway yes you can go to the bragging section now

Posted: Fri Aug 27, 2004 6:02 pm
by AfterDeath
Oh thanks. I will make that change into my coding. Thanks for putting the time and effort into it.
I actually never liked my way of doing it, I just couldn't think of any other way. Probably due to my lack of knowledge... I didn't know what waitframe did or how to use it... but now I see it.
I will try playing with the spawn targetname array later on. I think I see it now too. Thanks!

waitframe
Posted: Fri Aug 27, 2004 8:40 pm
by tltrude
In this case the "waitframe" line makes the thread hold for one frame per loop--until the while loop becomes false. He could of also used a fast wait time like "wait .001". All loops need some kind of wait, or they go too fast and crash the game.
Here is how the obj_team2 script does the wait lines.
Code: Select all
allies_win_bomb local.bomb1 local.bomb2:
while (local.bomb1.exploded != 1)
wait .1
while (local.bomb2.exploded != 1)
wait .1
teamwin allies
end
And here is how obj_team3 does it.
Code: Select all
allies_win_bomb local.bomb1 local.bomb2:
while (local.bomb1.exploded != 1)
waitframe
while (local.bomb2.exploded != 1)
waitframe
teamwin allies
end
You can also combine the while loops like this example form obj_team4.
//-----------------------------------------------------------------
axis_win_bomb local.bomb1 local.bomb2:
while ((local.bomb1.exploded != 1) && (local.bomb2.exploded != 1))
wait .1
teamwin axis
end
//-----------------------------------------------------------------
I hope that helps!
Posted: Sat Aug 28, 2004 6:05 am
by AfterDeath
Thanks for the suggestions. However these work for a fixed number of bombs, and I am looking at something that works for a variable number of bombs.
One question though... why does V2 and Omaha do it differently, if in the end it all works the same? Why "waitframe" instead of "wait .1" ? Any specific reason?
And yet another question. I don't fully understand how the following piece of coding works:
Code: Select all
win_time:
level waittill axiswin
end
Again ignorance. How does
waittill work? What if I want the allies to win instead?
allieswin? I like the
teamwin allies much better. Any thoughts?
Posted: Sat Aug 28, 2004 8:34 am
by jv_map
You can omit the win_time thread... it doesn't do anything at all (i.e. it
waits till the axis have won and then just exits

)
waitframe is equal to 'wait 0.05'... in this case it doesn't really matter what delay you use, anything will work (though, if you use a very large wait the timelimit might run out before your script detects victory).