home home

downloads files

forum forum

docs docs

wiki wiki

faq faq

Cube & Cube 2 FORUM


Aard - scripting language help

by _Fanatic on 06/14/2004 03:12, 20 messages, last message: 06/15/2004 15:53, 1327 views, last view: 05/03/2024 16:10

I'm trying to script some more intelligent stuff for my new level, like handling music and some sound events, and also some fancy pants effects elsewhere.

I'm having some trouble with the language tho.

For example, I want to define a list of songs, set one at a currentSong, and play it.

When the player hits a trigger, I want to evaluate it, and if the song is "foo_1", I want to play "foo_2", else play "foo_1".

That way I can have one trigger in a hallway, and depending on which song it's currently playing, I can make it flip to the other song.

I can't seem to get this working correctly, but this is what I have so far that I thought would work:

alias song_1 "fanatic/revenge_1.ogg"
alias song_2 "fanatic/revenge_2.ogg"
alias song_3 "fanatic/revenge_3.ogg"
alias currentSong $song_1
alias play "music $currentSong"
$play

alias level_trigger_1 "if ($currentSong = $song_1) $currentSong = $song_2;$play
"
alias level_trigger_2 "if ($currentSong = $song_2) $currentSong = $song_3;$play
"
alias level_trigger_3 "if ($currentSong = $song_3) $currentSong = $song_1;$play
"

I know the syntax might not be true to what Cube understands, but that's what I came up with.

Preferably I like to be able to define arrays with the song to play, and which index of the song array to play next for that song.

I can do it in Javascript, Cold Fusion's cfscript, or MS SQL, but I can't find an advanced users guide for Cube. :)

   Board Index   

#1: You have the syntax wrong....

by e:n:i:g:m:a on 06/14/2004 03:48

The syntax is wrong :(

Instead of a javascript or c++ like script, the operators must be before the argruments.

So instead of what you have for alias level_trigger_1, it should be

--code--

alias level_trigger_1 [if (= $currentsong $song_1) [alias currentsong $song_2; $play]

--/code--

While you can't define arrays, you can use integers, aliases, and concat to achieve a similar effect

Other than that, you've got it pretty right (the ideas are good, etc). The only other thing that I can see is that when scripting, $foo refers to the value of the alias, and "alias foo #" allows you to modify the alias.

Oh yeah, and also use [] if you are enclosing multiple commands, "" if you are enclosing single commands, and () if you want that expression to be evaluated first (mostly for if statements).

erm, did that all make sense?

(BTW Aard, I couldn't help but notice how similar Cube's scripting is to your progamming language false, did you use false as an idea base for the scripting?)

reply to this message

#2: ..

by e:n:i:g:m:a on 06/14/2004 03:51

Oops!!

I forgot the closing bracket thingy.

So alias level_trigger_1 should be:

alias level_trigger_1 [if (= $currentsong $song_1) [alias currentsong $song_2; $play]]

reply to this message

#3: Some other helpful info

by e:n:i:g:m:a on 06/14/2004 03:59

And some other helpful info:

The grouping symbols [] () can have more grouping nested inside them, however, "" cannot.

() is evaluated before []

"$foo" refers to the value of foo

"alias foo (expression)" lets you modify foo's value (the expression can be anything mathametical, any single number, or any value alias)

Operators come before the arguments. With that in mind, that means that (+ 1 2) returns 3

Do not try to redifine an alias when it has already been defined as a set of commands, cube crashes without any errors and locks the computer up.

Once a trigger is collected, it is removed from the map

And, there is a new trigger type in Cube '04 that doesn't make a noise (very useful for music changes)

reply to this message

#4: ..

by _Fanatic on 06/14/2004 04:09

Ah, thanks a bunch. I think I can mess with it and get something working with what I have in mind. I'm more used to the C++ type coding format, but I think I can manage. :)

reply to this message

#5: ..

by _Fanatic on 06/14/2004 04:19

Ok, this I assume should work, but it doesn't like the $play value.

I'm trying to create a global function in a way with the alias play. Is this possible, or do I have to do a music command in each trigger instead of calling $play?

alias song_1 "fanatic/revenge_1.ogg"
alias song_2 "fanatic/revenge_2.ogg"
alias song_3 "fanatic/revenge_3.ogg"
alias currentSong $song_1
alias play "music $currentSong"
$play

alias level_trigger_1 [if (= $currentSong $song_1) [alias currentSong $song_2; $play]]
alias level_trigger_2 [if (= $currentSong $song_2) [alias currentSong $song_3; $play]]
alias level_trigger_3 [if (= $currentSong $song_3) [alias currentSong $song_1; $play]]

reply to this message

#6: ..

by _Fanatic on 06/14/2004 04:23

If I change it to executing a music command instead of play, it runs the music, but gives an error about unknown command with the value of the song_1 alias. Not sure why it sets it properly but gives an error as well.

reply to this message

#7: Re: ..

by Aardappel on 06/14/2004 05:38, refers to #6

= compares number values, so the above is not going to work. really, if you use a language, make sure you read the docs, just trying is gonna be frustrating :)

something like this should work (not tested):


alias current 1
alias play [ concatword "fanatic/revenge_" $current ".ogg"; music $s ]
play
alias change [ if (= $current $arg1) [ alias current $arg2; play ] ]

alias level_trigger_1 "change 1 2"
alias level_trigger_2 "change 2 3"
alias level_trigger_3 "change 3 1"



(and no, it has very little to do with False, rather it tries to stay backwards compatible with the quake console language).

reply to this message

#8: ..

by e:n:i:g:m:a on 06/14/2004 05:52

Or you could do this

alias musiclist "fanatic/revenge_1 fanatic/reveng_2 fanatic/revenge_3"
alias playing 1
alias play [at musiclist playing; music $s]

Then have the triggers evaluate and change the playing alias... (1 for the first item in the list, 2 for the second...)

reply to this message

#9: Re: ..

by _Fanatic on 06/14/2004 06:14, refers to #7

Thanks for the examples, those seem to work. :)

Aard, I did read the documentation in the Cube release, not much to go on there and few examples. :\

Is there an else type keyword to use in evaluations?

if this then that else the other

reply to this message

#10: ..

by _Fanatic on 06/14/2004 06:22

Nevermind on the else statement. Figured that one out.

if (this) [that] [the other] (no 'else' is needed)

Is there no trigger type that is repeatable?

I was hoping to have a sort of live jukebox so a certain tune plays when you go into a certain area, and when you backtrack the appropriate song playes in the area again.

reply to this message

#11: ..

by _Fanatic on 06/14/2004 14:47

I realized that there are a few limitations for making a jukebox type thingie. One issue is there isn't a repeatable trigger, one time only.

The other is the carrots are so small in radius and height, a player can easily go around one or jump over it and mess up the music I'm intending. I have several mini-tunes to play that are meant to set a mood for certain chunks of the map. Works well when you hit the triggers in the right order. :)

Would it be possible to make certain cubes act as a trigger? Kinda how DOOM does linedef triggers? And the ability to make them repeatable or one off triggers?

Might need to post this in the requests thred. :)

reply to this message

#12: ..

by e:n:i:g:m:a on 06/14/2004 15:45

To have "repeatable" triggers, you have the triggers recreate the triggers...

--code--

alias musiclist "fanatic/revenge_1 fanatic/reveng_2 fanatic/revenge_3"
alias playing 1
alias play [at musiclist playing; music $s]

alias level_trigger_1 [select X Y; newent trigger 1 3; if (= $playing 1) [alias playing 2; $play;]]
alias level_trigger_2 [select X Y; newent trigger 2 3; if (= $playing 2) [alias playing 3; $play;]]
alias level_trigger_3 [select X Y; newent trigger 3 3; if (= $playing 3) [alias playing 1; $play;]]

--/code--

If you want them to work in reverse too, then perhaps evaluate them for what they are (instead of what they aren't) and change the music if they aren't what they are supposed to be...

--code--

alias musiclist "fanatic/revenge_1 fanatic/reveng_2 fanatic/revenge_3"
alias playing 1
alias play [at musiclist playing; music $s]

alias level_trigger_1 [select X Y; newent trigger 1 3; if (= $playing 2) [] [alias playing 2; $play;]]
alias level_trigger_2 [select X Y; newent trigger 2 3; if (= $playing 3) [] [alias playing 3; $play;]]
alias level_trigger_3 [select X Y; newent trigger 3 3; if (= $playing 1) [] [alias playing 1; $play;]]

--/code--

That way, it does these three things: recreates the trigger, then evaluates the currently playing song. Then, if it is the "correct" one, it does nothing, but if it is a different song, it changes to the "right" one.

**OTHER NOTES**

First of all, you need to know the X and Y coordinates on your map where you place the trigger, in the code above, replace X and Y with the coordinates for each trigger.

Second, in order to force each player to collect a trigger, place it in a doorway or tunnel that is 4 cubes high and 4 cubes wide. No player can jump and skip that.

Third, I believe 3 is the type of trigger that is invisible and doesn't make any noise when you collect it. (the trigger entity is like this: "newent trigger NUMBER TYPE" I forget what the other values are...

Fourth, the "at musiclist NUMBER" command selects the NUMBER'th item in musiclist, then stores that string in the alias s (so refer to the value as $s)

Finally, in order to find the coordinates, type "/select X Y" in the console untill you hit the right spot, then write them down for where you want

**note** the code above is untested, but it should work. And the second code is what I think you're looking for (so it will work in reverse)

reply to this message

#13: Re: ..

by spentron-postcrash2 on 06/14/2004 16:35, refers to #12

enigma, that won't work, to insert triggers requires edit mode toggling which affects everything.

You can use multiple triggers, including silent ones of the same number, but shouldn't use a lot because each one, when picked, causes a small hitch in play. Normally triggers need by placed in a narrow section of map. You'd need extra script to look for first:
alias gottrig1 1 // use 1 for off for short syntax
alias level_trigger_1 [if $gottrig1[dotrig1; alias gottrig1 0]]
... where "dotrig1" is a previously defined command or the text of the command you want.

Good examples of scripting are the original autoexec, my enhanced autoexec, some of my maps, piglet's "Arena Perpetual" includes a short tutorial.

A problem I can see with all of the above is savegame, presuming this is SP and save is supported. The triggers picked up by the player will always trigger in the same order on load, usually the order the triggers were placed in the map although this can only be relied upon if done as the last step in the build. Therefore a different song could end up playing on loadgame, maybe not a big deal if correct operation commences on the next trigger. The easiest solution would be if you just wanted to sequence the same tracks no matter what order the triggers are picked up, count triggers and play the song number. You could have scripting outside the map .cfg to solve this -- or least just leave the current song playing on loadgame --, either run by a start map or having the player start the map with an exec of a config which ends with a map command.

Often I use different music sections on areas that can only be visited once, but sometimes the player can go back but it doesn't seem like the same music must play, because the player is "done" there. Latest example Camera, after the music switch the player can turn around, but the music still leads towards the destination.

reply to this message

#14: Yow....

by Pxtl on 06/14/2004 16:38

Dude, Aard, I love Cube in so many ways - but that scripting language hurts to read. I can see the reasoning behind it - it has to be able to run console-style input (players don't want to say

SetFOV(120)

or

SetName("Frank")

but still, thats as hard to read as Lisp, and has none of the sexy hyper-mutable power of Lisp.

reply to this message

#15: ..

by _Fanatic on 06/14/2004 16:54

Ugh, handling the music stuff like that will be a nightmare. :)

I think instead of mini-tunes that loop (and keeps the file size small too) I'll just do one big song that loops.

Seems too much of a pain to make this work.

I also don't want to have a bunch of tiny hallways to control a player hitting a trigger too, this level is way too huge, and I was planning no 6-8 different songs for each section of the map. It would be like the tunnels in Portal 2 (a bad thing).

Would be nice to allow the console language, and have the scripting more Javascript or C++ styled, or like an optional language for scripting so the current style is backwards compatible.

Like in the script, tag certain cubes and have an alias or function that acts like a DOOM line trigger, that would be fairly easy to setup and do various things.

Might overcomplicate things for you developers of the engine I suppose, but as a level designer, I'd really dig it. Especially since I did so much work with the EDGE team and their engine, I can really appreciate a wide variety of ways to make an engine do things (e.g. QDOOM).

reply to this message

#16: Re: ..

by spentron-postcrash2 on 06/14/2004 19:44, refers to #15

I'd say just do what can be made to work. If you do one long song, remember it will restart on reload, this could make it better to split the song and put the beginning at the end and the original loop point in the middle, etc. ... one other answer for the reload problem is just play the starting song on reload (still have to test for condition -- the exec thing or use a persistent variable such as fog as an indicator, that's a good kludge).

I like that the script can be explained briefly and is in a central place, unlike controlling things with a bunch of simple widgets spread all over the map. Things to hook it to seems a bigger limitation.



reply to this message

#17: the language...

by Aardappel on 06/15/2004 07:11

those of you who know my background know that I am probably more capable than most to whip up the most advanced scripting language you can imagine... and I have in a few cases.

But cube is in part an exercise in minimalism. Most scripting systems are easily 10x the size in code of the entire cube engine. I wanted to keep it very small... go look at the source, cube implements a usable language in just a few K of code.

Also cube was never meant for extensive scripting. I wanted to make a game how I wanted it to be, hence the reason all the gameplay code is all in C++ and not scriptable.

As I have said before, sauerbraten should have more serious scripting capacity. This means actually making a nice language for it (which I will gladly help with), rather than just linking in python or lua.

reply to this message

#18: I had wondered about that...

by Pxtl on 06/15/2004 13:50

I had wondered about that - you've several far more advanced languages on your website, and you'd elected to make a very very simple one for Cube. I'd assumed it was a matter of convenience for the players (console-style calling convention) not lower memory impact and minimalism. Please excuse my ignorance.

reply to this message

#19: Re: the language...

by spentron-postcrash2 on 06/15/2004 15:16, refers to #17

As not a heavy coder, simple scripting is more powerful to me than something more complicated than I'm willing to use. But if Cube teaches us anything, those who assume impossibility on first glance aren't going to get very far. I presume Cube scripting is efficient, because I assume it can take anything I can actually make in it, when doing so.

"hence the reason all the gameplay code is all in C++ and not scriptable." ... Don't people kind of blur some lines when they talk about scriptable gameplay? It could range from some very serious code work to diddling a few numbers. Adding a few well chosen variables could be nice. Actually I've seen some of this stuff is more hard-coded than it tries to appear in another game, variables for everything doesn't mean they work consistently. For example a highly modified monster which spawns baby monsters ... of the unmodified type only, oops.





reply to this message

#20: Re: the language...

by e:n:i:g:m:a on 06/15/2004 15:53, refers to #19

Yeah, it's nice to have a more simplistic languange... I've even developed a system where I can tab back and forth through the various music tracks that I have for Cube, and it also displays the currently playing track when I switch...

I really like Cube's scripting language, the only thing that I wish there was were more in-game aliases for varible modifying and displaying scripts (such as current weapon, ammo/health/armor left, etc)

reply to this message

   Board Index   


Unvalidated accounts can only reply to the 'Permanent Threads' section!


content by Aardappel & eihrul © 2001-2024
website by SleepwalkR © 2001-2024
53863084 visitors requested 71638192 pages
page created in 0.025 seconds using 10 queries
hosted by Boost Digital