Author Topic: Scripting Guide by Daxziz  (Read 5921 times)

0 Members and 1 Guest are viewing this topic.

Offline Amy

  • Global Moderator
  • Level 3
  • *****
  • Posts: 1235
  • Karma: +85/-10
  • Gender: Female
    • View Profile
Scripting Guide by Daxziz
« on: July 11, 2012, 06:25:20 AM »
Scripting Guide!
By Daxziz

So you want to learn scripting. Understandable! Scripting is probably the most powerful thing we have in the view of modding. It enables us, to do almost everything. Want to spawn new monsters, NPCs in an area --- scripting! Want to make a cut-scene --- scripting, and I could continue, in mentioning things, where scripting would be the solution.
Well before we start, will I give my opinion, about people who want to start learn scripting, as the first thing. Don’t! Play around with the other things first. Start with items and spells, then creatures and so forth.
Now people think that scripting is hard, and I will say yes it is, to a certain area, but aint everything until you learn it?
The biggest problem is that many don’t know where to look or what programs to use. Well infact, you can write a script in all kinds of text editors, the problems lie in compiling it. Compiling? What do you mean, Dax?.. Ah well compiling means, ( to say it roughly in a common language, that you activates the script for use IN-Game ). And now we’re talking about compiling then lets introduce you to decompiling as well. Now what do you think that means? Correct, it means to see the script as it is written ( in plain text ). Now, I was asked “What programs can you use to compile a script?”, the answer is simple. Only 1, the script compiler, which came with your IE game. Now, I know that this person meant, which program he could use to write his script in ( most simple of course ), see now we have to find a program, which suite us, cause there are a few programs available, however they are all ( all I know of anyway ) available at TeamBG ( www.teambg.org ). I can mention 2 good right now offhanded, the first is; The TeamBG Scripting Suite and the other is Infinity Engine Scripter. Another one, which you probably will switch to later on, when you know just the basic scripting stuff, will be the program called NearInfinity ( or in common just called NI ).
The reason for I can remember those 2 program I recommends above, is that they have a Find Error function. When you try to compile your script, and have a error, will the program mention it, and The TeamBG Scripting Suite, wont even create the script, before the errors have been corrected, and the script commands exists. Script commands? Ah, yes, Scripts can’t just accept all kinds of things you write. You have to use special commands, all the time. What kind of commands? Now take a look at the files included with this guide. Action.ids and Trigger.ids, those 2 files are the same files which is send with the current IE Games, and they contain the all the needed things, which we gonna use.

Dax... you gonna continue all night, with your history lessons? Hehe, of course not! Now you know a good part of the basics in scripting, we’ll take the rest when we need it. So lets start looking at the stuff, you actually wanted to see in this guide, shall we?

A script is ALWAYS build like this:

IF
Trigger
THEN
RESPONSE#100
Action
END

See something you know? Yup, Trigger and Action, of cause are we not writing Trigger and Action inside a script, but that shows where the commands, found in Trigger.ids and Action.ids, shall be placed.

Well, before we go any further will I explain the base building of the script.
You have to give a command, and after that tell what the script shall do.
IF simply state, that *if* the command beneath is stated IN-Game, will it continue the script.
THEN, is just a thing, which shall be there, to tell the script what will happen, if the IF is meet.
RESPONSE#100, means the chance of the stuff beneath will happen, and 100 means 100%.
END, simply tells the script to end.

A good way of remembering the stuff above, is by using this small sentence: “IF that happens, THEN do this, END”. All you have to remember is to insert the RESPONSE#100.

Makes sense, right? I hope. Else take the time and read it again.

So lets try to make a bare and simply script, which you can use on your normal characters, in-game.
We just re-make one of the simple scripts, there already is. Simply; The attack if enemy is seen.

First we type the basic stuff:

IF

THEN
RESPONSE#100

END

This makes is easier for us, just to plug in the stuff we need. Later on, will we do it line by line, but hey; we still learn right now, don’t we?

First we have to give the script a command, which means we gonna have to look at the Trigger.ids.
We’re looking for a command, which we can use to see an enemy with, scroll through the document, until you find something you think we can use, or look at the next line.
I suggest we use See(:Object) just copy this line from the Trigger.ids, into the empty line under IF. So it looks like this.
But to help you a little, replace :Object with NearestEnemyOf(myself)) don't think that an explanation is needed. All it does is to activate when you see the nearest enemy.

IF
See(NearestEnemyOf(myself))
THEN
RESPONSE#100

END

Now that was the IF phase, now lets see what comes next? THEN RESPONSE#100, now we don’t have to chance that, cause our script does of course work every time an enemy is spotted.
Then we come to the last part of this small script. The END phase. Now you have to look at the Action.ids, and find a command you think we can use.
Ahh, yes... Attack.. what else..hehe. To use the attack command simply do as you did when using the See command. Replace :Obejct with (NearestEnemyOf(myself))



IF
See(NearestEnemyOf(myself))
THEN
RESPONSE#100
Attack(NearestEnemyOf(Myself))
END

That’s it! This is what is needed to create a very simple script for the BG2, which its engine is able to understand.

Now all we need is to compile it. I will in this case tell you how to compile it with The TeamBG Scripting Suite. Simply go up in the Compile menu, and compile it to BG2. It’ll ask you for an extension. In this case will you have to give it the .bs extension. So simply write bs, when it asks you. Then name the script, be sure to keep it at max. 8.

Wolá,... you have just made your very own first script... congratz!

Put it in the BG2 script folder, the same place as the other .bs files are found. This is the scripts, for the characters.. remember?

Launch game, and test!

Cool, right ? So now....huh?..hey..hey.. HEEEY.. easy now! Take it easy, you'll learn what you thought at there later, but right now, we're only able to make a few simple scripts. No no, don't get me wrong... still you are now further than other people. Feels great right ?
OKAY, shall we take one more ? huh ? huh ? I knew you would say yes. hehe. Don't worry it'll not be more difficult than the one above, but we'll make one for a mage this time.

Ready ? Good. First we type the standard stuff:

IF

THEN
RESPONSE#100

END

So... ow... you're done already.... cool, you're learning pretty fast.
Ok, now we need to find a trigger which is good for locating enemies... hmm which one could it be...hmm. What did you say ? Oh, See(NearestEnemyOf(myself)), yeah good idea. Good you remembered it. So let's add that to the trigger state.

IF
See(NearestEnemyOf(myself))
THEN
RESPONSE#100

END

Darn, you done already. Cool!
So what do you think we gonna do now ? Sorry, you where wrong this time, but hey.. who cares... we all make mistakes. We can't set it to cast a spell already. You see we need to add more to the trigger, to make the script function. What, Dax ? This isn’t a guessing-competition, ya know. Right, it aint, but here's a small thing which you always should use, when you make scripts for characters, cause else would you be able to make some pretty lame scripts which could blast your enemies away with Power word Kill, even though you where playing Berserker.
You guessed it ? Right, we need to make a check. A simple check to see if the character actually have the spell we want to cast. Now go look in your... in your what file ? Yup. Trigger.ids, that's right. Can you see something useful. Err, yup HaveSpell(I:Spell*Spell) is just what we need. Insert that.

IF
See(NearestEnemyOf(myself))
HaveSpell(I:Spell*Spell)
THEN
RESPONSE#100

END

Okay, reader! Does it make sense ? I hope. If not, then let's take a quick look at it. The script activates when you see an enemy. Ok, so far so good. Then the script makes a check. It checks if you have the spell we set later. And IF you have the spell, the script continues.
So, Dax, we gonna add the action command now ? Yup
Go look in the...err.. what's it's name...err.. oh, yeah that's right. Thanks, reader. Action.ids file, and find a good actioncommand.
You found one ? Good. You found Spell(O:Target*,I:Spell*Spell) , that'll be perfect. Inset that in the action part.

IF
See(NearestEnemyOf(myself))
HaveSpell(I:Spell*Spell)
THEN
RESPONSE#100
Spell(O:Target*,I:Spell*Spell)
END

There... the base structure is ready, but this won't work, not before we change the Target and Spell stuff.
Okay, let's make HaveSpell(I:Spell*Spell), to a working function. First we need to find out which spell we want to cast ( and of course have ). Let's take Mirror Image ( such a lovely spell ). First we need to set what kind of type the spell is. You know them ? Correct. There's Wizard, Priest and Innate ( and 1 more, but we don't need to be bothered about that ).
Well... I:Spell* have to be replaced with one of the types above, and because it's a script for a mage ( and because the spell is a wizard spell as well  ) we type wizard, AND add an underscore ( _ ) after it.

IF
See(NearestEnemyOf(myself))
HaveSpell(WIZARD_*Spell)
THEN
RESPONSE#100
Spell(O:Target*,I:Spell*Spell)
END

Cool, that was the type. Now we need the name of the spell. You can find the names by looking in other scripts or asking some people. Perhaps there is a file as well, but I can't remember the name of it. ( Feel free to tell me if ya know )
Well the name of the mirror image spell is very simple ( trust me... they all are ): MIRROR_IMAGE . Simply add that after our WIZARD_.

IF
See(NearestEnemyOf(myself))
HaveSpell(WIZARD_MIRROR_IMAGE)
THEN
RESPONSE#100
Spell(O:Target*,I:Spell*Spell)
END

Cool.. now there's only one more to change. The action command. See something familiar about the action command ? Right. Good. It's actually the same as the code above. It does also have I:Spell*Spell, so you know what we can do now? Correct, simply copy that and insert it instead of I:Spell*Spell

IF
See(NearestEnemyOf(myself))
HaveSpell(WIZARD_MIRROR_IMAGE)
THEN
RESPONSE#100
Spell(O:Target*,WIZARD_MIRROR_IMAGE)
END

Now we only have O:Target* left. This is something, which actually covers allot. Target can be anything ( mostly ). Let me list a few of them... the most common ones.

[ Separated by ; ]

Player1 ; Player2 ; Player3 ; Player4 ; Player5 ; Player6 ; myself

Now, reader, which should we use ? Nope, not Player1, cause even though you always have your main character as Player1, what do you think would happen, if you applied the spell to one of your NPC's ? Correct nothing. So, what do you say now ? myself, goodie.. that's correct.
Add that instead of O:Target.

IF
See(NearestEnemyOf(myself))
HaveSpell(WIZARD_MIRROR_IMAGE)
THEN
RESPONSE#100
Spell(myself,WIZARD_MIRROR_IMAGE)
END

Hey hey.. we're done again. Now you just need to compile it. Do it as I said above, if you're using TBG's Scripting Suite.

Go In-Game and test.

Cool right .

Now I can't do anything more for you. You have to fuzzle around with it yourself. Try making a few scripts like those we practiced here.
Here's a small test:
I want you to create a script, which cast stoneskin at yourself, when you see an enemy. Easy you say.. well I wasn't done. ( hehe ) When the stoneskin have been cast, then your character should cast magic missile at the nearest enemy near him.

When you have that script ready, we'll continue. But that's not fair, Dax. You promised that you would tell about .bcs scripts when we had made the other script. Oh, yes. The world is such an unfair place to live in, right? Well the same thing goes for scripts. You might think that you know just how to make a script, but when you make it, it acts completely in another way. Is that fair ?

Well good luck with the script, mate. See ya as soon as you are done.




----------- And then they arrived to the second part of Scripting. The .BCS FILES ----------


You're back. Cool, ready to continue making some .bcs scripts ? hehe, I knew it

Hmm, let me see, where do we start. You already know, that the script is running all the time, and that it's used for cut-scenes and areas. Hmm, you already know the basic then...soo... no stories this time. Sorry

I trust you practiced a bit yourself before you started on this part, cause it'll require a bit more expertise than what we used last time. Ok, shall we ?

Start with adding the IF, THE, END part.
Good. Let's make a cutscene. We make a small cutscene, which shows you how to make a simple one.

When making a cutscene there are a few things, which you ALWAYS have to use. Take a good notice at these commands:

StartCutSceneMode
CutSceneID
HideGUI()
UnhideGUI()
EndCutSceneMode

Look them all up. Some are triggers, others are actions.

I hope you know how to make a dialog, cause as I said. I would recommend it, and right now will I ask you to make a quick and simple dialog, which contains the script command. StartCutScene("nameofyourcutscene") in its action part.
And make another, which we will use later on in the script.

Done. ok, cool. Let's rock, baby.

In this script we will use True() in the trigger part of the script. Type that.
Goodie. Next things are to assign the StartCutSceneMode. Type that in the action part.
To this with the CutSceneID as well. and set the ID to myself.
So far so good, right ?. Now it's time to add something, which I think should be in any cutscene. It's not required to have it, but it does look better. And the player cannot click around at the map, so that he might ruin the cutscene. What I talk about here, is of course HideGUI(), ahh you already guessed that, right ?.
Ok, reader. Insert that as well.
I always insert a Wait(NUM) here. I find it nice to have a little time to let the scene start, so I recommend you insert a Wait(1) here.
Now has the time come to show that the script we're making, actually can do something. I mean, if you added this to the game as it is now. You would do nothing else, than loose your GUI. By the way, GUI means Graphical User Interface.
So let's add this command: DisplayStringHead(myself,THENUMBERYOUGET)

First we start with adding a trigger part. I this case we will use True() ( It could be a few others, but we will look at that later. )
Next things are to assign the StartCutSceneMode. Type that in the action part.
Do this with the CutSceneID as well. and set the ID to myself.

Stop. Let's see if we agree on this:

IF
True()
THEN
RESPONSE#100
StartCutSceneMode()
CutSceneID(myself)

We do ? Cool, I knew we did. But better save than sorry.

Then is the time come to add a thing which I personally use much. It's the HideGUI() command, which removes the Graphical User Interface ( there of GUI ).
Sometimes will you think, that it'll be dumb to add this command, but I will say that it's a rarity. But if such happens, simply don't add it. It's not a required thing.
Now the cutscene is actually started, but we can't really say this is something, which we can use to something, can we? No.
We are now going to add the things, which we want our cutscene to do. Even though I suggest that we quickly add a small Wait() command. Just to make a very short moment, where the cutscene is standing still. Insert Wait(1) after our last command.

Now let's compare again.

IF
True()
THEN
RESPONSE#100
StartCutSceneMode()
CutSceneID(myself)
HideGUI()
Wait(1) <----- It's up to you if you want this or not.


Ah well. This is quite simple, right ? Good, and the stuff looked right ? Cool.
Let's continue.
Okay, reader. Open your Dialog.tlk editor in IEEP, and add this string:
I’m learning to make a cutscene.
Write down the number, on your arm... a piece of paper... your wall...the dog.. where ever you want. Just make sure you can find it again in a moment.
Add this line as well:
I'm learning it, by reading a guide.
Again write this number down.
And last sentence:
I'm doing great progress.
And finally this number.
You didn't write them on top of each other did you? DOH.. huh? huh.. hehe.. you where joking. Bad boy / girl. NONO I didn't call you the opposite sex, it's just hard to know what kind of gender you're of, when I didn't knew you would read this guide. Oh yes yes.. let's continue

Find the command called DisplayStringHeadOwner, and insert that. Set it, so that it displays over you ( myself ), and after that type in your first number.

Now here's an important thing. If you don't add a Wait(NUM) command here, you would get all the text which we will have this cut-scene to display over you, in a few seconds. This is because that computers are dumb. They do as they are told to, and nothing more. So after the display string. Add a Wait command. I suggest you add a Wait(5). It's a good amount of seconds.
Add another DisplayHeadStringOwner... just copy the one above, but remember to change the number to the 2nd one you got. Again insert a wait command... if you want you can add a Wait(10), just to show you, that there really is a difference in the wait commands. Add a DisplayStringHeadOwner again, and change it to the 3rd and last number, and a minor Wait()... let's say 2. Add a Wait(2).

Let's compare:

IF
True()
THEN
RESPONSE#100
StartCutSceneMode()
CutSceneID(myself)
HideGUI()
Wait(1) <----- It's still up to you if you want this or not.
DisplayStringHeadOwner(myself,1st-number-here)
Wait(5)
DisplayStringHeadOwner(myself,2nd-number-here)
Wait(5)
DisplayStringHeadOwner(myself,3rd-number-here)
Wait(2)

Now this was simple, right ? Hehe, nah it's not that bad at all.
So, reader. Let's end this script here.
After the Wait(2) command, insert the opposite command of HideGUI(), which is ? Right, UnhideGUI(), *NOT* ShowGUI, which many people wants to use in the beginning.
Then add the EndCutSceneMode, and the END script command.

Let's compare:

IF
True()
THEN
RESPONSE#100
StartCutSceneMode()
CutSceneID(myself)
HideGUI()
Wait(1) <----- You do know it's up to you, right ?
DisplayStringHeadOwner(myself,1st-number-here)
Wait(5)
DisplayStringHeadOwner(myself,2nd-number-here)
Wait(5)
DisplayStringHeadOwner(myself,3rd-number-here)
Wait(2)
UnhideGUI()
EndCutSceneMode()
END

This is it. Your very own first cutscene. Congratz.
Now compile it, and save it as a .bcs script.
Now copy it, and put it in the OVERRIDE folder. This is different from .bs scripts.
In your dialog, type the name of the cutscene in the StartCutScene(nameofcutscene) place, and save that in the Override Folder as well.
Attach it as a default dialog ( yeah yeah.. just to make it easy ) to a creature.
CLUA the creature, by using the CLUAConsole command CLUAConsole:CreateCreature("nameofcreature")
Talk with the creature and the magic has started.


There's no way to learn you to make cutscenes... you need to try and try and try, and sudden can you remember all the commands, and know just what you can do with a current command.
The script we made above is actually showing you the ground of a cutscene.

RESPONSE#100
StartCutSceneMode()
CutSceneID(myself)
HideGUI()
----
UnhideGUI()
EndCutSceneMode()

This is actually THE cutscene. Everything in the middle is your commands.
As there wouldn't be any ideas in making yet another cutscene together. I'll give you a small assignment instead.
Make a cutscene where you move around at the map, in a few seconds. Then display a string over your head, while you stand still. Then again display a string. Cast a spell at yourself. Display an animation over yourself. And finally make the screen shake.

Do this now, and then return and read the rest of this guide.


Cool, you're back.
Wasn't it a pretty fun assignment ? Well yeah, it was pointless, but you learned to use a lot of commands, which you probably gonna use allot later on in your scripting career.
There's only one more thing I can offer you. Go to the tutorial forum at TeamBG, and download the description tutorial of the Trigger functions, made by a good friend of mine, Vaskez.

It has been fun to work with you, reader. I hope you have enjoyed it, and I wish you congratulations with your new scripting skills.
See ya around someday.


**********************************************************************************
-Daxziz
Email: Daxziz@hotmail.com
Website: www.adventurers.subnet.dk

---------------History------------------
Created the 9th of February 2002.
***********************************************************************