Hacen más fácil para todos mantener y leer el código escrito, además de darnos más control sobre él.
También pueden actuar como una salvaguarda para prevenir errores en el código.
Solo aceptamos código que esté escrito según los estándares; esto significa que un PR con el que quieras contribuir puede integrarse más rápido si sigues los estándares desde el principio.
Nunca usamos tabs; en su lugar, usamos espacios.
Un tab equivale a 4 espacios y eso es lo que debe usarse en todo el proyecto.
Visual Studio:
Tools -> Options -> Text Editor -> C/C++ -> Tabs -> Smart, 4, 4, Insert spaces.
Notepad++:
Settings -> Preferences -> Language -> Tab size: 4, Replace by space: checked
Comenta siempre el código donde no sea código repetido típico y donde el código no sea autoexplicativo.
Evita incluir hipervínculos en los comentarios del código, ya que pueden quedar desactualizados o rotos con el tiempo. Si un enlace es relevante, inclúyelo en la descripción del pull request en su lugar; se puede referenciar más adelante mediante el historial de Git.
Los comentarios deben colocarse directamente encima del código, o directamente al lado de él.
// A Comment
if (a == b)
if (a == b)
{
a = b; // A Comment
No se permiten espacios en blanco al final de la línea (trailing whitespace).
Tampoco deberías tener espacios innecesarios dentro de un paréntesis.
Incorrecto:
if( var )
if ( var )
Correcto:
if (var)
Se debe evitar usar llaves para las sentencias if que van seguidas de una sola línea.
if (var)
{
me->DoA();
me->DoB();
}
else
me->DoC();
for (uint32 i = 0; i < loopEnd; ++i)
{
DoSomething();
DoSomethingElse();
}
uint32 i = 0;
while (i < 10)
{
DoSomething();
DoSomethingElse();
++i;
}
do
{
DoSomething();
DoSomethingElse();
++i;
} while (i > 0);
Ten en cuenta que las llaves siempre deben empezar en una nueva línea, como se muestra en el ejemplo de arriba.
Las constantes hacen el código más fácil de leer y entender; también proporcionan una salvaguarda y evitan que los números queden hard-coded.
Incorrecto:
if (player->GetQuestStatus(10090) == 1)
me->RemoveFlag(58, 2);
Correcto:
if (player->GetQuestStatus(QUEST_BEAT_UP) == QUEST_STATUS_INCOMPLETE)
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
Las constantes se establecen con #defines, constexpr, o enum/enum class. Si no existe, crea una.
Siempre debe estar presente una acción default en una sentencia switch, aunque sea solo un break.
switch (spells)
{
case SPELL_1:
case SPELL_2:
{
if (moreThanOneLine)
UseBrackets();
break;
}
case SPELL_3:
DoSomethinCool();
[[fallthrough]]
default:
break;
}
Se aconseja encarecidamente evitar usar #define para las constantes. Usa o bien una variable const o un enum si se pueden agrupar varias variables.
Los enums deben tener un nombre. Separa las constantes en diferentes enums según su tipo.
enum Spells
{
SPELL_1 = 1111,
SPELL_2 = 2222,
SPELL_3 = 3333
};
constexpr uint32 SPELL_4 = 4444;
Se prefiere usar enum classes, ya que pueden causar menos sorpresas que podrían llevar a bugs, dado que el enum no se convertirá implícitamente a otros tipos como enteros u otros enums.
enum class Spell : uint32
{
One = 1111,
Two = 2222,
Three = 3333
}
Todas las constantes que almacenamos tienen un prefijo estandarizado.
| PREFIX | Comment |
|---|---|
| SPELL_ | Spell ID |
| NPC_ | creature_template.entry |
| ITEM_ | item_template.entry |
| GO_ | gameobject_template.entry |
| QUEST_ | quest_template.id |
| SAY_ | creature_text.GroupID |
| EMOTE_ | creature_text.GroupID Different prefix from SAY_ to show that this is an emote. |
| MODEL_ | Creature model, DisplayID |
| XX_G | Heroic mode prefix (goes after the other prefix) XX is the max man amount from mode. (OBSOLETE AS OF PATCH 3.2 WITH SpellDifficulty.dbc) |
| RAID_XX | Raid mode prefix (goes before the other prefix) XX is the max man amount from mode. (OBSOLETE AS OF PATCH 3.2 WITH SpellDifficulty.dbc) |
| EVENT_ | Event/Encounter identifier for instances |
| DATA_ | Identifiers in instance used for GUIDs/data not being event/encounter |
| ACHIEV_ | Achievement ID |
Correcto:
SPELL_ENRAGE
SPELL_ENRAGE_H
EVENT_ILLIDAN
DATA_ILLIDAN
ACHIEVE_MAKE_IT_COUNT
¡Nunca uses NOTACIÓN HÚNGARA en los nombres de variables!
para miembros public/protected o variables globales:
uint64 SomeGuid;
uint32 ShadowBoltTimer;
uint8 ShadowBoltCount;
bool IsEnraged;
float HeightData;
para miembros private:
uint64 _someGuid;
uint32 _mapEntry;
uint8 _count;
bool _isDead;
float _heightData;
Los métodos siempre van en UpperCamelCase y sus parámetros en lowerCamelCase
void DoSomething(uint32 someNumber)
{
uint32 someOtherNumber = 5;
}
Usa siempre 'f' después de los valores float al declararlos para evitar warnings de compilación.
float posX = 234.3456f;
Position const PosMobs[5] =
{
{-724.12f, -176.64f, 430.03f, 2.543f},
{-766.70f, -225.03f, 430.50f, 1.710f},
{-729.54f, -186.26f, 430.12f, 1.902f},
{-756.01f, -219.23f, 430.50f, 2.369f},
{-798.01f, -227.24f, 429.84f ,1.446f},
};
Definimos los WorldObjects de esta forma:
GameObject* go;
Creature* creature;
Item* item;
Player* player;
Unit* unit;
Nunca usamos declaraciones múltiples con punteros
Something* obj1, *obj2;
La forma correcta de hacer esto es
Something* obj1;
Something* obj2;
Las referencias se definen de forma similar (el & debe ir pegado al tipo)
Creature& creature;
¡Nunca definas "me" en un script de creature u objeto!
'me' es el puntero a la creature u objeto scripteado.
La palabra clave const siempre debe ir después del nombre del tipo
Player const* player; // player object is constant
Unit* const unit; // pointer to the unit is constant
SpellEntry const* const spell; // both spell and pointer to spell are constant
La palabra clave static siempre debe ponerse la primera
static uint32 someVar = 5;
static float const otherVar = 1.0f;
Todos los archivos de cabecera deben contener header guards
#ifndef MY_HEADER_H
#define MY_HEADER_H
// Header content here
#endif // MY_HEADER_H
Toda la salida de texto de scripts/sistema/comandos de C++ debe usar acore_string siempre que sea posible (p. ej. mensajes de ChatHandler, mensajes del sistema de scripts).
Los diálogos de NPC, emotes y otros textos dentro del juego que se gestionan mediante los sistemas de texto de la base de datos (como creature_text, broadcast_text, etc.) deben seguir usando esos sistemas en lugar de acore_string.
Al añadir nuevas strings, se debe proporcionar la localización para todos los idiomas disponibles.
Consejo: puedes usar IA para ayudarte a traducir las strings de localización.