Making IInstruction do stuffAs I said before, IInstruction doesn't do stuff. So why this section? For an example, I want the most basic instruction supported: End Script. Upon executing this command, the script will cease execution. End Script needs no data. I will therefore make a class called CEndScript. It will implement IInstruction. Therefore, you will have to implement all the functionality / state of IInstruction in CEndScript. PrevInstruction, NextInstruction, etc will always remain references to IInstruction classes, because this is how we keep all the instructions compatable with each other. Now, when loading the scripts, how do we differentiate an End Script from another command? Well, how does a CPU recgonise what to do? We use an OpCode. I find that if you use a 32-bit opcode, you'll give your scripting language a maximum library of 4.2 billion different types of instructions. I tend to use the OpCode 0 to mean a read error. If ever the script parser reads the opcode 0 from a file, abort, and crash Windows while you're at it! So I'll use the OpCode = 1 to signify an End Script. CScript_Open( filename ) Declare OpCode as 32bit Integer Declare TempIns as IInstruction Open the file. While Not Eof Read OpCode from file '// When OpCode = 1, create CEndScript Set Temp = New (whichever class signified by the opcode) Temp.Load( file_handle ) Append Temp to be the last element in the linked list. EndWhile Close file End Method This is *very* simplified. No support for child objects. There are ways to make this simple to code, but I'll let you work this out. The important thing to note here is that we're loading the *whole* script in at once - it's not streamed from the disk as it's executing. You might wish to stream it, but that's up to you to implement. Child InstructionsFirst, make sure you understand the previous section. This one extends on it. In the last section I introduced a linear script format, in the form of a linked list. Now, you're more than likely going to have to make an If type instruction. I have Simple If, Compound If, and a Switch (Select Case in VB) which implement all I'll ever want when it comes to decisions. You might decide to be clever and inplement proper looping as well. I'm implementing a Pre-test, Post-test and a For loop in my language. How can we implement this easilly in our language though? Let me write some Visual Basic code here: Sub DoIt() Debug.Print "Doing it!" If Game.Flags(456) < 344 Then Debug.Print "We had best make the flag up to 344!" For Counter = Game.Flags(456) To 344 Game.Flags(456) = Game.Flags(456) + 1 Next Counter Else Debug.Print "All is well." End If End Sub I'll not guarantee that'll work, since I just wrote it, but you'll see several layers of indenting. If you know anything about programming, you'll be indenting your code - it's much easiser to read. And it also makes it much easier to work out a way to implement something similar in our language. Could we not say that the incrementation of Game.Flags(456) is a child instruction of the For loop? And what about that If statement. I'd like to say that it's got 2 children - the True and the False case. A Switch could have any number of children instructions. Let's add 3 extra members to IInstruction:
First, let's get this Child() bit straight. If the above source code were my language, then the If instruction would have 2 children. One would be Debug.Print "We had....." and the other would be Debug.Print "All...". What about the For instruction you say? Well, it's the NextInstruction of Child(0).. In more of a programming sense: CIf.Child(0).NextInstruction. About the ParentInstruction: I find it beneficial to be able to move around my data structures easilly. PrevInstruction takes you to the previously executed instruction (which is mainly for the editor's use), and ParentInstruction takes you back up the tree. It gives a really fast way to escape from the "nesting" of our instructions. It also allows for a instruction called CToStartOfLoop - this is like a continue in c? Trust me, it's very little extra effort, and it makes a lot easier later on. And the ParentInstruction will be null or Nothing (in VB) if the instruction is in the highest level of the script (i.e. anything in line with CScript.FirstInstruction), but you already knew that. I'll leave it up to you to implement the decision and looping specifics. My language doesn't have ending instructions for these types of instructions (i.e. no End If, End Switch, End While, Next Counter, etc). Whenever an instruction's NextInstruction is Nothing, it's eary to use the ParentInstruction to go back to the start of the loop, if necessary (I also have a ParentsChild integer in IInstruction to tell the instruction which child it belongs in.. It saves fumbling around). How can this be loaded from a file? Recursion is always an option for this. VB people: beware of stack overflows! Another part of my game engine *used to* use recursion, and after loading about 3,500 maps, it'd die. I'm told on good authority that this is less of a problem in C++, but I dare say if you tried to load a script with 60,000 instructions in it, the stack would overflow. With that in consideration, you could run the risk of having some smart-arse trying to make your program crash that way, or you could use a single method to load it using a few loops, a user-implemented stack, temporary object references, and a few other tricks. I use that way, but not because I'm concerned about stack overflows (seriously, who in their right mind would want to have to add 4,000 instructions using RPG Studio??), but because I find the code runs faster than a similar recursive algorithm. This might not be the case in C++. Recursion is a lot easier than the alternative though. And chances are, there are many other ways of doing this. I'm not teaching you how to program, so you can work this one out yourself :-) Instruction data / parametersOk, you've implemented CMessageBox. It will show a message box in-game, and it will display some text on it. Where does the text come from? CMessageBox has a variable implemented in it called Msg. It's a String. In the Load method of CMessageBox, all you have to do is load the string from the file handle. Read the linked source code to Script_Teleport.txt. You should see how I implemented all this stuff.. It's a bit messy, but I'm still developing it. I might take this oppotunity to elaborate on a possible file format:
Ok, that was simple :-)
|