Célestes et ressources
Vos planètes et vos lunes, ce qu'elles produisent, ce qu'on y a construit. C'est la famille la plus employée : presque tout script commence par savoir où il est et ce qu'il a.
Ce que la version 13 a changé, et ce que vous n'avez pas à faire
En version 13 du jeu, plusieurs pages ont changé de nature. Les lectures qui les utilisaient échouent chez tout le monde, et leur message ne dit pas la vraie cause :
page=fetchResourcesetpage=fetchTechsrendent désormais la page de jeu entière au lieu du JSON attendu. La lecture accuse alors votre identifiant de céleste (« invalid planet id ») alors qu'il est bon.- la page du commissaire-priseur ne porte plus la variable que la lecture groupée y cherchait, d'où « failed to get resources json », qui laisse croire à un JSON absent.
- l'adresse des curseurs de production a changé de casse, et le serveur répond « An error has occured! ».
Cinq fonctions de cette page ont été réparées. Elles essaient d'abord la voie normale, et prennent une voie de secours quand elle ne répond pas. C'est transparent : vous les appelez comme avant, elles rendent le même nombre de valeurs qu'avant. Le jour où la voie normale répondra de nouveau, le secours ne servira plus, sans que vous ayez une ligne à changer.
| Fonction | Ce que fait le secours | Ce qu'il coûte en plus |
|---|---|---|
GetResources | relit les ressources à la nouvelle adresse | 1 requête |
GetResourcesDetails | la même | 1 requête |
GetAllResources | passe par la page d'empire, planètes puis lunes | 2 requêtes |
GetTechs | recompose le relevé par cinq lectures qui, elles, répondent | 5 requêtes, environ 1,5 s contre 0,3 s |
GetResourceSettings | relit les curseurs sur la page en minuscules | 1 requête |
Ces coûts s'ajoutent à l'essai perdu sur la voie normale, puisque c'est son échec qui déclenche le secours.
Sur un céleste, la même réparation
Ninja propose partout une seconde écriture, sur le céleste : resources, err = celestial.GetResources(). Elle passe par la même réparation que la fonction : même secours, même coût, même résultat, et elle attend comme elle la fin du mode manuel. Les deux écritures se valent.
c = GetCachedCelestial("1:2:3")
res, err = c.GetResources() // ✓ passe par le secours
res, err = GetResources(c.GetID()) // ✓ la même lecture
Cela vaut pour GetResources, GetResourcesDetails et GetTechs sur une planète comme sur une lune, pour GetResourceSettings et GetResourcesProductions sur une planète, et pour Phalanx sur une lune. Jusqu'à la version 1.82.322 comprise, ces méthodes-là échouaient en version 13 : si un de vos scripts les a remplacées par les fonctions, il n'a rien à changer.
Trois précisions :
GetTechs()rend une seule structure. Sur une planète, c'est le relevé entier deGetTechs2, formes de vie comprises ; sur une lune, celui deGetTechs.planet.GetResourceSettings()déclenchait dix tentatives avec attente croissante avant d'abandonner. Mesuré le 02/09/2026 sur un compte réel : 4 min 14 s pendant lesquelles le compte était retenu, sans worker, sans écran, sans navigateur intégré. Comme la fonction, elle renonce désormais au réessai : son premier échec tombe en trois cents millisecondes, et elle lit ensuite la bonne page.planet.GetResourcesProductions()lisait les curseurs par ce même chemin et calculait ensuite sur des curseurs à zéro. Elle lit à présent les bons, et une lecture qui échoue lui fait rendre une erreur plutôt qu'un chiffre faux.
Savoir où l'on est
| Fonction | Rend | |
|---|---|---|
GetUniverseName() | 1 : une chaîne | Le nom de l'univers. |
GetServerNumber() | 1 : un entier | Le numéro du serveur : s152-en donne 152. |
GetLang() | 1 : une chaîne | Le code de langue du serveur, fr, en… |
IsLoggedIn() | 1 : un booléen | Dit si la session est ouverte. |
Printf("%s s%d-%s", GetUniverseName(), GetServerNumber(), GetLang())
Sans session, ces quatre-là rendent la valeur nulle : chaîne vide, zéro, faux. Ce sont les seules de la page à ne rien écrire au journal dans ce cas, parce que cette valeur nulle dit déjà tout ce qu'il y a à dire.
GetLang et GetServerNumber sont propres à Kepler. Ninja les connaît, mais comme méthodes de son objet interne IVMBot, pas comme fonctions offertes à vos scripts.
Savoir qui l'on est
| Fonction | Rend | |
|---|---|---|
CharacterClass() | 1 : un entier | La classe : NO_CLASS, COLLECTOR, GENERAL ou DISCOVERER. |
IsCollector() | 1 : un booléen | Raccourci sur la classe. |
IsGeneral() | 1 : un booléen | Le même. |
IsDiscoverer() | 1 : un booléen | Le même. |
HasCommander() | 1 : un booléen | L'officier est-il engagé. |
HasAdmiral() | 1 : un booléen | Le même. |
HasEngineer() | 1 : un booléen | Le même. |
HasGeologist() | 1 : un booléen | Le même. |
HasTechnocrat() | 1 : un booléen | Le même. |
IsVacationModeEnabled() | 1 : un booléen | Le compte est-il en mode vacances. |
IsPioneers() | 1 : un booléen | Le compte passe-t-il par le lobby « pioneers ». |
Ces onze-là changent les chiffres de tout le reste. Un Collector porte plus, un Général vole plus vite, un Géologue produit un dixième de plus, un Amiral ajoute des emplacements de flotte et d'expédition, un Technocrate coupe un quart de chaque recherche. Un script qui calcule une charge, une durée de vol ou un ordre de construction sans les lire se trompe d'autant, et rien dans sa sortie ne le dira.
if IsCollector() {
Print("charge majorée, vitesse de transporteur majorée")
}
if !HasAdmiral() {
Print("moins d'emplacements de flotte que vous ne croyez")
}
if IsVacationModeEnabled() {
LogWarn("mode vacances : rien ne partira, ce n'est pas une panne du script")
return
}
Tout se lit au cache, sans une requête au jeu. Ces valeurs arrivent avec chaque page complète que le robot charge de toute façon. Les appeler dans une boucle ne coûte donc rien, et n'attend pas son tour dans la file.
IsVacationModeEnabled mérite un mot. Rien ne vole et rien ne se construit tant que le mode vacances est actif. Un script qui l'ignore lit chaque refus du jeu comme une panne de son propre code, et peut insister des heures.
IsPioneers n'est pas une classe, malgré le voisinage : c'est un autre lobby de Gameforge, celui par lequel passent certains serveurs. Le compte y joue de la même façon.
Mettre le compte en vacances
| Fonction | Rend | |
|---|---|---|
SetVacationMode() | 1 : une erreur | Gèle le compte. Quarante-huit heures au minimum. |
Rien ne l'annule avant deux jours - ni vous, ni le support, ni nous. C'est le jeu qui l'impose. C'est aussi la seule fonction de toute cette API dont un appel de trop ne se rattrape pas : une flotte se rappelle, un worker se rallume, une campagne se relance ; un mode vacances, non.
Elle refuse par défaut. Il faut avoir coché « autoriser un script à mettre le compte en vacances » dans les paramètres du robot, onglet « Généralités ». Case décochée, la fonction ne touche pas au jeu et rend une erreur qui nomme la case : un script recopié d'un forum se heurte donc au refus, pas au gel.
err = SetVacationMode()
if err != nil {
LogWarn("vacances refusées : " + err.Error())
}
La case est relue à chaque appel. La décocher reprend effet tout de suite, sans rien redémarrer.
Les planètes et les lunes
| Fonction | Rend | |
|---|---|---|
GetPlanets() | 1 : une liste | Toutes vos planètes. |
GetMoons() | 1 : une liste | Toutes vos lunes. |
GetPlanet(quoi) | 2 : la planète et une erreur | Une planète précise. |
GetMoon(quoi) | 2 : la lune et une erreur | Une lune précise. |
GetCelestial(quoi) | 2 : le céleste et une erreur | Une planète ou une lune précise, l'une ou l'autre. |
GetCelestials() | 2 : la liste et une erreur | Toutes vos planètes et lunes ensemble. |
GetCachedCelestial(quoi) | 1 : un céleste | Le céleste tel que le robot le connaît déjà. |
GetCachedCelestials() | 1 : une liste | Toutes vos planètes et lunes, telles que le robot les connaît déjà. |
GetCachedPlanets() | 1 : une liste | Vos planètes, prises dans le même cache. |
GetCachedMoons() | 1 : une liste | Vos lunes, prises dans le même cache. |
planetes = GetPlanets() // UNE cible : la liste
Print(len(planetes), "planetes")
p, err = GetPlanet("1:2:3") // DEUX cibles, la doc annonce l'erreur
if err != nil { LogError(err) }
GetPlanets et GetMoons rendent une seule valeur. Écrites planetes, err = GetPlanets(), elles laisseraient err non défini, avec les conséquences décrites au second piège.
Ce qui coûte une requête et ce qui n'en coûte pas. GetPlanets, GetMoons, GetPlanet, GetMoon, GetCelestial et GetCelestials relisent tous la même page d'aperçu du jeu, à chaque appel - GetCelestial comme GetCelestials n'y échappent pas, malgré un nom qui ressemble à GetCachedCelestial. GetCachedCelestial, GetCachedCelestials, GetCachedPlanets et GetCachedMoons ne demandent rien : elles répondent depuis ce que le robot a déjà en mémoire. Dans une boucle, préférez toujours une forme Cached.
Comment désigner un céleste. Un céleste se désigne par un identifiant (un nombre) ou par une coordonnée, "1:2:3" ou "M:1:2:3". Le préfixe P, M ou D est optionnel et vaut planète par défaut. Toutes les fonctions de cette page qui prennent un céleste acceptent ces formes. coord, err = ParseCoord("M:1:2:3") fait cette lecture pour vous, sans requête : elle rend une erreur si le préfixe n'est ni P, ni M, ni D.
Un nombre n'est pas vérifié. Les relevés (ressources, bâtiments, chantiers, curseurs) l'envoient tel quel au jeu, sans le chercher dans le cache. C'est voulu : cela vous permet de ranger un identifiant avec Put et de le relire au démarrage suivant, avant même que la liste des célestes soit chargée. En contrepartie, un numéro faux n'est refusé que par le jeu, pas par le robot. GetCachedCelestial, GetFields et GetDiameter, elles, passent par le cache.
Céleste introuvable : GetCachedCelestial rend nil. La méthode que vous enchaînez dessus échouera alors franchement, et le script s'arrêtera. C'est voulu : mieux vaut cela qu'un identifiant inventé qui partirait dans un ordre de flotte.
Choisir la base la plus proche
| Fonction | Rend | |
|---|---|---|
GetSortedCelestials(destination) | 1 : une liste | Vos célestes, du plus proche au plus loin. |
GetSortedPlanets(destination) | 1 : une liste | Vos planètes seules. |
GetSortedMoons(destination) | 1 : une liste | Vos lunes seules. |
base = GetSortedPlanets("4:212:9")[0] // la plus proche de la cible
Print("on part de", base.GetName())
À distance égale, les lunes passent avant les planètes. Une lune porte la coordonnée de sa planète, donc sa distance : c'est ce qui produit à la fois l'ordre M1, P1, M2, P2 quand les distances diffèrent, et « toutes les lunes puis toutes les planètes » quand elles sont égales.
La destination doit être une coordonnée, écrite "4:212:9", ou un objet qui en porte une, un céleste par exemple. Un simple identifiant de céleste n'est pas accepté : la fonction rend alors une liste vide et note l'échec au journal.
Ces trois lectures travaillent sur le cache. Elles ne coûtent aucune requête, et rendent une liste vide sans session.
Les ressources
| Fonction | Rend | |
|---|---|---|
GetResources(céleste) | 2 : les ressources et une erreur | Métal, cristal, deutérium, énergie, matière noire, population, nourriture. |
GetResourcesDetails(céleste) | 2 : le détail et une erreur | Les mêmes, avec la capacité de stockage et la production. |
GetAllResources() | 2 : une table et une erreur | Les ressources de tous les célestes d'un coup. |
r, err = GetResources("1:2:3")
if err != nil { LogError(err); return }
Print(r.Metal, r.Crystal, r.Deuterium)
d, err = GetResourcesDetails("1:2:3")
Print("metal", d.Metal.Available, "sur", d.Metal.StorageCapacity)
Print("production", d.Metal.CurrentProduction, "par heure")
La production est horaire. La page de version 13 la sert à la seconde ; elle est convertie avant de vous parvenir, pour coller à ce que le jeu affiche. C'est la production réelle, officiers, objets et formes de vie compris.
Sur un serveur en version 13, le détail est partiel. La voie de secours remplit ce que la nouvelle page donne, et rien de plus. Restent donc à zéro, sans que ce zéro soit un fait de jeu :
Energy.CurrentProductionetEnergy.Consumption, alors queEnergy.Availableest juste,Food.StorageCapacity,Food.Overproductionet le reste du bloc nourriture,- tout
PopulationsaufAvailable, Darkmatter.PurchasedetDarkmatter.Found.
GetAllResources rend une table dont la clé est l'identifiant du céleste.
toutes, err = GetAllResources()
if err != nil {
LogWarn("relevé groupé indisponible, on repasse céleste par céleste")
} else {
for p in GetPlanets() {
Print(p.GetName(), toutes[p.GetID()].Metal)
}
}
Prévoyez son échec. Elle refuse volontairement de rendre un relevé incomplet : une moitié muette, vos planètes sans vos lunes, vous ferait conclure que vous n'avez pas de lune. Elle rend alors une erreur, et c'est à votre script de retomber sur GetResources, céleste par céleste.
Ce contrôle compare le relevé à la liste des célestes que la session connaît. Tant que cette liste est vide, juste après le démarrage, il ne peut pas jouer.
L'empire en une requête
| Fonction | Rend | |
|---|---|---|
GetEmpire(type) | 2 : une liste et une erreur | Tout d'une nature de célestes : ressources, mines, installations, défenses, vaisseaux. |
// DEUX cibles. Écrit « for c in GetEmpire(PLANET_TYPE) », la boucle tournerait
// deux fois : une sur la liste, une sur l'erreur. C'est le premier piège.
empire, err = GetEmpire(PLANET_TYPE)
if err != nil { LogError(err); return }
for c in empire {
Print(c.Name, c.Coordinate, c.Resources.Metal, c.Supplies.MetalMine)
}
Le type se donne avec PLANET_TYPE ou MOON_TYPE. DEBRIS_TYPE n'a pas de sens ici et ressort en erreur.
Les champs qu'on lit d'une entrée : Name, ID, Type, Coordinate, Diameter, Fields, Temperature, Resources, Supplies (les mines et entrepôts), Facilities, Defenses, Ships et Researches.
C'est la lecture la plus économique du lot : une requête par nature de céleste, là où un relevé unitaire en demanderait quatre par planète. Elle vous coûte aussi moins d'activité : un relevé céleste par céleste inscrit une activité sur chacun d'eux, que vos voisins lisent dans la galaxie.
Gardez un repli. Cette page est optionnelle dans le jeu, et sa forme a déjà changé d'une version à l'autre.
Ce qu'il y a sur un céleste
| Fonction | Rend | |
|---|---|---|
GetResourcesBuildings(céleste) | 2 : les niveaux et une erreur | Les neuf : mines, centrale, réacteur à fusion, satellites, entrepôts. |
GetFacilities(céleste) | 2 : les niveaux et une erreur | Les onze : usines, chantier, labo, dépôt, silo, terraformeur, dock, base lunaire, phalange, porte de saut. |
GetShips(céleste) | 2 : les vaisseaux et une erreur | Ce qui est posé là, pas ce qui vole. |
GetDefense(céleste) | 2 : les défenses et une erreur | Missiles compris. |
GetTechs(céleste) | 6 : bâtiments, installations, vaisseaux, défenses, recherches, une erreur | Tout le relevé d'un coup. |
GetTechs2(céleste) | 8 : les six ci-dessus, plus les bâtiments et les recherches de forme de vie | Le relevé entier d'un céleste. |
GetResearch() | 1 : vos recherches | Elles appartiennent au compte, pas au céleste : aucun argument. |
// SIX cibles. C'est la fonction de la page qui en demande le plus.
bat, inst, vais, def, rech, err = GetTechs("1:2:3")
if err != nil { LogError(err); return }
Print(bat.MetalMine, inst.RoboticsFactory, vais.LargeCargo, rech.Astrophysics)
Ces quatre relevés répondent en version 13, et une cinquième lecture avec eux, GetResearch, qui appartient au compte et non au céleste. C'est sur ces cinq que s'appuie le secours de GetTechs. GetResearch ne rend qu'une valeur, sans erreur : une lecture qui échoue rend des recherches vides et le dit au journal.
GetTechs n'est plus la lecture la moins chère. Tant que le secours sert, elle coûte six requêtes, l'essai perdu compris, là où les quatre relevés séparés en coûtent quatre. Elle rend en plus les recherches, que ces quatre-là ne donnent pas. Si vous n'avez besoin que des mines, appelez GetResourcesBuildings.
Les quatre relevés savent répondre par identifiant, ce qui permet de boucler sur les tableaux de constantes.
bat, err = GetResourcesBuildings("1:2:3")
Print("mine de metal", bat.ByID(METALMINE))
Attention en bouclant sur BuildingsArr, qui compte vingt-trois entrées : ByID d'un relevé de bâtiments ne connaît que les neuf bâtiments de ressources, et celui des installations que les onze installations. Les trois entrepôts protégés, SHIELDEDMETALDEN, UNDERGROUNDCRYSTALDEN et SEABEDDEUTERIUMDEN, ressortent donc toujours à zéro par ce chemin.
GetTechs2 rend le relevé ENTIER, formes de vie comprises, en un seul appel :
// HUIT cibles, et l'erreur en dernier comme chez Ninja.
bat, inst, vais, def, rech, lfBat, lfRech, err = GetTechs2("1:2:3")
if err != nil { LogError(err); return }
Print(bat.MetalMine, inst.RoboticsFactory, rech.Astrophysics)
Elle coûte sept requêtes tant que le secours sert, contre cinq pour GetTechs : les deux lectures de forme de vie s'ajoutent. Un appel au lieu de cinq côté script, et une seule transaction - le céleste ne change pas d'état au milieu du relevé, ce qu'une jointure écrite à la main ne peut pas garantir.
L'exemple de la référence de Ninja est faux sur cette fonction. Il affecte huit cibles sans erreur là où sa propre déclaration met l'erreur en huitième position. C'est la déclaration qui fait foi ici.
Les chantiers en cours
| Fonction | Rend | |
|---|---|---|
GetProduction(céleste) | 3 : la file, les secondes restantes, une erreur | Vaisseaux et défenses au chantier spatial. |
ConstructionsBeingBuilt(céleste) | 4 : bâtiment, secondes, recherche, secondes | Le bâtiment et la recherche en cours. |
file, restant, err = GetProduction("1:2:3")
for q in file {
Print(q.ID, "x", q.Nbr)
}
Print("file vide dans", restant, "secondes")
// QUATRE valeurs, et AUCUNE erreur. Une cinquième cible resterait non définie.
bID, bSec, rID, rSec = ConstructionsBeingBuilt("1:2:3")
if bID != 0 {
Print("en construction :", bID, "encore", bSec, "s")
}
Les trois décomptes sont en secondes, mais pas pour la même raison. GetProduction rend celui que le jeu écrit lui-même, en secondes. ConstructionsBeingBuilt convertit : la bibliothèque de jeu porte ses deux décomptes en nanosecondes, et sans cette conversion dix minutes de chantier se liraient 600 000 000 000.
Zéro se lit « rien en construction », et c'est aussi ce que rend un échec. ConstructionsBeingBuilt n'a pas de valeur de retour où loger une erreur : page illisible ou session fermée, elle rend quatre zéros, comme un céleste au repos. Le seul moyen de les distinguer est le journal, où l'échec est noté. Un script qui relance un chantier sans le vérifier peut donc en lancer un de trop.
ConstructionsBeingBuiltLf, pour les formes de vie, n'existe pas encore.
Les curseurs de production
| Fonction | Rend | |
|---|---|---|
GetResourceSettings(planète) | 2 : les réglages et une erreur | Les sept curseurs de rendement. |
reg, err = GetResourceSettings("1:2:3")
if err != nil { LogError(err); return }
Print(reg.MetalMine, reg.CrystalMine, reg.DeuteriumSynthesizer)
Print(reg.SolarPlant, reg.FusionReactor, reg.SolarSatellite, reg.Crawler)
Planètes seulement. Une lune n'a pas de mines à régler, et vous n'obtiendrez qu'une erreur en lui en demandant.
Un curseur absent ressort à zéro. Une planète sans satellite ni foreuse n'en a que cinq sur sept, et la structure rendue n'a pas de place pour dire « absent ». Ne concluez donc pas d'un zéro que le bâtiment est bridé.
En revanche, une page dont aucun curseur ne serait lisible est refusée franchement, par une erreur. Vous ne lirez jamais « tout à 0 % » sur une planète réglée à cent.
Il n'y a pas de réglage en écriture : SetResourceSettings n'existe pas encore.
La fiche d'un céleste
| Fonction | Rend | |
|---|---|---|
GetFields(céleste) | 1 : les champs, Built et Total | |
GetDiameter(céleste) | 1 : un entier | Le diamètre, en kilomètres. |
ch = GetFields("1:2:3")
Print("libres :", ch.Total - ch.Built)
Print("rayon :", GetDiameter("1:2:3") / 2)
Ces deux-là lisent le cache, sans requête. Elles ne bougent pas d'une session à l'autre, sauf champs gagnés par un terraformeur.
Une seule valeur chacune, et c'est ce qui permet de les mettre dans un calcul : GetDiameter(c) / 2 donne bien la moitié du diamètre. Une fonction qui rendrait deux valeurs, elle, y donnerait zéro sans la moindre erreur. C'est le défaut que ces deux-là avaient avant réparation, et c'est ici qu'il faisait le plus de dégâts.
Ces deux fonctions globales sont propres à Kepler. Ninja ne connaît que les méthodes du céleste, c.GetFields() et c.GetDiameter(), qui marchent aussi et rendent la même chose.
Lancer et annuler un chantier
| Fonction | Rend | |
|---|---|---|
Build(céleste, quoi, nombre) | 1 : une erreur | Bâtiment, technologie, vaisseau ou défense. |
BuildBuilding(céleste, bâtiment) | 1 : une erreur | Refuse ce qui n'est pas un bâtiment. |
BuildTechnology(céleste, technologie) | 1 : une erreur | Refuse ce qui n'est pas une technologie. |
TearDown(céleste, bâtiment) | 1 : une erreur | Démolit un niveau. |
CancelBuilding(céleste) | 1 : une erreur | Annule le chantier en cours. |
CancelResearch(céleste) | 1 : une erreur | Annule la recherche en cours. |
Le céleste s'écrit comme partout ailleurs : une coordonnée "1:2:3", une fiche rendue par GetCachedCelestial, ou un identifiant nu.
Le nombre ne compte que pour ce qui se compte. Zéro sur une mine ou une technologie demande le niveau suivant : c'est la convention de l'outil de référence, pas un cas particulier.
c = GetCachedCelestial("1:2:3")
err = Build(c.GetID(), LIGHTFIGHTER, 5)
if err != nil { LogError("chasseurs :", err) }
Build(c.GetID(), LIGHTLASER, 5)
BuildBuilding(c.GetID(), METALMINE)
BuildTechnology(c.GetID(), ENERGYTECHNOLOGY)
TearDown(c.GetID(), SOLARPLANT)
CancelBuilding(c.GetID())
CancelResearch(c.GetID())
À lire avant de s'en servir : votre script et le Brain visent le même chantier. Le jeu n'en accepte qu'un par céleste, donc le second arrivé est refusé — et lequel des deux arrive en second ne se décide pas, il se constate. Ce n'est pas un défaut du robot, c'est la règle du jeu.
Choisissez donc, céleste par céleste : votre script ou le Brain, jamais les deux. StopBrain() éteint le Brain partout ; pour ne le retirer que d'un céleste, videz sa file depuis le panneau.
Annuler ce qui n'existe pas ne rend AUCUNE erreur. Vérifié en jeu le 05/09/2026 : CancelBuilding et CancelResearch sur un céleste qui ne construit rien rendent nil, comme si le geste avait eu lieu. Ne vous fiez donc pas au retour pour savoir s'il y avait quelque chose à annuler ; lisez ConstructionsBeingBuilt avant, si la réponse vous importe.
Quand il y avait bien un chantier, le jeu rend TOUT. Mesuré en jeu le 05/09/2026 sur un vrai compte : la mine de métal lancée puis annulée dans la même minute a laissé le stock identique à l'unité près. C'est la démolition, TearDown, qui n'en rend que la moitié.
Et ne jugez pas une commande de vaisseaux sur la file de production. Sur un univers rapide, trois petits transporteurs sont finis avant que la lecture suivante n'arrive : la file paraît vide alors que la commande est passée. Comptez les vaisseaux, pas la file.
Les formes de vie
| Fonction | Rend | |
|---|---|---|
GetLfBuildings(céleste) | 2 : les bâtiments et une erreur | Une requête à chaque appel. |
GetLfResearch(céleste) | 2 : les recherches et une erreur | Une requête à chaque appel. |
GetLfBonuses() | 2 : les bonus et une erreur | Relit les bonus dans le jeu. |
GetCachedLfBonuses() | 2 : les bonus et une erreur | Ce que le robot sait déjà. Aucune requête. |
GetPlanetLifeformType(planète) | 1 : la forme de vie | Une requête. Sans erreur : voir plus bas. |
c = GetCachedCelestial("1:2:3")
b, err = GetLfBuildings(c.GetID())
if err != nil { LogError("formes de vie :", err) }
rech, err = GetLfResearch(c.GetID())
Print(rech, err)
bonus, err = GetCachedLfBonuses()
Print(bonus, err)
frais, err = GetLfBonuses()
Print(frais, err)
Les bonus changent vos calculs. Ils portent sur la production, la vitesse et le fret : un script qui chiffre un transport sans eux raisonne sur un parc qui n'existe plus. CalcCargo et la famille des vols en tiennent déjà compte pour vous ; c'est votre propre arithmétique qui a besoin de les lire.
Laquelle des deux fonctions de bonus prendre. GetCachedLfBonuses ne coûte rien et suffit dans une boucle : les bonus ne bougent qu'avec vos recherches. GetLfBonuses relit le jeu, ce qui n'a d'intérêt qu'après en avoir terminé une. Le cache d'un compte qui vient de se connecter est vide et rend une erreur, plutôt que des zéros qui se liraient comme une vérité.
Les recherches valent pour le compte entier, mais le jeu les range sur le céleste depuis lequel on les consulte : d'où l'argument, que l'outil de référence demande aussi.
Quand une lecture échoue
Deux régimes cohabitent sur cette page, et la colonne « Rend » vous dit lequel s'applique.
Les fonctions qui rendent une erreur vous la remettent : testez-la.
Les autres n'ont nulle part où la loger. Elles rendent la valeur nulle, liste vide, zéro, nil, ou quatre zéros pour ConstructionsBeingBuilt, et écrivent une ligne au journal du robot, page Journaux, au niveau Warn :
api de célestes : lecture impossible script=ma-passe fonction=GetPlanets err=compte non connecté
Cette ligne ne va pas dans la console de votre script, seulement au journal. C'est le premier endroit à regarder quand un script se met à croire que vous n'avez plus de planètes.
Seules GetUniverseName, GetServerNumber, GetLang et IsLoggedIn se taisent : leur valeur nulle dit déjà « pas de session ».
Les formes de vie, au-delà des niveaux
| Fonction | Rend | |
|---|---|---|
CancelLfBuilding(céleste) | 1 : une erreur | Annule le bâtiment de forme de vie en cours. |
GetLfResearchDetails(céleste) | 2 : le détail et une erreur | Coûts, durées et ce qui est ouvert. |
La file des formes de vie est SÉPARÉE de celle des bâtiments ordinaires. Annuler l'une ne touche pas l'autre, et un céleste peut construire dans les deux à la fois : CancelBuilding et CancelLfBuilding ne se remplacent donc pas.
GetLfResearchDetails lit une page du jeu, là où GetLfResearch se contente des niveaux déjà connus. À ne pas mettre dans une boucle sur vingt célestes.
Les chapitres, et le choix d'une recherche de forme de vie
| Fonction | Rend | |
|---|---|---|
GetChapter(chapitre) | 2 : le chapitre et une erreur | Ses tâches, et l'état de chacune. |
ChapterCollectReward(tâche) | 1 : une erreur | Ramasse la récompense d'une tâche. |
ChapterClaimAll(chapitre) | 1 : une erreur | Ramasse tout ce qui est ramassable. |
SelectLfResearchSelect(planète, emplacement) | 1 : une erreur | Valide la recherche proposée. |
SelectLfResearchRandom(planète, emplacement) | 1 : une erreur | En retire une autre au sort. |
SelectLfResearchArtifacts(planète, emplacement, techno) | 1 : une erreur | L'échange contre des artefacts. |
FreeResetTree(planète, palier) | 1 : une erreur | Vide un palier entier. Gratuit, en nombre limité. |
BuyResetTree(planète, palier) | 1 : une erreur | Le même geste, contre de la matière noire. |
Un chapitre rapporte sans rien risquer : il distribue des ressources et des objets contre des tâches déjà accomplies. Il n'y a donc aucune raison de ne pas les ramasser, sinon qu'il faut y penser tous les jours — ce qu'un script fait mieux qu'un joueur.
CronExec("@09h00", func() {
err = ChapterClaimAll(4006) // ← à vous : l'identifiant du chapitre
if err != nil { LogError("chapitre :", err) }
})
ChapterClaimAll est propre à Kepler, et c'est un raccourci que l'outil de référence n'a pas : il oblige à boucler sur les tâches et à ramasser une par une. Le jeu sait le faire d'un seul appel, et vingt tâches ramassées à la main, ce sont vingt requêtes pour un geste qu'il compte comme un.
L'identifiant d'une tâche n'est pas celui de son chapitre. Les deux se ressemblent et ne s'échangent pas : ChapterCollectReward veut celui de la tâche, que GetChapter vous donne.
SelectLfResearchRandom coûte, et ne se défait pas : ce qui était proposé dans l'emplacement est perdu. Un script qui tire en boucle jusqu'à obtenir ce qu'il veut paiera chaque tour.
Les trois SelectLfResearch* veulent une planète : les recherches de forme de vie n'existent pas sur une lune, et une lune passée à leur place rend une erreur qui la nomme.
Les deux ResetTree vident un palier, et c'est la moitié qui manquait à la boucle : lire ce qui est proposé, le prendre s'il convient, tout remettre à zéro s'il ne convient pas, recommencer. SelectLfResearchRandom en approche, mais elle retire une case au sort — elle ne vide pas un palier.
p = GetCachedCelestial("1:2:3").GetID()
if GetPlanetLifeformType(p) != KAELESH {
return // ce script ne sait traiter que les Kaelesh
}
err = FreeResetTree(p, 1) // le palier 1, de nouveau vierge
if err != nil {
LogError("plus de remise à zéro gratuite :", err)
// err = BuyResetTree(p, 1) // ← celle-ci coûte de la matière noire
}
Le palier va de 1 à 3, et rien d'autre ne se tente : un autre nombre est refusé avant que la moindre requête parte.
Le vidage ne se défait pas. Tout ce qui était choisi dans le palier est perdu, et les points dépensés avec. C'est bien ce qu'on lui demande, mais un script qui se trompe de palier ne peut rien rattraper.
Le jeu n'offre qu'un nombre limité de remises à zéro gratuites, et personne ne dit combien — ni la bibliothèque, ni l'outil de référence, ni Kepler. Il n'y a pas moyen de le savoir à l'avance : on essaie, et on lit l'erreur. C'est pour cela que l'exemple ci-dessus enchaîne sur la version payante plutôt que de compter les coups.
BuyResetTree dépense de la matière noire, qui s'achète avec de l'argent réel. Le robot, lui, n'en dépense jamais de sa propre initiative : cette fonction n'existe que parce qu'un script est un geste du joueur, qui écrit lui-même le nom de ce qu'il dépense.
Le prix ne se lit nulle part avant de payer, ni chez nous ni dans le jeu : on l'apprend en regardant sa réserve baisser. Mesuré une fois, le 22/09/2026, sur un palier 2 en univers v13 : 8 000. Rien ne dit que ce soit le même prix partout, ni qu'il ne monte pas avec le nombre de remises à zéro déjà faites — c'est une mesure, pas un tarif. Un script qui l'appelle en boucle vide une réserve qui s'achète avec de l'argent réel.
GetPlanetLifeformType rend un nombre, pas un nom : 0 aucune, 1 HUMANS, 2 ROCKTAL, 3 MECHAS, 4 KAELESH. Les constantes du même nom existent, et == KAELESH se compare bien. Print affichera le chiffre.
Elle ne rend pas d'erreur, comme l'outil de référence la déclare. Elle lit pourtant une page du jeu, qui peut échouer : elle rend alors 0, et l'échec part à la console du script et au journal — il n'est pas muet, il est ailleurs que dans le retour. Une lune rend 0 elle aussi, et là c'est la bonne réponse.
Elle coûte une page pleine, à chaque appel. Douze planètes relues à chaque tour de boucle, ce sont douze pages par tour pour une donnée qui ne change pratiquement jamais : lisez-la une fois, gardez-la.
Les curseurs de production, et le prix sur place
| Fonction | Rend | |
|---|---|---|
NewResourceSettings(métal, cristal, deutérium, solaire, fusion, satellite, foreuse) | 1 : des réglages | Compose les sept curseurs. |
SetResourceSettings(planète, réglages) | 1 : une erreur | Les applique. |
TechnologyDetails(céleste, quoi) | 2 : le détail et une erreur | Prix, durée et niveau, sur ce céleste. |
Les sept comptent, et c'est le piège. Le jeu applique le réglage ENTIER, pas la différence. Un script qui ne veut changer que la mine de métal doit donc relire les six autres et les reposer telles quelles — sans quoi il les met toutes à zéro, et la planète cesse de produire sans un mot.
c = GetCachedPlanets()[0]
avant, err = GetResourceSettings(c.GetID())
if err != nil { LogError(err); return }
// On ne change QUE le deutérium : les six autres sont recopiés.
apres = NewResourceSettings(avant.MetalMine, avant.CrystalMine, 100,
avant.SolarPlant, avant.FusionReactor, avant.SolarSatellite, avant.Crawler)
err = SetResourceSettings(c.GetID(), apres)
Les curseurs vont de zéro à cent, par pas de dix : le jeu refuse les autres. Un curseur à zéro arrête la mine, il ne la met pas au minimum.
SetResourceSettings veut une planète : une lune ne produit rien, et une lune passée à sa place rend une erreur qui la nomme.
TechnologyDetails demande au jeu, là où GetPrice calcule. La différence tient à un mot : GetPrice chiffre un niveau qu'on lui donne, celle-ci demande ce qu'il en coûte ici, avec les installations, les bonus de forme de vie et les réductions de ce céleste-là. C'est une page du jeu — une requête par appel — et elle dit en plus si la démolition est ouverte, ce qu'aucun calcul ne sait.