Constantes et valeurs
Ce que le moteur pose dans votre script avant sa première ligne. Ce ne sont pas des fonctions : on les lit, on ne les appelle pas, et aucune ne rend d'erreur.
Certaines sont vraies et utiles. D'autres existent uniquement pour qu'un script venu de Ninja ne s'arrête pas sur un symbole inconnu, et ne valent rien. La dernière section dit lesquelles, parce que les confondre coûte cher.
Les quatre tableaux d'identifiants
| Valeur | Contient | |
|---|---|---|
ShipsArr | 16 identifiants | Les vaisseaux, du petit transporteur à l'éclaireur. |
DefencesArr | 10 identifiants | Les défenses, les deux missiles compris. |
TechnologiesArr | 16 identifiants | Les recherches, dans l'ordre de l'arbre du jeu. |
BuildingsArr | 23 identifiants | Les bâtiments, planète et lune confondues. |
L'ordre est garanti et ne change pas d'un démarrage à l'autre. Vous pouvez donc indexer, construire un tableau parallèle, ou afficher un rapport toujours dans le même ordre.
for id in ShipsArr {
Print(id) // écrit « SmallCargo », pas 202
}
Un identifiant s'affiche sous son nom, et ce nom est en anglais quelle que soit la langue de votre univers : il est écrit en dur dans la bibliothèque de jeu, pas lu sur vos pages. ID2Str(id) fait la même chose explicitement, et rend Invalid(99999) pour un numéro qu'elle ne connaît pas, plutôt que du vide.
SOLARSATELLITE est dans BuildingsArr, pas dans ShipsArr. Il se construit au chantier spatial, mais le jeu le compte parmi les bâtiments, et une boucle qui relève les niveaux d'une planète doit donc le voir passer là.
Chaque script reçoit sa propre copie des quatre tableaux. Trier ShipsArr ne dérange donc aucun autre script du compte. En revanche vous triez bien votre ShipsArr, pour toute la durée de votre script.
sort = import("sort")
arr = ShipsArr // arr désigne le même tableau, pas une copie
sort.Slice(arr, func(i, j) { return arr[i] < arr[j] })
// ShipsArr est trié lui aussi, jusqu'à la fin de ce script.
Les tableaux dérivés n'existent pas. PlanetBuildingsArr, MoonBuildingsArr, LfTechnologiesArr et les listes de formes de vie sont absents : un script qui les nomme s'arrête sur undefined symbol. Filtrez BuildingsArr vous-même.
Les noms d'identifiants
Chaque identifiant des quatre tableaux a sa constante nommée, et réciproquement. Elles s'écrivent en majuscules.
// Vaisseaux
SMALLCARGO LARGECARGO LIGHTFIGHTER HEAVYFIGHTER CRUISER
BATTLESHIP COLONYSHIP RECYCLER ESPIONAGEPROBE BOMBER
DESTROYER DEATHSTAR BATTLECRUISER CRAWLER REAPER
PATHFINDER
// Défenses
ROCKETLAUNCHER LIGHTLASER HEAVYLASER GAUSSCANNON
IONCANNON PLASMATURRET SMALLSHIELDDOME LARGESHIELDDOME
ANTIBALLISTICMISSILES INTERPLANETARYMISSILES
// Technologies
ESPIONAGETECHNOLOGY COMPUTERTECHNOLOGY WEAPONSTECHNOLOGY
SHIELDINGTECHNOLOGY ARMOURTECHNOLOGY ENERGYTECHNOLOGY
HYPERSPACETECHNOLOGY COMBUSTIONDRIVE IMPULSEDRIVE
HYPERSPACEDRIVE LASERTECHNOLOGY IONTECHNOLOGY
PLASMATECHNOLOGY INTERGALACTICRESEARCHNETWORK
ASTROPHYSICS GRAVITONTECHNOLOGY
// Bâtiments
METALMINE CRYSTALMINE DEUTERIUMSYNTHESIZER SOLARPLANT
FUSIONREACTOR SOLARSATELLITE METALSTORAGE CRYSTALSTORAGE
DEUTERIUMTANK SHIELDEDMETALDEN UNDERGROUNDCRYSTALDEN SEABEDDEUTERIUMDEN
ALLIANCEDEPOT ROBOTICSFACTORY SHIPYARD RESEARCHLAB
MISSILESILO NANITEFACTORY TERRAFORMER SPACEDOCK
LUNARBASE SENSORPHALANX JUMPGATE
Partout où une fonction attend un identifiant, le numéro brut passe aussi : ID2Str(204) et ID2Str(LIGHTFIGHTER) donnent le même résultat.
Missions
| Constante | Valeur | |
|---|---|---|
ATTACK | 1 | |
GROUPEDATTACK | 2 | |
TRANSPORT | 3 | |
PARK | 4 | Stationner sur une position à soi. |
PARKINTHATALLY | 5 | Stationner chez un allié. |
SPY | 6 | |
COLONIZE | 7 | |
RECYCLEDEBRISFIELD | 8 | |
DESTROY | 9 | Destruction de lune. |
MISSILEATTACK | 10 | |
EXPEDITION | 15 | |
SEARCHFORLIFEFORMS | 18 | S'affiche « SearchForLifeform », au singulier. |
Comme les identifiants, une mission s'affiche sous son nom : Print(EXPEDITION) écrit « Expedition », pas 15.
Vitesses
Vingt paliers en tout. Les dix entiers vont de TEN_PERCENT (valeur 1) à HUNDRED_PERCENT (valeur 10). Les dix demi-points s'intercalent : FIVE_PERCENT vaut 0,5, FIFTEEN_PERCENT 1,5, et ainsi jusqu'à NINETY_FIVE_PERCENT, qui vaut 9,5.
TEN_PERCENT TWENTY_PERCENT THIRTY_PERCENT FORTY_PERCENT FIFTY_PERCENT
SIXTY_PERCENT SEVENTY_PERCENT EIGHTY_PERCENT NINETY_PERCENT HUNDRED_PERCENT
FIVE_PERCENT FIFTEEN_PERCENT TWENTY_FIVE_PERCENT THIRTY_FIVE_PERCENT
FORTY_FIVE_PERCENT FIFTY_FIVE_PERCENT SIXTY_FIVE_PERCENT
SEVENTY_FIVE_PERCENT EIGHTY_FIVE_PERCENT NINETY_FIVE_PERCENT
Les demi-points ne sont proposés en jeu qu'à la classe Général. Kepler les expose à tout le monde pour qu'un script écrit pour un autre compte ne s'arrête pas dessus. Un compte Général les envoie tels quels ; un compte d'une autre classe part au cran entier inférieur, et jamais sous 10 % (FIFTY_FIVE_PERCENT part à 50 %, FIVE_PERCENT à 10 %). FlightTime, GetDepartureTime et LowestSpeed chiffrent ce cran-là, et SetSpeed sur un NewFleet() le retient : le calcul et le vol tombent d'accord.
Ce sont des nombres décimaux, et c'est exactement ce qu'attend le paramètre de vitesse de FlightTime.
Types de céleste, formes de vie, classes
| Constante | Valeur | |
|---|---|---|
PLANET_TYPE | 1 | |
DEBRIS_TYPE | 2 | Le champ de débris d'une position. |
MOON_TYPE | 3 | |
NONE_LF_TYPE HUMANS ROCKTAL MECHAS KAELESH | 0 à 4 | Formes de vie. |
NO_CLASS COLLECTOR GENERAL DISCOVERER | 0 à 3 | Classe de jeu. |
NO_ALLIANCE_CLASS WARRIOR TRADER RESEARCHER | 0 à 3 | Classe d'alliance. |
Les trois types de céleste servent vraiment : NewCoordinate(4, 128, 6, MOON_TYPE) et GetEmpire(PLANET_TYPE) les attendent.
Les formes de vie et les classes, non. Aucune fonction ne rend encore ces valeurs : rien ne donne la forme de vie d'une planète, ni votre classe de jeu, ni celle de votre alliance, et les fonctions de formes de vie sont absentes (voir le tableau des manques dans l'introduction). Ces treize constantes ne servent donc aujourd'hui qu'à ne pas faire échouer un script qui les nomme.
Les dimensions de l'univers
| Valeur | Contient | |
|---|---|---|
GALAXIES | un entier | Le nombre de galaxies de votre univers. |
SYSTEMS | un entier | Le nombre de systèmes par galaxie. |
Ces deux valeurs sont lues sur la fiche de votre univers, mais seulement si la session est ouverte au moment où le script démarre. Sans session, elles valent 9 et 499, qui sont les dimensions habituelles et non les vôtres.
Elles sont figées au démarrage du script. Un script lancé avant la connexion gardera 9 et 499 pour toute sa vie, même une fois le compte connecté. Aucune fonction ne rend ces deux nombres à la volée : le seul remède est de relancer le script une fois connecté.
// Balayer une galaxie entière sans coder 499 en dur.
for sys = 1; sys <= SYSTEMS; sys++ {
infos, err = GalaxyInfos(4, sys)
if err != nil { LogWarn(err); continue }
SleepRandMs(400, 900)
}
Le fichier, le serveur, la version
| Valeur | Contient | |
|---|---|---|
FILE __FILE__ | une chaîne | Le nom du script courant, extension comprise : ma-ronde.ank. |
OGAME_SERVER | une fiche | Le serveur : .Name, .Number, .Language, et .Settings. Champs vides sans session. |
VERSION __VERSION__ | une chaîne | Vaut littéralement Kepler 0.1. Voir l'avertissement plus bas. |
OGAME_SERVER n'est pas une chaîne, c'est une fiche, comme chez Ninja. Le nom de l'univers s'y lit OGAME_SERVER.Name.
Printf("%s (s%d-%s)", OGAME_SERVER.Name, OGAME_SERVER.Number, OGAME_SERVER.Language)
Print("vitesse d'économie :", OGAME_SERVER.Settings.EconomySpeed)
Les champs disponibles sont Name, Number, Language, PlayerCount, PlayersOnline, Opened, StartDate, ServerClosed, Prefered, SignupClosed, et Settings. Ce dernier porte les réglages de l'univers : EconomySpeed, FleetSpeedWar, FleetSpeedPeaceful, FleetSpeedHolding, UniverseSize, PlanetFields, DebrisFieldFactorShips, DebrisFieldFactorDefence, ResearchDurationDivisor, EspionageProbeRaids, WreckField, AKS, ServerLabel, ServerCategory, PremiumValidationGift.
EconomySpeed n'est pas toujours un nombre. Selon l'univers, le jeu y met 8 ou "x8". Testez avant de compter avec.
FILE ne sert pas à séparer vos clés de stockage. Chaque script a déjà sa propre mémoire : deux scripts qui rangent la clé dernier.systeme ne se marchent pas dessus, et préfixer ne protège de rien. FILE sert à se nommer, dans une alerte ou une ligne de journal.
SendDiscord(MON_WEBHOOK, FILE + " : débris à " + coord)
Dans !global.ank, FILE vaut toujours !global.ank. Une fonction définie là-bas lit les symboles de l'environnement où elle a été écrite, pas de celui qui l'appelle : elle se nommera !global.ank même appelée depuis ma-ronde.ank.
OGAME_SERVER ne contient ni l'adresse, ni le numéro, ni la langue du serveur, seulement le nom de l'univers. Il est figé au démarrage du script, comme GALAXIES et SYSTEMS : un script lancé avant la connexion le verra vide pour toujours. Pour obtenir la valeur à jour au moment où vous en avez besoin, appelez les fonctions. GetUniverseName(), GetServerNumber() et GetLang() rendent une valeur seule, vide ou nulle sans session. ServerURL() en rend deux : l'adresse et une erreur.
VERSION ne suit pas les versions de Kepler. C'est un texte fixe, écrit une fois dans le programme, qui ne change pas quand vous mettez le robot à jour. Une garde de version recopiée d'un script existant ne fait donc pas ce qu'elle dit :
// ✗ Toujours vrai chez nous, quelle que soit votre version.
if VersionCompare(VERSION, "0.91.8") == -1 {
Print("bot trop ancien")
Exit()
}
VersionCompare ne retient que les nombres d'une chaîne : de Kepler 0.1 il lit 0 puis 1, compare à 0 puis 91, et conclut que votre robot est plus ancien. Le script s'arrête alors qu'il n'y a rien à reprocher à votre installation. Supprimez ce genre de test.
Attendre l'arrêt : OnQuitCh
| Valeur | Contient | |
|---|---|---|
OnQuitCh | un canal | Se ferme quand le script s'arrête. |
C'est le seul canal d'événements disponible. Son emploi normal est de garder un script en vie après qu'il a planifié ses tâches : sans cela, le script arrive au bout de son texte, se termine, et emporte ses ExecAt et ses CronExec avec lui.
CronExec("0 3 * * *", func() { Print("il est trois heures") })
<-OnQuitCh // bloque jusqu'à l'arrêt du script
Il se ferme sur Exit(), sur Terminate(), sur le bouton Arrêter, et à l'extinction du robot. Ninja ne le déclenche que sur Exit ; chez nous, tous les arrêts le ferment.
Deux précautions :
- Les lignes qui suivent
<-OnQuitChne s'exécutent pas. Le canal ne se libère qu'une fois l'arrêt engagé, et le moteur refuse alors l'instruction suivante. Écrivez votre ligne d'adieu avant, ou dans une fonctionOnExit, que le robot appelle après coup, avec son propre délai. - Ne l'employez jamais dans
!global.ank. Ce fichier définit l'environnement commun, son canal ne se ferme jamais, et l'attente bloquerait le chargement des définitions partagées pour tous vos autres scripts.
Les valeurs de façade
Les sept valeurs qui suivent existent pour une seule raison : qu'un script venu de Ninja ne s'arrête pas sur undefined symbol. Elles ne sont reliées à rien. Elles ne lisent ni vos réglages, ni votre licence, ni votre mode d'hébergement.
Six d'entre elles portent deux noms. Ninja les écrit entourées de doubles tirets bas, __IS_CLOUD__ plutôt que IS_CLOUD, et c'est sous cette forme que les scripts venus de chez lui les lisent. Les deux écritures marchent ici et donnent la même valeur.
| Valeur | Vaut toujours | Ce que ça implique |
|---|---|---|
LICENSE_UUID __LICENSE_UUID__ | la chaîne vide | |
LICENSE_USERNAME __LICENSE_USERNAME__ | la chaîne vide | |
LICENSE_EMAIL __LICENSE_EMAIL__ | la chaîne vide | |
LICENSE_BOTS_ALLOWED __LICENSE_BOTS_ALLOWED__ | 0 | Ne veut pas dire « aucun robot autorisé ». |
IS_CLOUD __IS_CLOUD__ | faux | Faux même sur une instance cloud. |
IS_SELF_HOST __IS_SELF_HOST__ | vrai | Vrai même quand ce n'est pas le cas. |
CookieDomain | la chaîne vide | Chez Ninja, une instance cloud y porte son sous-domaine. |
DISCORD_WEBHOOK et TELEGRAM_CHAT_ID ne sont pas des bouchons : ils portent ce que vous avez rempli sur la page Notifications, et SendDiscord(DISCORD_WEBHOOK, msg) part tel quel, sans rien à régler de plus. Voir les notifications.
| Valeur | Vaut | Ce que ça implique |
|---|---|---|
DISCORD_WEBHOOK | le webhook Discord de la page Notifications | Vide si aucun n'est réglé : SendDiscord rend alors une erreur. |
TELEGRAM_CHAT_ID | le salon Telegram de la page Notifications | Zéro si aucun n'est réglé. |
Le piège le plus coûteux est ailleurs : if IS_CLOUD { ... } ne s'exécutera jamais, et un test sur LICENSE_BOTS_ALLOWED lira toujours zéro. Retirez ces branches plutôt que de les laisser mentir en silence.