Aller au contenu

Photo

Best practices


  • Veuillez vous connecter pour répondre
4 réponses à ce sujet

#1
_L_o_B_o_

_L_o_B_o_
  • Members
  • 117 messages
Since this forum has a bunch of good scripters, I think that it would be interesting to share some of our practices. Usually each programmer has his own preferences and the written code becomes something personal. Anyway, with this post I don't try to look for a unique way to create scripts. My aim here is to gather some scripting advices (let's not discuss if they are good or bad), so anybody can pick up those that they find useful.

Here is my contribution:

Naming scripts

When the number of managed scripts increases considerably, sometimes it is difficult to quickly find the one that you want to open. I decided to use the following naming convention, which helped me a lot.

<mod prefix><nnn>sc_<script type>_<script name>

"Script type" can take the following values depending on the resource it is attached to:
cr - Creature
ar - Area
pt - Plot
cs - Cutscene
tr - Trigger
ip - Placeable
dg - Dialog (or conversation)
im - Item

So I had scripts like,

ata100sc_cr_olias -> Just reading its name I know that it is a script attached to a creature.
ata100sc_cs_intro_end -> A script attached to a cutscene as ending script.
ata100sc_dg_olias_adds_pin -> A script used in a conversation branch. 

Unnecessary switch statements

It is also common to copy-paste large "switch" statements from the campaign core scripts and then remove the events that we don't want to override. The problem here is that sometimes the "switch" ends having just one or two "case" statements. The code will work (same way that a bazooka will kill a fly :D), but it is better to use an "if" statement instead. 

Comments

I got used to add the following comments at the beginning of all the scripts:

/*    
   Type:   Script played when a cutscene ends.    
   Owner:  ata102cs_corpses.cut    
   Desc:   Move the player to a new position.
*/

For "Type" I used values like "Creature script", "Script triggered in a conversation", ...
"Owner" is the name of the resource to which the script is attached. In this example, it is a cutscene.
"Desc" is just a short description of what the script does.
I have some more good practices to share, but I'll continue later =]

Modifié par _L_o_B_o_, 30 janvier 2011 - 06:01 .


#2
Proleric

Proleric
  • Members
  • 2 350 messages
The compatibility guidelines are an important aspect of best practice (albeit slightly wider in scope than scripting alone).

#3
TimelordDC

TimelordDC
  • Members
  • 923 messages
I name my scripts exactly the same as the resources they are attached to. For example, if I have an area called tlblori100ar_hillwoods, the area script will be called the same tlblori100ar_hillwoods, with the only difference being that it will be under a folder called tlblori100ar_hillwoods (with all the scripts related to creatures/items/etc in that area).
This way, I don't need a specific script identifier and I can use that space for more descriptive entries.

My convention is:
tlbl<module phase abbrev.><nnn within that phase><resource abbrev - 2 char>_<descriptive name>

I also have my own template scripts created and placed in the scripttemplates folder. Nothing fancy but they contain stripped down/extended versions of the different templates without many of the comments and formatted to how I like them to be.

I also use a similar Comments section (which can be added to the templates so you just have to fill in the relevant sections) at the top though mine looks like

/*
Name: :)
Author:
Function:
*/

I also separate core includes vs my own includes in their own group in the header list. A minor thing but it makes me happy when I look at it :P

Modifié par TimelordDC, 02 février 2011 - 03:51 .


#4
_L_o_B_o_

_L_o_B_o_
  • Members
  • 117 messages
Utility scripts

If you have some functions that are used in more than one script, or just might be needed somewhere else in the future, place them in an utility script. It is the same idea as the available "utility_h" file that you'll probably have already included, but with your own functions. The best name for this script is "utility_h", but since it is already in use, put a prefix to avoid the conflict. My mod is called "A Tale of Adventure", so my 3-letter prefix is "ata". I named my utility script "ata_utility_h".

Here is my file:
codeviewer.org/view/code:16e2

If you have too many utility functions and your script has so many lines that it is hard to manage, then it might be a good option to create more than one utility script. Just put in each file those functions that have something in common. For example, I could create another file named "ata_vector_utility_h" with only the functions that do operations with vectors. 

Generic scripts

Here the idea is the same that I commented for the utility script, but in this case we have functional scripts (no header scripts) that can be used in more than one resource. Following the given definition, they might be also considered templates.

They are also specially useful now that the "Parameter" field is working when setting a condition/action script on a converastion. For example, if I want to check if the player has a certain amount of money during different conversations, the first approach might be to write a script for each amount of money. It is obviously better to take advance of the "Parameter" field and create a generic script that will do exactly the same. 

codeviewer.org/view/code:16e3

Avoid multiple exit points in a function

It is easier to understand the logic of a function if it only has one exit point (return statement).

Avoid this code:

bool multipleExitPoints()
{
    // Do something.

    if (condition1)
    {
        return TRUE;
    }

    // Do something more.

    for (i = 0; i < 10; i++)
    {
        // Do something more.

        if (condition2)
        {
            return TRUE;
        }
    }

    // Do something more.

    return FALSE;
}

Use an auxiliar variable instead:

bool oneExitPoint()
{
    bool bResult = FALSE;

    // Do something.

    if (condition1)
    {
        bResult = TRUE;
    }

    if (!bResult)
    {
        // Do something more.

        i = 0;
        while (i < 10 && !bResult)
        {
            // Do something more.

            if (condition2)
            {
                bResult = TRUE;
            }
            i++;
        }
    }

    if (!bResult)
    {
        // Do something more.
    }

    return bResult;
}

You might think wrongly that the first function is better because it does the same with less code lines. Well, I think it is more valuable having a clear and easily understandable code.

Modifié par _L_o_B_o_, 03 février 2011 - 11:36 .


#5
Apolyon6k

Apolyon6k
  • Members
  • 175 messages
Combining Scripts
When writing scripts I try to combine scripts that are used in the same context like for the same converstion (Conditions or Actions that go beyond setting a mere plot flag) or quests (if it doesn't include too many different stages or is spread over too many areas.
An example would be a condition script for a converstation that checks for different plot flags and could be controlled with the scripting parameters.
Only problem could be keeping track of the different parameter values but there surely is a way to add contants into the toolset with a 2da or keeping detailed notes of parameters per conversation and script.:whistle: