Thread: Messages and global scripts?

  1. #1
    Registered User
    Join Date
    Jan 2005
    Posts
    106

    Messages and global scripts?

    Eh, someone mentioned I use these over on the game programming board. However, that sort of escaped the scope of that board. Anyway, I asked several people and none of them really had any idea what they were or how to use them. I guess I'm wondering if any of the guys on this board know what I'm on about. Because I sure don't.

    (Really sorry if this counts as illegal cross-posting. I honestly don't think that this fits with in the scope of game programming though. From what I've heard, it's somewhat advanced and has a wide range of applications).

  2. #2
    Handy Andy andyhunter's Avatar
    Join Date
    Dec 2004
    Posts
    540
    Ok, I attempted to read through your post on the C board and what I gather is you are making a text based game, correct? Additionally I wasn't able to determine if this is suppose to be a 'real time' multiuser game or a single player game. Could you clear that one up for me?
    i don't think most standard compilers support programmers with more than 4 red boxes - Misplaced

    It is my sacred duity to stand in the path of the flood of ignorance and blatant stupidity... - quzah

    Such pointless tricks ceased to be interesting or useful when we came down from the trees and started using higher level languages. - Salem

  3. #3
    Slave MadCow257's Avatar
    Join Date
    Jan 2005
    Posts
    735
    I think this answers your question but I'm not quite sure if I understand the question in the first place but anyways...
    Windows communicates with your program and gives you access to messages which it thinks might be useful to you such as a key has been pressed, the mouse has been double clicked etc. Then your program can either ignore the message or act on it. You should check out a book on windows programming to learn how to use it in your program.

  4. #4
    Registered User
    Join Date
    Jan 2005
    Posts
    106
    Quote Originally Posted by andyhunter
    Additionally I wasn't able to determine if this is suppose to be a 'real time' multiuser game or a single player game.
    Single-player, non-real-time. Although, I'm more interested in the theory behind this and what it is and what else it's useful for than how it relates to game programming, I guess, and searching google for it gives me nothing.

  5. #5
    Handy Andy andyhunter's Avatar
    Join Date
    Dec 2004
    Posts
    540
    Well, basically what I read is that you want a way to control messages between objects in your game. Assuming these active objects exist in a loop that cycles through each object you could build a message queue to store all messages in your program. These messages would be coded with an ID that designates which object it pertained to. Then each object could check for messages, and if found one, remove the message from the queue and process it.
    i don't think most standard compilers support programmers with more than 4 red boxes - Misplaced

    It is my sacred duity to stand in the path of the flood of ignorance and blatant stupidity... - quzah

    Such pointless tricks ceased to be interesting or useful when we came down from the trees and started using higher level languages. - Salem

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    106
    What, so you mean like storing the messages in, say, a linked list or something, and every time the component that may or may not trigger/recieve a message is activated somehow, it searches through the queue, and assuming conditions x, y, and z are go, it runs that message?

  7. #7
    Handy Andy andyhunter's Avatar
    Join Date
    Dec 2004
    Posts
    540
    something like that, yep.
    i don't think most standard compilers support programmers with more than 4 red boxes - Misplaced

    It is my sacred duity to stand in the path of the flood of ignorance and blatant stupidity... - quzah

    Such pointless tricks ceased to be interesting or useful when we came down from the trees and started using higher level languages. - Salem

  8. #8
    Registered User
    Join Date
    Jan 2005
    Posts
    106
    Okay, as for polling this event list...

    See, SDL does type checking on its even poll, I think. I could do that, but I don't think that's what I want.

    The events I have setup would require certain conditions to run. Let's say I've got five arbitrary conditions that must be satisfied. Now, I could have this event polling function run through the whole list and check every single condition, but somehow, this sounds ineffeccient, especially since I'll probably have more than five conditions. Is there a better way to handle this? I'm thinking maybe like a binary tree, or maybe a minmax tree. Or am I approaching the method to scan events in the wrong way?

  9. #9
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well I'm the one who posted this over on the game programming board.

    I will explain.

    The 'global script' is the script that is read by your program at the start of the game. Essentially in game design theory the engine itself is not the game...it is just the code that executes the game.

    The game 'data' is the game. The script is really where the true game is and your engine just acts on the script. At the start of the game you would compile the entire script into static code structures that would be checked periodically. Here might be an example.
    Code:
    struct Vector3
    {
       float x,y,z;
       //....
       //add more code as needed 
    };
    
    class Unit
    {
       //Position
       Vector3 Position;
       
       //Velocity vector
       Vector3 Velocity;
    
       //Rotation (facing)
       Vector3 Rotation;
       public:
          Unit() {}
          
          void Kill(void);
          void SetTarget(Unit *target);
    
          //more functions related to unit manipulation
    };
    
    //Defines an action for an event
    class Action
    {
      //Allows several actions to be fired off by one or more 
      //conditionals
      Action *NextAction;
    
      Unit *UnitPtr;
      public:
        Action() {UnitPtr=NULL;};
        void Attach(Unit *unit) {UnitPtr=unit;};
        
        void Kill(void) {UnitPtr->Kill();};
        void ToUnit(Unit *target) {UnitPtr->SetTarget(target);};
    
    };
    
    class Condition
    {
       //Allows you to specify several conditions to activate event(s)
       Condition *NextCondition;
    
       int m_iCondType;
       public:
          Condition() {}
          
          //add code
    
    };
    
    class Event
    {
       Action *ActionPtr;
       Condition *ConditionPtr;
    
       //Is this event firing?
       bool m_bActive;
     
       //How many times has this event fired?
       int m_iNumTimesFired;
    
       //How many seconds have elapsed since the last time this
       //event fired?
       int m_iElapsed;
       public:
          Event():ActionPtr(NULL),ConditionPtr(NULL) {}
         
          //Bind this event to a condition and an action or series of
          //actions
          void Create(Condition *condptr,Action *actionptr);      
                
          //Will test condition, if true, will fire event and return true -
          //else will return false
          bool IsTrue(void);   
    };
    Now I've just showed a simple skeleton of a basic scripting engine. So now let me demonstrate by using Novalogic's WAC script for Joint Operations and their Delta Force series.

    Code:
    if Elapsed(20) and Never() then
        SSNKill(66557)
        SSNKill(66558)
        SSN2SSN(66559,66700)
        farflash()
    endif
    What this means is:
    Code:
    IF 20 seconds have elapsed since this even last fired
    AND
    this event has NEVER fired before
    THEN
      kill unit with ID of 66557
      kill unit with ID of 66558
      move unit with ID of 66559 to unit with ID of 66700
      create a far flash of lighting 
    ENDIF
    So if you use this scripting language then you know what objects you need to create when you read the script.

    You need an event that tests for 20 seconds having elapsed. This would be a simple check of the iElapsed member of the class. Return true if 20 seconds have elapsed.

    Code:
    if (Event->Elapsed(20) && Event->HasNeverFired())
    {
       //Perform actions
    }
    All you are doing is turning the script language into C++ code at load time.

    It can get quite complex but using the robust features of CString and or std::string you will be able to produce some pretty fancy scripting languages with little effort.

    You could also write a class to handle user variables. No names or anything just stuff like this:

    VarSET(1,1)

    This would set variable 1 to a value of 1.

    Then VarTEST(1,1) would return true if Variable 1 was equal to 1.
    This would be a simple class that held information about 255 or 65535 variables. Your choice.

    Code:
    class CScriptVars
    {
      unsigned int m_uintVars[255];
      public:
        CScriptVars(void) {memset(m_uintVars,0,sizeof(unsigned int));};
    
        bool VarTEST(unsigned int varnum,unsigned int value) 
        {
          return (m_uintVars[varnum]==value);
        }
    
        void VarSET(unsigned int varnum,unsigned int value)
        {
          m_uintVars[varnum]=value;
        }
    
        //add more tests and arithmetic if needed
    };
    With this simple setup you could produce virtually anything you want -totally separate from the game engine. This is the key point. Keep the game data out of the game engine.

    I know this was long....but I hope it helped.

  10. #10
    Registered User
    Join Date
    Jan 2005
    Posts
    106
    Code:
    Event():ActionPtr(NULL),ConditionPtr(NULL) {}
    Okay, what's that line do?

    Also, are these just... global objects? Should I derive a new class for each condition, or do they just need to be given some arbitrary value? And... what do you mean by compiling into a static script?

  11. #11
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    That line is a constructor that has an initializer list.

    You don't need to derive new classes for conditions. A condition is usually a simple test. the only difference is the type of test.

    if (<condition>) then
    <event1>
    <event2>
    <event3>
    endif

    if - starts the if block
    <condition> can be any type of test that returns a bool or evaluates to a bool
    <event> essentially the action object of the condition - can be any number of things
    endif - ends the if block

    You don't have to use this script you can create your own. I'm just trying to show some principles.

    The parser for this type of script would be simple.
    • Extract a word from the script
    • If it's an 'if' - set InsideIfFlag or increment it to support nesting else this is not the start of an if block - pass word on to next portion of parser or simply return
    • Extract word following if - test against known and supported script functions/words etc.
    • Extract next word following condition. If it's another conditional function - repeat previous step - remember logical operator (OR, AND) - can use recursive descent for this
    • Test all conditions
    • Based on logical operators decide whther or not to perform events
    • If condition(s) evaluate to true, execute events one by one - if you allow nested conditions, you still must test to see if the next word is an 'if' or the start of another conditional block. If you don't support nested if's, then you only need to test the next word against supported event functions/keywords
    • After executing one event, test next word/phrase - if you encounter and endif - set InsideIfFlag to false and repeat entire process for next words encountered.


    This is NOT an exhaustive list but more of a guideline. Using this you could put together a very simple script engine.

    Just go through it step by step. Look at this statement.
    Code:
    if VarEQ(1,1) then
       GameOver()
    endif
    1. When you start the InsideIfFlag is false - this means that you cannot have action functions outside of an if block. Any if's followed by another 'if' is invalid. An 'endif' by itself with no preceding 'if' is invalid.
    2. Extract the first word.
    3. It's an 'if' - set InsideIfFlag to true
    4. Extract next word
    5. Since InsideIfFlag is true, we know the next word will not be 'if' (at least in our sample script language) so we set the parser into condition mode or something.
    6. Extract next word.
    7. It's VarEQ(1,1).
    8. For this example this is a function that tests to see if the variable indicated in the first parameter equals the value of the second parameter -> if variable in slot 1 equals 1
    9. Since VarEQ is a function you need to put the parser in function mode. This will then cause the parser to extract the params between the parentheses - but you must match the function call with the prototype of the function - if it doesn't match then flag an error.
    10. Now that you have the first param and the second param - all you need to do is call CScriptVariables::VarEQ(param1,param2)
    11. If this returns true then you know this conditional evaluates to true.
    12. If you wish to support the AND or OR keywords then you must check for those words as well while in conditional mode.
    13. The next word is 'then' - you can choose to ignore this or you can require the script to have it - your choice.
    14. Ok so we know the conditional is true so we stick the parser in event mode.
    15. Extract the next word and eat whitespace. This will allow the script to be formatted nicely for reading, but will still compile correctly. The next word is GameOver(). Well we know that GameOver is a function that will end the game and we know from our prototype (probably in another file) that this requires 0 parameters. So we execute CMyGameApp::EndGame() or something equivalent.
    16. At this point, the game is done. Normally you would execute conditions until you encounter an 'endif'. This marks the end of the if block. Reset the parser - set all flags back to false and repeat the process.


    Note that the parsing is done once when the game loads. You don't want to parse the script every frame of the game. So you must devise a system then will do everything I just said, but can create C++ classes/structures that will already have the script coded into them - in a matter of speaking. This is what I mean by static script. You take the script that the level designer created and you turn it into structures/objects that can be easily tested using C++ code.

    So you might keep a huge list of conditions and events. Testing the conditions and executing events would be a matter of calling the correct functions for the class that controls those objects which would then return values back - and you respond appropriately based on the return values.

    So your script class must be able to access pretty much everything in the game or be given a way to at least alter/manipulate objects within the game world.

    The game script really is a way for a non-programmer or a person w/o access to the source code for your game to manipulate objects and or create events in the game. This essentially is what makes the game...your engine just runs it.
    Last edited by VirtualAce; 02-18-2005 at 10:45 PM.

  12. #12
    Registered User
    Join Date
    Jan 2005
    Posts
    106
    Hm. So I guess where to store and how else to handle this global/static/whatever script thinger is up to me.

    So, back to handling multiple conditions. Could I have a sort of...

    "If condition 1 is true, set current_condition to next condition in linked list. If not, ABORT. If next item in list is null, return pointer to start of list and activate whatever is pointing to condition."

    So, from this point, I have an Event class, which contains my linked list of conditions. I'd probably derive a new class for each command because I'm a creep.

    Then I'd... have a command class, which contains the command name or something and then just points to an event. There'd also be... places for variables and stuff to be passed in. I just don't feel like mentioning it.

    Anyway, then somewhere, I'd either define various meta-commands for all of these function calls or just have some sort of program reading this stuff in.

    I guess my next question is whether or not I should read all of this stuff in/compile/whatever from the beginning or if I should interpret as it goes along. Maybe this just depends on the project. Or the script. I guess I could have some parts of the script compile from the beginning and other parts read in as they're needed.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Global Variables
    By Taka in forum C Programming
    Replies: 34
    Last Post: 11-02-2007, 03:25 AM
  2. Sending windows messages
    By Ideswa in forum Windows Programming
    Replies: 2
    Last Post: 03-02-2006, 01:27 PM
  3. edit box affecting displaying of text?
    By algi in forum Windows Programming
    Replies: 4
    Last Post: 05-04-2005, 03:28 PM
  4. global class pointers
    By dpro in forum Windows Programming
    Replies: 10
    Last Post: 11-17-2004, 06:24 PM
  5. Global hook only works on one window?
    By CornedBee in forum Windows Programming
    Replies: 5
    Last Post: 01-19-2004, 12:25 PM