Choosing a scripting language for game and implementing it

Posted by Radius on Stack Overflow See other posts from Stack Overflow or by Radius
Published on 2010-06-13T11:44:30Z Indexed on 2010/06/13 11:52 UTC
Read the original article Hit count: 320

Filed under:
|
|

Hello, I am currently developing a 3D Action/RPG game in C++, and I would like some advice in choosing a scripting language to program the AI of the game. My team comes from a modding background, and in fact we are still finishing work on a mod of the game Gothic. In that game (which we also got our inspiration from) the language DAEDALUS (created by Piranha Bytes, the makers of the game) is used. Here is a full description of said language.

The main thing to notice about this is that it uses instances moreso than classes. The game engine is closed, and so one can only guess about the internal implementation of this language, but the main thing I am looking for in a scripting language (which ideally would be quite similar but preferably also more powerful than DAEDALUS) is the fact that there are de facto 3 'separations' of classes - ie classes, instances and (instances of instances?).

I think it will be easier to understand what I want if I provide an example. Take a regular NPC. First of all you have a class defined which (I understand) mirrors the (class or structure) inside the engine:

CLASS C_NPC 
{
    VAR INT     id                              ;       //  absolute ID des NPCs
    VAR STRING  name            [5]             ;       //  Namen des NPC
    VAR STRING  slot                            ;           
    VAR INT     npcType                         ;           
    VAR INT     flags                           ;           
    VAR INT     attribute       [ATR_INDEX_MAX] ;           
    VAR INT     protection      [PROT_INDEX_MAX];           
    VAR INT     damage          [DAM_INDEX_MAX] ;           
    VAR INT     damagetype                      ;
    VAR INT     guild,level                     ;           

    VAR FUNC    mission         [MAX_MISSIONS]  ;           
    var INT     fight_tactic                    ;           
    VAR INT     weapon                          ;           

    VAR INT     voice                           ;           
    VAR INT     voicePitch                      ;           
    VAR INT     bodymass                        ;           

    VAR FUNC    daily_routine                   ;       //  Tagesablauf
    VAR FUNC    start_aistate                   ;       //  Zustandsgesteuert

    // **********************                   
    // Spawn                                    
    // **********************                   
    VAR STRING  spawnPoint                      ;       //  Beim Tod, wo respawnen ?
    VAR INT     spawnDelay                      ;       //  Mit Delay in (Echtzeit)-Sekunden

    // **********************                   
    // SENSES                                   
    // **********************                   
    VAR INT     senses                          ;       //  Sinne
    VAR INT     senses_range                    ;       //  Reichweite der Sinne in cm

    // **********************                   
    // Feel free to use                         
    // **********************                   
    VAR INT     aivar           [50]            ;                       
    VAR STRING  wp                              ;           

    // **********************                   
    // Experience dependant                     
    // **********************                   
    VAR INT     exp                             ;       // EXerience Points
    VAR INT     exp_next                        ;       // EXerience Points needed to advance to next level
    VAR INT     lp                              ;       // Learn Points     
};

Then, you can also define prototypes (which set some default values). But how you actually define an NPC is like this:

instance BAU_900_Ricelord (Npc_Default) //Inherit from prototype Npc_Default
{
    //-------- primary data --------

    name        =   "Ryzowy Ksiaze";
    npctype     =   NPCTYPE_GUARD;  
    guild       =   GIL_BAU;      
    level       =   10;
    voice       =   12;
    id          =   900; 

    //-------- abilities --------
    attribute[ATR_STRENGTH]     = 50;
    attribute[ATR_DEXTERITY]    = 10;
    attribute[ATR_MANA_MAX]     = 0;
    attribute[ATR_MANA]         = 0;
    attribute[ATR_HITPOINTS_MAX]= 170;
    attribute[ATR_HITPOINTS]    = 170;

    //-------- visuals --------
    //              animations
    Mdl_SetVisual       (self,"HUMANS.MDS");
    Mdl_ApplyOverlayMds (self,"Humans_Arrogance.mds");
    Mdl_ApplyOverlayMds (self,"HUMANS_DZIDA.MDS");
    //          body mesh     ,bdytex,skin,head mesh     ,headtex,teethtex,ruestung 
    Mdl_SetVisualBody (self,"Hum_Body_CookSmith",1,1,"Hum_Head_FatBald",91 ,  0,-1);

    B_Scale (self); 
    Mdl_SetModelFatness(self,2);

    fight_tactic    =   FAI_HUMAN_STRONG;

    //-------- Talente --------                                    
    Npc_SetTalentSkill  (self,NPC_TALENT_1H,1); 


    //-------- inventory --------                                    

        CreateInvItems (self, ItFoRice,10);
        CreateInvItem (self, ItFoWine);
        CreateInvItems(self, ItMiNugget,40);
        EquipItem  (self, Heerscherstab); 

        EquipItem  (self, MOD_AMULETTDESREISLORDS); 

        CreateInvItem (self, ItMi_Alchemy_Moleratlubric_01);
        //CreateInvItem (self,ItKey_RB_01);

        EquipItem (self, Ring_des_Lebens);

    //-------------Daily Routine-------------
    daily_routine = Rtn_start_900;

};

FUNC VOID Rtn_start_900 ()
{
    TA_Boss         (07,00,20,00,"NC_RICELORD");
    TA_SitAround    (20,00,24,00,"NC_RICELORD_SIT");
    TA_Sleep        (24,00,07,00,"NC_RICEBUNKER_10");
};

As you can see, the instance declaration is more like a constructor function, setting values and calling functions from within. This still wouldn't pose THAT much of a problem, if not for one more thing: multiple copies of this instance. For example, you can spawn multiple BAU_900_Ricelord's, and each of them keeps track of its own AI state, hitpoints etc.

Now I think the instances are represented as ints (maybe even as the id of the NPC) inside the engine, as whenever (inside the script) you use the expression BAU_900_Ricelord it can be only assigned to an int variable, and most functions that operate on NPCs take that int value. However to directly modify its hitpoints etc you have to do something like var C_NPC npc = GetNPC(Bau_900_Ricelord); npc.attribute[ATR_HITPOINTS] = 10; ie get the actual C_NPC object that represents it.

To finally recap - is it possible to get this kind of behaviour in any scripting languages you know of, or am I stuck with having to make my own? Or maybe there is an even better way of representing NPC's and their behaviours that way. The IDEAL language for scripting for me would be C#, as I simply adore that language, but somehow I doubt it is possible or indeed feasible to try and implement a similar kind of behaviour in C#.

Many thanks

© Stack Overflow or respective owner

Related posts about game-development

Related posts about script