From The Mana World
Line 1: Line 1:
{{Status_construction}}
{{Status_outdated}}
{{Status_outdated}}
{{Gaps|Needs to be updated with {{ForumThread|13653}} and {{ForumThread|13672}}, which are generally accepted but there might be more discussion}}
{{Gaps|Needs to be updated with {{ForumThread|13653}} and {{ForumThread|13672}}, which are generally accepted but there might be more discussion}}


This is an attempt to standardize the eAthena coding. Any suggestions are welcome to be posted on the discussion page before editing.
This is an attempt to standardize the eAthena coding. Any suggestions are welcome to be posted on the discussion page before editing.
 
=Code Formatting=
== Indentation ==
== Indentation ==
* Code is indented with four spaces.  
* Code is indented with four spaces.  
Line 12: Line 13:


== Code Blocks ==
== Code Blocks ==
* Code blocks should be separated from the others in a dinstinct way; the best way of doing it is to insert a blank line between code blocks.  
* Code blocks should be separated from the others in a dinstinct way: insert a blank line between code blocks.  
 
* Individual blocks should be together No blank lines within a block.  
* Individual blocks should be together (i.e. without blank lines within them).  
 
* The opening brackets should be at the end of the parent line, not in a new line; the closing ones should be in a line of their own.
* The opening brackets should be at the end of the parent line, not in a new line; the closing ones should be in a line of their own.
* newline between if (condition) and conditional_command, except when conditional_command is a goto at the beginning of a major script block (usually only at the beginning of a script), in which case if there are multiple if statements on adjacent lines, the gotos shall be aligned
<span style="color:OrangeRed">'''provide an example'''</span>


== Example ==
Remove unnecessary next;
An example is given by a quest to get a key for a chest:
Remove redundant code such as end; after close;
remove break; instead use end; (requires changing the java converter)
Replace monsters.txt with _mobs.txt except in special cases.
A standard for whitespace and comments.


{| style="width:850px;" border=0 cellspacing="10"  
    ?
|-valign="Top"  
    limit line length? (break long strings using + concatentation)
|<pre>
==Labels and Subfunctions==
// A treasure chest. You need three keys to open it.
* newline before every label
002-4.gat,93,37,0|script|Treasure|111,{
* no newline after a label
* Labels should always start with L_, except those that act as a subfunction, which should start with S_. There must not be a fallthrough or goto to a subfunction label.
<span style="color:OrangeRed">'''decision pending'''</span>
L_CamelCase: Current practice for labels and I don't think that is worth changing,
L_lower_case:, o11c prefers, especially for things like L_close:
* '''Subfunctions''':<span style="color:OrangeRed">'''to be discussed'''</span>
"[...]except those that act as a subfunction, which should start with S_"
Also, what should labels within a subfunction label use? I was thinking LS_ or SL_; loratay currently uses L_SUB_ ... or perhaps this should be refactored out into a standalone function?
''summary'': S_, LS_, SL_, L_SUB_, Sub_, refactor out into a standalone function.
==Comments==
<span style="color:OrangeRed">'''to be discussed'''</span>
* o11c suggests:
"^///" lines for documentation
"^// " lines to be commented out code (because that is what my editor uses automatically to disable code)
"^//[^ /]" for "other".  
Documentation should maybe have doxygen-like tags?
Dislikes boxed comments.
* Actual
// Yellow dog quests
// author: Saturn
// see bluesageConfig for detailed quest description
// NPC Arthur will not make the code for you...
// uses global vars ... f
// calls  global function  funkbeat () located at ... f


    if (TMW_Quest >= 38) goto L_Finished;
//#################################################################################
//# bla blabla - By Smith, reviewed by john                                      #
//# GPL v.2                                                                      #
//#  ...                                                                          #
//#################################################################################
=Variables=
==Document Variables==
in every file, document every variable as one of:


    mes "There is a chest here.";
*account variable (prefix #) (note that there are also ## variable but they don't work in the stable version of the server;)
    mes "Do you want to try to open it?";
*permanent player variable (no prefix)
    next;
*temporary player variable (prefix @) - used after the script close;s or end;s.
    menu
*dynamic player variable (prefix @) - passed into or out of callsub or callfunc
        "Yes.", L_Yes,
*lexical (local) player variable (prefix @) - used only within the function (scripthelp.txt documents that ".@" means this but I don't know if that works)
        "No.", -;
*local constant (prefix @) - not dependent on the player, used only within the function. e.g. lots of @QUEST_FOO_{SHIFT,MASK}
    close;
*global permanent variable (prefix $) (I'm not sure if we have any of these right now)
*npc permanent variable (prefix $) same as above but only used by one NPC
*global temporary variable (prefix $@)
*npc temporary variable (prefix $@) same as above but only used by one NPC, scripthelp.txt mentions prefix "." but I don't know if that works
*special variable (in db/const.txt with a 1 following)
*global constant (in const.txt)


L_Yes:
If we use a consistent method of documenting these, we can then generate a list of all variables by type.
    if(countitem("TreasureKey") < 3) goto L_Not_Enough;
==Variables initialization==
    getinventorylist;
Check for troublesome arrays:
    if (@inventorylist_count == 100 && countitem("TreasureKey") > 3) goto L_TooMany;
A troublesome array is defined as an array that is not
    mes "You opened the chest and found a short bow!";
*initialized all at once
    delitem "TreasureKey", 3;
*initialized by appending elements to the end, for use in a menu
    getitem "ShortBow", 1;
Nothing needs to be done, merely document them. I want this information at hand when I design the new scripting language to minimize conversion pains.
    set TMW_Quest, 38;
I wouldn't be surprised if there were no troublesome arrays at all. If there are only a couple it might be worth refactoring the code to remove them, but that might be a  high-level decision which is beyond the scope of this proposal.
    close;
 
L_Not_Enough:
    mes "It seems that you do not have the right key for this chest yet...";
    close;
 
L_Finished:
    mes "You have already opened this chest.";
    close;
 
L_TooMany:
    mes "You do not have enough room to loot this chest. Maybe you should try again later.";
    close;
}
</pre>
|}
This script starts with describing the NPC (the chest, NPC sprite 111) and its location (map 002-4 X=93, Y=37, in tiles from top left of the map). Then follows what happens on activation. A message is shown (mes), then an option dialog is displayed. Then, when the player has less than 3 keys (item id 537), he is told not to have the right key. If he does, the player looses three keys and receives a short sword (item id 536). This quest in particular is questionable as the explanation given to the player doesn't match the implemented behavior (possibly to make the quest more challenging), but I've put it here because it is short and shows one basic way to use the scripting system.


For more examples of the current system, check out the current scripts in use by the server. Beware though, this could affect your enjoyment of the game as it does spoil some of the mystery. Here's a link to git so you can view them in your browser:
Set dynamic and local @variables to 0 before close;
==Naming Variables==


https://github.com/themanaworld/tmwa-server-data/tree/master/world/map/npc


Note that anything said by an NPC should be put in double quotes ("). You can do that like this: "'''\"'''Hello!'''\"''' she said."


==Using as little variables as you need==
==Using as little variables as you need==
Line 150: Line 171:
[https://github.com/themanaworld/tmwa-server-data tmwa-server-data/world/map/npc/scripts.conf]  
[https://github.com/themanaworld/tmwa-server-data tmwa-server-data/world/map/npc/scripts.conf]  
The file [https://github.com/themanaworld/tmwa-server-data/blob/master/world/map/npc/_import.txt tmwa-server-data/world/map/npc/_import.txt] imports all NPC scripts wich are stored under the respective map name folders, usually under NPC name.
The file [https://github.com/themanaworld/tmwa-server-data/blob/master/world/map/npc/_import.txt tmwa-server-data/world/map/npc/_import.txt] imports all NPC scripts wich are stored under the respective map name folders, usually under NPC name.
=Examples=
== Open a chest and get reward ==
An example is given by a quest to get a key for a chest (in fact 3 keys):


See [[EAthena Scripting Reference]]
{| style="width:850px;" border=0 cellspacing="10"
|-valign="Top"
|<pre>
// A treasure chest. You need three keys to open it.
002-4.gat,93,37,0|script|Treasure|111,{
 
    if (TMW_Quest >= 38) goto L_Finished;
 
    mes "There is a chest here.";
    mes "Do you want to try to open it?";
    next;
    menu
        "Yes.", L_Yes,
        "No.", -;
    close;
 
L_Yes:
    if(countitem("TreasureKey") < 3) goto L_Not_Enough;
    getinventorylist;
    if (@inventorylist_count == 100 && countitem("TreasureKey") > 3) goto L_TooMany;
    mes "You opened the chest and found a short bow!";
    delitem "TreasureKey", 3;
    getitem "ShortBow", 1;
    set TMW_Quest, 38;
    close;
 
L_Not_Enough:
    mes "It seems that you do not have the right key for this chest yet...";
    close;
 
L_Finished:
    mes "You have already opened this chest.";
    close;
 
L_TooMany:
    mes "You do not have enough room to loot this chest. Maybe you should try again later.";
    close;
}
</pre>
|}
This script starts with describing the NPC (the chest, NPC sprite 111) and its location (map 002-4 X=93, Y=37, in tiles from top left of the map). Then follows what happens on activation:
First, the variable ''"TMW_Quest"'' is checked to know if the player already accomplished the quest<span style="color:OrangeRed">'''(the variable should be documented)'''</span>, If he has the script continues at label ''L_Finished'', the player is reminded fe alredy accomplished the task and script finishes, if not the scrip continues. A message is shown (mes), then an option dialog (menu) is displayed with two possible answers : "Yes." or "No.". If the player answers "No." the script stops (close;); if he answers "Yes." the script continues at label ''L_Yes''. Now player is checked to know if he has at least 3 keys, if not script branches to label ''L_Not_Enough'' tells the player he  "has not the right key" and script closes. If he has keys enough, his inventory list is retrieved by the built-in function "getinventorylist" and it's content is checked to know if the player will have room enough to store the reward after the 3 keys use. If not, script goes to label ''L_TooMany'' and script close after a warning message, If yes 3 keys are deleted in player's inventory,  he gets the reward: a Short Bow and the variable TMW_Quest is set to 38.
 
For more examples of the current system, check out the current scripts in use by the server. Beware though, this could affect your enjoyment of the game as it does spoil some of the mystery. Here's a link to git so you can view them in your browser:
 
https://github.com/themanaworld/tmwa-server-data/tree/master/world/map/npc
 
Note that anything said by an NPC should be put in double quotes ("). You can do that like this: "'''\"'''Hello!'''\"''' she said."
=References=
* [[EAthena Scripting Basics]]
* [[EAthena Scripting Reference]]
* [http://forums.themanaworld.org/viewtopic.php?f=13&t=13653 script cleanup/scripting standards proposal]

Revision as of 22:08, 14 November 2012

Outdated template, please use Template:Status Under Construction to mark pages as unfinished. Template:Status outdated

This article has the following gaps: Needs to be updated with Thread 13653 and Thread 13672, which are generally accepted but there might be more discussion

This is an attempt to standardize the eAthena coding. Any suggestions are welcome to be posted on the discussion page before editing.

Code Formatting

Indentation

  • Code is indented with four spaces.
  • Code in the same block should have the same indentation.
  • Labels have no indentation.
  • Menu options are on their own lines and are indented further.
  • When using an if-statement, there should be a line break after the condition and the conditional command should be indented further.

Code Blocks

  • Code blocks should be separated from the others in a dinstinct way: insert a blank line between code blocks.
  • Individual blocks should be together No blank lines within a block.
  • The opening brackets should be at the end of the parent line, not in a new line; the closing ones should be in a line of their own.
  • newline between if (condition) and conditional_command, except when conditional_command is a goto at the beginning of a major script block (usually only at the beginning of a script), in which case if there are multiple if statements on adjacent lines, the gotos shall be aligned

provide an example

Remove unnecessary next; Remove redundant code such as end; after close; remove break; instead use end; (requires changing the java converter) Replace monsters.txt with _mobs.txt except in special cases. A standard for whitespace and comments.

    ?
   limit line length? (break long strings using + concatentation)

Labels and Subfunctions

  • newline before every label
  • no newline after a label
  • Labels should always start with L_, except those that act as a subfunction, which should start with S_. There must not be a fallthrough or goto to a subfunction label.

decision pending

L_CamelCase: Current practice for labels and I don't think that is worth changing,
L_lower_case:, o11c prefers, especially for things like L_close:
  • Subfunctions:to be discussed
"[...]except those that act as a subfunction, which should start with S_"
Also, what should labels within a subfunction label use? I was thinking LS_ or SL_; loratay currently uses L_SUB_ ... or perhaps this should be refactored out into a standalone function?
summary: S_, LS_, SL_, L_SUB_, Sub_, refactor out into a standalone function.

Comments

to be discussed

  • o11c suggests:
"^///" lines for documentation
"^// " lines to be commented out code (because that is what my editor uses automatically to disable code)
"^//[^ /]" for "other". 
Documentation should maybe have doxygen-like tags?
Dislikes boxed comments.
  • Actual
// Yellow dog quests
// author: Saturn
// see bluesageConfig for detailed quest description
// NPC Arthur will not make the code for you...
// uses global vars ... f
// calls  global function  funkbeat () located at ... f
//#################################################################################
//# bla blabla - By Smith, reviewed by john                                       #
//# GPL v.2                                                                       #
//#  ...                                                                          #
//#################################################################################

Variables

Document Variables

in every file, document every variable as one of:

  • account variable (prefix #) (note that there are also ## variable but they don't work in the stable version of the server;)
  • permanent player variable (no prefix)
  • temporary player variable (prefix @) - used after the script close;s or end;s.
  • dynamic player variable (prefix @) - passed into or out of callsub or callfunc
  • lexical (local) player variable (prefix @) - used only within the function (scripthelp.txt documents that ".@" means this but I don't know if that works)
  • local constant (prefix @) - not dependent on the player, used only within the function. e.g. lots of @QUEST_FOO_{SHIFT,MASK}
  • global permanent variable (prefix $) (I'm not sure if we have any of these right now)
  • npc permanent variable (prefix $) same as above but only used by one NPC
  • global temporary variable (prefix $@)
  • npc temporary variable (prefix $@) same as above but only used by one NPC, scripthelp.txt mentions prefix "." but I don't know if that works
  • special variable (in db/const.txt with a 1 following)
  • global constant (in const.txt)

If we use a consistent method of documenting these, we can then generate a list of all variables by type.

Variables initialization

Check for troublesome arrays: A troublesome array is defined as an array that is not

  • initialized all at once
  • initialized by appending elements to the end, for use in a menu
Nothing needs to be done, merely document them. I want this information at hand when I design the new scripting language to minimize conversion pains.
I wouldn't be surprised if there were no troublesome arrays at all. If there are only a couple it might be worth refactoring the code to remove them, but that might be a  high-level decision which is beyond the scope of this proposal.

Set dynamic and local @variables to 0 before close;

Naming Variables

Using as little variables as you need

So there are some quests, which require lots of variables. Think of monster oil quest, Oric and Warum quest etc.

This can often be done by bitmasking: One variable has 32 bits. So a variabe can store 2^32 different numbers: 4294967296

But sometimes you only need numbers from 0 to 15, but more of these variables. but numbers in range 0 to 15 can be stored in 4 bits ( 2^4 = 16 different numbers)

Here is an example how to use bitmasking: Media:Tester.txt

Defining Map Objects

These sections describe how to define map objects.

Warp Definitions

Warps are what move players between maps. They can also be used to move players around a single map, if needed. Warps are defined like this:

map1,startX,startY|warp|name|width,height,map2,endX,endY

Key:

map1
the starting map
startX
the x-coordinate of the starting warp tile
startY
the y-coordinate of the starting warp tile
name
the name of the warp, unused but must be defined
width
the width of the warp
height
the height of the warp
map2
the ending map
endX
the x-coordinate of the tile the player will end up on
endY
the y-coordinate of the tile the player will end up on

Width and height are described in detail here: Warp Details.

Monster Definitions

Monsters are defined like this:

map,x,y,width,height|monster<TAB>name|mobID,count,spawn1,spawn2,event

map
the map the monsters should appear on
x
the x-coordinate of the spawn tile
y
the y-coordinate of the spawn tile
width
the tile width of the spawn area
height
the tile height of the spawn area
name
the name of the mob, unused but must be defined
mobID
the mob identifier of the desired monster (in the monster db)
count
the number to spawn
spawn1
the minimum delay between successive spawns (per individual)
spawn2
the minimum delay between death and respawn (per individual)
event
the script event to fire upon death

A detailed description of position and area can be found here: Mob Details.

NPC Definitions

Script Functions

Actual script functions are stored or imported in the file, regardless rhey are called from a Map, NPC, Mob or item: tmwa-server-data/world/map/npc/scripts.conf The file tmwa-server-data/world/map/npc/_import.txt imports all NPC scripts wich are stored under the respective map name folders, usually under NPC name.

Examples

Open a chest and get reward

An example is given by a quest to get a key for a chest (in fact 3 keys):

// A treasure chest. You need three keys to open it.
002-4.gat,93,37,0|script|Treasure|111,{

    if (TMW_Quest >= 38) goto L_Finished;

    mes "There is a chest here.";
    mes "Do you want to try to open it?";
    next;
    menu
        "Yes.", L_Yes,
        "No.", -;
    close;

L_Yes:
    if(countitem("TreasureKey") < 3) goto L_Not_Enough;
    getinventorylist;
    if (@inventorylist_count == 100 && countitem("TreasureKey") > 3) goto L_TooMany;
    mes "You opened the chest and found a short bow!";
    delitem "TreasureKey", 3;
    getitem "ShortBow", 1;
    set TMW_Quest, 38;
    close;

L_Not_Enough:
    mes "It seems that you do not have the right key for this chest yet...";
    close;

L_Finished:
    mes "You have already opened this chest.";
    close;

L_TooMany:
    mes "You do not have enough room to loot this chest. Maybe you should try again later.";
    close;
}

This script starts with describing the NPC (the chest, NPC sprite 111) and its location (map 002-4 X=93, Y=37, in tiles from top left of the map). Then follows what happens on activation: First, the variable "TMW_Quest" is checked to know if the player already accomplished the quest(the variable should be documented), If he has the script continues at label L_Finished, the player is reminded fe alredy accomplished the task and script finishes, if not the scrip continues. A message is shown (mes), then an option dialog (menu) is displayed with two possible answers : "Yes." or "No.". If the player answers "No." the script stops (close;); if he answers "Yes." the script continues at label L_Yes. Now player is checked to know if he has at least 3 keys, if not script branches to label L_Not_Enough tells the player he "has not the right key" and script closes. If he has keys enough, his inventory list is retrieved by the built-in function "getinventorylist" and it's content is checked to know if the player will have room enough to store the reward after the 3 keys use. If not, script goes to label L_TooMany and script close after a warning message, If yes 3 keys are deleted in player's inventory, he gets the reward: a Short Bow and the variable TMW_Quest is set to 38.

For more examples of the current system, check out the current scripts in use by the server. Beware though, this could affect your enjoyment of the game as it does spoil some of the mystery. Here's a link to git so you can view them in your browser:

https://github.com/themanaworld/tmwa-server-data/tree/master/world/map/npc

Note that anything said by an NPC should be put in double quotes ("). You can do that like this: "\"Hello!\" she said."

References