19Day's Scripting Tutorial ---------------------------------------------------------------------- 19day here, and this is a tutorial that will teach you all aboutscripting for your RPG. First things first though, scripting is useful not only for RPG's, butfor other types of games as well, I can't think of any off the top of myhead, but you'll see. Anyway, here's the rundown of what scripts are and what they can do: Scripts are like mini-languages that your game engine can interpret and run. Now, in an RPG this is especially useful. Lets say your RPG has lots of NPC's (non player characters) and you want them to say things, but you don't want to flood your source with tons of IF playposx = blah AND playposy = bleh then npc$ = "Hey, I'm Diddddddly" If you had tons of guys in your game, this is a horrible way to do it. Now, if you had a scriping language in your game, you just call apon an external file it sure makes things simpler. Now, what is the actual language like. Well, it's all up to you. My language, called TLK (talk) is a ascii text file format that has each command on it's own line, and the engine parses each bit of each line. Nekrophidius' Wrath of Sona's EXT (Extended Text) has each command on aline but each parameter is on other lines just after it. I don't happen to like that format, so that's why mine is the way it is. Another way to have your scripts is to make them like the above, butthen make a compiler to convert the scripts to a binary format. This is almost like assembly, where each command is reduced to a byte, and the parameters are usually bytes. This has one one advantage that I canthink of, and that's to prevent people from altering your scripts, but to me, since this is all in QB, this is not a concern. so you might as well start with the text based scripts, and then later on you can make a compiler for them. Basically, what you need for your scripts, first, is a method of the syntax, which you'll want to make constant. You need some way to define a command in the file, I use /, like in IRC, when you don't have anymeta commands or comments, there's really no point, but it just makes it look neater. (Nekro uses HTML like tags, < and > surround the command. This has an advantage. He can make his commands as long as he wants, because the names starts at the < and ends at the >, where as mine, I have only 3 characters, which only presents a small problem, that of meaningfulnames, but I think 3 letters is enough, and the number of commands are high, with over 50 characters per position, 50*50*50 is just a lot. But ofcourse not all of the combos will have meaningful names, so you just have to improvise) Now, you need to have some commands to start with, and the commandindicator, which in this tutorial, I will make $, so whenever a line begins with a$ that means that it is a command to interpret. Now, we need some simplecommands: $say - prints text on the screen$col - changes color of text $end - ends the script Now, two of these commands need parameters, so $say will have aparameter like text$, so an example of the command will be:$say Hello there And $col needs a color parameter, now you would think that if you wanted to change the text color to white (15), you would do this:$col 15 But then you would be wrong, because remember, this is text, and sincethe numbers can go as high as three digits, the interpreter would crash(more on that later) so we would need to do this:$col 015and $end takes no parameters. The interpreter is a different matter, now, I'm just going to give you the code, which is pretty simple, but I'll tell you what it all meansafter. ---------------------------------------------------------------------- SUB talk (talkfile$) open talkfile$ for input as #1 talklines% = 0do line input crap$ talklines% = talklines% + 1 loop until EOF(1) close #1 'the above just figures out the number of lines in the file open talkfile$ for input as #1 for i% = 1 to talklines% line input hold$ 'take in a whole command if mid$(hold$, 1, 1) = "$" then 'make sure it is a command if mid$(hold$, 1, 4) = "$say" then print mid$(hold$, 6) endif if mid$(hold$, 1, 4) = "$col" then COLOR VAL(mid$(hold$, 6, 3)) endif if mid$(hold$, 1, 4) = "$end" then goto quittalk endif endifnext i% quittalk:END SUB ---------------------------------------------------------------------- Pretty simple, eh? well, it's good to get the basics out of the way. What it does is figure out the number of lines in the file, and then it goes and reads in each line and depending on what the first 4 letters are (commands start with a $ anyway) it decides if there is anything else to parse and then does what it's supposed to do. Remember that undefined length things, like text for the $say command, is a difficult matter, because we can't know how long the parameter is. Now, since it's on it's own, we can just do MID$(hold$, 6) becausewithout the last parameter in MID$ it just takes it until the end of the line. But if we have a few paraters that are unknown, like speaker and text, we need to make it one parameter with some sort of divider. In my /YRN command takes 1 parameter, which is the text for the yes and the textfor the no (just in case it is a 2 choice question, but not a yes or no one) but since the lengths of the two are unknown, I just say whatever-whatever,so in the command, if it were a yes or no question, I would say.../YRN Yes-No and the if statement in the interpreter would then parse out the whole big parameter, by searching for the '-' and then having the YES textfrom the '-' to the beginning of the parameter and the NO text from the '-'to the end of the parameter. EVENTS: The next thing you're going to have to learn is event handling, it's the sort of thing that allows NPC's to say "Go kill that evil wolf in the forest" and then, when you do kill it, they say "Thank you so much" Basically, events are like triggers that make things happen, like when you talk to a guy, a door opens and stuff like that. this is anotherthing that would make hardcoding it a big mess, so, what we need is an event holder, which, in an ideal world, would be an array of the booleantype, but since there is no boolean in QB, and we don't want to have to screw around with bits, we'll use STRING * 1 to make bytes. This also hasit's use, becuase instead of using lots of events to record repeated NPC actions, you can just change the number in one event, so basically you can have 1 even per each unique NPC. So here's are event array: ---------------------------------------------------------------------- DIM SHARED events(100) AS STRING * 1 '101 events ---------------------------------------------------------------------- And now, we can make commands to set and do things with this events, here are the new commands: ---------------------------------------------------------------------- $set ### ###$ife ### ### $cmd ---------------------------------------------------------------------- So, $set takes 2, 3 digit numbers, the first one is the event holdernumber, and the second is the new value that that event holder will hold. ---------------------------------------------------------------------- EX: $set 001 100 'sets holder 1 to 100 ---------------------------------------------------------------------- And $ife takes 3 parameters, the event holder to check, the value to check for and the command to do if it's true. ---------------------------------------------------------------------- EX: $ife 001 100 /say it's right ---------------------------------------------------------------------- The IF statements in the interpreter would be this... ---------------------------------------------------------------------- if mid$(hold$, 1, 4) = "$set" then events(val(mid$(hold$, 6, 3))) = chr$(val(mid$(hold$, 10, 3))) endif if mid$(hold$, 1, 4) = "$ife" then if events(val(mid$(hold$, 6, 3))) = chr$(val(mid$(hold$, 10, 3))) then hold$ = mid$(hold$, 14) goto top 'top would be a line label right after the line input line endif endif ---------------------------------------------------------------------- IF Structures: This is a interesting thing to do, I'm not going to give you real code for a proper if structure, becuase I haven't actually made my script engine be able to do it, I use lots of GOTO's and SUB's in my scripts :) Basically, you'll just a need to keep a stack to record the beginningand endings of each and just skip the bits that you should. My newer way, consists of using /+### commands one right after theother, but they only do it like AND, let's say I wanted to have my NPC say "You're a very mean man!" if event 1 was 1, 2 was 10 and 3 was 0. Well, one way I could do it is this... ---------------------------------------------------------------------- /+001 01 /+002 10 /003 00 /say You're a very mean man! ---------------------------------------------------------------------- But if I wanted it do do more than just the one command, I could use a subroutine... ---------------------------------------------------------------------- /+001 01 /+002 10 /+003 00 /cal npc1.. other commands./sub npc1 /col 050/say You're a very mean man!/ret ---------------------------------------------------------------------- There is a flaw with my SUB methods though, and that is that I have no stack, that means I can't call a sub within a sub, now, I could rig that up easily, but I just haven't come across a situation that I need that for, so Ijust haven't.Another problem with my IF structures, is that I wanted something to be this AND (this OR this), I would need 2 commands... (lets say, in Qb, it would be ---------------------------------------------------------------------- EVENT 1 = 1 AND (EVENT 2 = 2 OR EVENT 2 = 3) ---------------------------------------------------------------------- ---------------------------------------------------------------------- /+001 01 /+002 02 /do whatever/+001 01 /+002 03 /do whatever ---------------------------------------------------------------------- Really doesn't mean much, but it just makes the files a little bigger and harder to understand. So that's it really. Legend = * not yet implemented # a number parameter, number of # signs indicates number ofdigits. $ a stringMy set: If you need ideas, here's my complete set of tags and commands: /SAY text$ 'prints text/COL # 'new color number /YRN ans1-ans2 'Asks for an answer, left returns variable SEL = 1,right ' to 0/SLP 'wait for a key /LOC x y 'Locate for new printing position /ON0 ## 'if sel = 0 then goto line number ## /ON1 ## 'if sel = 1 then goto line number ## /3D0 'shuts 3d text off/3D1 'turns 3d text on /NEW 'loads a new TLK file and runs it /END 'end the talk /+### ## /cmd 'if event ### equal to ## then do /cmd (see farbelow) /(### ### ## ## 'if events ### through ### are = to ## goto line ## /=### ## 'event ## is now equal to ## (in that ## order) ' ++ or -- add or subtract from current value /giv ## 'Give item number ## to player * /L## 'Line lable ##, for use with goto's /IMG file$ * 'instead of talk, show image. (would have to be 1sttag) /TIL ### ### ### 'put a tile at x coord ###, y coord ###, use tilenum ### /IFC ### ### ## 'if player coords at x ###, y ### then goto linenumber ' ## /OBJ ### ### ## 'if the object currently talking is at ### ### thengoto ' ##/SND file$ 'plays the Voc file$ /WLK string$ 'string$ is a series of U, D, L and R's that movethe dot. /JMP ## 'immediately jump to line ## /MAP ### ### ### 'actually change the tile in ### ### position totile ### ' if ### is pmx and ### is pmy then it will useplayers XY ' position, can also be in p+# or p-# to add orsubtract ' a number from player position to find pos /IFT ### ### ### ## 'if the tile at ### ### is = ### jump to line ## ' if ### is pmx and ### is pmy then it will useplayers XY ' position, can also be in p+# or p-# to add orsubtract ' a number from player position to find pos /BRK * 'A tag that tells the talk reader whether or not to ' allow the player to escape from the dialogue. /DEL $ ###### 'A delay tag, if $ is V, then it waits for the ' vertical retrace and it's end ##### number oftimes, ' if it's S then the program SLEEP's for #####seconds, ' and if its D then the program does a FOR NEXT loop ' from 1 to ##### (##### doesn't need 0's like00001) /FD+ ## ## ## ### ### ### ### 'a really complex but useful command, ascreen 'fader. The ## ## ## are the R G and Bvalues 'to fade to, the ### is the number offrames, 'almost a delay, while the ### is theamount 'for a partial fade, which is alwaysdependant 'on the first ###, where half of thefirst ### 'is a 50% fade, and the ### and the last### 'is the low and high color numbers tofade 'from and to. Usually 000 and 255 /FD- ## ## ## ### ### ### ### 'Fades back from /FD+, like a fade infrom a 'fade out /MLD ### ### map$ 'loads a new map when the TLK isfinished. /SUB name$ 'at the bottom of the script, one may use ' subroutines that act like GOSUB's, and ' the /SUB command is the declaration,start. /CAL name$ 'Calls the subroutine from the mainscript. /RET 'Marks the end of a SUB, and retunrsscript ' execution to the line from which it was ' called. /WRP ### ### ### ### # * 'Warps the players from coords ###,### to ' coords ###,### usign effect number # Well, I hope some of this helps you. 19day